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

Side by Side 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.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/typedObjects.js ('k') | lib/typedObjects/utils.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2014 Eyeo GmbH 3 * Copyright (C) 2006-2014 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 "use strict"; 18 "use strict";
19 19
20 let {fixedPropertyDescriptor, getViewsForType, defineProperties} = require("type dObjects/utils"); 20 let {fixedPropertyDescriptor, getViewsForType, defineProperties} = require("type dObjects/utils");
21 let {Reference, TypedReference} = require("typedObjects/references"); 21 let {Reference, TypedReference} = require("typedObjects/references");
22 let {uint8, uint32} = require("typedObjects/primitiveTypes");
23
24 const STATE_UNINITIALIZED = 0;
25 const STATE_CREATED = 1;
26 const STATE_RELEASING = 2;
22 27
23 /** 28 /**
24 * List of registered types (typeId is the index in that array). 29 * List of registered types (typeId is the index in that array).
25 */ 30 */
26 let types = []; 31 let types = [];
27 32
28 function fromReference(reference) 33 function fromReference(reference)
29 { 34 {
30 let typeInfo = reference.typeInfo; 35 let typeInfo = reference.typeInfo;
31 if (typeInfo) 36 if (typeInfo)
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 this.firstFree.targetBufferIndex = bufferIndex; 81 this.firstFree.targetBufferIndex = bufferIndex;
77 this.firstFree.targetByteOffset = nextByteOffset; 82 this.firstFree.targetByteOffset = nextByteOffset;
78 } 83 }
79 } 84 }
80 85
81 let result = Object.create(this.proto, { 86 let result = Object.create(this.proto, {
82 typeId: fixedPropertyDescriptor(this.typeId), 87 typeId: fixedPropertyDescriptor(this.typeId),
83 bufferIndex: fixedPropertyDescriptor(bufferIndex), 88 bufferIndex: fixedPropertyDescriptor(bufferIndex),
84 byteOffset: fixedPropertyDescriptor(byteOffset) 89 byteOffset: fixedPropertyDescriptor(byteOffset)
85 }); 90 });
91
92 result._state = STATE_UNINITIALIZED;
93 for (let [prop, value] of this.cleanupValues)
94 result[prop] = value;
95 result._state = STATE_CREATED;
96 result._refCount = 1;
97
86 if (this.constructor) 98 if (this.constructor)
87 this.constructor.apply(result, arguments); 99 this.constructor.apply(result, arguments);
88 return result; 100 return result;
89 } 101 }
90 102
103 function free(obj)
104 {
105 try
106 {
107 if (this.destructor)
108 {
109 this.destructor.call(obj);
110 if (obj._refCount | 0)
111 throw new Error("Reference count is no longer zero after calling the des tructor");
112 }
113 }
114 finally
115 {
116 for (let [prop, value] of this.cleanupValues)
117 obj[prop] = value;
118
119 // Mark object as first free spot
120 let oldFreeBufferIndex = this.firstFree.bufferIndex;
121 let oldFreeByteOffset = this.firstFree.byteOffset;
122 this.firstFree.bufferIndex = obj.bufferIndex;
123 this.firstFree.byteOffset = obj.byteOffset;
124 this.firstFree.targetBufferIndex = oldFreeBufferIndex;
125 this.firstFree.targetByteOffset = oldFreeByteOffset;
126 }
127 }
128
91 function createGetter(offset) 129 function createGetter(offset)
92 { 130 {
93 offset = offset | 0; 131 offset = offset | 0;
94 132
95 let views = Array.prototype.slice.call(arguments, 1); 133 let views = Array.prototype.slice.call(arguments, 1);
96 let reference = new Reference(types, views); 134 let reference = new Reference(types, views);
97 return function() 135 return function()
98 { 136 {
99 reference.bufferIndex = this.bufferIndex | 0; 137 reference.bufferIndex = this.bufferIndex | 0;
100 reference.byteOffset = (this.byteOffset | 0) + offset; 138 reference.byteOffset = (this.byteOffset | 0) + offset;
101 return fromReference(reference); 139 return fromReference(reference);
102 }; 140 };
103 } 141 }
104 142
105 function createSetter(typeId, offset) 143 function createSetter(typeId, offset)
106 { 144 {
107 typeId = typeId | 0; 145 typeId = typeId | 0;
108 offset = offset | 0; 146 offset = offset | 0;
109 147
110 let views = Array.prototype.slice.call(arguments, 2); 148 let views = Array.prototype.slice.call(arguments, 2);
111 let reference = new Reference(types, views); 149 let reference = new Reference(types, views);
112 return function(value) 150 return function(value)
113 { 151 {
114 if (value && !isinstance(typeId, value)) 152 if (value && !isinstance(typeId, value))
115 throw new Error("Incompatible type"); 153 throw new Error("Incompatible type");
116 154
117 reference.bufferIndex = this.bufferIndex | 0; 155 reference.bufferIndex = this.bufferIndex | 0;
118 reference.byteOffset = (this.byteOffset | 0) + offset; 156 reference.byteOffset = (this.byteOffset | 0) + offset;
157
158 if ((this._state | 0) > STATE_UNINITIALIZED)
159 {
160 let oldValue = fromReference(reference);
161 if (oldValue)
162 oldValue.release();
163 }
164
119 if (value) 165 if (value)
120 { 166 {
121 reference.typeId = value.typeId; 167 reference.typeId = value.typeId;
122 reference.targetBufferIndex = value.bufferIndex; 168 reference.targetBufferIndex = value.bufferIndex;
123 reference.targetByteOffset = value.byteOffset; 169 reference.targetByteOffset = value.byteOffset;
170 value.retain();
124 } 171 }
125 else 172 else
126 reference.typeId = -1; 173 reference.typeId = -1;
127 }; 174 };
128 } 175 }
129 176
130 /** 177 /**
131 * Overridden methods get the respective method of the superclass as the first 178 * Overridden methods get the respective method of the superclass as the first
132 * parameter. This function will create a wrapper function for the method that 179 * parameter. This function will create a wrapper function for the method that
133 * forwards all arguments to the actual methods but also injects super as first 180 * forwards all arguments to the actual methods but also injects super as first
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 methods[name] = fixedPropertyDescriptor(type); 238 methods[name] = fixedPropertyDescriptor(type);
192 } 239 }
193 else 240 else
194 throw new Error("Unrecognized type " + type + " given for property " + nam e); 241 throw new Error("Unrecognized type " + type + " given for property " + nam e);
195 } 242 }
196 243
197 let proto = {}; 244 let proto = {};
198 let buffers = []; 245 let buffers = [];
199 let viewTypes = []; 246 let viewTypes = [];
200 let views = []; 247 let views = [];
201 let byteLength = defineProperties(proto, properties, viewTypes, views, 0); 248 let cleanupValues = [];
249 let byteLength = defineProperties(proto, properties, viewTypes, views, 0, clea nupValues);
202 Object.defineProperties(proto, methods); 250 Object.defineProperties(proto, methods);
203 251
204 // Round up to be a multiple of the maximal property size 252 // Round up to be a multiple of the maximal property size
205 byteLength = ((byteLength - 1) | (maxReferenceLength - 1)) + 1; 253 byteLength = ((byteLength - 1) | (maxReferenceLength - 1)) + 1;
206 254
207 // We need to be able to store a typed reference in the object's buffer 255 // We need to be able to store a typed reference in the object's buffer
208 byteLength = Math.max(byteLength, TypedReference.byteLength) | 0; 256 byteLength = Math.max(byteLength, TypedReference.byteLength) | 0;
209 let typedReferenceViews = getViewsForType(TypedReference, viewTypes, views); 257 let typedReferenceViews = getViewsForType(TypedReference, viewTypes, views);
210 258
211 // Take constructor from meta parameter, allow calling superclass constructor. 259 // Take constructor and destructor from meta parameters, allow calling
260 // superclass constructor/destructor.
212 let constructor = parentTypeInfo && parentTypeInfo.constructor; 261 let constructor = parentTypeInfo && parentTypeInfo.constructor;
213 if (meta.hasOwnProperty("constructor") && typeof meta.constructor == "function ") 262 if (meta.hasOwnProperty("constructor") && typeof meta.constructor == "function ")
214 { 263 {
215 if (constructor) 264 if (constructor)
216 constructor = createSubclassMethod(meta.constructor, constructor); 265 constructor = createSubclassMethod(meta.constructor, constructor);
217 else 266 else
218 constructor = meta.constructor; 267 constructor = meta.constructor;
219 } 268 }
220 269
270 let destructor = parentTypeInfo && parentTypeInfo.destructor;
271 if (meta.hasOwnProperty("destructor") && typeof meta.destructor == "function")
272 {
273 if (destructor)
274 destructor = createSubclassMethod(meta.destructor, destructor);
275 else
276 destructor = meta.destructor;
277 }
278
221 let typeId = types.length | 0; 279 let typeId = types.length | 0;
222 let typeInfo = { 280 let typeInfo = {
223 byteLength: byteLength, 281 byteLength: byteLength,
224 bufferSize: "bufferSize" in meta ? Math.max(meta.bufferSize | 0, 2) : 128, 282 bufferSize: "bufferSize" in meta ? Math.max(meta.bufferSize | 0, 2) : 128,
225 firstFree: new TypedReference(typeId, typedReferenceViews), 283 firstFree: new TypedReference(typeId, typedReferenceViews),
226 proto: proto, 284 proto: proto,
227 properties: properties, 285 properties: properties,
228 methods: methods, 286 methods: methods,
229 buffers: buffers, 287 buffers: buffers,
230 viewTypes: viewTypes, 288 viewTypes: viewTypes,
231 views: views, 289 views: views,
290 cleanupValues: cleanupValues,
232 typeId: typeId, 291 typeId: typeId,
233 parentTypeInfo: parentTypeInfo, 292 parentTypeInfo: parentTypeInfo,
234 constructor: constructor 293 constructor: constructor,
294 destructor: destructor
235 }; 295 };
236 296
237 let result = create.bind(typeInfo); 297 let result = create.bind(typeInfo);
238 Object.defineProperties(result, { 298 Object.defineProperties(result, {
239 byteLength: fixedPropertyDescriptor(byteLength), 299 byteLength: fixedPropertyDescriptor(byteLength),
240 300
241 referenceLength: fixedPropertyDescriptor(Reference.byteLength), 301 referenceLength: fixedPropertyDescriptor(Reference.byteLength),
242 viewTypes: fixedPropertyDescriptor(Reference.viewTypes), 302 viewTypes: fixedPropertyDescriptor(Reference.viewTypes),
303 cleanupValue: fixedPropertyDescriptor(null),
243 304
244 typeId: fixedPropertyDescriptor(typeId), 305 typeId: fixedPropertyDescriptor(typeId),
245 extend: fixedPropertyDescriptor(extend.bind(null, typeInfo)), 306 extend: fixedPropertyDescriptor(extend.bind(null, typeInfo)),
246 isinstance: fixedPropertyDescriptor(isinstance.bind(null, typeId)), 307 isinstance: fixedPropertyDescriptor(isinstance.bind(null, typeId)),
247 308
248 createGetter: fixedPropertyDescriptor(createGetter), 309 createGetter: fixedPropertyDescriptor(createGetter),
249 createSetter: fixedPropertyDescriptor(createSetter.bind(null, typeId)) 310 createSetter: fixedPropertyDescriptor(createSetter.bind(null, typeId))
250 }); 311 });
251 types.push(typeInfo); 312 types.push(typeInfo);
252 return result; 313 return result;
253 } 314 }
254 315
255 function isinstance(typeId, obj) 316 function isinstance(typeId, obj)
256 { 317 {
257 typeId = typeId | 0; 318 typeId = typeId | 0;
258 319
259 // TODO: This could be optimized by compiling the list of all subclasses for 320 // TODO: This could be optimized by compiling the list of all subclasses for
260 // each type up front. Question is whether this is worth it. 321 // each type up front. Question is whether this is worth it.
261 let typeInfo = types[obj.typeId | 0]; 322 let typeInfo = types[obj.typeId | 0];
262 while (typeInfo) 323 while (typeInfo)
263 { 324 {
264 if ((typeInfo.typeId | 0) == typeId) 325 if ((typeInfo.typeId | 0) == typeId)
265 return true; 326 return true;
266 typeInfo = typeInfo.parentTypeInfo; 327 typeInfo = typeInfo.parentTypeInfo;
267 } 328 }
268 return false; 329 return false;
269 } 330 }
270 331
271 let ObjectBase = exports.ObjectBase = extend(null, { 332 let ObjectBase = exports.ObjectBase = extend(null, {
333 _state: uint8,
334 _refCount: uint32,
335
272 equals: function(obj) 336 equals: function(obj)
273 { 337 {
274 if (!obj) 338 if (!obj)
275 return false; 339 return false;
276 return this.typeId == obj.typeId && this.bufferIndex == obj.bufferIndex && t his.byteOffset == obj.byteOffset; 340 return this.typeId == obj.typeId && this.bufferIndex == obj.bufferIndex && t his.byteOffset == obj.byteOffset;
341 },
342
343 retain: function()
344 {
345 this._refCount++;
346 },
347
348 release: function()
349 {
350 this._refCount--;
351 if (this._refCount == 0 && this._state < STATE_RELEASING)
352 {
353 this._state = STATE_RELEASING;
354 free.call(types[this.typeId | 0], this);
355 }
277 } 356 }
278 }, null); 357 }, null);
279 358
280 exports.ObjectType = ObjectBase.extend; 359 exports.ObjectType = ObjectBase.extend;
OLDNEW
« 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