55
55
public class BucketsHashStore {
56
56
57
57
private final Entry [] entries ;
58
+ private Entry firstInSequence ;
59
+ private Entry lastInSequence ;
58
60
59
- public BucketsHashStore (Entry [] entries ) {
61
+ public BucketsHashStore (Entry [] entries , Entry firstInSequence , Entry lastInSequence ) {
60
62
this .entries = entries ;
63
+ this .firstInSequence = firstInSequence ;
64
+ this .lastInSequence = lastInSequence ;
61
65
}
62
66
63
67
// region Constants
@@ -121,49 +125,52 @@ static int getBucketIndex(int hashed, int bucketsCount) {
121
125
}
122
126
123
127
@ TruffleBoundary
124
- private static void resize (RubyHash hash ) {
125
- final int bucketsCount = capacityGreaterThan (hash . size ) * OVERALLOCATE_FACTOR ;
128
+ private void resize (RubyHash hash , int size ) {
129
+ final int bucketsCount = capacityGreaterThan (size ) * OVERALLOCATE_FACTOR ;
126
130
final Entry [] newEntries = new Entry [bucketsCount ];
127
131
128
- Entry entry = hash .firstInSequence ;
132
+ final Entry firstInSequence = this .firstInSequence ;
133
+ Entry lastInSequence = null ;
134
+ Entry entry = firstInSequence ;
129
135
130
136
while (entry != null ) {
131
137
final int bucketIndex = getBucketIndex (entry .getHashed (), bucketsCount );
132
138
appendToLookupChain (newEntries , entry , bucketIndex );
133
139
134
140
entry .setNextInLookup (null );
141
+ lastInSequence = entry ;
135
142
entry = entry .getNextInSequence ();
136
143
}
137
144
138
- hash .store = new BucketsHashStore (newEntries );
145
+ hash .store = new BucketsHashStore (newEntries , firstInSequence , lastInSequence );
139
146
}
140
147
141
- public static void getAdjacentObjects (Set <Object > reachable , Entry firstInSequence ) {
142
- Entry entry = firstInSequence ;
148
+ public void getAdjacentObjects (Set <Object > reachable ) {
149
+ Entry entry = this . firstInSequence ;
143
150
while (entry != null ) {
144
151
ObjectGraph .addProperty (reachable , entry .getKey ());
145
152
ObjectGraph .addProperty (reachable , entry .getValue ());
146
153
entry = entry .getNextInSequence ();
147
154
}
148
155
}
149
156
150
- private static void removeFromSequenceChain (RubyHash hash , Entry entry ) {
157
+ private void removeFromSequenceChain (Entry entry ) {
151
158
final Entry previousInSequence = entry .getPreviousInSequence ();
152
159
final Entry nextInSequence = entry .getNextInSequence ();
153
160
154
161
if (previousInSequence == null ) {
155
- assert hash .firstInSequence == entry ;
156
- hash .firstInSequence = nextInSequence ;
162
+ assert this .firstInSequence == entry ;
163
+ this .firstInSequence = nextInSequence ;
157
164
} else {
158
- assert hash .firstInSequence != entry ;
165
+ assert this .firstInSequence != entry ;
159
166
previousInSequence .setNextInSequence (nextInSequence );
160
167
}
161
168
162
169
if (nextInSequence == null ) {
163
- assert hash .lastInSequence == entry ;
164
- hash .lastInSequence = previousInSequence ;
170
+ assert this .lastInSequence == entry ;
171
+ this .lastInSequence = previousInSequence ;
165
172
} else {
166
- assert hash .lastInSequence != entry ;
173
+ assert this .lastInSequence != entry ;
167
174
nextInSequence .setPreviousInSequence (previousInSequence );
168
175
}
169
176
}
@@ -243,20 +250,20 @@ protected boolean set(RubyHash hash, Object key, Object value, boolean byIdentit
243
250
result .getPreviousEntry ().setNextInLookup (newEntry );
244
251
}
245
252
246
- final Entry lastInSequence = hash .lastInSequence ;
253
+ final Entry lastInSequence = this .lastInSequence ;
247
254
if (appending .profile (lastInSequence == null )) {
248
- hash .firstInSequence = newEntry ;
255
+ this .firstInSequence = newEntry ;
249
256
} else {
250
257
lastInSequence .setNextInSequence (newEntry );
251
258
newEntry .setPreviousInSequence (lastInSequence );
252
259
}
253
- hash .lastInSequence = newEntry ;
260
+ this .lastInSequence = newEntry ;
254
261
255
262
final int newSize = (hash .size += 1 );
256
263
assert verify (hash );
257
264
258
265
if (resize .profile (newSize / (double ) entries .length > LOAD_FACTOR )) {
259
- resize (hash );
266
+ resize (hash , newSize );
260
267
assert ((BucketsHashStore ) hash .store ).verify (hash ); // store changed!
261
268
}
262
269
return true ;
@@ -281,7 +288,7 @@ protected Object delete(RubyHash hash, Object key,
281
288
return null ;
282
289
}
283
290
284
- removeFromSequenceChain (hash , entry );
291
+ removeFromSequenceChain (entry );
285
292
removeFromLookupChain (entries , lookupResult .getIndex (), entry , lookupResult .getPreviousEntry ());
286
293
hash .size -= 1 ;
287
294
assert verify (hash );
@@ -294,7 +301,7 @@ protected Object deleteLast(RubyHash hash, Object key,
294
301
assert verify (hash );
295
302
296
303
final Entry [] entries = this .entries ;
297
- final Entry lastEntry = hash .lastInSequence ;
304
+ final Entry lastEntry = this .lastInSequence ;
298
305
if (key != lastEntry .getKey ()) {
299
306
CompilerDirectives .transferToInterpreterAndInvalidate ();
300
307
throw CompilerDirectives
@@ -311,15 +318,15 @@ protected Object deleteLast(RubyHash hash, Object key,
311
318
}
312
319
assert entry .getNextInSequence () == null ;
313
320
314
- if (singleEntry .profile (hash .firstInSequence == entry )) {
321
+ if (singleEntry .profile (this .firstInSequence == entry )) {
315
322
assert entry .getPreviousInSequence () == null ;
316
- hash .firstInSequence = null ;
317
- hash .lastInSequence = null ;
323
+ this .firstInSequence = null ;
324
+ this .lastInSequence = null ;
318
325
} else {
319
326
assert entry .getPreviousInSequence () != null ;
320
327
final Entry previousInSequence = entry .getPreviousInSequence ();
321
328
previousInSequence .setNextInSequence (null );
322
- hash .lastInSequence = previousInSequence ;
329
+ this .lastInSequence = previousInSequence ;
323
330
}
324
331
325
332
removeFromLookupChain (entries , index , entry , previousEntry );
@@ -336,7 +343,7 @@ protected Object eachEntry(RubyHash hash, EachEntryCallback callback, Object sta
336
343
assert verify (hash );
337
344
loopProfile .profileCounted (hash .size );
338
345
int i = 0 ;
339
- Entry entry = hash .firstInSequence ;
346
+ Entry entry = this .firstInSequence ;
340
347
try {
341
348
while (loopProfile .inject (entry != null )) {
342
349
callback .accept (i ++, entry .getKey (), entry .getValue (), state );
@@ -370,7 +377,7 @@ protected void replace(RubyHash hash, RubyHash dest,
370
377
371
378
Entry firstInSequence = null ;
372
379
Entry lastInSequence = null ;
373
- Entry entry = hash .firstInSequence ;
380
+ Entry entry = this .firstInSequence ;
374
381
375
382
while (entry != null ) {
376
383
final Entry newEntry = new Entry (entry .getHashed (), entry .getKey (), entry .getValue ());
@@ -388,10 +395,8 @@ protected void replace(RubyHash hash, RubyHash dest,
388
395
entry = entry .getNextInSequence ();
389
396
}
390
397
391
- dest .store = new BucketsHashStore (newEntries );
398
+ dest .store = new BucketsHashStore (newEntries , firstInSequence , lastInSequence );
392
399
dest .size = hash .size ;
393
- dest .firstInSequence = firstInSequence ;
394
- dest .lastInSequence = lastInSequence ;
395
400
dest .defaultBlock = hash .defaultBlock ;
396
401
dest .defaultValue = hash .defaultValue ;
397
402
dest .compareByIdentity = hash .compareByIdentity ;
@@ -406,21 +411,18 @@ protected RubyArray shift(RubyHash hash,
406
411
assert verify (hash );
407
412
408
413
final Entry [] entries = this .entries ;
409
- final Entry first = hash .firstInSequence ;
414
+ final Entry first = this .firstInSequence ;
410
415
assert first .getPreviousInSequence () == null ;
411
416
412
417
final Object key = first .getKey ();
413
418
final Object value = first .getValue ();
414
419
415
- hash .firstInSequence = first .getNextInSequence ();
416
-
417
- if (first .getNextInSequence () != null ) {
418
- first .getNextInSequence ().setPreviousInSequence (null );
419
- hash .firstInSequence = first .getNextInSequence ();
420
- }
421
-
422
- if (hash .lastInSequence == first ) {
423
- hash .lastInSequence = null ;
420
+ final Entry second = first .getNextInSequence ();
421
+ this .firstInSequence = second ;
422
+ if (second == null ) {
423
+ this .lastInSequence = null ;
424
+ } else {
425
+ second .setPreviousInSequence (null );
424
426
}
425
427
426
428
final int index = getBucketIndex (first .getHashed (), entries .length );
@@ -452,7 +454,7 @@ protected void rehash(RubyHash hash,
452
454
final Entry [] entries = this .entries ;
453
455
Arrays .fill (entries , null );
454
456
455
- Entry entry = hash .firstInSequence ;
457
+ Entry entry = this .firstInSequence ;
456
458
while (entry != null ) {
457
459
final int newHash = hashNode .execute (entry .getKey (), hash .compareByIdentity );
458
460
entry .setHashed (newHash );
@@ -474,7 +476,7 @@ protected void rehash(RubyHash hash,
474
476
newHash ,
475
477
bucketEntry .getKey (),
476
478
bucketEntry .getHashed ())) {
477
- removeFromSequenceChain (hash , entry );
479
+ removeFromSequenceChain (entry );
478
480
size --;
479
481
break ;
480
482
}
@@ -498,8 +500,8 @@ public boolean verify(RubyHash hash) {
498
500
499
501
final Entry [] entries = this .entries ;
500
502
final int size = hash .size ;
501
- final Entry firstInSequence = hash .firstInSequence ;
502
- final Entry lastInSequence = hash .lastInSequence ;
503
+ final Entry firstInSequence = this .firstInSequence ;
504
+ final Entry lastInSequence = this .lastInSequence ;
503
505
assert lastInSequence == null || lastInSequence .getNextInSequence () == null ;
504
506
505
507
Entry foundFirst = null ;
@@ -603,10 +605,8 @@ public Object execute(VirtualFrame frame) {
603
605
coreLibrary ().hashClass ,
604
606
getLanguage ().hashShape ,
605
607
getContext (),
606
- new BucketsHashStore (new Entry [bucketsCount ]),
608
+ new BucketsHashStore (new Entry [bucketsCount ], null , null ),
607
609
0 ,
608
- null ,
609
- null ,
610
610
nil ,
611
611
nil ,
612
612
false );
0 commit comments