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

Side by Side Diff: lib/typedObjects/objectTypes.js

Issue 5728072976302080: Issue 151 - [Typed objects] Implement dynamically-sized array types (Closed)
Patch Set: Created July 11, 2014, 7:26 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/arrayTypes.js ('k') | lib/typedObjects/primitiveTypes.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, alloc, dealloc} = require("typedObjects/utils");
21 let {Reference, TypedReference} = require("typedObjects/references"); 21 let {Reference, TypedReference} = require("typedObjects/references");
22 let {uint8, uint32} = require("typedObjects/primitiveTypes"); 22 let {uint8, uint32} = require("typedObjects/primitiveTypes");
23 let {createArrayType} = require("typedObjects/arrayTypes");
23 24
24 const STATE_UNINITIALIZED = 0; 25 const STATE_UNINITIALIZED = exports.STATE_UNINITIALIZED = 0;
25 const STATE_CREATED = 1; 26 const STATE_CREATED = exports.STATE_CREATED = 1;
26 const STATE_RELEASING = 2; 27 const STATE_RELEASING = exports.STATE_RELEASING = 2;
27 28
28 /** 29 /**
29 * List of registered types (typeId is the index in that array). 30 * List of registered types (typeId is the index in that array).
30 */ 31 */
31 let types = []; 32 let types = [];
32 33
33 function fromReference(reference) 34 function fromReference(reference)
34 { 35 {
35 let typeInfo = reference.typeInfo; 36 let typeInfo = reference.typeInfo;
36 if (typeInfo) 37 if (typeInfo)
37 { 38 {
38 return Object.create(typeInfo.proto, { 39 return Object.create(typeInfo.proto, {
39 typeId: fixedPropertyDescriptor(typeInfo.typeId), 40 typeId: fixedPropertyDescriptor(typeInfo.typeId),
40 bufferIndex: fixedPropertyDescriptor(reference.targetBufferIndex), 41 bufferIndex: fixedPropertyDescriptor(reference.targetBufferIndex),
41 byteOffset: fixedPropertyDescriptor(reference.targetByteOffset) 42 byteOffset: fixedPropertyDescriptor(reference.targetByteOffset)
42 }); 43 });
43 } 44 }
44 else 45 else
45 return null; 46 return null;
46 } 47 }
47 48
48 function create() 49 function create()
49 { 50 {
50 let {bufferIndex, byteOffset} = this.firstFree; 51 let [bufferIndex, byteOffset] = alloc(this.firstFree, this.byteLength,
51 if (bufferIndex >= 0) 52 this.bufferSize, this.buffers, this.viewTypes, this.views);
52 {
53 // There is still a free spot, simply move on firstFree reference
54 [this.firstFree.bufferIndex, this.firstFree.byteOffset] =
55 [this.firstFree.targetBufferIndex, this.firstFree.targetByteOffset];
56 }
57 else
58 {
59 let viewTypes = this.viewTypes;
60 let views = this.views;
61 let byteLength = this.byteLength | 0;
62 let bufferSize = this.bufferSize | 0;
63
64 // Create new buffer and use the first element of it
65 let buffer = new ArrayBuffer(byteLength * bufferSize);
66 bufferIndex = (this.buffers.push(buffer) | 0) - 1;
67 byteOffset = 0;
68 for (let i = 0, l = viewTypes.length | 0; i < l; i++)
69 views[i].push(new viewTypes[i](buffer));
70
71 // Mark last element of the new buffer as the last free spot
72 this.firstFree.bufferIndex = bufferIndex;
73 this.firstFree.byteOffset = (bufferSize - 1) * byteLength;
74 this.firstFree.targetBufferIndex = -1;
75
76 // Make each remaining element of the new buffer point to the next one
77 for (let i = bufferSize - 2; i >= 1; i--)
78 {
79 let nextByteOffset = this.firstFree.byteOffset;
80 this.firstFree.byteOffset = nextByteOffset - byteLength;
81 this.firstFree.targetBufferIndex = bufferIndex;
82 this.firstFree.targetByteOffset = nextByteOffset;
83 }
84 }
85 53
86 let result = Object.create(this.proto, { 54 let result = Object.create(this.proto, {
87 typeId: fixedPropertyDescriptor(this.typeId), 55 typeId: fixedPropertyDescriptor(this.typeId),
88 bufferIndex: fixedPropertyDescriptor(bufferIndex), 56 bufferIndex: fixedPropertyDescriptor(bufferIndex),
89 byteOffset: fixedPropertyDescriptor(byteOffset) 57 byteOffset: fixedPropertyDescriptor(byteOffset)
90 }); 58 });
91 59
92 result._state = STATE_UNINITIALIZED; 60 result._state = STATE_UNINITIALIZED;
93 for (let [prop, value] of this.cleanupValues) 61 for (let [prop, value] of this.initialValues)
94 result[prop] = value; 62 result[prop] = value;
95 result._state = STATE_CREATED; 63 result._state = STATE_CREATED;
96 result._refCount = 1; 64 result._refCount = 1;
97 65
98 if (this.constructor) 66 if (this.constructor)
99 this.constructor.apply(result, arguments); 67 this.constructor.apply(result, arguments);
100 return result; 68 return result;
101 } 69 }
102 70
103 function free(obj) 71 function free(obj)
104 { 72 {
105 try 73 try
106 { 74 {
107 if (this.destructor) 75 if (this.destructor)
108 { 76 {
109 this.destructor.call(obj); 77 this.destructor.call(obj);
110 if (obj._refCount | 0) 78 if (obj._refCount | 0)
111 throw new Error("Reference count is no longer zero after calling the des tructor"); 79 throw new Error("Reference count is no longer zero after calling the des tructor");
112 } 80 }
113 } 81 }
114 finally 82 finally
115 { 83 {
116 for (let [prop, value] of this.cleanupValues) 84 for (let [prop, value] of this.initialValues)
117 obj[prop] = value; 85 obj[prop] = value;
118 86
119 // Mark object as first free spot 87 dealloc(this.firstFree, obj.bufferIndex, obj.byteOffset);
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 } 88 }
127 } 89 }
128 90
129 function createGetter(offset) 91 function createGetter(offset)
130 { 92 {
131 offset = offset | 0; 93 offset = offset | 0;
132 94
133 let views = Array.prototype.slice.call(arguments, 1); 95 let views = Array.prototype.slice.call(arguments, 1);
134 let reference = new Reference(types, views); 96 let reference = new Reference(types, views);
135 return function() 97 return function(bufferIndex, byteOffset)
136 { 98 {
137 reference.bufferIndex = this.bufferIndex | 0; 99 reference.bufferIndex = bufferIndex | 0;
138 reference.byteOffset = (this.byteOffset | 0) + offset; 100 reference.byteOffset = (byteOffset | 0) + offset;
139 return fromReference(reference); 101 return fromReference(reference);
140 }; 102 };
141 } 103 }
142 104
143 function createSetter(typeId, offset) 105 function createSetter(typeId, offset)
144 { 106 {
145 typeId = typeId | 0; 107 typeId = typeId | 0;
146 offset = offset | 0; 108 offset = offset | 0;
147 109
148 let views = Array.prototype.slice.call(arguments, 2); 110 let views = Array.prototype.slice.call(arguments, 2);
149 let reference = new Reference(types, views); 111 let reference = new Reference(types, views);
150 return function(value) 112 return function(bufferIndex, byteOffset, value)
151 { 113 {
152 if (value && !isInstance(typeId, value)) 114 if (value && !isInstance(typeId, value))
153 throw new Error("Incompatible type"); 115 throw new Error("Incompatible type");
154 116
155 reference.bufferIndex = this.bufferIndex | 0; 117 reference.bufferIndex = bufferIndex | 0;
156 reference.byteOffset = (this.byteOffset | 0) + offset; 118 reference.byteOffset = (byteOffset | 0) + offset;
157 119
158 if ((this._state | 0) > STATE_UNINITIALIZED) 120 if ((this._state | 0) > STATE_UNINITIALIZED)
159 { 121 {
160 let oldValue = fromReference(reference); 122 let oldValue = fromReference(reference);
161 if (oldValue) 123 if (oldValue)
162 oldValue.release(); 124 oldValue.release();
163 } 125 }
164 126
165 if (value) 127 if (value)
166 { 128 {
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 throw new Error("Method " + name + " masks a property with the same name "); 196 throw new Error("Method " + name + " masks a property with the same name ");
235 197
236 if (name in methods) 198 if (name in methods)
237 type = createSubclassMethod(type, methods[name].value); 199 type = createSubclassMethod(type, methods[name].value);
238 methods[name] = fixedPropertyDescriptor(type); 200 methods[name] = fixedPropertyDescriptor(type);
239 } 201 }
240 else 202 else
241 throw new Error("Unrecognized type " + type + " given for property " + nam e); 203 throw new Error("Unrecognized type " + type + " given for property " + nam e);
242 } 204 }
243 205
206 // Combine inherited watchers with the ones specified for this object
207 let watchers = parentTypeInfo && parentTypeInfo.watchers;
208 if (meta.watch)
209 {
210 watchers = Object.create(watchers);
211 for (let key in meta.watch)
212 watchers[key] = meta.watch[key];
213 }
214
244 let proto = {}; 215 let proto = {};
245 let buffers = []; 216 let buffers = [];
246 let viewTypes = []; 217 let viewTypes = [];
247 let views = []; 218 let views = [];
248 let cleanupValues = []; 219 let initialValues = [];
249 let byteLength = defineProperties(proto, properties, viewTypes, views, 0, clea nupValues); 220 let byteLength = defineProperties(proto, properties, viewTypes, views, 0, watc hers, initialValues);
250 Object.defineProperties(proto, methods); 221 Object.defineProperties(proto, methods);
251 222
252 // Round up to be a multiple of the maximal property size 223 // Round up to be a multiple of the maximal property size
253 byteLength = ((byteLength - 1) | (maxReferenceLength - 1)) + 1; 224 byteLength = ((byteLength - 1) | (maxReferenceLength - 1)) + 1;
254 225
255 // We need to be able to store a typed reference in the object's buffer 226 // We need to be able to store a typed reference in the object's buffer
256 byteLength = Math.max(byteLength, TypedReference.byteLength) | 0; 227 byteLength = Math.max(byteLength, TypedReference.byteLength) | 0;
257 let typedReferenceViews = getViewsForType(TypedReference, viewTypes, views); 228 let typedReferenceViews = getViewsForType(TypedReference, viewTypes, views);
258 229
259 // Take constructor and destructor from meta parameters, allow calling 230 // Take constructor and destructor from meta parameters, allow calling
(...skipping 17 matching lines...) Expand all
277 } 248 }
278 249
279 let typeId = types.length | 0; 250 let typeId = types.length | 0;
280 let typeInfo = { 251 let typeInfo = {
281 byteLength: byteLength, 252 byteLength: byteLength,
282 bufferSize: "bufferSize" in meta ? Math.max(meta.bufferSize | 0, 2) : 128, 253 bufferSize: "bufferSize" in meta ? Math.max(meta.bufferSize | 0, 2) : 128,
283 firstFree: new TypedReference(typeId, typedReferenceViews), 254 firstFree: new TypedReference(typeId, typedReferenceViews),
284 proto: proto, 255 proto: proto,
285 properties: properties, 256 properties: properties,
286 methods: methods, 257 methods: methods,
258 watchers: watchers,
287 buffers: buffers, 259 buffers: buffers,
288 viewTypes: viewTypes, 260 viewTypes: viewTypes,
289 views: views, 261 views: views,
290 cleanupValues: cleanupValues, 262 initialValues: initialValues,
291 typeId: typeId, 263 typeId: typeId,
292 parentTypeInfo: parentTypeInfo, 264 parentTypeInfo: parentTypeInfo,
293 constructor: constructor, 265 constructor: constructor,
294 destructor: destructor 266 destructor: destructor
295 }; 267 };
296 268
297 let result = create.bind(typeInfo); 269 let result = create.bind(typeInfo);
298 Object.defineProperties(result, { 270 Object.defineProperties(result, {
299 byteLength: fixedPropertyDescriptor(byteLength), 271 byteLength: fixedPropertyDescriptor(byteLength),
300 272
301 referenceLength: fixedPropertyDescriptor(Reference.byteLength), 273 referenceLength: fixedPropertyDescriptor(Reference.byteLength),
302 viewTypes: fixedPropertyDescriptor(Reference.viewTypes), 274 viewTypes: fixedPropertyDescriptor(Reference.viewTypes),
303 cleanupValue: fixedPropertyDescriptor(null), 275 initialValue: fixedPropertyDescriptor(null),
304 276
305 typeId: fixedPropertyDescriptor(typeId), 277 typeId: fixedPropertyDescriptor(typeId),
306 extend: fixedPropertyDescriptor(extend.bind(null, typeInfo)), 278 extend: fixedPropertyDescriptor(extend.bind(null, typeInfo)),
307 isInstance: fixedPropertyDescriptor(isInstance.bind(null, typeId)), 279 isInstance: fixedPropertyDescriptor(isInstance.bind(null, typeId)),
280 Array: fixedPropertyDescriptor(createArrayType.bind(null, result)),
308 281
309 createGetter: fixedPropertyDescriptor(createGetter), 282 createGetter: fixedPropertyDescriptor(createGetter),
310 createSetter: fixedPropertyDescriptor(createSetter.bind(null, typeId)) 283 createSetter: fixedPropertyDescriptor(createSetter.bind(null, typeId))
311 }); 284 });
312 types.push(typeInfo); 285 types.push(typeInfo);
313 return result; 286 return result;
314 } 287 }
315 288
316 function isInstance(typeId, obj) 289 function isInstance(typeId, obj)
317 { 290 {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 this._refCount--; 323 this._refCount--;
351 if (this._refCount == 0 && this._state < STATE_RELEASING) 324 if (this._refCount == 0 && this._state < STATE_RELEASING)
352 { 325 {
353 this._state = STATE_RELEASING; 326 this._state = STATE_RELEASING;
354 free.call(types[this.typeId | 0], this); 327 free.call(types[this.typeId | 0], this);
355 } 328 }
356 } 329 }
357 }, null); 330 }, null);
358 331
359 exports.ObjectType = ObjectBase.extend; 332 exports.ObjectType = ObjectBase.extend;
OLDNEW
« no previous file with comments | « lib/typedObjects/arrayTypes.js ('k') | lib/typedObjects/primitiveTypes.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld