Skip to content

Commit

Permalink
Showing 1 changed file with 37 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -25,6 +25,8 @@
import org.jruby.truffle.nodes.core.BasicObjectNodesFactory;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.nodes.objects.IsFrozenNode;
import org.jruby.truffle.nodes.objects.IsFrozenNodeGen;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.hash.*;
import org.jruby.truffle.runtime.layouts.Layouts;
@@ -48,6 +50,12 @@ public abstract class SetNode extends RubyNode {
private final BranchProfile extendProfile = BranchProfile.create();
private final ConditionProfile strategyProfile = ConditionProfile.createBinaryProfile();

@Child private IsFrozenNode isFrozenNode;
@Child private CallDispatchHeadNode dupNode;
@Child private CallDispatchHeadNode freezeNode;

private final ConditionProfile frozenProfile = ConditionProfile.createBinaryProfile();

public SetNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
hashNode = new HashNode(context, sourceSection);
@@ -72,12 +80,12 @@ public Object setNull(VirtualFrame frame, DynamicObject hash, Object key, Object

@Specialization(guards = {"isNullHash(hash)", "byIdentity", "isRubyString(key)"})
public Object setNullByIdentity(VirtualFrame frame, DynamicObject hash, DynamicObject key, Object value, boolean byIdentity) {
return setNull(frame, hash, (Object) key, value, byIdentity);
return setNull(frame, hash, key, value, byIdentity);
}

@Specialization(guards = {"isNullHash(hash)", "!byIdentity", "isRubyString(key)"})
public Object setNullNotByIdentity(VirtualFrame frame, DynamicObject hash, DynamicObject key, Object value, boolean byIdentity) {
return setNull(frame, hash, ruby(frame, "key.frozen? ? key : key.dup.freeze", "key", key), value, byIdentity);
return setNull(frame, hash, freezeAndDupIfNeeded(frame, key), value, byIdentity);
}

@ExplodeLoop
@@ -133,7 +141,7 @@ public Object setPackedArrayByIdentity(VirtualFrame frame, DynamicObject hash, D

@Specialization(guards = {"isPackedHash(hash)", "!byIdentity", "isRubyString(key)"})
public Object setPackedArrayNotByIdentity(VirtualFrame frame, DynamicObject hash, DynamicObject key, Object value, boolean byIdentity) {
return setPackedArray(frame, hash, ruby(frame, "key.frozen? ? key : key.dup.freeze", "key", key), value, byIdentity);
return setPackedArray(frame, hash, freezeAndDupIfNeeded(frame, key), value, byIdentity);
}

// Can't be @Cached yet as we call from the RubyString specialisation
@@ -197,12 +205,36 @@ public Object setBuckets(VirtualFrame frame, DynamicObject hash, Object key, Obj

@Specialization(guards = {"isBucketHash(hash)", "byIdentity", "isRubyString(key)"})
public Object setBucketsByIdentity(VirtualFrame frame, DynamicObject hash, DynamicObject key, Object value, boolean byIdentity) {
return setBuckets(frame, hash, (Object) key, value, byIdentity);
return setBuckets(frame, hash, key, value, byIdentity);
}

@Specialization(guards = {"isBucketHash(hash)", "!byIdentity", "isRubyString(key)"})
public Object setBucketsNotByIdentity(VirtualFrame frame, DynamicObject hash, DynamicObject key, Object value, boolean byIdentity) {
return setBuckets(frame, hash, ruby(frame, "key.frozen? ? key : key.dup.freeze", "key", key), value, byIdentity);
return setBuckets(frame, hash, freezeAndDupIfNeeded(frame, key), value, byIdentity);
}

private DynamicObject freezeAndDupIfNeeded(VirtualFrame frame, DynamicObject key) {
if (isFrozenNode == null) {
CompilerDirectives.transferToInterpreter();
isFrozenNode = insert(IsFrozenNodeGen.create(getContext(), getSourceSection(), null));
}

if (frozenProfile.profile(isFrozenNode.executeIsFrozen(key))) {

This comment has been minimized.

Copy link
@thedarkone

thedarkone Oct 6, 2015

Contributor

The if/else branches seem to be inverted to me. If the String is frozen, use it as a key, if it is not frozen dup & freeze and use the obj as a key.

This comment has been minimized.

Copy link
@chrisseaton

chrisseaton Oct 6, 2015

Author Contributor

Ah yeah you're right - thanks

if (dupNode == null) {
CompilerDirectives.transferToInterpreter();
dupNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

if (freezeNode == null) {
CompilerDirectives.transferToInterpreter();
freezeNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

final Object dupped = dupNode.call(frame, key, "dup", null);

This comment has been minimized.

Copy link
@nirvdrum

nirvdrum Oct 6, 2015

Contributor

Typo? Or have you been using dupped right along and I just didn't notice? It's local, so not a big deal. I'd just rather match if I'm not conforming (I've been using duped).

This comment has been minimized.

Copy link
@chrisseaton

chrisseaton Oct 6, 2015

Author Contributor

Yeah typo.

return (DynamicObject) freezeNode.call(frame, dupped, "freeze", null);

This comment has been minimized.

Copy link
@nirvdrum

nirvdrum Oct 6, 2015

Contributor

Should we be casting like this? I've just been promoting to Object.

This comment has been minimized.

Copy link
@chrisseaton

chrisseaton Oct 6, 2015

Author Contributor

Yeah I'm not sure about things like this. If String#freeze doesn't return a DynamicObject though, this is probably the least of your troubles. In this case I guess I can just return Object though. Will fix.

This comment has been minimized.

Copy link
@nirvdrum

nirvdrum Oct 6, 2015

Contributor

I guess you'd get a ClassCastException here, which could be easier to debug that propagating something further down the chain.

} else {
return key;
}
}

}

0 comments on commit dffe5aa

Please sign in to comment.