Index: lib/typedObjects/objectTypes.js |
=================================================================== |
--- a/lib/typedObjects/objectTypes.js |
+++ b/lib/typedObjects/objectTypes.js |
@@ -12,23 +12,24 @@ |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
*/ |
"use strict"; |
-let {fixedPropertyDescriptor, getViewsForType, defineProperties} = require("typedObjects/utils"); |
+let {fixedPropertyDescriptor, getViewsForType, defineProperties, alloc, dealloc} = require("typedObjects/utils"); |
let {Reference, TypedReference} = require("typedObjects/references"); |
let {uint8, uint32} = require("typedObjects/primitiveTypes"); |
+let {createArrayType} = require("typedObjects/arrayTypes"); |
-const STATE_UNINITIALIZED = 0; |
-const STATE_CREATED = 1; |
-const STATE_RELEASING = 2; |
+const STATE_UNINITIALIZED = exports.STATE_UNINITIALIZED = 0; |
+const STATE_CREATED = exports.STATE_CREATED = 1; |
+const STATE_RELEASING = exports.STATE_RELEASING = 2; |
/** |
* List of registered types (typeId is the index in that array). |
*/ |
let types = []; |
function fromReference(reference) |
{ |
@@ -42,60 +43,27 @@ function fromReference(reference) |
}); |
} |
else |
return null; |
} |
function create() |
{ |
- let {bufferIndex, byteOffset} = this.firstFree; |
- if (bufferIndex >= 0) |
- { |
- // There is still a free spot, simply move on firstFree reference |
- [this.firstFree.bufferIndex, this.firstFree.byteOffset] = |
- [this.firstFree.targetBufferIndex, this.firstFree.targetByteOffset]; |
- } |
- else |
- { |
- let viewTypes = this.viewTypes; |
- let views = this.views; |
- let byteLength = this.byteLength | 0; |
- let bufferSize = this.bufferSize | 0; |
- |
- // Create new buffer and use the first element of it |
- let buffer = new ArrayBuffer(byteLength * bufferSize); |
- bufferIndex = (this.buffers.push(buffer) | 0) - 1; |
- byteOffset = 0; |
- for (let i = 0, l = viewTypes.length | 0; i < l; i++) |
- views[i].push(new viewTypes[i](buffer)); |
- |
- // Mark last element of the new buffer as the last free spot |
- this.firstFree.bufferIndex = bufferIndex; |
- this.firstFree.byteOffset = (bufferSize - 1) * byteLength; |
- this.firstFree.targetBufferIndex = -1; |
- |
- // Make each remaining element of the new buffer point to the next one |
- for (let i = bufferSize - 2; i >= 1; i--) |
- { |
- let nextByteOffset = this.firstFree.byteOffset; |
- this.firstFree.byteOffset = nextByteOffset - byteLength; |
- this.firstFree.targetBufferIndex = bufferIndex; |
- this.firstFree.targetByteOffset = nextByteOffset; |
- } |
- } |
+ let [bufferIndex, byteOffset] = alloc(this.firstFree, this.byteLength, |
+ this.bufferSize, this.buffers, this.viewTypes, this.views); |
let result = Object.create(this.proto, { |
typeId: fixedPropertyDescriptor(this.typeId), |
bufferIndex: fixedPropertyDescriptor(bufferIndex), |
byteOffset: fixedPropertyDescriptor(byteOffset) |
}); |
result._state = STATE_UNINITIALIZED; |
- for (let [prop, value] of this.cleanupValues) |
+ for (let [prop, value] of this.initialValues) |
result[prop] = value; |
result._state = STATE_CREATED; |
result._refCount = 1; |
if (this.constructor) |
this.constructor.apply(result, arguments); |
return result; |
} |
@@ -108,57 +76,51 @@ function free(obj) |
{ |
this.destructor.call(obj); |
if (obj._refCount | 0) |
throw new Error("Reference count is no longer zero after calling the destructor"); |
} |
} |
finally |
{ |
- for (let [prop, value] of this.cleanupValues) |
+ for (let [prop, value] of this.initialValues) |
obj[prop] = value; |
- // Mark object as first free spot |
- let oldFreeBufferIndex = this.firstFree.bufferIndex; |
- let oldFreeByteOffset = this.firstFree.byteOffset; |
- this.firstFree.bufferIndex = obj.bufferIndex; |
- this.firstFree.byteOffset = obj.byteOffset; |
- this.firstFree.targetBufferIndex = oldFreeBufferIndex; |
- this.firstFree.targetByteOffset = oldFreeByteOffset; |
+ dealloc(this.firstFree, obj.bufferIndex, obj.byteOffset); |
} |
} |
function createGetter(offset) |
{ |
offset = offset | 0; |
let views = Array.prototype.slice.call(arguments, 1); |
let reference = new Reference(types, views); |
- return function() |
+ return function(bufferIndex, byteOffset) |
{ |
- reference.bufferIndex = this.bufferIndex | 0; |
- reference.byteOffset = (this.byteOffset | 0) + offset; |
+ reference.bufferIndex = bufferIndex | 0; |
+ reference.byteOffset = (byteOffset | 0) + offset; |
return fromReference(reference); |
}; |
} |
function createSetter(typeId, offset) |
{ |
typeId = typeId | 0; |
offset = offset | 0; |
let views = Array.prototype.slice.call(arguments, 2); |
let reference = new Reference(types, views); |
- return function(value) |
+ return function(bufferIndex, byteOffset, value) |
{ |
if (value && !isInstance(typeId, value)) |
throw new Error("Incompatible type"); |
- reference.bufferIndex = this.bufferIndex | 0; |
- reference.byteOffset = (this.byteOffset | 0) + offset; |
+ reference.bufferIndex = bufferIndex | 0; |
+ reference.byteOffset = (byteOffset | 0) + offset; |
if ((this._state | 0) > STATE_UNINITIALIZED) |
{ |
let oldValue = fromReference(reference); |
if (oldValue) |
oldValue.release(); |
} |
@@ -236,22 +198,31 @@ function extend(parentTypeInfo, typeDesc |
if (name in methods) |
type = createSubclassMethod(type, methods[name].value); |
methods[name] = fixedPropertyDescriptor(type); |
} |
else |
throw new Error("Unrecognized type " + type + " given for property " + name); |
} |
+ // Combine inherited watchers with the ones specified for this object |
+ let watchers = parentTypeInfo && parentTypeInfo.watchers; |
+ if (meta.watch) |
+ { |
+ watchers = Object.create(watchers); |
+ for (let key in meta.watch) |
+ watchers[key] = meta.watch[key]; |
+ } |
+ |
let proto = {}; |
let buffers = []; |
let viewTypes = []; |
let views = []; |
- let cleanupValues = []; |
- let byteLength = defineProperties(proto, properties, viewTypes, views, 0, cleanupValues); |
+ let initialValues = []; |
+ let byteLength = defineProperties(proto, properties, viewTypes, views, 0, watchers, initialValues); |
Object.defineProperties(proto, methods); |
// Round up to be a multiple of the maximal property size |
byteLength = ((byteLength - 1) | (maxReferenceLength - 1)) + 1; |
// We need to be able to store a typed reference in the object's buffer |
byteLength = Math.max(byteLength, TypedReference.byteLength) | 0; |
let typedReferenceViews = getViewsForType(TypedReference, viewTypes, views); |
@@ -279,37 +250,39 @@ function extend(parentTypeInfo, typeDesc |
let typeId = types.length | 0; |
let typeInfo = { |
byteLength: byteLength, |
bufferSize: "bufferSize" in meta ? Math.max(meta.bufferSize | 0, 2) : 128, |
firstFree: new TypedReference(typeId, typedReferenceViews), |
proto: proto, |
properties: properties, |
methods: methods, |
+ watchers: watchers, |
buffers: buffers, |
viewTypes: viewTypes, |
views: views, |
- cleanupValues: cleanupValues, |
+ initialValues: initialValues, |
typeId: typeId, |
parentTypeInfo: parentTypeInfo, |
constructor: constructor, |
destructor: destructor |
}; |
let result = create.bind(typeInfo); |
Object.defineProperties(result, { |
byteLength: fixedPropertyDescriptor(byteLength), |
referenceLength: fixedPropertyDescriptor(Reference.byteLength), |
viewTypes: fixedPropertyDescriptor(Reference.viewTypes), |
- cleanupValue: fixedPropertyDescriptor(null), |
+ initialValue: fixedPropertyDescriptor(null), |
typeId: fixedPropertyDescriptor(typeId), |
extend: fixedPropertyDescriptor(extend.bind(null, typeInfo)), |
isInstance: fixedPropertyDescriptor(isInstance.bind(null, typeId)), |
+ Array: fixedPropertyDescriptor(createArrayType.bind(null, result)), |
createGetter: fixedPropertyDescriptor(createGetter), |
createSetter: fixedPropertyDescriptor(createSetter.bind(null, typeId)) |
}); |
types.push(typeInfo); |
return result; |
} |