Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/typedObjects/objectTypes.js

Issue 6213754488356864: Issue 258 - [Typed objects] Implement a garbage collection mechanism (Closed)
Patch Set: Updated inline documentation Created April 28, 2014, 8:22 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/typedObjects.js ('k') | lib/typedObjects/utils.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/typedObjects/objectTypes.js
===================================================================
--- a/lib/typedObjects/objectTypes.js
+++ b/lib/typedObjects/objectTypes.js
@@ -14,16 +14,21 @@
* 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 {Reference, TypedReference} = require("typedObjects/references");
+let {uint8, uint32} = require("typedObjects/primitiveTypes");
+
+const STATE_UNINITIALIZED = 0;
+const STATE_CREATED = 1;
+const STATE_RELEASING = 2;
/**
* List of registered types (typeId is the index in that array).
*/
let types = [];
function fromReference(reference)
{
@@ -78,21 +83,54 @@ function create()
}
}
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)
+ result[prop] = value;
+ result._state = STATE_CREATED;
+ result._refCount = 1;
+
if (this.constructor)
this.constructor.apply(result, arguments);
return result;
}
+function free(obj)
+{
+ try
+ {
+ if (this.destructor)
+ {
+ 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)
+ 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;
+ }
+}
+
function createGetter(offset)
{
offset = offset | 0;
let views = Array.prototype.slice.call(arguments, 1);
let reference = new Reference(types, views);
return function()
{
@@ -111,21 +149,30 @@ function createSetter(typeId, offset)
let reference = new Reference(types, views);
return function(value)
{
if (value && !isinstance(typeId, value))
throw new Error("Incompatible type");
reference.bufferIndex = this.bufferIndex | 0;
reference.byteOffset = (this.byteOffset | 0) + offset;
+
+ if ((this._state | 0) > STATE_UNINITIALIZED)
+ {
+ let oldValue = fromReference(reference);
+ if (oldValue)
+ oldValue.release();
+ }
+
if (value)
{
reference.typeId = value.typeId;
reference.targetBufferIndex = value.bufferIndex;
reference.targetByteOffset = value.byteOffset;
+ value.retain();
}
else
reference.typeId = -1;
};
}
/**
* Overridden methods get the respective method of the superclass as the first
@@ -193,58 +240,72 @@ function extend(parentTypeInfo, typeDesc
else
throw new Error("Unrecognized type " + type + " given for property " + name);
}
let proto = {};
let buffers = [];
let viewTypes = [];
let views = [];
- let byteLength = defineProperties(proto, properties, viewTypes, views, 0);
+ let cleanupValues = [];
+ let byteLength = defineProperties(proto, properties, viewTypes, views, 0, cleanupValues);
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);
- // Take constructor from meta parameter, allow calling superclass constructor.
+ // Take constructor and destructor from meta parameters, allow calling
+ // superclass constructor/destructor.
let constructor = parentTypeInfo && parentTypeInfo.constructor;
if (meta.hasOwnProperty("constructor") && typeof meta.constructor == "function")
{
if (constructor)
constructor = createSubclassMethod(meta.constructor, constructor);
else
constructor = meta.constructor;
}
+ let destructor = parentTypeInfo && parentTypeInfo.destructor;
+ if (meta.hasOwnProperty("destructor") && typeof meta.destructor == "function")
+ {
+ if (destructor)
+ destructor = createSubclassMethod(meta.destructor, destructor);
+ else
+ destructor = meta.destructor;
+ }
+
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,
buffers: buffers,
viewTypes: viewTypes,
views: views,
+ cleanupValues: cleanupValues,
typeId: typeId,
parentTypeInfo: parentTypeInfo,
- constructor: constructor
+ 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),
typeId: fixedPropertyDescriptor(typeId),
extend: fixedPropertyDescriptor(extend.bind(null, typeInfo)),
isinstance: fixedPropertyDescriptor(isinstance.bind(null, typeId)),
createGetter: fixedPropertyDescriptor(createGetter),
createSetter: fixedPropertyDescriptor(createSetter.bind(null, typeId))
});
@@ -264,17 +325,35 @@ function isinstance(typeId, obj)
if ((typeInfo.typeId | 0) == typeId)
return true;
typeInfo = typeInfo.parentTypeInfo;
}
return false;
}
let ObjectBase = exports.ObjectBase = extend(null, {
+ _state: uint8,
+ _refCount: uint32,
+
equals: function(obj)
{
if (!obj)
return false;
return this.typeId == obj.typeId && this.bufferIndex == obj.bufferIndex && this.byteOffset == obj.byteOffset;
+ },
+
+ retain: function()
+ {
+ this._refCount++;
+ },
+
+ release: function()
+ {
+ this._refCount--;
+ if (this._refCount == 0 && this._state < STATE_RELEASING)
+ {
+ this._state = STATE_RELEASING;
+ free.call(types[this.typeId | 0], this);
+ }
}
}, null);
exports.ObjectType = ObjectBase.extend;
« no previous file with comments | « lib/typedObjects.js ('k') | lib/typedObjects/utils.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld