Skip to content

Commit c3400a8

Browse files
horakivoeregon
authored andcommitted
[GR-17457] Remove loop in special variable lookup
PullRequest: truffleruby/3949
2 parents f954b46 + be521f1 commit c3400a8

13 files changed

+142
-108
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
import org.truffleruby.language.objects.classvariables.ClassVariableStorage;
112112
import org.truffleruby.language.threadlocal.SpecialVariableStorage;
113113
import org.truffleruby.options.LanguageOptions;
114+
import org.truffleruby.parser.BlockDescriptorInfo;
114115
import org.truffleruby.parser.ParserContext;
115116
import org.truffleruby.parser.ParsingParameters;
116117
import org.truffleruby.parser.RubySource;
@@ -189,8 +190,8 @@ public final class RubyLanguage extends TruffleLanguage<RubyContext> {
189190
public static final TruffleLogger LOGGER = TruffleLogger.getLogger(TruffleRuby.LANGUAGE_ID);
190191

191192
/** This is a truly empty frame descriptor and should only by dummy root nodes which require no variables. Any other
192-
* root nodes should should use
193-
* {@link TranslatorEnvironment#newFrameDescriptorBuilder(org.truffleruby.parser.ParentFrameDescriptor, boolean)}. */
193+
* root nodes should should use either {@link TranslatorEnvironment#newFrameDescriptorBuilderForMethod()} or
194+
* {@link TranslatorEnvironment#newFrameDescriptorBuilderForBlock(BlockDescriptorInfo)}. */
194195
public static final FrameDescriptor EMPTY_FRAME_DESCRIPTOR = new FrameDescriptor(nil);
195196

196197
private RubyThread getOrCreateForeignThread(RubyContext context, Thread thread) {
@@ -336,7 +337,7 @@ private RubyThread getOrCreateForeignThread(RubyContext context, Thread thread)
336337
* special variable storage. This frame descriptor should be used for those frames to provide a constant frame
337338
* descriptor in those cases. */
338339
public final FrameDescriptor emptyDeclarationDescriptor = TranslatorEnvironment
339-
.newFrameDescriptorBuilder(null, true).build();
340+
.newFrameDescriptorBuilderForMethod().build();
340341

341342
public MaterializedFrame createEmptyDeclarationFrame(Object[] packedArgs, SpecialVariableStorage variables) {
342343
// createVirtualFrame().materialize() compiles better if this is in PE code

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
import com.oracle.truffle.api.source.SourceSection;
5858
import org.truffleruby.language.locals.WriteFrameSlotNode;
5959
import org.truffleruby.language.locals.WriteFrameSlotNodeGen;
60-
import org.truffleruby.parser.ParentFrameDescriptor;
60+
import org.truffleruby.parser.BlockDescriptorInfo;
6161
import org.truffleruby.parser.TranslatorEnvironment;
6262

6363
@CoreModule(value = "Binding", isClass = true)
@@ -80,8 +80,8 @@ public static RubyBinding createBinding(RubyContext context, RubyLanguage langua
8080
@TruffleBoundary
8181
public static FrameDescriptor newFrameDescriptor(RubyBinding binding) {
8282
FrameDescriptor parentDescriptor = binding.getFrame().getFrameDescriptor();
83-
var ref = new ParentFrameDescriptor(parentDescriptor);
84-
return TranslatorEnvironment.newFrameDescriptorBuilder(ref, false).build();
83+
var ref = new BlockDescriptorInfo(parentDescriptor);
84+
return TranslatorEnvironment.newFrameDescriptorBuilderForBlock(ref).build();
8585
}
8686

8787
static final int NEW_VAR_INDEX = 1;
@@ -90,8 +90,8 @@ public static FrameDescriptor newFrameDescriptor(RubyBinding binding) {
9090
public static FrameDescriptor newFrameDescriptor(FrameDescriptor parentDescriptor, String name) {
9191
assert name != null && !name.isEmpty();
9292

93-
var ref = new ParentFrameDescriptor(parentDescriptor);
94-
var builder = TranslatorEnvironment.newFrameDescriptorBuilder(ref, false);
93+
var ref = new BlockDescriptorInfo(parentDescriptor);
94+
var builder = TranslatorEnvironment.newFrameDescriptorBuilderForBlock(ref);
9595
int index = builder.addSlot(FrameSlotKind.Illegal, name, null);
9696
if (index != NEW_VAR_INDEX) {
9797
throw CompilerDirectives.shouldNotReachHere("new binding variable not at index 1");

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import org.truffleruby.language.arguments.RubyArguments;
2323
import org.truffleruby.language.loader.CodeLoader;
2424
import org.truffleruby.language.methods.DeclarationContext;
25-
import org.truffleruby.parser.ParentFrameDescriptor;
25+
import org.truffleruby.parser.BlockDescriptorInfo;
2626
import org.truffleruby.parser.ParserContext;
2727
import org.truffleruby.parser.RubySource;
2828
import org.truffleruby.parser.TranslatorEnvironment;
@@ -67,8 +67,8 @@ public static Object eval(RubyContext context, String code, Object... arguments)
6767
RubyNode.EMPTY_ARGUMENTS);
6868

6969

70-
var builder = TranslatorEnvironment.newFrameDescriptorBuilder(new ParentFrameDescriptor(currentFrameDescriptor),
71-
false);
70+
var builder = TranslatorEnvironment
71+
.newFrameDescriptorBuilderForBlock(new BlockDescriptorInfo(currentFrameDescriptor));
7272

7373
for (int i = 0; i < nArgs; i++) {
7474
final Object identifier = arguments[i * 2];

src/main/java/org/truffleruby/language/RubyRootNode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import com.oracle.truffle.api.frame.VirtualFrame;
2626
import com.oracle.truffle.api.source.SourceSection;
2727
import org.truffleruby.annotations.Split;
28-
import org.truffleruby.parser.ParentFrameDescriptor;
28+
import org.truffleruby.parser.BlockDescriptorInfo;
2929

3030
import java.util.ArrayList;
3131
import java.util.IdentityHashMap;
@@ -83,8 +83,8 @@ public Object execute(VirtualFrame frame) {
8383
@Override
8484
public FrameDescriptor getParentFrameDescriptor() {
8585
var info = getFrameDescriptor().getInfo();
86-
if (info instanceof ParentFrameDescriptor) {
87-
return ((ParentFrameDescriptor) info).getDescriptor();
86+
if (info instanceof BlockDescriptorInfo) {
87+
return ((BlockDescriptorInfo) info).getParentDescriptor();
8888
} else {
8989
return null;
9090
}

src/main/java/org/truffleruby/language/SpecialVariablesSendingNode.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import org.truffleruby.core.kernel.TruffleKernelNodes.GetSpecialVariableStorage;
1717
import org.truffleruby.language.arguments.ReadCallerVariablesNode;
1818

19-
import org.truffleruby.language.locals.FindDeclarationVariableNodes;
2019
import org.truffleruby.language.threadlocal.SpecialVariableStorage;
20+
import org.truffleruby.parser.BlockDescriptorInfo;
2121

2222
/** Some Ruby methods need access to the caller special variables: see usages of {@link ReadCallerVariablesNode}. This
2323
* is used for methods which need to access the last regexp MatchData or the last IO line.
@@ -45,10 +45,12 @@ protected Assumption getSpecialVariableAssumption(Frame frame) {
4545
return Assumption.ALWAYS_VALID;
4646
}
4747

48-
var outerFrameDescriptor = FindDeclarationVariableNodes.getOuterFrameDescriptor(frame.getFrameDescriptor());
48+
var descriptor = frame.getFrameDescriptor();
4949

50-
if (SpecialVariableStorage.hasSpecialVariableAssumption(outerFrameDescriptor)) {
51-
return SpecialVariableStorage.getAssumption(outerFrameDescriptor);
50+
if (SpecialVariableStorage.hasSpecialVariableAssumption(descriptor)) {
51+
return SpecialVariableStorage.getAssumption(descriptor);
52+
} else if (descriptor.getInfo() instanceof BlockDescriptorInfo blockDescriptorInfo) {
53+
return blockDescriptorInfo.getSpecialVariableAssumption();
5254
} else {
5355
return Assumption.ALWAYS_VALID;
5456
}

src/main/java/org/truffleruby/language/locals/FindDeclarationVariableNodes.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import com.oracle.truffle.api.dsl.ReportPolymorphism;
2626
import com.oracle.truffle.api.dsl.Specialization;
2727
import com.oracle.truffle.api.frame.FrameDescriptor;
28-
import org.truffleruby.parser.ParentFrameDescriptor;
2928

3029
public abstract class FindDeclarationVariableNodes {
3130
public static final class FrameSlotAndDepth {
@@ -50,13 +49,6 @@ public static MaterializedFrame getOuterDeclarationFrame(MaterializedFrame topFr
5049
return frame;
5150
}
5251

53-
public static FrameDescriptor getOuterFrameDescriptor(FrameDescriptor descriptor) {
54-
while (descriptor.getInfo() instanceof ParentFrameDescriptor nextDescriptor) {
55-
descriptor = nextDescriptor.getDescriptor();
56-
}
57-
return descriptor;
58-
}
59-
6052
private static int findSlot(FrameDescriptor descriptor, String name) {
6153
assert descriptor.getNumberOfAuxiliarySlots() == 0;
6254
int slots = descriptor.getNumberOfSlots();

src/main/java/org/truffleruby/language/locals/ReadDeclarationVariableNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
import com.oracle.truffle.api.CompilerDirectives;
1717
import com.oracle.truffle.api.frame.VirtualFrame;
18-
import org.truffleruby.parser.ParentFrameDescriptor;
18+
import org.truffleruby.parser.BlockDescriptorInfo;
1919

2020
public final class ReadDeclarationVariableNode extends ReadLocalNode {
2121

@@ -57,7 +57,7 @@ public WriteLocalNode makeWriteNode(RubyNode rhs) {
5757

5858
@Override
5959
protected String getVariableName() {
60-
var descriptor = ParentFrameDescriptor.getDeclarationFrameDescriptor(
60+
var descriptor = BlockDescriptorInfo.getDeclarationFrameDescriptor(
6161
getRootNode().getFrameDescriptor(), frameDepth);
6262
return descriptor.getSlotName(frameSlot).toString();
6363
}

src/main/java/org/truffleruby/language/locals/WriteDeclarationVariableNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import com.oracle.truffle.api.CompilerDirectives;
1818
import com.oracle.truffle.api.frame.VirtualFrame;
19-
import org.truffleruby.parser.ParentFrameDescriptor;
19+
import org.truffleruby.parser.BlockDescriptorInfo;
2020

2121
public final class WriteDeclarationVariableNode extends WriteLocalNode {
2222

@@ -60,7 +60,7 @@ public AssignableNode cloneUninitializedAssignable() {
6060

6161
@Override
6262
protected String getVariableName() {
63-
var descriptor = ParentFrameDescriptor.getDeclarationFrameDescriptor(
63+
var descriptor = BlockDescriptorInfo.getDeclarationFrameDescriptor(
6464
getRootNode().getFrameDescriptor(), frameDepth);
6565
return descriptor.getSlotName(frameSlot).toString();
6666
}

src/main/java/org/truffleruby/language/threadlocal/SpecialVariableStorage.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,13 @@ public static Assumption getAssumption(FrameDescriptor descriptor) {
5151
return (Assumption) descriptor.getInfo();
5252
}
5353

54+
public static boolean isSpecialVariableAssumption(Assumption assumption) {
55+
return assumption.getName() == ASSUMPTION_NAME;
56+
}
57+
5458
public static boolean hasSpecialVariableAssumption(FrameDescriptor descriptor) {
5559
var info = descriptor.getInfo();
56-
return info instanceof Assumption assumption && assumption.getName() == ASSUMPTION_NAME;
60+
return info instanceof Assumption assumption && isSpecialVariableAssumption(assumption);
5761
}
5862

5963
public static boolean hasSpecialVariableStorageSlot(Frame frame) {
@@ -65,7 +69,7 @@ private static boolean hasSpecialVariableStorageSlot(FrameDescriptor descriptor)
6569
assert SLOT_INDEX < descriptor.getNumberOfSlots();
6670
assert descriptor.getSlotName(SLOT_INDEX) == SLOT_NAME;
6771
Assumption assumption = (Assumption) descriptor.getInfo();
68-
return assumption.getName() == ASSUMPTION_NAME;
72+
return isSpecialVariableAssumption(assumption);
6973
}
7074

7175
/** $~ */
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2022, 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.parser;
11+
12+
import com.oracle.truffle.api.Assumption;
13+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
14+
import com.oracle.truffle.api.frame.FrameDescriptor;
15+
import com.oracle.truffle.api.nodes.ExplodeLoop;
16+
import org.truffleruby.language.threadlocal.SpecialVariableStorage;
17+
18+
/** This is the {@link FrameDescriptor#getInfo() descriptor info} for blocks. The descriptor info for methods is an
19+
* {@link SpecialVariableStorage#getAssumption(FrameDescriptor) Assumption}. */
20+
public final class BlockDescriptorInfo {
21+
22+
@ExplodeLoop
23+
public static FrameDescriptor getDeclarationFrameDescriptor(FrameDescriptor topDescriptor, int depth) {
24+
assert depth > 0;
25+
FrameDescriptor descriptor = topDescriptor;
26+
for (int i = 0; i < depth; i++) {
27+
descriptor = ((BlockDescriptorInfo) descriptor.getInfo()).getParentDescriptor();
28+
}
29+
return descriptor;
30+
}
31+
32+
@CompilationFinal private FrameDescriptor parentDescriptor;
33+
private final Assumption specialVariableAssumption;
34+
35+
public BlockDescriptorInfo(Assumption specialVariableAssumption) {
36+
assert SpecialVariableStorage.isSpecialVariableAssumption(specialVariableAssumption);
37+
this.specialVariableAssumption = specialVariableAssumption;
38+
}
39+
40+
public BlockDescriptorInfo(FrameDescriptor parentDescriptor) {
41+
this.parentDescriptor = parentDescriptor;
42+
this.specialVariableAssumption = getSpecialVariableAssumptionFromDescriptor(parentDescriptor);
43+
}
44+
45+
private Assumption getSpecialVariableAssumptionFromDescriptor(FrameDescriptor descriptor) {
46+
if (descriptor.getInfo() instanceof BlockDescriptorInfo blockDescriptorInfo) {
47+
return blockDescriptorInfo.getSpecialVariableAssumption();
48+
} else {
49+
return SpecialVariableStorage.getAssumption(descriptor);
50+
}
51+
}
52+
53+
public FrameDescriptor getParentDescriptor() {
54+
assert parentDescriptor != null;
55+
return parentDescriptor;
56+
}
57+
58+
void setParentDescriptor(FrameDescriptor parentDescriptor) {
59+
assert this.parentDescriptor == null;
60+
this.parentDescriptor = parentDescriptor;
61+
}
62+
63+
public Assumption getSpecialVariableAssumption() {
64+
assert specialVariableAssumption != null;
65+
return specialVariableAssumption;
66+
}
67+
}

0 commit comments

Comments
 (0)