Skip to content

Commit

Permalink
Showing 3 changed files with 28 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -14,19 +14,25 @@
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.*;
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.core.RubyHash;
import org.jruby.truffle.runtime.core.RubyString;

import java.util.LinkedHashMap;

public abstract class HashLiteralNode extends RubyNode {

@Children protected final RubyNode[] keyValues;
@Child protected DispatchHeadNode dupNode;
@Child protected DispatchHeadNode freezeNode;

protected HashLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] keyValues) {
super(context, sourceSection);
assert keyValues.length % 2 == 0;
this.keyValues = keyValues;
dupNode = new DispatchHeadNode(context);
freezeNode = new DispatchHeadNode(context);
}

public static HashLiteralNode create(RubyContext context, SourceSection sourceSection, RubyNode[] keyValues) {
@@ -84,8 +90,16 @@ public SmallHashLiteralNode(RubyContext context, SourceSection sourceSection, Ru
public RubyHash executeRubyHash(VirtualFrame frame) {
final Object[] storage = new Object[RubyContext.HASHES_SMALL * 2];

for (int n = 0; n < keyValues.length; n++) {
storage[n] = keyValues[n].execute(frame);
for (int n = 0; n < keyValues.length; n += 2) {
Object key = keyValues[n].execute(frame);
final Object value = keyValues[n + 1].execute(frame);

if (key instanceof RubyString) {
key = freezeNode.call(frame, dupNode.call(frame, key, "dup", null), "freeze", null);
}

storage[n] = key;
storage[n + 1] = value;
}

return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, storage, keyValues.length / 2);
@@ -107,7 +121,14 @@ public RubyHash executeRubyHash(VirtualFrame frame) {
final LinkedHashMap<Object, Object> storage = new LinkedHashMap<>();

for (int n = 0; n < keyValues.length; n += 2) {
storage.put(keyValues[n].execute(frame), keyValues[n + 1].execute(frame));
Object key = keyValues[n].execute(frame);
final Object value = keyValues[n + 1].execute(frame);

if (key instanceof RubyString) {
key = freezeNode.call(frame, dupNode.call(frame, key, "dup", null), "freeze", null);
}

storage.put(key, value);
}

return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, storage, 0);
Original file line number Diff line number Diff line change
@@ -27,6 +27,10 @@ public RubyObject(RubyClass rubyClass) {
super(rubyClass);
}

public boolean isFrozen() {
return frozen;
}

public void checkFrozen(Node currentNode) {
if (frozen) {
CompilerDirectives.transferToInterpreter();
1 change: 0 additions & 1 deletion spec/truffle/tags/language/hash_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
fails:Hash literal freezes string keys on initialization
fails:Hash literal checks duplicated keys on initialization

3 comments on commit fb49596

@eregon
Copy link
Member

@eregon eregon commented on fb49596 Oct 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the key is already frozen?
MRI does not duplicate it in that case.

@chrisseaton
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, should be key instanceof RubyString && !((RubyString) key).isFrozen() - thanks.

@eregon
Copy link
Member

@eregon eregon commented on fb49596 Oct 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8d1f6d2.

Please sign in to comment.