| 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; |
| } |