Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1309)

Side by Side Diff: src/collection.js

Issue 947683002: Reimplement Maps and Sets in JS (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Disable one more test Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/hydrogen.h » ('j') | src/hydrogen.h » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 "use strict";
6
7 // This file relies on the fact that the following declaration has been made 5 // This file relies on the fact that the following declaration has been made
8 // in runtime.js: 6 // in runtime.js:
7 // var $Object = global.Object;
9 // var $Array = global.Array; 8 // var $Array = global.Array;
10 9
11 var $Set = global.Set; 10 var $Set = global.Set;
12 var $Map = global.Map; 11 var $Map = global.Map;
13 12
14 13
15 // ------------------------------------------------------------------- 14 (function() {
16 // Harmony Set 15 "use strict";
17 16
18 function SetConstructor(iterable) { 17
19 if (!%_IsConstructCall()) { 18 function HashToBucket(hash, numBuckets) {
20 throw MakeTypeError('constructor_not_function', ['Set']); 19 return hash & (numBuckets - 1);
21 } 20 }
22 21 %SetInlineBuiltinFlag(HashToBucket);
23 var iter, adder; 22
24 23
25 if (!IS_NULL_OR_UNDEFINED(iterable)) { 24 function HashToEntry(table, hash, numBuckets) {
26 iter = GetIterator(iterable); 25 var bucket = HashToBucket(hash, numBuckets);
27 adder = this.add; 26 return %_FixedArrayGet(table, HASH_TABLE_START_INDEX + bucket);
28 if (!IS_SPEC_FUNCTION(adder)) { 27 }
29 throw MakeTypeError('property_not_function', ['add', this]); 28 %SetInlineBuiltinFlag(HashToEntry);
30 } 29
31 } 30
32 31 function SetFindEntry(table, numBuckets, key, hash) {
33 %_SetInitialize(this); 32 var keyIsNaN = IS_NUMBER(key) && NUMBER_IS_NAN(key);
34 33 for (var entry = HashToEntry(table, hash, numBuckets);
35 if (IS_UNDEFINED(iter)) return; 34 entry !== NOT_FOUND;
36 35 entry = SET_CHAIN_AT(table, entry, numBuckets)) {
37 var next, done; 36 var candidate = SET_KEY_AT(table, entry, numBuckets);
38 while (!(next = iter.next()).done) { 37 if (key === candidate) {
39 if (!IS_SPEC_OBJECT(next)) { 38 return entry;
40 throw MakeTypeError('iterator_result_not_an_object', [next]); 39 }
41 } 40 if (keyIsNaN && IS_NUMBER(candidate) && NUMBER_IS_NAN(candidate)) {
arv (Not doing code reviews) 2015/02/21 16:20:16 Nice optimization to get around the NaN SameValueZ
arv (Not doing code reviews) 2015/02/21 16:20:16 Nice optimization to get around the NaN SameValueZ
42 %_CallFunction(this, next.value, adder); 41 return entry;
43 } 42 }
44 } 43 }
45 44 return NOT_FOUND;
46 45 }
47 function SetAddJS(key) { 46 %SetInlineBuiltinFlag(SetFindEntry);
48 if (!IS_SET(this)) { 47
49 throw MakeTypeError('incompatible_method_receiver', 48
50 ['Set.prototype.add', this]); 49 function MapFindEntry(table, numBuckets, key, hash) {
51 } 50 var keyIsNaN = IS_NUMBER(key) && NUMBER_IS_NAN(key);
52 // Normalize -0 to +0 as required by the spec. 51 for (var entry = HashToEntry(table, hash, numBuckets);
53 // Even though we use SameValueZero as the comparison for the keys we don't 52 entry !== NOT_FOUND;
54 // want to ever store -0 as the key since the key is directly exposed when 53 entry = MAP_CHAIN_AT(table, entry, numBuckets)) {
55 // doing iteration. 54 var candidate = MAP_KEY_AT(table, entry, numBuckets);
56 if (key === 0) { 55 if (key === candidate) {
57 key = 0; 56 return entry;
58 } 57 }
59 return %_SetAdd(this, key); 58 if (keyIsNaN && IS_NUMBER(candidate) && NUMBER_IS_NAN(candidate)) {
60 } 59 return entry;
61 60 }
62 61 }
63 function SetHasJS(key) { 62 return NOT_FOUND;
64 if (!IS_SET(this)) { 63 }
65 throw MakeTypeError('incompatible_method_receiver', 64 %SetInlineBuiltinFlag(MapFindEntry);
66 ['Set.prototype.has', this]); 65
67 } 66
68 return %_SetHas(this, key); 67 function GetHash(key) {
69 } 68 if (%_IsSmi(key)) return %_SmiHash(key);
70 69 if (IS_STRING(key)) return %_StringHash(key);
71 70 return %GenericHash(key);
72 function SetDeleteJS(key) { 71 }
73 if (!IS_SET(this)) { 72 %SetInlineBuiltinFlag(GetHash);
74 throw MakeTypeError('incompatible_method_receiver', 73
75 ['Set.prototype.delete', this]); 74
76 } 75 // -------------------------------------------------------------------
77 return %_SetDelete(this, key); 76 // Harmony Set
78 } 77
79 78 function SetConstructor(iterable) {
80 79 if (!%_IsConstructCall()) {
81 function SetGetSizeJS() { 80 throw MakeTypeError('constructor_not_function', ['Set']);
82 if (!IS_SET(this)) { 81 }
83 throw MakeTypeError('incompatible_method_receiver', 82
84 ['Set.prototype.size', this]); 83 var iter, adder;
85 } 84
86 return %_SetGetSize(this); 85 if (!IS_NULL_OR_UNDEFINED(iterable)) {
87 } 86 iter = GetIterator(iterable);
88 87 adder = this.add;
89 88 if (!IS_SPEC_FUNCTION(adder)) {
90 function SetClearJS() { 89 throw MakeTypeError('property_not_function', ['add', this]);
91 if (!IS_SET(this)) { 90 }
92 throw MakeTypeError('incompatible_method_receiver', 91 }
93 ['Set.prototype.clear', this]); 92
94 } 93 %_SetInitialize(this);
95 %_SetClear(this); 94
96 } 95 if (IS_UNDEFINED(iter)) return;
97 96
98 97 var next, done;
99 function SetForEach(f, receiver) { 98 while (!(next = iter.next()).done) {
100 if (!IS_SET(this)) { 99 if (!IS_SPEC_OBJECT(next)) {
101 throw MakeTypeError('incompatible_method_receiver', 100 throw MakeTypeError('iterator_result_not_an_object', [next]);
102 ['Set.prototype.forEach', this]); 101 }
103 } 102 %_CallFunction(this, next.value, adder);
104 103 }
105 if (!IS_SPEC_FUNCTION(f)) { 104 }
106 throw MakeTypeError('called_non_callable', [f]); 105
107 } 106
108 var needs_wrapper = false; 107 function SetAdd(key) {
109 if (IS_NULL_OR_UNDEFINED(receiver)) { 108 if (!IS_SET(this)) {
110 receiver = %GetDefaultReceiver(f) || receiver; 109 throw MakeTypeError('incompatible_method_receiver',
111 } else { 110 ['Set.prototype.add', this]);
112 needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver); 111 }
113 } 112 // Normalize -0 to +0 as required by the spec.
114 113 // Even though we use SameValueZero as the comparison for the keys we don't
115 var iterator = new SetIterator(this, ITERATOR_KIND_VALUES); 114 // want to ever store -0 as the key since the key is directly exposed when
116 var key; 115 // doing iteration.
117 var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f); 116 if (IS_NUMBER(key) && key === 0) {
118 var value_array = [UNDEFINED]; 117 key = 0;
119 while (%SetIteratorNext(iterator, value_array)) { 118 }
120 if (stepping) %DebugPrepareStepInIfStepping(f); 119 var table = %_JSCollectionGetTable(this);
121 key = value_array[0]; 120 var numBuckets = %_FixedArrayGet(table, NUMBER_OF_BUCKETS_INDEX);
122 var new_receiver = needs_wrapper ? ToObject(receiver) : receiver; 121 var hash = GetHash(key);
123 %_CallFunction(new_receiver, key, key, this, f); 122 if (SetFindEntry(table, numBuckets, key, hash) !== NOT_FOUND) return this;
124 } 123
125 } 124 var nof = %_FixedArrayGet(table, NUMBER_OF_ELEMENTS_INDEX);
126 125 var nod = %_FixedArrayGet(table, NUMBER_OF_DELETED_ELEMENTS_INDEX);
127 126 var capacity = numBuckets << 1;
128 // ------------------------------------------------------------------- 127 if ((nof + nod) >= capacity) {
129 128 // Need to grow, bail out to runtime.
130 function SetUpSet() { 129 %SetGrow(this);
131 %CheckIsBootstrapping(); 130 // Re-enter...TODO(adamk) Fix this
132 131 return %_CallFunction(this, key, SetAdd);
133 %SetCode($Set, SetConstructor); 132 }
134 %FunctionSetPrototype($Set, new $Object()); 133 var entry = nof + nod;
135 %AddNamedProperty($Set.prototype, "constructor", $Set, DONT_ENUM); 134 var index = SET_ENTRY_TO_INDEX(entry, numBuckets);
136 %AddNamedProperty( 135 var bucket = HashToBucket(hash, numBuckets);
137 $Set.prototype, symbolToStringTag, "Set", DONT_ENUM | READ_ONLY); 136 var chainEntry = %_FixedArrayGet(table, HASH_TABLE_START_INDEX + bucket);
138 137 %_FixedArraySet(table, HASH_TABLE_START_INDEX + bucket, entry);
139 %FunctionSetLength(SetForEach, 1); 138 %_FixedArraySet(table, index + SET_CHAIN_OFFSET, chainEntry);
140 139 %_FixedArraySet(table, NUMBER_OF_ELEMENTS_INDEX, nof + 1);
141 // Set up the non-enumerable functions on the Set prototype object. 140 %_FixedArraySet(table, index, key);
142 InstallGetter($Set.prototype, "size", SetGetSizeJS); 141 return this;
143 InstallFunctions($Set.prototype, DONT_ENUM, $Array( 142 }
144 "add", SetAddJS, 143
145 "has", SetHasJS, 144
146 "delete", SetDeleteJS, 145 function SetHas(key) {
147 "clear", SetClearJS, 146 if (!IS_SET(this)) {
148 "forEach", SetForEach 147 throw MakeTypeError('incompatible_method_receiver',
149 )); 148 ['Set.prototype.has', this]);
150 } 149 }
151 150 var table = %_JSCollectionGetTable(this);
152 SetUpSet(); 151 var numBuckets = %_FixedArrayGet(table, NUMBER_OF_BUCKETS_INDEX);
153 152 var hash = GetHash(key);
154 153 return SetFindEntry(table, numBuckets, key, hash) !== NOT_FOUND;
155 // ------------------------------------------------------------------- 154 }
156 // Harmony Map 155
157 156
158 function MapConstructor(iterable) { 157 function SetDelete(key) {
159 if (!%_IsConstructCall()) { 158 if (!IS_SET(this)) {
160 throw MakeTypeError('constructor_not_function', ['Map']); 159 throw MakeTypeError('incompatible_method_receiver',
161 } 160 ['Set.prototype.delete', this]);
162 161 }
163 var iter, adder; 162 var table = %_JSCollectionGetTable(this);
164 163 var numBuckets = %_FixedArrayGet(table, NUMBER_OF_BUCKETS_INDEX);
165 if (!IS_NULL_OR_UNDEFINED(iterable)) { 164 var hash = GetHash(key);
166 iter = GetIterator(iterable); 165 var entry = SetFindEntry(table, numBuckets, key, hash);
167 adder = this.set; 166 if (entry === NOT_FOUND) return false;
168 if (!IS_SPEC_FUNCTION(adder)) { 167
169 throw MakeTypeError('property_not_function', ['set', this]); 168 var nof = %_FixedArrayGet(table, NUMBER_OF_ELEMENTS_INDEX) - 1;
170 } 169 var nod = %_FixedArrayGet(table, NUMBER_OF_DELETED_ELEMENTS_INDEX) + 1;
171 } 170 var index = SET_ENTRY_TO_INDEX(entry, numBuckets);
172 171 %_FixedArraySetTheHole(table, index);
173 %_MapInitialize(this); 172 %_FixedArraySet(table, NUMBER_OF_ELEMENTS_INDEX, nof);
174 173 %_FixedArraySet(table, NUMBER_OF_DELETED_ELEMENTS_INDEX, nod);
175 if (IS_UNDEFINED(iter)) return; 174 if (nof < (numBuckets >> 1)) %SetShrink(this);
176 175 return true;
177 var next, done, nextItem; 176 }
178 while (!(next = iter.next()).done) { 177
179 if (!IS_SPEC_OBJECT(next)) { 178
180 throw MakeTypeError('iterator_result_not_an_object', [next]); 179 function SetGetSize() {
181 } 180 if (!IS_SET(this)) {
182 nextItem = next.value; 181 throw MakeTypeError('incompatible_method_receiver',
183 if (!IS_SPEC_OBJECT(nextItem)) { 182 ['Set.prototype.size', this]);
184 throw MakeTypeError('iterator_value_not_an_object', [nextItem]); 183 }
185 } 184 var table = %_JSCollectionGetTable(this);
186 %_CallFunction(this, nextItem[0], nextItem[1], adder); 185 return %_FixedArrayGet(table, NUMBER_OF_ELEMENTS_INDEX);
187 } 186 }
188 } 187
189 188
190 189 function SetClearJS() {
191 function MapGetJS(key) { 190 if (!IS_SET(this)) {
192 if (!IS_MAP(this)) { 191 throw MakeTypeError('incompatible_method_receiver',
193 throw MakeTypeError('incompatible_method_receiver', 192 ['Set.prototype.clear', this]);
194 ['Map.prototype.get', this]); 193 }
195 } 194 %_SetClear(this);
196 return %_MapGet(this, key); 195 }
197 } 196
198 197
199 198 function SetForEach(f, receiver) {
200 function MapSetJS(key, value) { 199 if (!IS_SET(this)) {
201 if (!IS_MAP(this)) { 200 throw MakeTypeError('incompatible_method_receiver',
202 throw MakeTypeError('incompatible_method_receiver', 201 ['Set.prototype.forEach', this]);
203 ['Map.prototype.set', this]); 202 }
204 } 203
205 // Normalize -0 to +0 as required by the spec. 204 if (!IS_SPEC_FUNCTION(f)) {
206 // Even though we use SameValueZero as the comparison for the keys we don't 205 throw MakeTypeError('called_non_callable', [f]);
207 // want to ever store -0 as the key since the key is directly exposed when 206 }
208 // doing iteration. 207 var needs_wrapper = false;
209 if (key === 0) { 208 if (IS_NULL_OR_UNDEFINED(receiver)) {
210 key = 0; 209 receiver = %GetDefaultReceiver(f) || receiver;
211 } 210 } else {
212 return %_MapSet(this, key, value); 211 needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
213 } 212 }
214 213
215 214 var iterator = new SetIterator(this, ITERATOR_KIND_VALUES);
216 function MapHasJS(key) { 215 var key;
217 if (!IS_MAP(this)) { 216 var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
218 throw MakeTypeError('incompatible_method_receiver', 217 var value_array = [UNDEFINED];
219 ['Map.prototype.has', this]); 218 while (%SetIteratorNext(iterator, value_array)) {
arv (Not doing code reviews) 2015/02/21 16:20:16 This one can get much faster now that we have acce
adamk 2015/02/23 18:43:34 Yeah, there are definitely opportunities to speed
220 } 219 if (stepping) %DebugPrepareStepInIfStepping(f);
221 return %_MapHas(this, key); 220 key = value_array[0];
222 } 221 var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
223 222 %_CallFunction(new_receiver, key, key, this, f);
224 223 }
225 function MapDeleteJS(key) { 224 }
226 if (!IS_MAP(this)) { 225
227 throw MakeTypeError('incompatible_method_receiver', 226
228 ['Map.prototype.delete', this]); 227 // -------------------------------------------------------------------
229 } 228
230 return %_MapDelete(this, key); 229 function SetUpSet() {
231 } 230 %CheckIsBootstrapping();
232 231
233 232 %SetCode($Set, SetConstructor);
234 function MapGetSizeJS() { 233 %FunctionSetPrototype($Set, new $Object());
235 if (!IS_MAP(this)) { 234 %AddNamedProperty($Set.prototype, "constructor", $Set, DONT_ENUM);
236 throw MakeTypeError('incompatible_method_receiver', 235 %AddNamedProperty(
237 ['Map.prototype.size', this]); 236 $Set.prototype, symbolToStringTag, "Set", DONT_ENUM | READ_ONLY);
238 } 237
239 return %_MapGetSize(this); 238 %FunctionSetLength(SetForEach, 1);
240 } 239
241 240 // Set up the non-enumerable functions on the Set prototype object.
242 241 InstallGetter($Set.prototype, "size", SetGetSize);
243 function MapClearJS() { 242 InstallFunctions($Set.prototype, DONT_ENUM, $Array(
244 if (!IS_MAP(this)) { 243 "add", SetAdd,
245 throw MakeTypeError('incompatible_method_receiver', 244 "has", SetHas,
246 ['Map.prototype.clear', this]); 245 "delete", SetDelete,
247 } 246 "clear", SetClearJS,
248 %_MapClear(this); 247 "forEach", SetForEach
249 } 248 ));
250 249 }
251 250
252 function MapForEach(f, receiver) { 251 SetUpSet();
253 if (!IS_MAP(this)) { 252
254 throw MakeTypeError('incompatible_method_receiver', 253
255 ['Map.prototype.forEach', this]); 254 // -------------------------------------------------------------------
256 } 255 // Harmony Map
257 256
258 if (!IS_SPEC_FUNCTION(f)) { 257 function MapConstructor(iterable) {
259 throw MakeTypeError('called_non_callable', [f]); 258 if (!%_IsConstructCall()) {
260 } 259 throw MakeTypeError('constructor_not_function', ['Map']);
261 var needs_wrapper = false; 260 }
262 if (IS_NULL_OR_UNDEFINED(receiver)) { 261
263 receiver = %GetDefaultReceiver(f) || receiver; 262 var iter, adder;
264 } else { 263
265 needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver); 264 if (!IS_NULL_OR_UNDEFINED(iterable)) {
266 } 265 iter = GetIterator(iterable);
267 266 adder = this.set;
268 var iterator = new MapIterator(this, ITERATOR_KIND_ENTRIES); 267 if (!IS_SPEC_FUNCTION(adder)) {
269 var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f); 268 throw MakeTypeError('property_not_function', ['set', this]);
270 var value_array = [UNDEFINED, UNDEFINED]; 269 }
271 while (%MapIteratorNext(iterator, value_array)) { 270 }
272 if (stepping) %DebugPrepareStepInIfStepping(f); 271
273 var new_receiver = needs_wrapper ? ToObject(receiver) : receiver; 272 %_MapInitialize(this);
274 %_CallFunction(new_receiver, value_array[1], value_array[0], this, f); 273
275 } 274 if (IS_UNDEFINED(iter)) return;
276 } 275
277 276 var next, done, nextItem;
278 277 while (!(next = iter.next()).done) {
279 // ------------------------------------------------------------------- 278 if (!IS_SPEC_OBJECT(next)) {
280 279 throw MakeTypeError('iterator_result_not_an_object', [next]);
281 function SetUpMap() { 280 }
282 %CheckIsBootstrapping(); 281 nextItem = next.value;
283 282 if (!IS_SPEC_OBJECT(nextItem)) {
284 %SetCode($Map, MapConstructor); 283 throw MakeTypeError('iterator_value_not_an_object', [nextItem]);
285 %FunctionSetPrototype($Map, new $Object()); 284 }
286 %AddNamedProperty($Map.prototype, "constructor", $Map, DONT_ENUM); 285 %_CallFunction(this, nextItem[0], nextItem[1], adder);
287 %AddNamedProperty( 286 }
288 $Map.prototype, symbolToStringTag, "Map", DONT_ENUM | READ_ONLY); 287 }
289 288
290 %FunctionSetLength(MapForEach, 1); 289
291 290 function MapGet(key) {
292 // Set up the non-enumerable functions on the Map prototype object. 291 if (!IS_MAP(this)) {
293 InstallGetter($Map.prototype, "size", MapGetSizeJS); 292 throw MakeTypeError('incompatible_method_receiver',
294 InstallFunctions($Map.prototype, DONT_ENUM, $Array( 293 ['Map.prototype.get', this]);
295 "get", MapGetJS, 294 }
296 "set", MapSetJS, 295 var table = %_JSCollectionGetTable(this);
297 "has", MapHasJS, 296 var numBuckets = %_FixedArrayGet(table, NUMBER_OF_BUCKETS_INDEX);
298 "delete", MapDeleteJS, 297 var hash = GetHash(key);
299 "clear", MapClearJS, 298 var entry = MapFindEntry(table, numBuckets, key, hash);
300 "forEach", MapForEach 299 if (entry === NOT_FOUND) return UNDEFINED;
301 )); 300 return MAP_VALUE_AT(table, entry, numBuckets);
302 } 301 }
303 302
304 SetUpMap(); 303
304 function MapSet(key, value) {
305 if (!IS_MAP(this)) {
306 throw MakeTypeError('incompatible_method_receiver',
307 ['Map.prototype.set', this]);
308 }
309 // Normalize -0 to +0 as required by the spec.
310 // Even though we use SameValueZero as the comparison for the keys we don't
311 // want to ever store -0 as the key since the key is directly exposed when
312 // doing iteration.
313 if (IS_NUMBER(key) && key === 0) {
314 key = 0;
315 }
316
317 var table = %_JSCollectionGetTable(this);
318 var numBuckets = %_FixedArrayGet(table, NUMBER_OF_BUCKETS_INDEX);
319 var hash = GetHash(key);
320 var entry = MapFindEntry(table, numBuckets, key, hash);
321 if (entry !== NOT_FOUND) {
322 var existingIndex = MAP_ENTRY_TO_INDEX(entry, numBuckets);
323 %_FixedArraySet(table, existingIndex + 1, value);
324 return this;
325 }
326
327 var nof = %_FixedArrayGet(table, NUMBER_OF_ELEMENTS_INDEX);
328 var nod = %_FixedArrayGet(table, NUMBER_OF_DELETED_ELEMENTS_INDEX);
329 var capacity = numBuckets << 1;
330 if ((nof + nod) >= capacity) {
331 // Need to grow, bail out to runtime.
332 %MapGrow(this);
333 // Re-enter...TODO(adamk) Fix this
334 return %_CallFunction(this, key, value, MapSet);
335 }
336 entry = nof + nod;
337 var index = MAP_ENTRY_TO_INDEX(entry, numBuckets);
338 var bucket = HashToBucket(hash, numBuckets);
339 var chainEntry = %_FixedArrayGet(table, HASH_TABLE_START_INDEX + bucket);
340 %_FixedArraySet(table, HASH_TABLE_START_INDEX + bucket, entry);
341 %_FixedArraySet(table, index + MAP_CHAIN_OFFSET, chainEntry);
342 %_FixedArraySet(table, NUMBER_OF_ELEMENTS_INDEX, nof + 1);
343 %_FixedArraySet(table, index, key);
344 %_FixedArraySet(table, index + 1, value);
345 return this;
346 }
347
348
349 function MapHas(key) {
350 if (!IS_MAP(this)) {
351 throw MakeTypeError('incompatible_method_receiver',
352 ['Map.prototype.has', this]);
353 }
354 var table = %_JSCollectionGetTable(this);
355 var numBuckets = %_FixedArrayGet(table, NUMBER_OF_BUCKETS_INDEX);
356 var hash = GetHash(key);
357 return MapFindEntry(table, numBuckets, key, hash) !== NOT_FOUND;
358 }
359
360
361 function MapDelete(key) {
362 if (!IS_MAP(this)) {
363 throw MakeTypeError('incompatible_method_receiver',
364 ['Map.prototype.delete', this]);
365 }
366 var table = %_JSCollectionGetTable(this);
367 var numBuckets = %_FixedArrayGet(table, NUMBER_OF_BUCKETS_INDEX);
368 var hash = GetHash(key);
369 var entry = MapFindEntry(table, numBuckets, key, hash);
370 if (entry === NOT_FOUND) return false;
371
372 var nof = %_FixedArrayGet(table, NUMBER_OF_ELEMENTS_INDEX) - 1;
373 var nod = %_FixedArrayGet(table, NUMBER_OF_DELETED_ELEMENTS_INDEX) + 1;
374 var index = MAP_ENTRY_TO_INDEX(entry, numBuckets);
375 %_FixedArraySetTheHole(table, index);
376 %_FixedArraySetTheHole(table, index + 1);
377 %_FixedArraySet(table, NUMBER_OF_ELEMENTS_INDEX, nof);
378 %_FixedArraySet(table, NUMBER_OF_DELETED_ELEMENTS_INDEX, nod);
379 if (nof < (numBuckets >> 1)) %MapShrink(this);
380 return true;
381 }
382
383
384 function MapGetSize() {
385 if (!IS_MAP(this)) {
386 throw MakeTypeError('incompatible_method_receiver',
387 ['Map.prototype.size', this]);
388 }
389 var table = %_JSCollectionGetTable(this);
390 return %_FixedArrayGet(table, NUMBER_OF_ELEMENTS_INDEX);
391 }
392
393
394 function MapClearJS() {
395 if (!IS_MAP(this)) {
396 throw MakeTypeError('incompatible_method_receiver',
397 ['Map.prototype.clear', this]);
398 }
399 %_MapClear(this);
400 }
401
402
403 function MapForEach(f, receiver) {
404 if (!IS_MAP(this)) {
405 throw MakeTypeError('incompatible_method_receiver',
406 ['Map.prototype.forEach', this]);
407 }
408
409 if (!IS_SPEC_FUNCTION(f)) {
410 throw MakeTypeError('called_non_callable', [f]);
411 }
412 var needs_wrapper = false;
413 if (IS_NULL_OR_UNDEFINED(receiver)) {
414 receiver = %GetDefaultReceiver(f) || receiver;
415 } else {
416 needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
417 }
418
419 var iterator = new MapIterator(this, ITERATOR_KIND_ENTRIES);
420 var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
421 var value_array = [UNDEFINED, UNDEFINED];
422 while (%MapIteratorNext(iterator, value_array)) {
423 if (stepping) %DebugPrepareStepInIfStepping(f);
424 var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
425 %_CallFunction(new_receiver, value_array[1], value_array[0], this, f);
426 }
427 }
428
429
430 // -------------------------------------------------------------------
431
432 function SetUpMap() {
433 %CheckIsBootstrapping();
434
435 %SetCode($Map, MapConstructor);
436 %FunctionSetPrototype($Map, new $Object());
437 %AddNamedProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
438 %AddNamedProperty(
439 $Map.prototype, symbolToStringTag, "Map", DONT_ENUM | READ_ONLY);
440
441 %FunctionSetLength(MapForEach, 1);
442
443 // Set up the non-enumerable functions on the Map prototype object.
444 InstallGetter($Map.prototype, "size", MapGetSize);
445 InstallFunctions($Map.prototype, DONT_ENUM, $Array(
446 "get", MapGet,
447 "set", MapSet,
448 "has", MapHas,
449 "delete", MapDelete,
450 "clear", MapClearJS,
451 "forEach", MapForEach
452 ));
453 }
454
455 SetUpMap();
456
457 })();
OLDNEW
« no previous file with comments | « no previous file | src/hydrogen.h » ('j') | src/hydrogen.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698