@@ -12,6 +12,86 @@ var $Set = global.Set;
1212var $Map = global . Map ;
1313
1414
15+ // Used by harmony-templates.js
16+ var $MapGet ;
17+ var $MapSet ;
18+
19+
20+ ( function ( ) {
21+
22+
23+ function HashToEntry ( table , hash , numBuckets ) {
24+ var bucket = ORDERED_HASH_TABLE_HASH_TO_BUCKET ( hash , numBuckets ) ;
25+ return ORDERED_HASH_TABLE_BUCKET_AT ( table , bucket ) ;
26+ }
27+ % SetInlineBuiltinFlag ( HashToEntry ) ;
28+
29+
30+ function SetFindEntry ( table , numBuckets , key , hash ) {
31+ var keyIsNaN = IS_NUMBER ( key ) && NUMBER_IS_NAN ( key ) ;
32+ for ( var entry = HashToEntry ( table , hash , numBuckets ) ;
33+ entry !== NOT_FOUND ;
34+ entry = ORDERED_HASH_SET_CHAIN_AT ( table , entry , numBuckets ) ) {
35+ var candidate = ORDERED_HASH_SET_KEY_AT ( table , entry , numBuckets ) ;
36+ if ( key === candidate ) {
37+ return entry ;
38+ }
39+ if ( keyIsNaN && IS_NUMBER ( candidate ) && NUMBER_IS_NAN ( candidate ) ) {
40+ return entry ;
41+ }
42+ }
43+ return NOT_FOUND ;
44+ }
45+ % SetInlineBuiltinFlag ( SetFindEntry ) ;
46+
47+
48+ function MapFindEntry ( table , numBuckets , key , hash ) {
49+ var keyIsNaN = IS_NUMBER ( key ) && NUMBER_IS_NAN ( key ) ;
50+ for ( var entry = HashToEntry ( table , hash , numBuckets ) ;
51+ entry !== NOT_FOUND ;
52+ entry = ORDERED_HASH_MAP_CHAIN_AT ( table , entry , numBuckets ) ) {
53+ var candidate = ORDERED_HASH_MAP_KEY_AT ( table , entry , numBuckets ) ;
54+ if ( key === candidate ) {
55+ return entry ;
56+ }
57+ if ( keyIsNaN && IS_NUMBER ( candidate ) && NUMBER_IS_NAN ( candidate ) ) {
58+ return entry ;
59+ }
60+ }
61+ return NOT_FOUND ;
62+ }
63+ % SetInlineBuiltinFlag ( MapFindEntry ) ;
64+
65+
66+ function ComputeIntegerHash ( key , seed ) {
67+ var hash = key ;
68+ hash = hash ^ seed ;
69+ hash = ~ hash + ( hash << 15 ) ; // hash = (hash << 15) - hash - 1;
70+ hash = hash ^ ( hash >>> 12 ) ;
71+ hash = hash + ( hash << 2 ) ;
72+ hash = hash ^ ( hash >>> 4 ) ;
73+ hash = ( hash * 2057 ) | 0 ; // hash = (hash + (hash << 3)) + (hash << 11);
74+ hash = hash ^ ( hash >>> 16 ) ;
75+ return hash ;
76+ }
77+ % SetInlineBuiltinFlag ( ComputeIntegerHash ) ;
78+
79+
80+ function GetHash ( key ) {
81+ if ( % _IsSmi ( key ) ) {
82+ return ComputeIntegerHash ( key , 0 ) ;
83+ }
84+ if ( IS_STRING ( key ) ) {
85+ var field = % _StringGetRawHashField ( key ) ;
86+ if ( ( field & 1 /* Name::kHashNotComputedMask */ ) === 0 ) {
87+ return field >>> 2 /* Name::kHashShift */ ;
88+ }
89+ }
90+ return % GenericHash ( key ) ;
91+ }
92+ % SetInlineBuiltinFlag ( GetHash ) ;
93+
94+
1595// -------------------------------------------------------------------
1696// Harmony Set
1797
@@ -35,7 +115,7 @@ function SetConstructor(iterable) {
35115}
36116
37117
38- function SetAddJS ( key ) {
118+ function SetAdd ( key ) {
39119 if ( ! IS_SET ( this ) ) {
40120 throw MakeTypeError ( 'incompatible_method_receiver' ,
41121 [ 'Set.prototype.add' , this ] ) ;
@@ -47,34 +127,76 @@ function SetAddJS(key) {
47127 if ( key === 0 ) {
48128 key = 0 ;
49129 }
50- return % _SetAdd ( this , key ) ;
130+ var table = % _JSCollectionGetTable ( this ) ;
131+ var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT ( table ) ;
132+ var hash = GetHash ( key ) ;
133+ if ( SetFindEntry ( table , numBuckets , key , hash ) !== NOT_FOUND ) return this ;
134+
135+ var nof = ORDERED_HASH_TABLE_ELEMENT_COUNT ( table ) ;
136+ var nod = ORDERED_HASH_TABLE_DELETED_COUNT ( table ) ;
137+ var capacity = numBuckets << 1 ;
138+ if ( ( nof + nod ) >= capacity ) {
139+ // Need to grow, bail out to runtime.
140+ % SetGrow ( this ) ;
141+ // Re-load state from the grown backing store.
142+ table = % _JSCollectionGetTable ( this ) ;
143+ numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT ( table ) ;
144+ nof = ORDERED_HASH_TABLE_ELEMENT_COUNT ( table ) ;
145+ nod = ORDERED_HASH_TABLE_DELETED_COUNT ( table ) ;
146+ }
147+ var entry = nof + nod ;
148+ var index = ORDERED_HASH_SET_ENTRY_TO_INDEX ( entry , numBuckets ) ;
149+ var bucket = ORDERED_HASH_TABLE_HASH_TO_BUCKET ( hash , numBuckets ) ;
150+ var chainEntry = ORDERED_HASH_TABLE_BUCKET_AT ( table , bucket ) ;
151+ ORDERED_HASH_TABLE_SET_BUCKET_AT ( table , bucket , entry ) ;
152+ ORDERED_HASH_TABLE_SET_ELEMENT_COUNT ( table , nof + 1 ) ;
153+ FIXED_ARRAY_SET ( table , index , key ) ;
154+ FIXED_ARRAY_SET_SMI ( table , index + 1 , chainEntry ) ;
155+ return this ;
51156}
52157
53158
54- function SetHasJS ( key ) {
159+ function SetHas ( key ) {
55160 if ( ! IS_SET ( this ) ) {
56161 throw MakeTypeError ( 'incompatible_method_receiver' ,
57162 [ 'Set.prototype.has' , this ] ) ;
58163 }
59- return % _SetHas ( this , key ) ;
164+ var table = % _JSCollectionGetTable ( this ) ;
165+ var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT ( table ) ;
166+ var hash = GetHash ( key ) ;
167+ return SetFindEntry ( table , numBuckets , key , hash ) !== NOT_FOUND ;
60168}
61169
62170
63- function SetDeleteJS ( key ) {
171+ function SetDelete ( key ) {
64172 if ( ! IS_SET ( this ) ) {
65173 throw MakeTypeError ( 'incompatible_method_receiver' ,
66174 [ 'Set.prototype.delete' , this ] ) ;
67175 }
68- return % _SetDelete ( this , key ) ;
176+ var table = % _JSCollectionGetTable ( this ) ;
177+ var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT ( table ) ;
178+ var hash = GetHash ( key ) ;
179+ var entry = SetFindEntry ( table , numBuckets , key , hash ) ;
180+ if ( entry === NOT_FOUND ) return false ;
181+
182+ var nof = ORDERED_HASH_TABLE_ELEMENT_COUNT ( table ) - 1 ;
183+ var nod = ORDERED_HASH_TABLE_DELETED_COUNT ( table ) + 1 ;
184+ var index = ORDERED_HASH_SET_ENTRY_TO_INDEX ( entry , numBuckets ) ;
185+ FIXED_ARRAY_SET ( table , index , % _TheHole ( ) ) ;
186+ ORDERED_HASH_TABLE_SET_ELEMENT_COUNT ( table , nof ) ;
187+ ORDERED_HASH_TABLE_SET_DELETED_COUNT ( table , nod ) ;
188+ if ( nof < ( numBuckets >>> 1 ) ) % SetShrink ( this ) ;
189+ return true ;
69190}
70191
71192
72- function SetGetSizeJS ( ) {
193+ function SetGetSize ( ) {
73194 if ( ! IS_SET ( this ) ) {
74195 throw MakeTypeError ( 'incompatible_method_receiver' ,
75196 [ 'Set.prototype.size' , this ] ) ;
76197 }
77- return % _SetGetSize ( this ) ;
198+ var table = % _JSCollectionGetTable ( this ) ;
199+ return ORDERED_HASH_TABLE_ELEMENT_COUNT ( table ) ;
78200}
79201
80202
@@ -130,11 +252,11 @@ function SetUpSet() {
130252 % FunctionSetLength ( SetForEach , 1 ) ;
131253
132254 // Set up the non-enumerable functions on the Set prototype object.
133- InstallGetter ( $Set . prototype , "size" , SetGetSizeJS ) ;
255+ InstallGetter ( $Set . prototype , "size" , SetGetSize ) ;
134256 InstallFunctions ( $Set . prototype , DONT_ENUM , $Array (
135- "add" , SetAddJS ,
136- "has" , SetHasJS ,
137- "delete" , SetDeleteJS ,
257+ "add" , SetAdd ,
258+ "has" , SetHas ,
259+ "delete" , SetDelete ,
138260 "clear" , SetClearJS ,
139261 "forEach" , SetForEach
140262 ) ) ;
@@ -169,16 +291,21 @@ function MapConstructor(iterable) {
169291}
170292
171293
172- function MapGetJS ( key ) {
294+ function MapGet ( key ) {
173295 if ( ! IS_MAP ( this ) ) {
174296 throw MakeTypeError ( 'incompatible_method_receiver' ,
175297 [ 'Map.prototype.get' , this ] ) ;
176298 }
177- return % _MapGet ( this , key ) ;
299+ var table = % _JSCollectionGetTable ( this ) ;
300+ var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT ( table ) ;
301+ var hash = GetHash ( key ) ;
302+ var entry = MapFindEntry ( table , numBuckets , key , hash ) ;
303+ if ( entry === NOT_FOUND ) return UNDEFINED ;
304+ return ORDERED_HASH_MAP_VALUE_AT ( table , entry , numBuckets ) ;
178305}
179306
180307
181- function MapSetJS ( key , value ) {
308+ function MapSet ( key , value ) {
182309 if ( ! IS_MAP ( this ) ) {
183310 throw MakeTypeError ( 'incompatible_method_receiver' ,
184311 [ 'Map.prototype.set' , this ] ) ;
@@ -190,34 +317,84 @@ function MapSetJS(key, value) {
190317 if ( key === 0 ) {
191318 key = 0 ;
192319 }
193- return % _MapSet ( this , key , value ) ;
320+
321+ var table = % _JSCollectionGetTable ( this ) ;
322+ var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT ( table ) ;
323+ var hash = GetHash ( key ) ;
324+ var entry = MapFindEntry ( table , numBuckets , key , hash ) ;
325+ if ( entry !== NOT_FOUND ) {
326+ var existingIndex = ORDERED_HASH_MAP_ENTRY_TO_INDEX ( entry , numBuckets ) ;
327+ FIXED_ARRAY_SET ( table , existingIndex + 1 , value ) ;
328+ return this ;
329+ }
330+
331+ var nof = ORDERED_HASH_TABLE_ELEMENT_COUNT ( table ) ;
332+ var nod = ORDERED_HASH_TABLE_DELETED_COUNT ( table ) ;
333+ var capacity = numBuckets << 1 ;
334+ if ( ( nof + nod ) >= capacity ) {
335+ // Need to grow, bail out to runtime.
336+ % MapGrow ( this ) ;
337+ // Re-load state from the grown backing store.
338+ table = % _JSCollectionGetTable ( this ) ;
339+ numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT ( table ) ;
340+ nof = ORDERED_HASH_TABLE_ELEMENT_COUNT ( table ) ;
341+ nod = ORDERED_HASH_TABLE_DELETED_COUNT ( table ) ;
342+ }
343+ entry = nof + nod ;
344+ var index = ORDERED_HASH_MAP_ENTRY_TO_INDEX ( entry , numBuckets ) ;
345+ var bucket = ORDERED_HASH_TABLE_HASH_TO_BUCKET ( hash , numBuckets ) ;
346+ var chainEntry = ORDERED_HASH_TABLE_BUCKET_AT ( table , bucket ) ;
347+ ORDERED_HASH_TABLE_SET_BUCKET_AT ( table , bucket , entry ) ;
348+ ORDERED_HASH_TABLE_SET_ELEMENT_COUNT ( table , nof + 1 ) ;
349+ FIXED_ARRAY_SET ( table , index , key ) ;
350+ FIXED_ARRAY_SET ( table , index + 1 , value ) ;
351+ FIXED_ARRAY_SET ( table , index + 2 , chainEntry ) ;
352+ return this ;
194353}
195354
196355
197- function MapHasJS ( key ) {
356+ function MapHas ( key ) {
198357 if ( ! IS_MAP ( this ) ) {
199358 throw MakeTypeError ( 'incompatible_method_receiver' ,
200359 [ 'Map.prototype.has' , this ] ) ;
201360 }
202- return % _MapHas ( this , key ) ;
361+ var table = % _JSCollectionGetTable ( this ) ;
362+ var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT ( table ) ;
363+ var hash = GetHash ( key ) ;
364+ return MapFindEntry ( table , numBuckets , key , hash ) !== NOT_FOUND ;
203365}
204366
205367
206- function MapDeleteJS ( key ) {
368+ function MapDelete ( key ) {
207369 if ( ! IS_MAP ( this ) ) {
208370 throw MakeTypeError ( 'incompatible_method_receiver' ,
209371 [ 'Map.prototype.delete' , this ] ) ;
210372 }
211- return % _MapDelete ( this , key ) ;
373+ var table = % _JSCollectionGetTable ( this ) ;
374+ var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT ( table ) ;
375+ var hash = GetHash ( key ) ;
376+ var entry = MapFindEntry ( table , numBuckets , key , hash ) ;
377+ if ( entry === NOT_FOUND ) return false ;
378+
379+ var nof = ORDERED_HASH_TABLE_ELEMENT_COUNT ( table ) - 1 ;
380+ var nod = ORDERED_HASH_TABLE_DELETED_COUNT ( table ) + 1 ;
381+ var index = ORDERED_HASH_MAP_ENTRY_TO_INDEX ( entry , numBuckets ) ;
382+ FIXED_ARRAY_SET ( table , index , % _TheHole ( ) ) ;
383+ FIXED_ARRAY_SET ( table , index + 1 , % _TheHole ( ) ) ;
384+ ORDERED_HASH_TABLE_SET_ELEMENT_COUNT ( table , nof ) ;
385+ ORDERED_HASH_TABLE_SET_DELETED_COUNT ( table , nod ) ;
386+ if ( nof < ( numBuckets >>> 1 ) ) % MapShrink ( this ) ;
387+ return true ;
212388}
213389
214390
215- function MapGetSizeJS ( ) {
391+ function MapGetSize ( ) {
216392 if ( ! IS_MAP ( this ) ) {
217393 throw MakeTypeError ( 'incompatible_method_receiver' ,
218394 [ 'Map.prototype.size' , this ] ) ;
219395 }
220- return % _MapGetSize ( this ) ;
396+ var table = % _JSCollectionGetTable ( this ) ;
397+ return ORDERED_HASH_TABLE_ELEMENT_COUNT ( table ) ;
221398}
222399
223400
@@ -271,15 +448,20 @@ function SetUpMap() {
271448 % FunctionSetLength ( MapForEach , 1 ) ;
272449
273450 // Set up the non-enumerable functions on the Map prototype object.
274- InstallGetter ( $Map . prototype , "size" , MapGetSizeJS ) ;
451+ InstallGetter ( $Map . prototype , "size" , MapGetSize ) ;
275452 InstallFunctions ( $Map . prototype , DONT_ENUM , $Array (
276- "get" , MapGetJS ,
277- "set" , MapSetJS ,
278- "has" , MapHasJS ,
279- "delete" , MapDeleteJS ,
453+ "get" , MapGet ,
454+ "set" , MapSet ,
455+ "has" , MapHas ,
456+ "delete" , MapDelete ,
280457 "clear" , MapClearJS ,
281458 "forEach" , MapForEach
282459 ) ) ;
460+
461+ $MapGet = MapGet ;
462+ $MapSet = MapSet ;
283463}
284464
285465SetUpMap ( ) ;
466+
467+ } ) ( ) ;
0 commit comments