Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * This file is part of Adblock Plus <http://adblockplus.org/>, | |
3 * Copyright (C) 2006-2014 Eyeo GmbH | |
4 * | |
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 | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * Adblock Plus is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 * GNU General Public License for more details. | |
13 * | |
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/>. | |
16 */ | |
17 | |
18 "use strict"; | |
19 | |
20 let {fixedPropertyDescriptor, getViewsForType, defineProperties} = require("type dObjects/utils"); | |
21 let {Reference, TypedReference} = require("typedObjects/references"); | |
22 | |
23 /** | |
24 * List of registered types (typeId is the index in that array). | |
25 */ | |
26 let types = []; | |
27 | |
28 function fromReference(reference) | |
29 { | |
30 let typeInfo = reference.typeInfo; | |
31 if (typeInfo) | |
32 { | |
33 return Object.create(typeInfo.proto, { | |
34 typeId: fixedPropertyDescriptor(typeInfo.typeId), | |
35 bufferIndex: fixedPropertyDescriptor(reference.targetBufferIndex), | |
36 byteOffset: fixedPropertyDescriptor(reference.targetByteOffset) | |
37 }); | |
38 } | |
39 else | |
40 return null; | |
41 } | |
42 | |
43 function create() | |
44 { | |
45 let views = this.views; | |
46 let {bufferIndex, byteOffset} = this.firstFree; | |
47 if (bufferIndex >= 0) | |
48 { | |
49 // There is still a free spot, simply move on firstFree reference | |
50 [this.firstFree.bufferIndex, this.firstFree.byteOffset] = | |
51 [this.firstFree.targetBufferIndex, this.firstFree.targetByteOffset]; | |
René Jeschke
2014/04/21 17:24:12
Do we gain anything from [a, b] = [c, d] instead o
Wladimir Palant
2014/04/22 15:25:05
reference.bufferIndex = reference.targetBufferInde
René Jeschke
2014/04/22 15:40:34
Right, using temporaries also will look ugly. So:
| |
52 } | |
53 else | |
54 { | |
55 let viewTypes = this.viewTypes; | |
56 let byteLength = this.byteLength | 0; | |
57 let bufferSize = this.bufferSize | 0; | |
58 | |
59 // Create new buffer and use the first element of it | |
60 let buffer = new ArrayBuffer(byteLength * bufferSize); | |
61 bufferIndex = (this.buffers.push(buffer) | 0) - 1; | |
62 byteOffset = 0; | |
63 for (let i = 0, l = viewTypes.length | 0; i < l; i++) | |
64 views[i].push(new viewTypes[i](buffer)); | |
65 | |
66 // Mark last element of the new buffer as the last free spot | |
67 this.firstFree.bufferIndex = bufferIndex; | |
68 this.firstFree.byteOffset = (bufferSize - 1) * byteLength; | |
69 this.firstFree.targetBufferIndex = -1; | |
70 | |
71 // Make each remaining element of the new buffer point to the next one | |
72 for (let i = bufferSize - 2; i >= 1; i--) | |
73 { | |
74 let nextByteOffset = this.firstFree.byteOffset; | |
75 this.firstFree.byteOffset = nextByteOffset - byteLength; | |
76 this.firstFree.targetBufferIndex = bufferIndex; | |
77 this.firstFree.targetByteOffset = nextByteOffset; | |
78 } | |
79 } | |
80 | |
81 let result = Object.create(this.proto, { | |
82 typeId: fixedPropertyDescriptor(this.typeId), | |
83 bufferIndex: fixedPropertyDescriptor(bufferIndex), | |
84 byteOffset: fixedPropertyDescriptor(byteOffset) | |
85 }); | |
86 if (this.constructor) | |
87 this.constructor.apply(result, arguments); | |
88 return result; | |
89 } | |
90 | |
91 function createGetter(offset) | |
92 { | |
93 offset = offset | 0; | |
94 | |
95 let views = Array.prototype.slice.call(arguments, 1); | |
96 let reference = new Reference(types, views); | |
97 return function() | |
98 { | |
99 reference.bufferIndex = this.bufferIndex | 0; | |
100 reference.byteOffset = (this.byteOffset | 0) + offset; | |
101 return fromReference(reference); | |
102 }; | |
103 } | |
104 | |
105 function createSetter(typeId, offset) | |
106 { | |
107 typeId = typeId | 0; | |
108 offset = offset | 0; | |
109 | |
110 let views = Array.prototype.slice.call(arguments, 2); | |
111 let reference = new Reference(types, views); | |
112 return function(value) | |
113 { | |
114 if (value && value.typeId != typeId) | |
115 throw new Error("Incompatible type"); | |
116 | |
117 reference.bufferIndex = this.bufferIndex | 0; | |
118 reference.byteOffset = (this.byteOffset | 0) + offset; | |
119 if (value) | |
120 { | |
121 reference.typeId = value.typeId; | |
122 reference.targetBufferIndex = value.bufferIndex; | |
123 reference.targetByteOffset = value.byteOffset; | |
124 } | |
125 else | |
126 reference.typeId = -1; | |
127 }; | |
128 } | |
129 | |
130 function ObjectType(properties, meta) | |
131 { | |
132 if (typeof meta != "object" || meta == null) | |
133 meta = {}; | |
134 | |
135 let propList = []; | |
136 let proto = {}; | |
137 let maxReferenceLength = TypedReference.byteLength | 0; | |
138 for (let name in properties) | |
139 { | |
140 let type = properties[name]; | |
141 if (type && typeof type.referenceLength == "number") | |
142 { | |
143 // Property with type | |
144 propList.push([name, type]); | |
145 | |
146 let referenceLength = type.referenceLength | 0; | |
147 if (referenceLength > maxReferenceLength) | |
148 maxReferenceLength = referenceLength; | |
149 } | |
150 else if (typeof type == "function") | |
151 { | |
152 // Method | |
153 Object.defineProperty(proto, name, fixedPropertyDescriptor(type)); | |
154 } | |
155 else | |
156 throw new Error("Unrecognized type " + type + " given for property " + nam e); | |
157 } | |
158 | |
159 let buffers = []; | |
160 let viewTypes = []; | |
161 let views = []; | |
162 let byteLength = defineProperties(proto, propList, viewTypes, views, 0); | |
163 | |
164 // Round up to be a multiple of the maximal property size | |
165 byteLength = ((byteLength - 1) | (maxReferenceLength - 1)) + 1; | |
René Jeschke
2014/04/21 17:24:12
This only works correctly if either 'byteLength' o
Wladimir Palant
2014/04/22 15:25:05
No, maxReferenceLength has to be a power of two -
René Jeschke
2014/04/22 15:40:34
Okay then.
| |
166 | |
167 // We need to be able to store a typed reference in the object's buffer | |
168 byteLength = Math.max(byteLength, TypedReference.byteLength) | 0; | |
169 let typedReferenceViews = getViewsForType(TypedReference, viewTypes, views); | |
170 | |
171 let typeId = types.length | 0; | |
172 let typeInfo = { | |
173 byteLength: byteLength, | |
174 bufferSize: "bufferSize" in meta ? Math.max(meta.bufferSize | 0, 2) : 128, | |
175 firstFree: new TypedReference(typeId, typedReferenceViews), | |
176 proto: proto, | |
177 buffers: buffers, | |
178 viewTypes: viewTypes, | |
179 views: views, | |
180 typeId: typeId, | |
181 constructor: (typeof meta.constructor == "function" ? meta.constructor : nul l) | |
Wladimir Palant
2014/04/22 15:25:05
This was a bug - each JavaScript object has a cons
René Jeschke
2014/04/22 15:40:34
Didn't know that, now I do. Finally a good use cas
| |
182 }; | |
183 | |
184 let result = create.bind(typeInfo); | |
185 Object.defineProperties(result, { | |
186 byteLength: fixedPropertyDescriptor(byteLength), | |
187 | |
188 referenceLength: fixedPropertyDescriptor(Reference.byteLength), | |
189 viewTypes: fixedPropertyDescriptor(Reference.viewTypes), | |
190 | |
191 typeId: fixedPropertyDescriptor(typeId), | |
192 | |
193 createGetter: fixedPropertyDescriptor(createGetter), | |
194 createSetter: fixedPropertyDescriptor(createSetter.bind(null, typeId)) | |
195 }); | |
196 types.push(typeInfo); | |
197 return result; | |
198 } | |
199 exports.ObjectType = ObjectType; | |
OLD | NEW |