Skip to content

Commit 000b1c0

Browse files
committed
Move the firstInSequence/lastInSequence fields to BucketsHashStore
* Other strategies do not need them.
1 parent 5dd3741 commit 000b1c0

File tree

7 files changed

+50
-75
lines changed

7 files changed

+50
-75
lines changed

src/main/java/org/truffleruby/core/hash/HashNodes.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
5858
protected RubyHash allocate(RubyClass rubyClass) {
5959
final Shape shape = getLanguage().hashShape;
6060
final EmptyHashStore store = EmptyHashStore.NULL_HASH_STORE;
61-
final RubyHash hash = new RubyHash(rubyClass, shape, getContext(), store, 0, null, null, nil, nil, false);
61+
final RubyHash hash = new RubyHash(rubyClass, shape, getContext(), store, 0, nil, nil, false);
6262
AllocationTracing.trace(hash, this);
6363
return hash;
6464
}
@@ -109,7 +109,7 @@ protected Object construct(RubyClass hashClass, Object[] args,
109109
}
110110

111111
final Shape shape = getLanguage().hashShape;
112-
return new RubyHash(hashClass, shape, getContext(), newStore, size, null, null, nil, nil, false);
112+
return new RubyHash(hashClass, shape, getContext(), newStore, size, nil, nil, false);
113113
}
114114

115115
@Specialization(guards = "!isSmallArrayOfPairs(args, getLanguage())")

src/main/java/org/truffleruby/core/hash/HashOperations.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ public static RubyHash newEmptyHash(RubyContext context, RubyLanguage language)
2727
context,
2828
EmptyHashStore.NULL_HASH_STORE,
2929
0,
30-
null,
31-
null,
3230
nil,
3331
nil,
3432
false);

src/main/java/org/truffleruby/core/hash/RubyHash.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ public class RubyHash extends RubyDynamicObject implements ObjectGraphNode {
4646
public Object defaultValue;
4747
public Object store;
4848
public int size;
49-
public Entry firstInSequence;
50-
public Entry lastInSequence;
5149
public boolean compareByIdentity;
5250
public boolean ruby2_keywords = false;
5351

@@ -57,8 +55,6 @@ public RubyHash(
5755
RubyContext context,
5856
Object store,
5957
int size,
60-
Entry firstInSequence,
61-
Entry lastInSequence,
6258
Object defaultBlock,
6359
Object defaultValue,
6460
boolean compareByIdentity) {
@@ -67,8 +63,6 @@ public RubyHash(
6763
this.defaultValue = defaultValue;
6864
this.store = store;
6965
this.size = size;
70-
this.firstInSequence = firstInSequence;
71-
this.lastInSequence = lastInSequence;
7266
this.compareByIdentity = compareByIdentity;
7367

7468
if (context.isPreInitializing()) {
@@ -79,7 +73,7 @@ public RubyHash(
7973
@TruffleBoundary
8074
public void getAdjacentObjects(Set<Object> reachable) {
8175
if (store instanceof BucketsHashStore) {
82-
BucketsHashStore.getAdjacentObjects(reachable, firstInSequence);
76+
((BucketsHashStore) store).getAdjacentObjects(reachable);
8377
} else {
8478
ObjectGraph.addProperty(reachable, store);
8579
}

src/main/java/org/truffleruby/core/hash/library/BucketsHashStore.java

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,13 @@
5555
public class BucketsHashStore {
5656

5757
private final Entry[] entries;
58+
private Entry firstInSequence;
59+
private Entry lastInSequence;
5860

59-
public BucketsHashStore(Entry[] entries) {
61+
public BucketsHashStore(Entry[] entries, Entry firstInSequence, Entry lastInSequence) {
6062
this.entries = entries;
63+
this.firstInSequence = firstInSequence;
64+
this.lastInSequence = lastInSequence;
6165
}
6266

6367
// region Constants
@@ -121,49 +125,52 @@ static int getBucketIndex(int hashed, int bucketsCount) {
121125
}
122126

123127
@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;
126130
final Entry[] newEntries = new Entry[bucketsCount];
127131

128-
Entry entry = hash.firstInSequence;
132+
final Entry firstInSequence = this.firstInSequence;
133+
Entry lastInSequence = null;
134+
Entry entry = firstInSequence;
129135

130136
while (entry != null) {
131137
final int bucketIndex = getBucketIndex(entry.getHashed(), bucketsCount);
132138
appendToLookupChain(newEntries, entry, bucketIndex);
133139

134140
entry.setNextInLookup(null);
141+
lastInSequence = entry;
135142
entry = entry.getNextInSequence();
136143
}
137144

138-
hash.store = new BucketsHashStore(newEntries);
145+
hash.store = new BucketsHashStore(newEntries, firstInSequence, lastInSequence);
139146
}
140147

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;
143150
while (entry != null) {
144151
ObjectGraph.addProperty(reachable, entry.getKey());
145152
ObjectGraph.addProperty(reachable, entry.getValue());
146153
entry = entry.getNextInSequence();
147154
}
148155
}
149156

150-
private static void removeFromSequenceChain(RubyHash hash, Entry entry) {
157+
private void removeFromSequenceChain(Entry entry) {
151158
final Entry previousInSequence = entry.getPreviousInSequence();
152159
final Entry nextInSequence = entry.getNextInSequence();
153160

154161
if (previousInSequence == null) {
155-
assert hash.firstInSequence == entry;
156-
hash.firstInSequence = nextInSequence;
162+
assert this.firstInSequence == entry;
163+
this.firstInSequence = nextInSequence;
157164
} else {
158-
assert hash.firstInSequence != entry;
165+
assert this.firstInSequence != entry;
159166
previousInSequence.setNextInSequence(nextInSequence);
160167
}
161168

162169
if (nextInSequence == null) {
163-
assert hash.lastInSequence == entry;
164-
hash.lastInSequence = previousInSequence;
170+
assert this.lastInSequence == entry;
171+
this.lastInSequence = previousInSequence;
165172
} else {
166-
assert hash.lastInSequence != entry;
173+
assert this.lastInSequence != entry;
167174
nextInSequence.setPreviousInSequence(previousInSequence);
168175
}
169176
}
@@ -243,20 +250,20 @@ protected boolean set(RubyHash hash, Object key, Object value, boolean byIdentit
243250
result.getPreviousEntry().setNextInLookup(newEntry);
244251
}
245252

246-
final Entry lastInSequence = hash.lastInSequence;
253+
final Entry lastInSequence = this.lastInSequence;
247254
if (appending.profile(lastInSequence == null)) {
248-
hash.firstInSequence = newEntry;
255+
this.firstInSequence = newEntry;
249256
} else {
250257
lastInSequence.setNextInSequence(newEntry);
251258
newEntry.setPreviousInSequence(lastInSequence);
252259
}
253-
hash.lastInSequence = newEntry;
260+
this.lastInSequence = newEntry;
254261

255262
final int newSize = (hash.size += 1);
256263
assert verify(hash);
257264

258265
if (resize.profile(newSize / (double) entries.length > LOAD_FACTOR)) {
259-
resize(hash);
266+
resize(hash, newSize);
260267
assert ((BucketsHashStore) hash.store).verify(hash); // store changed!
261268
}
262269
return true;
@@ -281,7 +288,7 @@ protected Object delete(RubyHash hash, Object key,
281288
return null;
282289
}
283290

284-
removeFromSequenceChain(hash, entry);
291+
removeFromSequenceChain(entry);
285292
removeFromLookupChain(entries, lookupResult.getIndex(), entry, lookupResult.getPreviousEntry());
286293
hash.size -= 1;
287294
assert verify(hash);
@@ -294,7 +301,7 @@ protected Object deleteLast(RubyHash hash, Object key,
294301
assert verify(hash);
295302

296303
final Entry[] entries = this.entries;
297-
final Entry lastEntry = hash.lastInSequence;
304+
final Entry lastEntry = this.lastInSequence;
298305
if (key != lastEntry.getKey()) {
299306
CompilerDirectives.transferToInterpreterAndInvalidate();
300307
throw CompilerDirectives
@@ -311,15 +318,15 @@ protected Object deleteLast(RubyHash hash, Object key,
311318
}
312319
assert entry.getNextInSequence() == null;
313320

314-
if (singleEntry.profile(hash.firstInSequence == entry)) {
321+
if (singleEntry.profile(this.firstInSequence == entry)) {
315322
assert entry.getPreviousInSequence() == null;
316-
hash.firstInSequence = null;
317-
hash.lastInSequence = null;
323+
this.firstInSequence = null;
324+
this.lastInSequence = null;
318325
} else {
319326
assert entry.getPreviousInSequence() != null;
320327
final Entry previousInSequence = entry.getPreviousInSequence();
321328
previousInSequence.setNextInSequence(null);
322-
hash.lastInSequence = previousInSequence;
329+
this.lastInSequence = previousInSequence;
323330
}
324331

325332
removeFromLookupChain(entries, index, entry, previousEntry);
@@ -336,7 +343,7 @@ protected Object eachEntry(RubyHash hash, EachEntryCallback callback, Object sta
336343
assert verify(hash);
337344
loopProfile.profileCounted(hash.size);
338345
int i = 0;
339-
Entry entry = hash.firstInSequence;
346+
Entry entry = this.firstInSequence;
340347
try {
341348
while (loopProfile.inject(entry != null)) {
342349
callback.accept(i++, entry.getKey(), entry.getValue(), state);
@@ -370,7 +377,7 @@ protected void replace(RubyHash hash, RubyHash dest,
370377

371378
Entry firstInSequence = null;
372379
Entry lastInSequence = null;
373-
Entry entry = hash.firstInSequence;
380+
Entry entry = this.firstInSequence;
374381

375382
while (entry != null) {
376383
final Entry newEntry = new Entry(entry.getHashed(), entry.getKey(), entry.getValue());
@@ -388,10 +395,8 @@ protected void replace(RubyHash hash, RubyHash dest,
388395
entry = entry.getNextInSequence();
389396
}
390397

391-
dest.store = new BucketsHashStore(newEntries);
398+
dest.store = new BucketsHashStore(newEntries, firstInSequence, lastInSequence);
392399
dest.size = hash.size;
393-
dest.firstInSequence = firstInSequence;
394-
dest.lastInSequence = lastInSequence;
395400
dest.defaultBlock = hash.defaultBlock;
396401
dest.defaultValue = hash.defaultValue;
397402
dest.compareByIdentity = hash.compareByIdentity;
@@ -406,21 +411,18 @@ protected RubyArray shift(RubyHash hash,
406411
assert verify(hash);
407412

408413
final Entry[] entries = this.entries;
409-
final Entry first = hash.firstInSequence;
414+
final Entry first = this.firstInSequence;
410415
assert first.getPreviousInSequence() == null;
411416

412417
final Object key = first.getKey();
413418
final Object value = first.getValue();
414419

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);
424426
}
425427

426428
final int index = getBucketIndex(first.getHashed(), entries.length);
@@ -452,7 +454,7 @@ protected void rehash(RubyHash hash,
452454
final Entry[] entries = this.entries;
453455
Arrays.fill(entries, null);
454456

455-
Entry entry = hash.firstInSequence;
457+
Entry entry = this.firstInSequence;
456458
while (entry != null) {
457459
final int newHash = hashNode.execute(entry.getKey(), hash.compareByIdentity);
458460
entry.setHashed(newHash);
@@ -474,7 +476,7 @@ protected void rehash(RubyHash hash,
474476
newHash,
475477
bucketEntry.getKey(),
476478
bucketEntry.getHashed())) {
477-
removeFromSequenceChain(hash, entry);
479+
removeFromSequenceChain(entry);
478480
size--;
479481
break;
480482
}
@@ -498,8 +500,8 @@ public boolean verify(RubyHash hash) {
498500

499501
final Entry[] entries = this.entries;
500502
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;
503505
assert lastInSequence == null || lastInSequence.getNextInSequence() == null;
504506

505507
Entry foundFirst = null;
@@ -603,10 +605,8 @@ public Object execute(VirtualFrame frame) {
603605
coreLibrary().hashClass,
604606
getLanguage().hashShape,
605607
getContext(),
606-
new BucketsHashStore(new Entry[bucketsCount]),
608+
new BucketsHashStore(new Entry[bucketsCount], null, null),
607609
0,
608-
null,
609-
null,
610610
nil,
611611
nil,
612612
false);

src/main/java/org/truffleruby/core/hash/library/EmptyHashStore.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ protected void replace(RubyHash hash, RubyHash dest,
8686
propagateSharing.executePropagate(dest, hash);
8787
dest.store = EmptyHashStore.NULL_HASH_STORE;
8888
dest.size = 0;
89-
dest.firstInSequence = null;
90-
dest.lastInSequence = null;
9189
dest.defaultBlock = hash.defaultBlock;
9290
dest.defaultValue = hash.defaultValue;
9391
dest.compareByIdentity = hash.compareByIdentity;
@@ -110,8 +108,6 @@ public boolean verify(RubyHash hash) {
110108
assert hash.store == this;
111109
assert hash.store == NULL_HASH_STORE;
112110
assert hash.size == 0;
113-
assert hash.firstInSequence == null;
114-
assert hash.lastInSequence == null;
115111
return true;
116112
}
117113

src/main/java/org/truffleruby/core/hash/library/HashStoreLibrary.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ public abstract Object lookupOrDefault(Object store, Frame frame, RubyHash hash,
7272
public void clear(Object store, RubyHash hash) {
7373
hash.store = EmptyHashStore.NULL_HASH_STORE;
7474
hash.size = 0;
75-
hash.firstInSequence = null;
76-
hash.lastInSequence = null;
7775
}
7876

7977
/** Removes the entry for the key from the hash, and returns the associated value. If the hash does not have an

src/main/java/org/truffleruby/core/hash/library/PackedHashStoreLibrary.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,8 @@ private static void promoteToBuckets(RubyHash hash, Object[] store, int size) {
150150
BucketsHashStore.appendToLookupChain(buckets, entry, bucketIndex);
151151
}
152152

153-
hash.store = new BucketsHashStore(buckets);
153+
hash.store = new BucketsHashStore(buckets, firstInSequence, lastInSequence);
154154
hash.size = size;
155-
hash.firstInSequence = firstInSequence;
156-
hash.lastInSequence = lastInSequence;
157155
}
158156

159157
// endregion
@@ -317,8 +315,6 @@ protected static void replace(Object[] store, RubyHash hash, RubyHash dest,
317315
int size = hash.size;
318316
dest.store = storeCopy;
319317
dest.size = size;
320-
dest.firstInSequence = null;
321-
dest.lastInSequence = null;
322318
dest.defaultBlock = hash.defaultBlock;
323319
dest.defaultValue = hash.defaultValue;
324320
dest.compareByIdentity = hash.compareByIdentity;
@@ -377,11 +373,6 @@ protected static boolean verify(Object[] store, RubyHash hash) {
377373
final int size = hash.size;
378374
assert store.length == TOTAL_ELEMENTS : store.length;
379375

380-
final Entry firstInSequence = hash.firstInSequence;
381-
final Entry lastInSequence = hash.lastInSequence;
382-
assert firstInSequence == null;
383-
assert lastInSequence == null;
384-
385376
for (int i = 0; i < size * ELEMENTS_PER_ENTRY; i++) {
386377
assert store[i] != null;
387378
}
@@ -534,8 +525,6 @@ public Object execute(VirtualFrame frame) {
534525
getContext(),
535526
store,
536527
size,
537-
null,
538-
null,
539528
nil,
540529
nil,
541530
false);

0 commit comments

Comments
 (0)