-
-
Notifications
You must be signed in to change notification settings - Fork 941
[Truffle] New implementation of non-small hashes #2328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
9810a50
0eee052
3e82545
579881f
4b6b34a
3c5c26d
18593e6
35c1350
96c8da6
b2a89e6
639ecf6
2bb0e15
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,6 @@ | |
| import com.oracle.truffle.api.frame.*; | ||
| import com.oracle.truffle.api.utilities.BranchProfile; | ||
| import org.jruby.runtime.Visibility; | ||
| import org.jruby.truffle.nodes.RubyNode; | ||
| import org.jruby.truffle.nodes.RubyRootNode; | ||
| import org.jruby.truffle.nodes.dispatch.DispatchHeadNode; | ||
| import org.jruby.truffle.nodes.dispatch.PredicateDispatchHeadNode; | ||
|
|
@@ -25,6 +24,9 @@ | |
| import org.jruby.truffle.runtime.core.*; | ||
| import org.jruby.truffle.runtime.core.RubyArray; | ||
| import org.jruby.truffle.runtime.core.RubyHash; | ||
| import org.jruby.truffle.runtime.hash.Bucket; | ||
| import org.jruby.truffle.runtime.hash.BucketSearchResult; | ||
| import org.jruby.truffle.runtime.hash.Entry; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
|
|
@@ -57,8 +59,8 @@ public boolean equalNull(RubyHash a, RubyHash b) { | |
| public boolean equal(VirtualFrame frame, RubyHash a, RubyHash b) { | ||
| notDesignedForCompilation(); | ||
|
|
||
| final List<RubyHash.Entry> aEntries = a.verySlowToEntries(); | ||
| final List<RubyHash.Entry> bEntries = a.verySlowToEntries(); | ||
| final List<Entry> aEntries = a.verySlowToEntries(); | ||
| final List<Entry> bEntries = a.verySlowToEntries(); | ||
|
|
||
| if (aEntries.size() != bEntries.size()) { | ||
| return false; | ||
|
|
@@ -68,7 +70,7 @@ public boolean equal(VirtualFrame frame, RubyHash a, RubyHash b) { | |
|
|
||
| final boolean[] bUsed = new boolean[bEntries.size()]; | ||
|
|
||
| for (RubyHash.Entry aEntry : aEntries) { | ||
| for (Entry aEntry : aEntries) { | ||
| boolean found = false; | ||
|
|
||
| for (int n = 0; n < bEntries.size(); n++) { | ||
|
|
@@ -177,10 +179,10 @@ public RubyHash construct(Object[] args) { | |
| } else { | ||
| keyValues.enter(); | ||
|
|
||
| final List<RubyHash.Entry> entries = new ArrayList<>(); | ||
| final List<Entry> entries = new ArrayList<>(); | ||
|
|
||
| for (int n = 0; n < args.length; n += 2) { | ||
| entries.add(new RubyHash.Entry(args[n], args[n + 1])); | ||
| entries.add(new Entry(args[n], args[n + 1])); | ||
| } | ||
|
|
||
| return RubyHash.verySlowFromEntries(getContext(), entries); | ||
|
|
@@ -254,10 +256,10 @@ public Object getObjectArray(VirtualFrame frame, RubyHash hash, Object key) { | |
| public Object getBucketArray(VirtualFrame frame, RubyHash hash, Object key) { | ||
| notDesignedForCompilation(); | ||
|
|
||
| final RubyHash.BucketAndIndex bucketAndIndex = hash.verySlowFindBucket(key); | ||
| final BucketSearchResult bucketSearchResult = hash.verySlowFindBucket(key); | ||
|
|
||
| if (bucketAndIndex.getBucket() != null) { | ||
| return bucketAndIndex.getBucket().value; | ||
| if (bucketSearchResult.getBucket() != null) { | ||
| return bucketSearchResult.getBucket().getValue(); | ||
| } | ||
|
|
||
| notInHashProfile.enter(); | ||
|
|
@@ -335,11 +337,11 @@ public Object setObjectArray(VirtualFrame frame, RubyHash hash, Object key, Obje | |
|
|
||
| // TODO(CS): need to watch for that transfer until we make the following fast path | ||
|
|
||
| final List<RubyHash.Entry> entries = hash.verySlowToEntries(); | ||
| final List<Entry> entries = hash.verySlowToEntries(); | ||
|
|
||
| hash.setStore(new RubyHash.Bucket[RubyHash.capacityGreaterThan(newSize)], newSize, null, null); | ||
| hash.setStore(new Bucket[RubyHash.capacityGreaterThan(newSize)], newSize, null, null); | ||
|
|
||
| for (RubyHash.Entry entry : entries) { | ||
| for (Entry entry : entries) { | ||
| hash.verySlowSetInBuckets(entry.getKey(), entry.getValue()); | ||
| } | ||
|
|
||
|
|
@@ -433,43 +435,43 @@ public Object deleteObjectArray(VirtualFrame frame, RubyHash hash, Object key) { | |
| public Object delete(RubyHash hash, Object key) { | ||
| notDesignedForCompilation(); | ||
|
|
||
| final RubyHash.BucketAndIndex bucketAndIndex = hash.verySlowFindBucket(key); | ||
| final BucketSearchResult bucketSearchResult = hash.verySlowFindBucket(key); | ||
|
|
||
| if (bucketAndIndex.getBucket() == null) { | ||
| if (bucketSearchResult.getBucket() == null) { | ||
| return getContext().getCoreLibrary().getNilObject(); | ||
| } | ||
|
|
||
| final RubyHash.Bucket bucket = bucketAndIndex.getBucket(); | ||
| final Bucket bucket = bucketSearchResult.getBucket(); | ||
|
|
||
| // Remove from the sequence chain | ||
|
|
||
| if (bucket.previousInSequence == null) { | ||
| hash.firstInSequence = bucket.nextInSequence; | ||
| if (bucket.getPreviousInSequence() == null) { | ||
| hash.firstInSequence = bucket.getNextInSequence(); | ||
| } else { | ||
| bucket.previousInSequence.nextInSequence = bucket.nextInSequence; | ||
| bucket.getPreviousInSequence().setNextInSequence(bucket.getNextInSequence()); | ||
| } | ||
|
|
||
| if (bucket.nextInSequence == null) { | ||
| hash.lastInSequence = bucket.previousInSequence; | ||
| if (bucket.getNextInSequence() == null) { | ||
| hash.lastInSequence = bucket.getPreviousInSequence(); | ||
| } else { | ||
| bucket.nextInSequence.previousInSequence = bucket.previousInSequence; | ||
| bucket.getNextInSequence().setPreviousInSequence(bucket.getPreviousInSequence()); | ||
| } | ||
|
|
||
| // Remove from the lookup chain | ||
|
|
||
| if (bucket.previousInLookup == null) { | ||
| ((RubyHash.Bucket[]) hash.getStore())[bucketAndIndex.getIndex()] = bucket.nextInLookup; | ||
| if (bucket.getPreviousInLookup() == null) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So here is the only usage of |
||
| ((Bucket[]) hash.getStore())[bucketSearchResult.getIndex()] = bucket.getNextInLookup(); | ||
| } else { | ||
| bucket.previousInLookup.nextInLookup = bucket.nextInLookup; | ||
| bucket.getPreviousInLookup().setNextInLookup(bucket.getNextInLookup()); | ||
| } | ||
|
|
||
| if (bucket.nextInLookup != null) { | ||
| bucket.nextInLookup.previousInLookup = bucket.previousInLookup; | ||
| if (bucket.getNextInLookup() != null) { | ||
| bucket.getNextInLookup().setPreviousInLookup(bucket.getPreviousInLookup()); | ||
| } | ||
|
|
||
| hash.setStoreSize(hash.getStoreSize() - 1); | ||
|
|
||
| return bucket.value; | ||
| return bucket.getValue(); | ||
| } | ||
|
|
||
| } | ||
|
|
@@ -526,7 +528,7 @@ public RubyHash eachObjectArray(VirtualFrame frame, RubyHash hash, RubyProc bloc | |
| public RubyHash eachBucketArray(VirtualFrame frame, RubyHash hash, RubyProc block) { | ||
| notDesignedForCompilation(); | ||
|
|
||
| for (RubyHash.Entry entry : hash.verySlowToEntries()) { | ||
| for (Entry entry : hash.verySlowToEntries()) { | ||
| yield(frame, block, RubyArray.fromObjects(getContext().getCoreLibrary().getArrayClass(), entry.getKey(), entry.getValue())); | ||
| } | ||
|
|
||
|
|
@@ -681,7 +683,7 @@ public RubyString inspectObjectArray(VirtualFrame frame, RubyHash hash) { | |
|
|
||
| builder.append("{"); | ||
|
|
||
| for (RubyHash.Entry entry : hash.verySlowToEntries()) { | ||
| for (Entry entry : hash.verySlowToEntries()) { | ||
| if (builder.length() > 1) { | ||
| builder.append(", "); | ||
| } | ||
|
|
@@ -740,7 +742,7 @@ public boolean keyObjectArray(VirtualFrame frame, RubyHash hash, Object key) { | |
| public boolean keyBucketArray(VirtualFrame frame, RubyHash hash, Object key) { | ||
| notDesignedForCompilation(); | ||
|
|
||
| for (RubyHash.Entry entry : hash.verySlowToEntries()) { | ||
| for (Entry entry : hash.verySlowToEntries()) { | ||
| if (eqlNode.call(frame, entry.getKey(), "eql?", null, key)) { | ||
| return true; | ||
| } | ||
|
|
@@ -788,13 +790,13 @@ public RubyArray keysBucketArray(RubyHash hash) { | |
|
|
||
| final Object[] keys = new Object[hash.getStoreSize()]; | ||
|
|
||
| RubyHash.Bucket bucket = hash.firstInSequence; | ||
| Bucket bucket = hash.firstInSequence; | ||
| int n = 0; | ||
|
|
||
| while (bucket != null) { | ||
| keys[n] = bucket.key; | ||
| keys[n] = bucket.getKey(); | ||
| n++; | ||
| bucket = bucket.nextInSequence; | ||
| bucket = bucket.getNextInSequence(); | ||
| } | ||
|
|
||
| return new RubyArray(getContext().getCoreLibrary().getArrayClass(), keys, keys.length); | ||
|
|
@@ -852,7 +854,7 @@ public RubyArray mapBucketArray(VirtualFrame frame, RubyHash hash, RubyProc bloc | |
|
|
||
| final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass(), null, 0); | ||
|
|
||
| for (RubyHash.Entry entry : hash.verySlowToEntries()) { | ||
| for (Entry entry : hash.verySlowToEntries()) { | ||
| array.slowPush(yield(frame, block, entry.getKey(), entry.getValue())); | ||
| } | ||
|
|
||
|
|
@@ -974,13 +976,13 @@ public RubyHash mergeObjectArrayObjectArray(VirtualFrame frame, RubyHash hash, R | |
|
|
||
| @Specialization | ||
| public RubyHash mergeBucketArrayBucketArray(VirtualFrame frame, RubyHash hash, RubyHash other) { | ||
| final RubyHash merged = new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, new RubyHash.Bucket[RubyHash.capacityGreaterThan(hash.getStoreSize() + hash.getStoreSize())], 0, null); | ||
| final RubyHash merged = new RubyHash(getContext().getCoreLibrary().getHashClass(), null, null, new Bucket[RubyHash.capacityGreaterThan(hash.getStoreSize() + hash.getStoreSize())], 0, null); | ||
|
|
||
| for (RubyHash.Entry entry : hash.verySlowToEntries()) { | ||
| for (Entry entry : hash.verySlowToEntries()) { | ||
| merged.verySlowSetInBuckets(entry.getKey(), entry.getValue()); | ||
| } | ||
|
|
||
| for (RubyHash.Entry entry : other.verySlowToEntries()) { | ||
| for (Entry entry : other.verySlowToEntries()) { | ||
| merged.verySlowSetInBuckets(entry.getKey(), entry.getValue()); | ||
| } | ||
|
|
||
|
|
@@ -1083,13 +1085,13 @@ public RubyArray valuesBucketArray(RubyHash hash) { | |
|
|
||
| final Object[] values = new Object[hash.getStoreSize()]; | ||
|
|
||
| RubyHash.Bucket bucket = hash.firstInSequence; | ||
| Bucket bucket = hash.firstInSequence; | ||
| int n = 0; | ||
|
|
||
| while (bucket != null) { | ||
| values[n] = bucket.value; | ||
| values[n] = bucket.getValue(); | ||
| n++; | ||
| bucket = bucket.nextInSequence; | ||
| bucket = bucket.getNextInSequence(); | ||
| } | ||
|
|
||
| return new RubyArray(getContext().getCoreLibrary().getArrayClass(), values, values.length); | ||
|
|
@@ -1139,7 +1141,7 @@ public RubyArray toArrayBucketArray(RubyHash hash) { | |
|
|
||
| int n = 0; | ||
|
|
||
| for (RubyHash.Entry entry : hash.verySlowToEntries()) { | ||
| for (Entry entry : hash.verySlowToEntries()) { | ||
| pairs[n] = RubyArray.fromObjects(getContext().getCoreLibrary().getArrayClass(), entry.getValue(), entry.getValue()); | ||
| n++; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |
| import org.jruby.truffle.runtime.*; | ||
| import org.jruby.truffle.runtime.core.RubyHash; | ||
| import org.jruby.truffle.runtime.core.RubyString; | ||
| import org.jruby.truffle.runtime.hash.Entry; | ||
|
|
||
| import java.util.*; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor, but JRuby core prefers these be expanded. |
||
|
|
||
|
|
@@ -126,12 +127,12 @@ public GenericHashLiteralNode(RubyContext context, SourceSection sourceSection, | |
| public RubyHash executeRubyHash(VirtualFrame frame) { | ||
| notDesignedForCompilation(); | ||
|
|
||
| final List<RubyHash.Entry> entries = new ArrayList<>(); | ||
| final List<Entry> entries = new ArrayList<>(); | ||
|
|
||
| for (int n = 0; n < keyValues.length; n += 2) { | ||
| final Object key = keyValues[n].execute(frame); | ||
| final Object value = keyValues[n + 1].execute(frame); | ||
| entries.add(new RubyHash.Entry(key, value)); | ||
| entries.add(new Entry(key, value)); | ||
| } | ||
|
|
||
| return RubyHash.verySlowFromEntries(getContext(), entries); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this means there is no good way to check that the ObjectArray strategy is actually only using
justaObject[]withinstanceof?But
getClass()should do it then, so the assertions in RubyHash constructor should be adapted?Wondering if 2
instanceofis also better than 1getClass().