Skip to content

Commit ee84d28

Browse files
committed
Always inline Module#using and main.using to not need to lookup the caller frame
1 parent 8818341 commit ee84d28

File tree

5 files changed

+51
-53
lines changed

5 files changed

+51
-53
lines changed

spec/truffle/always_inlined_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@
6464
}.should raise_error(FrozenError) { |e| e.backtrace_locations[0].label.should == 'foo=' }
6565
end
6666
end
67+
68+
it "for main.using" do
69+
-> do
70+
eval('using "foo"', TOPLEVEL_BINDING)
71+
end.should raise_error(TypeError) { |e| e.backtrace_locations[0].label.should == 'using' }
72+
end
6773
end
6874

6975
describe "are not part of the backtrace if the error happens in a different method" do

src/main/java/org/truffleruby/core/MainNodes.java

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,19 @@
1515
import org.truffleruby.RubyContext;
1616
import org.truffleruby.RubyLanguage;
1717
import org.truffleruby.builtins.CoreMethod;
18-
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
1918
import org.truffleruby.builtins.CoreModule;
2019
import org.truffleruby.core.inlined.AlwaysInlinedMethodNode;
2120
import org.truffleruby.core.module.ModuleNodes;
22-
import org.truffleruby.core.module.RubyModule;
2321
import org.truffleruby.language.Visibility;
2422
import org.truffleruby.language.arguments.RubyArguments;
2523
import org.truffleruby.language.control.RaiseException;
24+
import org.truffleruby.language.methods.InternalMethod;
2625
import org.truffleruby.language.methods.UsingNode;
27-
import org.truffleruby.language.methods.UsingNodeGen;
2826

2927
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
3028
import com.oracle.truffle.api.dsl.Cached;
3129
import com.oracle.truffle.api.dsl.Specialization;
3230
import com.oracle.truffle.api.frame.Frame;
33-
import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
3431
import com.oracle.truffle.api.profiles.BranchProfile;
3532

3633
@CoreModule(value = "main", isClass = true)
@@ -58,31 +55,30 @@ protected Object forward(Frame callerFrame, Object self, Object[] args, Object b
5855
}
5956
}
6057

61-
@CoreMethod(names = "using", required = 1, needsSelf = false)
62-
public abstract static class MainUsingNode extends CoreMethodArrayArgumentsNode {
63-
64-
@Child private UsingNode usingNode = UsingNodeGen.create();
65-
58+
@GenerateUncached
59+
@CoreMethod(names = "using", required = 1, alwaysInlined = true)
60+
public abstract static class MainUsingNode extends UsingNode {
6661
@Specialization
67-
protected Object mainUsing(RubyModule refinementModule,
62+
protected Object mainUsing(Frame callerFrame, Object self, Object[] args, Object block, RootCallTarget target,
63+
@CachedContext(RubyLanguage.class) RubyContext context,
6864
@Cached BranchProfile errorProfile) {
69-
if (!isCalledFromTopLevel()) {
65+
final Object refinementModule = args[0];
66+
final InternalMethod callerMethod = RubyArguments.getMethod(callerFrame);
67+
if (!isCalledFromTopLevel(callerMethod)) {
7068
errorProfile.enter();
7169
throw new RaiseException(
72-
getContext(),
73-
coreExceptions().runtimeError("main.using is permitted only at toplevel", this));
70+
context,
71+
context.getCoreExceptions().runtimeError("main.using is permitted only at toplevel", this));
7472
}
75-
usingNode.executeUsing(refinementModule);
73+
using(context, callerFrame, refinementModule, errorProfile);
7674
return nil;
7775
}
7876

7977
@TruffleBoundary
80-
private boolean isCalledFromTopLevel() {
81-
final Frame callerFrame = getContext().getCallStack().getCallerFrame(FrameAccess.READ_ONLY);
82-
final String name = RubyArguments.getMethod(callerFrame).getSharedMethodInfo().getBacktraceName();
78+
private boolean isCalledFromTopLevel(InternalMethod callerMethod) {
79+
final String name = callerMethod.getSharedMethodInfo().getBacktraceName();
8380
return name.equals("<main>") || name.startsWith("<top ");
8481
}
85-
8682
}
8783

8884
}

src/main/java/org/truffleruby/core/module/ModuleNodes.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@
105105
import org.truffleruby.language.methods.SharedMethodInfo;
106106
import org.truffleruby.language.methods.Split;
107107
import org.truffleruby.language.methods.UsingNode;
108-
import org.truffleruby.language.methods.UsingNodeGen;
109108
import org.truffleruby.language.objects.AllocationTracing;
110109
import org.truffleruby.language.objects.IsANode;
111110
import org.truffleruby.language.objects.SingletonClassNode;
@@ -2264,32 +2263,33 @@ private RubyModule newRefinementModule(RubyModule namespace, RubyModule moduleTo
22642263

22652264
}
22662265

2267-
@CoreMethod(names = "using", required = 1, visibility = Visibility.PRIVATE)
2268-
public abstract static class ModuleUsingNode extends CoreMethodArrayArgumentsNode {
2269-
2270-
@Child private UsingNode usingNode = UsingNodeGen.create();
2271-
2272-
@TruffleBoundary
2266+
@CoreMethod(names = "using", required = 1, visibility = Visibility.PRIVATE, alwaysInlined = true)
2267+
public abstract static class ModuleUsingNode extends UsingNode {
22732268
@Specialization
2274-
protected RubyModule moduleUsing(RubyModule self, RubyModule refinementModule) {
2275-
final Frame callerFrame = getContext().getCallStack().getCallerFrame(FrameAccess.READ_ONLY);
2269+
protected Object moduleUsing(Frame callerFrame, Object self, Object[] args, Object block, RootCallTarget target,
2270+
@CachedContext(RubyLanguage.class) RubyContext context,
2271+
@Cached BranchProfile errorProfile) {
2272+
final Object refinementModule = args[0];
22762273
if (self != RubyArguments.getSelf(callerFrame)) {
2274+
errorProfile.enter();
22772275
throw new RaiseException(
2278-
getContext(),
2279-
coreExceptions().runtimeError("Module#using is not called on self", this));
2276+
context,
2277+
context.getCoreExceptions().runtimeError("Module#using is not called on self", this));
22802278
}
2281-
if (!isCalledFromClassOrModule(callerFrame)) {
2279+
final InternalMethod callerMethod = RubyArguments.getMethod(callerFrame);
2280+
if (!isCalledFromClassOrModule(callerMethod)) {
2281+
errorProfile.enter();
22822282
throw new RaiseException(
2283-
getContext(),
2284-
coreExceptions().runtimeError("Module#using is not permitted in methods", this));
2283+
context,
2284+
context.getCoreExceptions().runtimeError("Module#using is not permitted in methods", this));
22852285
}
2286-
usingNode.executeUsing(refinementModule);
2286+
using(context, callerFrame, refinementModule, errorProfile);
22872287
return self;
22882288
}
22892289

22902290
@TruffleBoundary
2291-
private boolean isCalledFromClassOrModule(Frame callerFrame) {
2292-
final String name = RubyArguments.getMethod(callerFrame).getSharedMethodInfo().getBacktraceName();
2291+
private boolean isCalledFromClassOrModule(InternalMethod callerMethod) {
2292+
final String name = callerMethod.getSharedMethodInfo().getBacktraceName();
22932293
// Handles cases: <main> | <top | <class: | <module: | <singleton
22942294
return name.startsWith("<");
22952295
}

src/main/java/org/truffleruby/language/methods/DeclarationContext.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ public static void setCurrentVisibility(Frame callerFrame, Visibility visibility
131131
changeVisibility(callerFrame, visibility);
132132
}
133133

134-
@TruffleBoundary
135134
public static void setRefinements(Frame callerFrame, DeclarationContext declarationContext,
136135
Map<RubyModule, RubyModule[]> refinements) {
137136
RubyArguments.setDeclarationContext(callerFrame, declarationContext.withRefinements(refinements));

src/main/java/org/truffleruby/language/methods/UsingNode.java

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,36 @@
1515
import java.util.Map;
1616
import java.util.concurrent.ConcurrentMap;
1717

18+
import com.oracle.truffle.api.profiles.BranchProfile;
19+
import org.truffleruby.RubyContext;
1820
import org.truffleruby.core.array.ArrayUtils;
19-
import org.truffleruby.core.klass.RubyClass;
21+
import org.truffleruby.core.inlined.AlwaysInlinedMethodNode;
2022
import org.truffleruby.core.module.RubyModule;
21-
import org.truffleruby.language.RubyContextNode;
2223
import org.truffleruby.language.arguments.RubyArguments;
2324
import org.truffleruby.language.control.RaiseException;
2425

2526
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
26-
import com.oracle.truffle.api.dsl.Specialization;
2727
import com.oracle.truffle.api.frame.Frame;
28-
import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
2928

30-
public abstract class UsingNode extends RubyContextNode {
29+
public abstract class UsingNode extends AlwaysInlinedMethodNode {
3130

32-
public abstract void executeUsing(RubyModule module);
33-
34-
@TruffleBoundary
35-
@Specialization
36-
protected void using(RubyModule module) {
37-
if (module instanceof RubyClass) {
38-
throw new RaiseException(getContext(), coreExceptions().typeErrorWrongArgumentType(module, "Module", this));
31+
protected void using(RubyContext context, Frame callerFrame, Object refinementModule, BranchProfile errorProfile) {
32+
if (refinementModule.getClass() != RubyModule.class) {
33+
errorProfile.enter();
34+
throw new RaiseException(
35+
context,
36+
context.getCoreExceptions().typeErrorWrongArgumentType(refinementModule, "Module", this));
3937
}
40-
41-
final Frame callerFrame = getContext().getCallStack().getCallerFrame(FrameAccess.READ_WRITE);
38+
final RubyModule module = (RubyModule) refinementModule;
4239
final DeclarationContext declarationContext = RubyArguments.getDeclarationContext(callerFrame);
4340
final Map<RubyModule, RubyModule[]> newRefinements = usingModule(declarationContext, module);
44-
if (!newRefinements.isEmpty()) {
41+
if (newRefinements != null) {
4542
DeclarationContext.setRefinements(callerFrame, declarationContext, newRefinements);
4643
}
4744
}
4845

4946
@TruffleBoundary
50-
private Map<RubyModule, RubyModule[]> usingModule(DeclarationContext declarationContext, RubyModule module) {
47+
private static Map<RubyModule, RubyModule[]> usingModule(DeclarationContext declarationContext, RubyModule module) {
5148
final Map<RubyModule, RubyModule[]> newRefinements = new HashMap<>(declarationContext.getRefinements());
5249

5350
// Iterate ancestors in reverse order so refinements upper in the chain have precedence
@@ -64,7 +61,7 @@ private Map<RubyModule, RubyModule[]> usingModule(DeclarationContext declaration
6461
}
6562
}
6663

67-
return newRefinements;
64+
return newRefinements.isEmpty() ? null : newRefinements;
6865
}
6966

7067
private static void applyRefinements(RubyModule refinedModule, RubyModule refinementModule,

0 commit comments

Comments
 (0)