Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: feb3c574ac2e
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 0c7ea04af5d1
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Apr 1, 2016

  1. Copy the full SHA
    5b4cdca View commit details
  2. Copy the full SHA
    86ac1ae View commit details
  3. Copy the full SHA
    0c7ea04 View commit details
9 changes: 9 additions & 0 deletions spec/ruby/core/hash/compare_by_identity_spec.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../fixtures/classes', __FILE__)

describe "Hash#compare_by_identity" do
before :each do
@h = {}
@@ -38,6 +41,12 @@
@idh[obj].should == :a
end

it "does not call #hash on keys" do
key = HashSpecs::ByIdentityKey.new
@idh[key] = 1
@idh[key].should == 1
end

it "regards #dup'd objects as having different identities" do
str = 'foo'
@idh[str.dup] = :str
6 changes: 6 additions & 0 deletions spec/ruby/core/hash/fixtures/classes.rb
Original file line number Diff line number Diff line change
@@ -33,6 +33,12 @@ class KeyWithPrivateHash
private :hash
end

class ByIdentityKey
def hash
fail("#hash should not be called on compare_by_identity Hash")
end
end

def self.empty_frozen_hash
@empty ||= {}
@empty.freeze
44 changes: 31 additions & 13 deletions truffle/src/main/java/org/jruby/truffle/core/hash/HashNodes.java
Original file line number Diff line number Diff line change
@@ -253,9 +253,8 @@ protected boolean equal(VirtualFrame frame, Object key1, Object key2) {
}

@ExplodeLoop
@Specialization(guards = "isPackedHash(hash)", contains = "getConstantIndexPackedArray")
@Specialization(guards = { "isPackedHash(hash)", "!isCompareByIdentity(hash)" }, contains = "getConstantIndexPackedArray")
public Object getPackedArray(VirtualFrame frame, DynamicObject hash, Object key,
@Cached("createBinaryProfile()") ConditionProfile byIdentityProfile,
@Cached("create()") BranchProfile notInHashProfile,
@Cached("create()") BranchProfile useDefaultProfile) {
final int hashed = hashNode.hash(frame, key);
@@ -265,24 +264,43 @@ public Object getPackedArray(VirtualFrame frame, DynamicObject hash, Object key,

for (int n = 0; n < getContext().getOptions().HASH_PACKED_ARRAY_MAX; n++) {
if (n < size) {
if (hashed == PackedArrayStrategy.getHashed(store, n)) {
final boolean equal;
if (hashed == PackedArrayStrategy.getHashed(store, n) &&
eql(frame, key, PackedArrayStrategy.getKey(store, n))) {
return PackedArrayStrategy.getValue(store, n);
}
}
}

if (byIdentityProfile.profile(Layouts.HASH.getCompareByIdentity(hash))) {
equal = equal(frame, key, PackedArrayStrategy.getKey(store, n));
} else {
equal = eql(frame, key, PackedArrayStrategy.getKey(store, n));
}
notInHashProfile.enter();

if (equal) {
return PackedArrayStrategy.getValue(store, n);
}
if (undefinedValue != null) {
return undefinedValue;
}

useDefaultProfile.enter();
return callDefaultNode.call(frame, hash, "default", null, key);

}

@ExplodeLoop
@Specialization(guards = { "isPackedHash(hash)", "isCompareByIdentity(hash)" },
contains = "getConstantIndexPackedArray")
public Object getPackedArrayByIdentity(VirtualFrame frame, DynamicObject hash, Object key,
@Cached("create()") BranchProfile notInHashProfile,
@Cached("create()") BranchProfile useDefaultProfile) {
final Object[] store = (Object[]) Layouts.HASH.getStore(hash);
final int size = Layouts.HASH.getSize(hash);

for (int n = 0; n < getContext().getOptions().HASH_PACKED_ARRAY_MAX; n++) {
if (n < size) {
if (equal(frame, key, PackedArrayStrategy.getKey(store, n))) {
return PackedArrayStrategy.getValue(store, n);
}
}
}

notInHashProfile.enter();

if (undefinedValue != null) {
return undefinedValue;
}
33 changes: 18 additions & 15 deletions truffle/src/main/java/org/jruby/truffle/core/hash/SetNode.java
Original file line number Diff line number Diff line change
@@ -92,27 +92,30 @@ public Object setNullNotByIdentity(VirtualFrame frame, DynamicObject hash, Dynam
public Object setPackedArray(VirtualFrame frame, DynamicObject hash, Object key, Object value, boolean byIdentity) {
assert HashOperations.verifyStore(getContext(), hash);

final int hashed = hashNode.hash(frame, key);
boolean profiledByIdentity = byIdentityProfile.profile(byIdentity);

int hashed = 0;
if (profiledByIdentity) {
hashed = hashNode.hash(frame, key);
}

final Object[] store = (Object[]) Layouts.HASH.getStore(hash);
final int size = Layouts.HASH.getSize(hash);

for (int n = 0; n < getContext().getOptions().HASH_PACKED_ARRAY_MAX; n++) {
if (n < size) {
if (hashed == PackedArrayStrategy.getHashed(store, n)) {
final boolean equal;

if (byIdentityProfile.profile(byIdentity)) {
equal = equalNode.executeReferenceEqual(frame, key, PackedArrayStrategy.getKey(store, n));
} else {
equal = eqlNode.callBoolean(frame, key, "eql?", null, PackedArrayStrategy.getKey(store, n));
}

if (equal) {
PackedArrayStrategy.setValue(store, n, value);
assert HashOperations.verifyStore(getContext(), hash);
return value;
}
final boolean equal;
if (profiledByIdentity) {
equal = equalNode.executeReferenceEqual(frame, key, PackedArrayStrategy.getKey(store, n));
} else {
equal = hashed == PackedArrayStrategy.getHashed(store, n) &&
eqlNode.callBoolean(frame, key, "eql?", null, PackedArrayStrategy.getKey(store, n));
}

if (equal) {
PackedArrayStrategy.setValue(store, n, value);
assert HashOperations.verifyStore(getContext(), hash);
return value;
}
}
}