Skip to content

Commit fb49596

Browse files
committed
[Truffle] Dup and freeze string keys in hash literals.
1 parent 6d43d9f commit fb49596

File tree

3 files changed

+28
-4
lines changed

3 files changed

+28
-4
lines changed

core/src/main/java/org/jruby/truffle/nodes/literal/HashLiteralNode.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,25 @@
1414
import com.oracle.truffle.api.frame.*;
1515
import com.oracle.truffle.api.nodes.*;
1616
import org.jruby.truffle.nodes.*;
17+
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
1718
import org.jruby.truffle.runtime.*;
1819
import org.jruby.truffle.runtime.core.RubyHash;
20+
import org.jruby.truffle.runtime.core.RubyString;
1921

2022
import java.util.LinkedHashMap;
2123

2224
public abstract class HashLiteralNode extends RubyNode {
2325

2426
@Children protected final RubyNode[] keyValues;
27+
@Child protected DispatchHeadNode dupNode;
28+
@Child protected DispatchHeadNode freezeNode;
2529

2630
protected HashLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] keyValues) {
2731
super(context, sourceSection);
2832
assert keyValues.length % 2 == 0;
2933
this.keyValues = keyValues;
34+
dupNode = new DispatchHeadNode(context);
35+
freezeNode = new DispatchHeadNode(context);
3036
}
3137

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

87-
for (int n = 0; n < keyValues.length; n++) {
88-
storage[n] = keyValues[n].execute(frame);
93+
for (int n = 0; n < keyValues.length; n += 2) {
94+
Object key = keyValues[n].execute(frame);
95+
final Object value = keyValues[n + 1].execute(frame);
96+
97+
if (key instanceof RubyString) {
98+
key = freezeNode.call(frame, dupNode.call(frame, key, "dup", null), "freeze", null);
99+
}
100+
101+
storage[n] = key;
102+
storage[n + 1] = value;
89103
}
90104

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

109123
for (int n = 0; n < keyValues.length; n += 2) {
110-
storage.put(keyValues[n].execute(frame), keyValues[n + 1].execute(frame));
124+
Object key = keyValues[n].execute(frame);
125+
final Object value = keyValues[n + 1].execute(frame);
126+
127+
if (key instanceof RubyString) {
128+
key = freezeNode.call(frame, dupNode.call(frame, key, "dup", null), "freeze", null);
129+
}
130+
131+
storage.put(key, value);
111132
}
112133

113134
return new RubyHash(getContext().getCoreLibrary().getHashClass(), null, storage, 0);

core/src/main/java/org/jruby/truffle/runtime/core/RubyObject.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ public RubyObject(RubyClass rubyClass) {
2727
super(rubyClass);
2828
}
2929

30+
public boolean isFrozen() {
31+
return frozen;
32+
}
33+
3034
public void checkFrozen(Node currentNode) {
3135
if (frozen) {
3236
CompilerDirectives.transferToInterpreter();
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
fails:Hash literal freezes string keys on initialization
21
fails:Hash literal checks duplicated keys on initialization

0 commit comments

Comments
 (0)