| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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; |
| OLD | NEW |