Skip to content

Commit b29826b

Browse files
committed
[GR-36678] Migrate to indexed frame slots
PullRequest: truffleruby/3163
2 parents f6f7135 + 650df69 commit b29826b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+640
-502
lines changed

mx.truffleruby/mx_truffleruby.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ def clean(self, forBuild=False):
105105
def contents(self, result):
106106
classpath_deps = [dep for dep in self.subject.buildDependencies if isinstance(dep, mx.ClasspathDependency)]
107107
jvm_args = [pipes.quote(arg) for arg in mx.get_runtime_jvm_args(classpath_deps)]
108+
debug_args = mx.java_debug_args()
109+
jvm_args.extend(debug_args)
110+
if debug_args:
111+
jvm_args.extend(['-ea', '-esa'])
108112
jvm_args.append('-Dorg.graalvm.language.ruby.home=' + root)
109113
main_class = 'org.truffleruby.launcher.RubyLauncher'
110114
ruby_options = [

mx.truffleruby/suite.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
{
88
"name": "regex",
99
"subdir": True,
10-
"version": "749e1e32ba43b105196fd630900243400241e38f",
10+
"version": "f8d52b2eccdc79c738b950a03d8d72adc08bd6bd",
1111
"urls": [
1212
{"url": "https://github.com/oracle/graal.git", "kind": "git"},
1313
{"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"},
@@ -16,7 +16,7 @@
1616
{
1717
"name": "sulong",
1818
"subdir": True,
19-
"version": "749e1e32ba43b105196fd630900243400241e38f",
19+
"version": "f8d52b2eccdc79c738b950a03d8d72adc08bd6bd",
2020
"urls": [
2121
{"url": "https://github.com/oracle/graal.git", "kind": "git"},
2222
{"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"},

src/main/java/org/truffleruby/Layouts.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,4 @@ public abstract class Layouts {
2929
public static final HiddenKey VALUE_WRAPPER_IDENTIFIER = new HiddenKey("value_wrapper"); // ValueWrapper
3030
public static final HiddenKey ALLOCATION_TRACE_IDENTIFIER = new HiddenKey("allocation_trace"); // AllocationTrace
3131

32-
// Frame slot name for special variable storage.
33-
34-
public static final String SPECIAL_VARIABLES_STORAGE = TEMP_PREFIX + "$~_";
35-
3632
}

src/main/java/org/truffleruby/RubyLanguage.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import com.oracle.truffle.api.ContextThreadLocal;
2424
import com.oracle.truffle.api.TruffleFile;
2525
import com.oracle.truffle.api.frame.FrameDescriptor;
26-
import com.oracle.truffle.api.frame.FrameSlot;
26+
import com.oracle.truffle.api.frame.MaterializedFrame;
2727
import com.oracle.truffle.api.instrumentation.AllocationReporter;
2828
import com.oracle.truffle.api.instrumentation.Instrumenter;
2929
import com.oracle.truffle.api.nodes.Node;
@@ -100,17 +100,18 @@
100100
import org.truffleruby.core.string.ImmutableRubyString;
101101
import org.truffleruby.interop.RubyInnerContext;
102102
import org.truffleruby.language.LexicalScope;
103-
import org.truffleruby.language.Nil;
104103
import org.truffleruby.language.RubyDynamicObject;
105104
import org.truffleruby.language.RubyEvalInteractiveRootNode;
106105
import org.truffleruby.language.RubyInlineParsingRequestNode;
107106
import org.truffleruby.language.RubyParsingRequestNode;
108107
import org.truffleruby.language.objects.RubyObjectType;
109108
import org.truffleruby.language.objects.classvariables.ClassVariableStorage;
109+
import org.truffleruby.language.threadlocal.SpecialVariableStorage;
110110
import org.truffleruby.options.LanguageOptions;
111111
import org.truffleruby.parser.ParserContext;
112112
import org.truffleruby.parser.ParsingParameters;
113113
import org.truffleruby.parser.RubySource;
114+
import org.truffleruby.parser.TranslatorEnvironment;
114115
import org.truffleruby.platform.Platform;
115116
import org.truffleruby.shared.Metrics;
116117
import org.truffleruby.shared.TruffleRuby;
@@ -287,9 +288,19 @@ public static final class ThreadLocalState {
287288
/* Some things (such as procs created from symbols) require a declaration frame, and this should include a slot for
288289
* special variable storage. This frame descriptor should be used for those frames to provide a constant frame
289290
* descriptor in those cases. */
290-
public final FrameDescriptor emptyDeclarationDescriptor = new FrameDescriptor(Nil.INSTANCE);
291-
public final FrameSlot emptyDeclarationSpecialVariableSlot = emptyDeclarationDescriptor
292-
.addFrameSlot(Layouts.SPECIAL_VARIABLES_STORAGE);
291+
public final FrameDescriptor emptyDeclarationDescriptor = TranslatorEnvironment
292+
.newFrameDescriptorBuilder(null, true).build();
293+
294+
public MaterializedFrame createEmptyDeclarationFrame(Object[] packedArgs, SpecialVariableStorage variables) {
295+
// createVirtualFrame().materialize() compiles better if this is in PE code
296+
final MaterializedFrame declarationFrame = Truffle
297+
.getRuntime()
298+
.createVirtualFrame(packedArgs, emptyDeclarationDescriptor)
299+
.materialize();
300+
301+
SpecialVariableStorage.set(declarationFrame, variables);
302+
return declarationFrame;
303+
}
293304

294305
private static final LanguageReference<RubyLanguage> REFERENCE = LanguageReference.create(RubyLanguage.class);
295306

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

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
import java.util.List;
1515
import java.util.Set;
1616

17+
import com.oracle.truffle.api.CompilerDirectives;
1718
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
1819
import com.oracle.truffle.api.dsl.GenerateUncached;
1920
import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
21+
import com.oracle.truffle.api.frame.FrameSlotKind;
2022
import com.oracle.truffle.api.profiles.ConditionProfile;
2123
import org.truffleruby.Layouts;
2224
import org.truffleruby.RubyContext;
@@ -35,7 +37,6 @@
3537
import org.truffleruby.core.string.RubyString;
3638
import org.truffleruby.core.string.StringNodes.MakeStringNode;
3739
import org.truffleruby.language.CallStackManager;
38-
import org.truffleruby.language.Nil;
3940
import org.truffleruby.language.RubyBaseNode;
4041
import org.truffleruby.language.RubyBaseNodeWithExecute;
4142
import org.truffleruby.language.RubyNode;
@@ -47,6 +48,7 @@
4748
import org.truffleruby.language.locals.FindDeclarationVariableNodes;
4849
import org.truffleruby.language.locals.FindDeclarationVariableNodes.FindAndReadDeclarationVariableNode;
4950
import org.truffleruby.language.locals.FindDeclarationVariableNodes.FrameSlotAndDepth;
51+
import org.truffleruby.language.locals.FrameDescriptorNamesIterator;
5052
import org.truffleruby.language.locals.WriteFrameSlotNode;
5153
import org.truffleruby.language.locals.WriteFrameSlotNodeGen;
5254

@@ -60,10 +62,11 @@
6062
import com.oracle.truffle.api.dsl.Specialization;
6163
import com.oracle.truffle.api.frame.Frame;
6264
import com.oracle.truffle.api.frame.FrameDescriptor;
63-
import com.oracle.truffle.api.frame.FrameSlot;
6465
import com.oracle.truffle.api.frame.MaterializedFrame;
6566
import com.oracle.truffle.api.frame.VirtualFrame;
6667
import com.oracle.truffle.api.source.SourceSection;
68+
import org.truffleruby.parser.ParentFrameDescriptor;
69+
import org.truffleruby.parser.TranslatorEnvironment;
6770

6871
@CoreModule(value = "Binding", isClass = true)
6972
public abstract class BindingNodes {
@@ -83,25 +86,34 @@ public static RubyBinding createBinding(RubyContext context, RubyLanguage langua
8386
}
8487

8588
@TruffleBoundary
86-
public static FrameDescriptor newFrameDescriptor() {
87-
return new FrameDescriptor(Nil.INSTANCE);
89+
public static FrameDescriptor newFrameDescriptor(RubyBinding binding) {
90+
FrameDescriptor parentDescriptor = binding.getFrame().getFrameDescriptor();
91+
var ref = new ParentFrameDescriptor(parentDescriptor);
92+
return TranslatorEnvironment.newFrameDescriptorBuilder(ref, false).build();
8893
}
8994

95+
static final int NEW_VAR_INDEX = 1;
96+
9097
@TruffleBoundary
91-
public static FrameDescriptor newFrameDescriptor(String name) {
92-
final FrameDescriptor frameDescriptor = new FrameDescriptor(Nil.INSTANCE);
98+
public static FrameDescriptor newFrameDescriptor(FrameDescriptor parentDescriptor, String name) {
9399
assert name != null && !name.isEmpty();
94-
frameDescriptor.addFrameSlot(name);
95-
return frameDescriptor;
100+
101+
var ref = new ParentFrameDescriptor(parentDescriptor);
102+
var builder = TranslatorEnvironment.newFrameDescriptorBuilder(ref, false);
103+
int index = builder.addSlot(FrameSlotKind.Illegal, name, null);
104+
if (index != NEW_VAR_INDEX) {
105+
throw CompilerDirectives.shouldNotReachHere("new binding variable not at index 1");
106+
}
107+
return builder.build();
96108
}
97109

98110
public static FrameDescriptor getFrameDescriptor(RubyBinding binding) {
99111
return binding.getFrame().getFrameDescriptor();
100112
}
101113

102114
public static MaterializedFrame newFrame(RubyBinding binding, FrameDescriptor frameDescriptor) {
103-
final MaterializedFrame frame = binding.getFrame();
104-
final MaterializedFrame newFrame = newFrame(frame, frameDescriptor);
115+
final MaterializedFrame parentFrame = binding.getFrame();
116+
final MaterializedFrame newFrame = newFrame(parentFrame, frameDescriptor);
105117
binding.setFrame(newFrame);
106118
return newFrame;
107119
}
@@ -121,20 +133,17 @@ public static MaterializedFrame newFrame(MaterializedFrame parent, FrameDescript
121133
}
122134

123135
public static void insertAncestorFrame(RubyBinding binding, MaterializedFrame ancestorFrame) {
124-
MaterializedFrame frame = binding.getFrame();
125-
while (RubyArguments.getDeclarationFrame(frame) != null) {
126-
frame = RubyArguments.getDeclarationFrame(frame);
127-
}
136+
MaterializedFrame frame = FindDeclarationVariableNodes.getOuterDeclarationFrame(binding.getFrame());
128137
RubyArguments.setDeclarationFrame(frame, ancestorFrame);
129138

130139
// We need to invalidate caches depending on the top frame, so create a new empty frame
131-
newFrame(binding, newFrameDescriptor());
140+
newFrame(binding, newFrameDescriptor(binding));
132141
}
133142

134143
@TruffleBoundary
135144
public static boolean assignsNewUserVariables(FrameDescriptor descriptor) {
136-
for (FrameSlot slot : descriptor.getSlots()) {
137-
if (!BindingNodes.isHiddenVariable(slot.getIdentifier())) {
145+
for (Object identifier : FrameDescriptorNamesIterator.iterate(descriptor)) {
146+
if (!BindingNodes.isHiddenVariable(identifier)) {
138147
return true;
139148
}
140149
}
@@ -151,8 +160,9 @@ public static boolean isHiddenVariable(Object name) {
151160

152161
private static boolean isHiddenVariable(String name) {
153162
assert !name.isEmpty();
154-
return name.charAt(0) == '$' || // Frame-local global variable
155-
name.charAt(0) == Layouts.TEMP_PREFIX_CHAR;
163+
final char first = name.charAt(0);
164+
return first == '$' || // Frame-local global variable
165+
first == Layouts.TEMP_PREFIX_CHAR;
156166
}
157167

158168
@CoreMethod(names = { "dup", "clone" })
@@ -324,13 +334,12 @@ protected RubyBaseNodeWithExecute coerceToString(RubyBaseNodeWithExecute name) {
324334
"!isHiddenVariable(cachedName)",
325335
"getFrameDescriptor(binding) == cachedFrameDescriptor",
326336
"cachedFrameSlot != null" },
327-
assumptions = "cachedFrameDescriptor.getVersion()",
328337
limit = "getCacheLimit()")
329338
protected Object localVariableSetCached(RubyBinding binding, String name, Object value,
330339
@Cached("name") String cachedName,
331340
@Cached("getFrameDescriptor(binding)") FrameDescriptor cachedFrameDescriptor,
332341
@Cached("findFrameSlotOrNull(name, binding.getFrame())") FrameSlotAndDepth cachedFrameSlot,
333-
@Cached("createWriteNode(cachedFrameSlot)") WriteFrameSlotNode writeLocalVariableNode) {
342+
@Cached("createWriteNode(cachedFrameSlot.slot)") WriteFrameSlotNode writeLocalVariableNode) {
334343
final MaterializedFrame frame = RubyArguments
335344
.getDeclarationFrame(binding.getFrame(), cachedFrameSlot.depth);
336345
writeLocalVariableNode.executeWrite(frame, value);
@@ -343,15 +352,13 @@ protected Object localVariableSetCached(RubyBinding binding, String name, Object
343352
"!isHiddenVariable(cachedName)",
344353
"getFrameDescriptor(binding) == cachedFrameDescriptor",
345354
"cachedFrameSlot == null" },
346-
assumptions = "cachedFrameDescriptor.getVersion()",
347355
limit = "getCacheLimit()")
348356
protected Object localVariableSetNewCached(RubyBinding binding, String name, Object value,
349357
@Cached("name") String cachedName,
350358
@Cached("getFrameDescriptor(binding)") FrameDescriptor cachedFrameDescriptor,
351359
@Cached("findFrameSlotOrNull(name, binding.getFrame())") FrameSlotAndDepth cachedFrameSlot,
352-
@Cached("newFrameDescriptor(name)") FrameDescriptor newDescriptor,
353-
@Cached("findFrameSlot(name, newDescriptor)") FrameSlotAndDepth newFrameSlot,
354-
@Cached("createWriteNode(newFrameSlot)") WriteFrameSlotNode writeLocalVariableNode) {
360+
@Cached("newFrameDescriptor(cachedFrameDescriptor, name)") FrameDescriptor newDescriptor,
361+
@Cached("createWriteNode(NEW_VAR_INDEX)") WriteFrameSlotNode writeLocalVariableNode) {
355362
final MaterializedFrame frame = newFrame(binding, newDescriptor);
356363
writeLocalVariableNode.executeWrite(frame, value);
357364
return value;
@@ -364,13 +371,15 @@ protected Object localVariableSetNewCached(RubyBinding binding, String name, Obj
364371
protected Object localVariableSetUncached(RubyBinding binding, String name, Object value) {
365372
MaterializedFrame frame = binding.getFrame();
366373
final FrameSlotAndDepth frameSlot = FindDeclarationVariableNodes.findFrameSlotOrNull(name, frame);
367-
final FrameSlot slot;
374+
final int slot;
368375
if (frameSlot != null) {
369376
frame = RubyArguments.getDeclarationFrame(frame, frameSlot.depth);
370377
slot = frameSlot.slot;
371378
} else {
372-
frame = newFrame(binding, newFrameDescriptor(name));
373-
slot = frame.getFrameDescriptor().findFrameSlot(name);
379+
var newDescriptor = newFrameDescriptor(getFrameDescriptor(binding), name);
380+
frame = newFrame(binding, newDescriptor);
381+
assert newDescriptor.getSlotName(NEW_VAR_INDEX) == name;
382+
slot = NEW_VAR_INDEX;
374383
}
375384
frame.setObject(slot, value);
376385
return value;
@@ -384,8 +393,8 @@ protected Object localVariableSetLastLine(RubyBinding binding, String name, Obje
384393
coreExceptions().nameError("Bad local variable name", binding, name, this));
385394
}
386395

387-
protected WriteFrameSlotNode createWriteNode(FrameSlotAndDepth frameSlot) {
388-
return WriteFrameSlotNodeGen.create(frameSlot.slot);
396+
protected WriteFrameSlotNode createWriteNode(int frameSlot) {
397+
return WriteFrameSlotNodeGen.create(frameSlot);
389398
}
390399

391400
protected int getCacheLimit() {
@@ -397,10 +406,7 @@ protected int getCacheLimit() {
397406
@ImportStatic(BindingNodes.class)
398407
public abstract static class LocalVariablesNode extends PrimitiveArrayArgumentsNode {
399408

400-
@Specialization(
401-
guards = "getFrameDescriptor(binding) == cachedFrameDescriptor",
402-
assumptions = "cachedFrameDescriptor.getVersion()",
403-
limit = "getCacheLimit()")
409+
@Specialization(guards = "getFrameDescriptor(binding) == cachedFrameDescriptor", limit = "getCacheLimit()")
404410
protected RubyArray localVariablesCached(RubyBinding binding,
405411
@Cached("getFrameDescriptor(binding)") FrameDescriptor cachedFrameDescriptor,
406412
@Cached("listLocalVariablesAsSymbols(getContext(), binding.getFrame())") RubyArray names) {
@@ -423,9 +429,9 @@ public RubyArray listLocalVariablesAsSymbols(RubyContext context, MaterializedFr
423429
}
424430

425431
private void addNamesFromFrame(Frame frame, Set<Object> names) {
426-
for (FrameSlot slot : frame.getFrameDescriptor().getSlots()) {
427-
if (!isHiddenVariable(slot.getIdentifier())) {
428-
names.add(getSymbol((String) slot.getIdentifier()));
432+
for (Object identifier : FrameDescriptorNamesIterator.iterate(frame.getFrameDescriptor())) {
433+
if (!isHiddenVariable(identifier)) {
434+
names.add(getSymbol((String) identifier));
429435
}
430436
}
431437
}
@@ -436,9 +442,9 @@ public static List<String> listLocalVariablesWithDuplicates(MaterializedFrame fr
436442
Frame currentFrame = frame;
437443
while (currentFrame != null) {
438444
final FrameDescriptor frameDescriptor = currentFrame.getFrameDescriptor();
439-
for (FrameSlot slot : frameDescriptor.getSlots()) {
440-
if (!isHiddenVariable(slot.getIdentifier())) {
441-
members.add(slot.getIdentifier().toString());
445+
for (Object identifier : FrameDescriptorNamesIterator.iterate(frameDescriptor)) {
446+
if (!isHiddenVariable(identifier)) {
447+
members.add((String) identifier);
442448
}
443449
}
444450
if (receiverName != null) {
@@ -524,7 +530,8 @@ protected RubyBinding binding(VirtualFrame frame) {
524530
// Use the current frame to initialize the arguments, etc, correctly
525531
final RubyBinding binding = BindingNodes
526532
.createBinding(getContext(), getLanguage(), frame.materialize(), getEncapsulatingSourceSection());
527-
final MaterializedFrame newFrame = newFrame(binding, newFrameDescriptor());
533+
534+
final MaterializedFrame newFrame = newFrame(binding, getLanguage().emptyDeclarationDescriptor);
528535
RubyArguments.setDeclarationFrame(newFrame, null); // detach from the current frame
529536
return binding;
530537
}

0 commit comments

Comments
 (0)