Skip to content

Commit 4eff8c1

Browse files
committed
Refactor LocalVariableSetNode node to support DSL inlining
1 parent a63aa78 commit 4eff8c1

File tree

4 files changed

+120
-92
lines changed

4 files changed

+120
-92
lines changed

src/main/java/org/truffleruby/core/binding/BindingNodes.java

Lines changed: 6 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@
4343
import org.truffleruby.language.locals.FindDeclarationVariableNodes;
4444
import org.truffleruby.language.locals.FindDeclarationVariableNodes.FrameSlotAndDepth;
4545
import org.truffleruby.language.locals.FrameDescriptorNamesIterator;
46-
import org.truffleruby.language.locals.WriteFrameSlotNode;
47-
import org.truffleruby.language.locals.WriteFrameSlotNodeGen;
4846

4947
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5048
import com.oracle.truffle.api.Truffle;
@@ -312,26 +310,12 @@ public RubyNode cloneUninitialized() {
312310
}
313311

314312
@ReportPolymorphism
315-
@GenerateUncached
316313
@GenerateNodeFactory
317314
@CoreMethod(names = "local_variable_set", required = 2)
318315
@NodeChild(value = "bindingNode", type = RubyNode.class)
319316
@NodeChild(value = "nameNode", type = RubyBaseNodeWithExecute.class)
320317
@NodeChild(value = "valueNode", type = RubyNode.class)
321-
@ImportStatic({ BindingNodes.class, FindDeclarationVariableNodes.class })
322-
public abstract static class LocalVariableSetNode extends RubySourceNode {
323-
324-
@NeverDefault
325-
public static LocalVariableSetNode create() {
326-
return BindingNodesFactory.LocalVariableSetNodeFactory.create(null, null, null);
327-
}
328-
329-
public static LocalVariableSetNode create(RubyNode bindingNode, RubyBaseNodeWithExecute nameNode,
330-
RubyNode valueNode) {
331-
return BindingNodesFactory.LocalVariableSetNodeFactory.create(bindingNode, nameNode, valueNode);
332-
}
333-
334-
public abstract Object execute(RubyBinding binding, String name, Object value);
318+
public abstract static class BindingLocalVariableSetNode extends RubySourceNode {
335319

336320
abstract RubyNode getBindingNode();
337321

@@ -344,77 +328,10 @@ protected RubyBaseNodeWithExecute coerceToString(RubyBaseNodeWithExecute name) {
344328
return NameToJavaStringNode.create(name);
345329
}
346330

347-
@Specialization(
348-
guards = {
349-
"name == cachedName",
350-
"!isHiddenVariable(cachedName)",
351-
"getFrameDescriptor(binding) == cachedFrameDescriptor",
352-
"cachedFrameSlot != null" },
353-
limit = "getCacheLimit()")
354-
protected Object localVariableSetCached(RubyBinding binding, String name, Object value,
355-
@Cached("name") String cachedName,
356-
@Cached("getFrameDescriptor(binding)") FrameDescriptor cachedFrameDescriptor,
357-
@Cached("findFrameSlotOrNull(name, binding.getFrame())") FrameSlotAndDepth cachedFrameSlot,
358-
@Cached("createWriteNode(cachedFrameSlot.slot)") WriteFrameSlotNode writeLocalVariableNode) {
359-
final MaterializedFrame frame = RubyArguments
360-
.getDeclarationFrame(binding.getFrame(), cachedFrameSlot.depth);
361-
writeLocalVariableNode.executeWrite(frame, value);
362-
return value;
363-
}
364-
365-
@Specialization(
366-
guards = {
367-
"name == cachedName",
368-
"!isHiddenVariable(cachedName)",
369-
"getFrameDescriptor(binding) == cachedFrameDescriptor",
370-
"cachedFrameSlot == null" },
371-
limit = "getCacheLimit()")
372-
protected Object localVariableSetNewCached(RubyBinding binding, String name, Object value,
373-
@Cached("name") String cachedName,
374-
@Cached("getFrameDescriptor(binding)") FrameDescriptor cachedFrameDescriptor,
375-
@Cached("findFrameSlotOrNull(name, binding.getFrame())") FrameSlotAndDepth cachedFrameSlot,
376-
@Cached("newFrameDescriptor(cachedFrameDescriptor, name)") FrameDescriptor newDescriptor,
377-
@Cached("createWriteNode(NEW_VAR_INDEX)") WriteFrameSlotNode writeLocalVariableNode) {
378-
final MaterializedFrame frame = newFrame(binding, newDescriptor);
379-
writeLocalVariableNode.executeWrite(frame, value);
380-
return value;
381-
}
382-
383-
@TruffleBoundary
384-
@Specialization(
385-
guards = "!isHiddenVariable(name)",
386-
replaces = { "localVariableSetCached", "localVariableSetNewCached" })
387-
protected Object localVariableSetUncached(RubyBinding binding, String name, Object value) {
388-
MaterializedFrame frame = binding.getFrame();
389-
final FrameSlotAndDepth frameSlot = FindDeclarationVariableNodes.findFrameSlotOrNull(name, frame);
390-
final int slot;
391-
if (frameSlot != null) {
392-
frame = RubyArguments.getDeclarationFrame(frame, frameSlot.depth);
393-
slot = frameSlot.slot;
394-
} else {
395-
var newDescriptor = newFrameDescriptor(getFrameDescriptor(binding), name);
396-
frame = newFrame(binding, newDescriptor);
397-
assert newDescriptor.getSlotName(NEW_VAR_INDEX) == name;
398-
slot = NEW_VAR_INDEX;
399-
}
400-
frame.setObject(slot, value);
401-
return value;
402-
}
403-
404-
@TruffleBoundary
405-
@Specialization(guards = "isHiddenVariable(name)")
406-
protected Object localVariableSetLastLine(RubyBinding binding, String name, Object value) {
407-
throw new RaiseException(
408-
getContext(),
409-
coreExceptions().nameError("Bad local variable name", binding, name, this));
410-
}
411-
412-
protected WriteFrameSlotNode createWriteNode(int frameSlot) {
413-
return WriteFrameSlotNodeGen.create(frameSlot);
414-
}
415-
416-
protected int getCacheLimit() {
417-
return getLanguage().options.BINDING_LOCAL_VARIABLE_CACHE;
331+
@Specialization
332+
protected Object localVariableSet(RubyBinding binding, String name, Object value,
333+
@Cached LocalVariableSetNode localVariableSetNode) {
334+
return localVariableSetNode.execute(binding, name, value);
418335
}
419336

420337
private RubyBaseNodeWithExecute getNameNodeBeforeCasting() {
@@ -423,12 +340,11 @@ private RubyBaseNodeWithExecute getNameNodeBeforeCasting() {
423340

424341
@Override
425342
public RubyNode cloneUninitialized() {
426-
return create(
343+
return BindingNodesFactory.BindingLocalVariableSetNodeFactory.create(
427344
getBindingNode().cloneUninitialized(),
428345
getNameNodeBeforeCasting().cloneUninitialized(),
429346
getValueNode().cloneUninitialized()).copyFlags(this);
430347
}
431-
432348
}
433349

434350
@Primitive(name = "local_variable_names")
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 2.0, or
7+
* GNU General Public License version 2, or
8+
* GNU Lesser General Public License version 2.1.
9+
*/
10+
package org.truffleruby.core.binding;
11+
12+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
13+
import com.oracle.truffle.api.dsl.Cached;
14+
import com.oracle.truffle.api.dsl.GenerateUncached;
15+
import com.oracle.truffle.api.dsl.ImportStatic;
16+
import com.oracle.truffle.api.dsl.Specialization;
17+
import com.oracle.truffle.api.frame.FrameDescriptor;
18+
import com.oracle.truffle.api.frame.MaterializedFrame;
19+
import org.truffleruby.language.RubyBaseNode;
20+
import org.truffleruby.language.arguments.RubyArguments;
21+
import org.truffleruby.language.control.RaiseException;
22+
import org.truffleruby.language.locals.FindDeclarationVariableNodes;
23+
import org.truffleruby.language.locals.WriteFrameSlotNode;
24+
import org.truffleruby.language.locals.WriteFrameSlotNodeGen;
25+
26+
import static org.truffleruby.core.binding.BindingNodes.NEW_VAR_INDEX;
27+
import static org.truffleruby.core.binding.BindingNodes.getFrameDescriptor;
28+
import static org.truffleruby.core.binding.BindingNodes.newFrame;
29+
import static org.truffleruby.core.binding.BindingNodes.newFrameDescriptor;
30+
31+
@GenerateUncached
32+
@ImportStatic({ BindingNodes.class, FindDeclarationVariableNodes.class })
33+
public abstract class LocalVariableSetNode extends RubyBaseNode {
34+
35+
public abstract Object execute(RubyBinding binding, String name, Object value);
36+
37+
@Specialization(
38+
guards = {
39+
"name == cachedName",
40+
"!isHiddenVariable(cachedName)",
41+
"getFrameDescriptor(binding) == cachedFrameDescriptor",
42+
"cachedFrameSlot != null" },
43+
limit = "getCacheLimit()")
44+
protected Object localVariableSetCached(RubyBinding binding, String name, Object value,
45+
@Cached("name") String cachedName,
46+
@Cached("getFrameDescriptor(binding)") FrameDescriptor cachedFrameDescriptor,
47+
@Cached("findFrameSlotOrNull(name, binding.getFrame())") FindDeclarationVariableNodes.FrameSlotAndDepth cachedFrameSlot,
48+
@Cached("createWriteNode(cachedFrameSlot.slot)") WriteFrameSlotNode writeLocalVariableNode) {
49+
final MaterializedFrame frame = RubyArguments
50+
.getDeclarationFrame(binding.getFrame(), cachedFrameSlot.depth);
51+
writeLocalVariableNode.executeWrite(frame, value);
52+
return value;
53+
}
54+
55+
@Specialization(
56+
guards = {
57+
"name == cachedName",
58+
"!isHiddenVariable(cachedName)",
59+
"getFrameDescriptor(binding) == cachedFrameDescriptor",
60+
"cachedFrameSlot == null" },
61+
limit = "getCacheLimit()")
62+
protected Object localVariableSetNewCached(RubyBinding binding, String name, Object value,
63+
@Cached("name") String cachedName,
64+
@Cached("getFrameDescriptor(binding)") FrameDescriptor cachedFrameDescriptor,
65+
@Cached("findFrameSlotOrNull(name, binding.getFrame())") FindDeclarationVariableNodes.FrameSlotAndDepth cachedFrameSlot,
66+
@Cached("newFrameDescriptor(cachedFrameDescriptor, name)") FrameDescriptor newDescriptor,
67+
@Cached("createWriteNode(NEW_VAR_INDEX)") WriteFrameSlotNode writeLocalVariableNode) {
68+
final MaterializedFrame frame = newFrame(binding, newDescriptor);
69+
writeLocalVariableNode.executeWrite(frame, value);
70+
return value;
71+
}
72+
73+
@TruffleBoundary
74+
@Specialization(
75+
guards = "!isHiddenVariable(name)",
76+
replaces = { "localVariableSetCached", "localVariableSetNewCached" })
77+
protected Object localVariableSetUncached(RubyBinding binding, String name, Object value) {
78+
MaterializedFrame frame = binding.getFrame();
79+
final FindDeclarationVariableNodes.FrameSlotAndDepth frameSlot = FindDeclarationVariableNodes
80+
.findFrameSlotOrNull(name, frame);
81+
final int slot;
82+
if (frameSlot != null) {
83+
frame = RubyArguments.getDeclarationFrame(frame, frameSlot.depth);
84+
slot = frameSlot.slot;
85+
} else {
86+
var newDescriptor = newFrameDescriptor(getFrameDescriptor(binding), name);
87+
frame = newFrame(binding, newDescriptor);
88+
assert newDescriptor.getSlotName(NEW_VAR_INDEX) == name;
89+
slot = NEW_VAR_INDEX;
90+
}
91+
frame.setObject(slot, value);
92+
return value;
93+
}
94+
95+
@TruffleBoundary
96+
@Specialization(guards = "isHiddenVariable(name)")
97+
protected Object localVariableSetLastLine(RubyBinding binding, String name, Object value) {
98+
throw new RaiseException(
99+
getContext(),
100+
coreExceptions().nameError("Bad local variable name", binding, name, this));
101+
}
102+
103+
protected WriteFrameSlotNode createWriteNode(int frameSlot) {
104+
return WriteFrameSlotNodeGen.create(frameSlot);
105+
}
106+
107+
protected int getCacheLimit() {
108+
return getLanguage().options.BINDING_LOCAL_VARIABLE_CACHE;
109+
}
110+
}

src/main/java/org/truffleruby/debug/BindingLocalVariablesObject.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.oracle.truffle.api.library.CachedLibrary;
1414
import org.truffleruby.core.binding.BindingNodes;
1515
import org.truffleruby.core.binding.LocalVariableGetNode;
16+
import org.truffleruby.core.binding.LocalVariableSetNode;
1617
import org.truffleruby.core.binding.RubyBinding;
1718
import org.truffleruby.core.string.StringUtils;
1819
import org.truffleruby.language.control.RaiseException;
@@ -67,7 +68,7 @@ protected Object readMember(String member,
6768

6869
@ExportMessage
6970
protected void writeMember(String member, Object value,
70-
@Cached BindingNodes.LocalVariableSetNode localVariableSetNode) throws UnknownIdentifierException {
71+
@Cached LocalVariableSetNode localVariableSetNode) throws UnknownIdentifierException {
7172
if (isValidLocalVariableName(member)) {
7273
localVariableSetNode.execute(binding, member, value);
7374
} else {

src/main/java/org/truffleruby/debug/RubyScope.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.truffleruby.RubyLanguage;
2929
import org.truffleruby.core.binding.BindingNodes;
3030
import org.truffleruby.core.binding.LocalVariableGetNode;
31+
import org.truffleruby.core.binding.LocalVariableSetNode;
3132
import org.truffleruby.core.binding.RubyBinding;
3233
import org.truffleruby.core.string.StringUtils;
3334
import org.truffleruby.language.RubyNode;
@@ -177,7 +178,7 @@ static final class WriteMember {
177178
@Specialization
178179
protected static void writeMember(RubyScope scope, String member, Object value,
179180
@CachedLibrary("scope") InteropLibrary interopLibrary,
180-
@Cached BindingNodes.LocalVariableSetNode localVariableSetNode) throws UnknownIdentifierException {
181+
@Cached LocalVariableSetNode localVariableSetNode) throws UnknownIdentifierException {
181182
if (interopLibrary.isMemberModifiable(scope, member)) {
182183
localVariableSetNode.execute(scope.binding, member, value);
183184
} else {

0 commit comments

Comments
 (0)