Skip to content

Commit e2f62b8

Browse files
committed
[GR-28711] Make the CallTarget for Method#to_proc context-independent
PullRequest: truffleruby/3354
2 parents 606438b + 1ea6310 commit e2f62b8

File tree

16 files changed

+113
-113
lines changed

16 files changed

+113
-113
lines changed

src/main/java/org/truffleruby/core/basicobject/BasicObjectNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ protected Object instanceExec(VirtualFrame frame, Object receiver, Object[] argu
448448
block.declarationContext.getRefinements());
449449
var descriptor = RubyArguments.getDescriptor(frame);
450450
return callBlockNode.executeCallBlock(
451-
declarationContext, block, receiver, block.block, descriptor, arguments, null);
451+
declarationContext, block, receiver, nil, descriptor, arguments, null);
452452
}
453453

454454
@Specialization

src/main/java/org/truffleruby/core/fiber/FiberManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public FiberManager(RubyLanguage language, RubyContext context) {
5858
}
5959

6060
public void initialize(RubyFiber fiber, boolean blocking, RubyProc block, Node currentNode) {
61-
final SourceSection sourceSection = block.sharedMethodInfo.getSourceSection();
61+
final SourceSection sourceSection = block.getSharedMethodInfo().getSourceSection();
6262
fiber.sourceLocation = RubyLanguage.fileLine(sourceSection);
6363
fiber.blocking = blocking;
6464

@@ -99,7 +99,7 @@ private void fiberMain(RubyContext context, RubyFiber fiber, RubyProc block, Nod
9999
assertNotEntered("Fibers should start unentered to avoid triggering multithreading");
100100

101101
final FiberPoolThread thread = (FiberPoolThread) Thread.currentThread();
102-
final SourceSection sourceSection = block.sharedMethodInfo.getSourceSection();
102+
final SourceSection sourceSection = block.getSharedMethodInfo().getSourceSection();
103103
final String oldName = thread.getName();
104104
thread.setName(NAME_PREFIX + " id=" + thread.getId() + " from " + RubyLanguage.fileLine(sourceSection));
105105

src/main/java/org/truffleruby/core/hash/library/HashStoreLibrary.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ protected Object yieldPair(RubyProc block, Object key, Object value,
135135
@Cached ConditionProfile arityMoreThanOne) {
136136
// MRI behavior, see rb_hash_each_pair()
137137
// We use getMethodArityNumber() here since for non-lambda the semantics are the same for both branches
138-
if (arityMoreThanOne.profile(block.sharedMethodInfo.getArity().getMethodArityNumber() > 1)) {
138+
if (arityMoreThanOne.profile(block.arity.getMethodArityNumber() > 1)) {
139139
return yieldNode.yield(block, key, value);
140140
} else {
141141
return yieldNode.yield(block, createArray(new Object[]{ key, value }));

src/main/java/org/truffleruby/core/method/MethodNodes.java

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.truffleruby.language.control.RaiseException;
4646
import org.truffleruby.language.methods.CallInternalMethodNode;
4747
import org.truffleruby.language.methods.InternalMethod;
48+
import org.truffleruby.language.methods.SharedMethodInfo;
4849
import org.truffleruby.language.objects.AllocationTracing;
4950
import org.truffleruby.language.objects.MetaClassNode;
5051
import org.truffleruby.language.threadlocal.SpecialVariableStorage;
@@ -135,10 +136,16 @@ public abstract static class CallNode extends AlwaysInlinedMethodNode {
135136
protected Object call(Frame callerFrame, RubyMethod method, Object[] rubyArgs, RootCallTarget target,
136137
@Cached CallInternalMethodNode callInternalMethodNode) {
137138
final InternalMethod internalMethod = method.method;
138-
final Object[] newArgs = RubyArguments.repack(rubyArgs, method.receiver);
139+
final Object receiver = method.receiver;
140+
return callBoundMethod(callerFrame, internalMethod, receiver, rubyArgs, callInternalMethodNode);
141+
}
142+
143+
static Object callBoundMethod(Frame frame, InternalMethod internalMethod, Object receiver,
144+
Object[] callerRubyArgs, CallInternalMethodNode callInternalMethodNode) {
145+
final Object[] newArgs = RubyArguments.repack(callerRubyArgs, receiver);
139146
RubyArguments.setMethod(newArgs, internalMethod);
140147
assert RubyArguments.assertFrameArguments(newArgs);
141-
return callInternalMethodNode.execute(callerFrame, internalMethod, method.receiver, newArgs, null);
148+
return callInternalMethodNode.execute(frame, internalMethod, receiver, newArgs, null);
142149
}
143150
}
144151

@@ -273,28 +280,29 @@ protected RubyUnboundMethod unbind(RubyMethod method) {
273280
@CoreMethod(names = "to_proc")
274281
public abstract static class ToProcNode extends CoreMethodArrayArgumentsNode {
275282

276-
@Specialization(guards = "methodObject == cachedMethodObject", limit = "getCacheLimit()")
277-
protected RubyProc toProcCached(RubyMethod methodObject,
283+
@Specialization(guards = { "isSingleContext()", "methodObject == cachedMethodObject" },
284+
limit = "getCacheLimit()")
285+
protected RubyProc toProcCachedSingleContext(RubyMethod methodObject,
278286
@Cached("methodObject") RubyMethod cachedMethodObject,
279287
@Cached("toProcUncached(cachedMethodObject)") RubyProc proc) {
280288
return proc;
281289
}
282290

283291
@Specialization(
284-
guards = "cachedMethod == methodObject.method",
292+
guards = "methodObject.method.getCallTarget() == methodCallTarget",
285293
limit = "getCacheLimit()",
286-
replaces = "toProcCached")
294+
replaces = "toProcCachedSingleContext")
287295
protected RubyProc toProcCachedTarget(RubyMethod methodObject,
288-
@Cached("methodObject.method") InternalMethod cachedMethod,
289-
@Cached("methodCallTarget(cachedMethod)") RootCallTarget callTarget) {
290-
return createProc(callTarget, cachedMethod, methodObject.receiver);
296+
@Cached("methodObject.method.getCallTarget()") RootCallTarget methodCallTarget,
297+
@Cached("procCallTargetToCallRubyMethod(methodCallTarget)") RootCallTarget procCallTarget) {
298+
return createProc(procCallTarget, methodObject.method, methodObject.receiver);
291299
}
292300

293-
@Specialization
301+
@Specialization(replaces = { "toProcCachedSingleContext", "toProcCachedTarget" })
294302
protected RubyProc toProcUncached(RubyMethod methodObject) {
295303
final InternalMethod method = methodObject.method;
296-
final RootCallTarget callTarget = methodCallTarget(method);
297304
final Object receiver = methodObject.receiver;
305+
final RootCallTarget callTarget = procCallTargetToCallRubyMethod(method.getCallTarget());
298306
return createProc(callTarget, method, receiver);
299307
}
300308

@@ -312,55 +320,48 @@ private RubyProc createProc(RootCallTarget callTarget, InternalMethod method, Ob
312320
declarationFrame,
313321
variables,
314322
method,
315-
nil,
316323
null,
317324
method.getDeclarationContext());
318325
}
319326

320327
@TruffleBoundary
321-
protected RootCallTarget methodCallTarget(InternalMethod method) {
328+
protected RootCallTarget procCallTargetToCallRubyMethod(RootCallTarget callTarget) {
322329
// translate to something like:
323330
// lambda { |same args list| method.call(args) }
324331
// We need to preserve the method receiver and we want to have the same argument list.
325332
// We create a new CallTarget for the Proc that calls the method CallTarget and passes the correct receiver.
326333

327-
final SourceSection sourceSection = method.getSharedMethodInfo().getSourceSection();
328-
final RubyRootNode methodRootNode = RubyRootNode.of(method.getCallTarget());
334+
final RubyRootNode methodRootNode = RubyRootNode.of(callTarget);
335+
final SharedMethodInfo sharedMethodInfo = methodRootNode.getSharedMethodInfo();
329336

330-
final SetReceiverNode setReceiverNode = new SetReceiverNode(method);
337+
var callWithRubyMethodReceiverNode = new CallWithRubyMethodReceiverNode();
331338
final RubyLambdaRootNode wrapRootNode = new RubyLambdaRootNode(
332339
getLanguage(),
333-
sourceSection,
340+
sharedMethodInfo.getSourceSection(),
334341
methodRootNode.getFrameDescriptor(),
335-
method.getSharedMethodInfo(),
336-
setReceiverNode,
342+
sharedMethodInfo,
343+
callWithRubyMethodReceiverNode,
337344
methodRootNode.getSplit(),
338345
methodRootNode.returnID,
339346
BreakID.INVALID,
340-
method.getSharedMethodInfo().getArity());
347+
sharedMethodInfo.getArity());
341348
return wrapRootNode.getCallTarget();
342349
}
343350

344351
protected int getCacheLimit() {
345352
return getLanguage().options.METHOD_TO_PROC_CACHE;
346353
}
347354

348-
}
355+
private static class CallWithRubyMethodReceiverNode extends RubyContextSourceNode {
356+
@Child private CallInternalMethodNode callInternalMethodNode = CallInternalMethodNode.create();
349357

350-
private static class SetReceiverNode extends RubyContextSourceNode {
351-
private final InternalMethod method;
352-
@Child private CallInternalMethodNode callInternalMethodNode = CallInternalMethodNode.create();
353-
354-
public SetReceiverNode(InternalMethod method) {
355-
this.method = method;
356-
}
357-
358-
@Override
359-
public Object execute(VirtualFrame frame) {
360-
final Object originalBoundMethodReceiver = RubyArguments.getSelf(RubyArguments.getDeclarationFrame(frame));
361-
Object[] rubyArgs = RubyArguments.repack(frame.getArguments(), originalBoundMethodReceiver);
362-
RubyArguments.setMethod(rubyArgs, method);
363-
return callInternalMethodNode.execute(frame, method, originalBoundMethodReceiver, rubyArgs, null);
358+
@Override
359+
public Object execute(VirtualFrame frame) {
360+
final MaterializedFrame declarationFrame = RubyArguments.getDeclarationFrame(frame);
361+
final Object receiver = RubyArguments.getSelf(declarationFrame);
362+
final InternalMethod method = RubyArguments.getMethod(declarationFrame);
363+
return CallNode.callBoundMethod(frame, method, receiver, frame.getArguments(), callInternalMethodNode);
364+
}
364365
}
365366
}
366367

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ public Object classExec(ArgumentsDescriptor descriptor, RubyModule self, Object[
810810
new FixedDefaultDefinee(self),
811811
block.declarationContext.getRefinements());
812812

813-
return callBlockNode.executeCallBlock(declarationContext, block, self, block.block, descriptor, args, null);
813+
return callBlockNode.executeCallBlock(declarationContext, block, self, nil, descriptor, args, null);
814814
}
815815
}
816816

@@ -1334,7 +1334,7 @@ private RubySymbol defineMethod(RubyModule module, String name, RubyProc proc,
13341334
MaterializedFrame callerFrame) {
13351335
final RootCallTarget callTargetForLambda = proc.callTargets.getCallTargetForLambda();
13361336
final RubyLambdaRootNode rootNode = RubyLambdaRootNode.of(callTargetForLambda);
1337-
final SharedMethodInfo info = proc.sharedMethodInfo.forDefineMethod(module, name);
1337+
final SharedMethodInfo info = proc.getSharedMethodInfo().forDefineMethod(module, name);
13381338
final RubyNode body = rootNode.copyBody();
13391339
final RubyNode newBody = new CallMethodWithLambdaBody(isSingleContext() ? proc : null,
13401340
callTargetForLambda, body);
@@ -2289,7 +2289,7 @@ protected RubyModule refine(RubyModule namespace, RubyModule moduleToRefine, Rub
22892289
declarationContext,
22902290
block,
22912291
refinement,
2292-
block.block,
2292+
nil,
22932293
EmptyArgumentsDescriptor.INSTANCE,
22942294
EMPTY_ARGUMENTS,
22952295
null);

src/main/java/org/truffleruby/core/proc/ProcNodes.java

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import org.truffleruby.language.dispatch.DispatchNode;
4141
import org.truffleruby.language.locals.FindDeclarationVariableNodes.FindAndReadDeclarationVariableNode;
4242
import org.truffleruby.language.methods.Arity;
43-
import org.truffleruby.language.methods.SharedMethodInfo;
4443
import org.truffleruby.language.objects.AllocationTracing;
4544
import org.truffleruby.language.objects.LogicalClassNode;
4645
import org.truffleruby.language.yield.CallBlockNode;
@@ -119,13 +118,13 @@ protected RubyProc procSpecial(VirtualFrame frame, RubyClass procClass, Object[]
119118
procClass,
120119
getLanguage().procShape,
121120
block.type,
122-
block.sharedMethodInfo,
121+
block.arity,
122+
block.argumentDescriptors,
123123
block.callTargets,
124124
block.callTarget,
125125
block.declarationFrame,
126126
block.declarationVariables,
127127
block.method,
128-
block.block,
129128
block.frameOnStackMarker,
130129
block.declarationContext);
131130

@@ -157,13 +156,13 @@ protected RubyProc dup(RubyProc proc) {
157156
logicalClass,
158157
getLanguage().procShape,
159158
proc.type,
160-
proc.sharedMethodInfo,
159+
proc.arity,
160+
proc.argumentDescriptors,
161161
proc.callTargets,
162162
proc.callTarget,
163163
proc.declarationFrame,
164164
proc.declarationVariables,
165165
proc.method,
166-
proc.block,
167166
proc.frameOnStackMarker,
168167
proc.declarationContext);
169168

@@ -187,7 +186,7 @@ public abstract static class BindingNode extends CoreMethodArrayArgumentsNode {
187186
@Specialization
188187
protected RubyBinding binding(RubyProc proc) {
189188
final MaterializedFrame frame = proc.declarationFrame;
190-
final SourceSection sourceSection = proc.sharedMethodInfo.getSourceSection();
189+
final SourceSection sourceSection = proc.getSharedMethodInfo().getSourceSection();
191190
return BindingNodes.createBinding(getContext(), getLanguage(), frame, sourceSection);
192191
}
193192
}
@@ -247,7 +246,7 @@ public abstract static class ParametersNode extends CoreMethodArrayArgumentsNode
247246
@TruffleBoundary
248247
@Specialization
249248
protected RubyArray parameters(RubyProc proc) {
250-
final ArgumentDescriptor[] argsDesc = proc.sharedMethodInfo.getArgumentDescriptors();
249+
final ArgumentDescriptor[] argsDesc = proc.getArgumentDescriptors();
251250
final boolean isLambda = proc.type == ProcType.LAMBDA;
252251
return ArgumentDescriptorUtils
253252
.argumentDescriptorsToParameters(getLanguage(), getContext(), argsDesc, isLambda);
@@ -263,7 +262,7 @@ public abstract static class SourceLocationNode extends CoreMethodArrayArguments
263262
@TruffleBoundary
264263
@Specialization
265264
protected Object sourceLocation(RubyProc proc) {
266-
SourceSection sourceSection = proc.sharedMethodInfo.getSourceSection();
265+
SourceSection sourceSection = proc.getSharedMethodInfo().getSourceSection();
267266

268267
final String sourcePath = getLanguage().getSourcePath(sourceSection.getSource());
269268
if (!sourceSection.isAvailable() || sourcePath.endsWith("/lib/truffle/truffle/cext.rb")) {
@@ -286,8 +285,9 @@ public abstract static class ProcCreateSameArityNode extends PrimitiveArrayArgum
286285

287286
@Specialization
288287
protected RubyProc createSameArityProc(RubyProc userProc, RubyProc block) {
289-
final RubyProc composedProc = block.withSharedMethodInfo(
290-
userProc.sharedMethodInfo,
288+
final RubyProc composedProc = block.withArity(
289+
userProc.arity,
290+
userProc.argumentDescriptors,
291291
coreLibrary().procClass,
292292
getLanguage().procShape);
293293
AllocationTracing.trace(composedProc, this);
@@ -299,17 +299,16 @@ protected RubyProc createSameArityProc(RubyProc userProc, RubyProc block) {
299299
public abstract static class ProcSpecifyArityNode extends PrimitiveArrayArgumentsNode {
300300
@Specialization
301301
protected RubyProc specifyArityProc(RubyProc block, int argc) {
302-
Arity oldArity = block.sharedMethodInfo.getArity();
303302
final Arity newArity;
304303
if (argc <= -1) {
305304
newArity = new Arity(-(argc + 1), 0, true);
306305
} else {
307306
newArity = new Arity(argc, 0, false);
308307
}
309308

310-
SharedMethodInfo newSharedMethodInfo = block.sharedMethodInfo.withArity(newArity);
311-
final RubyProc composedProc = block.withSharedMethodInfo(
312-
newSharedMethodInfo,
309+
final RubyProc composedProc = block.withArity(
310+
newArity,
311+
null,
313312
coreLibrary().procClass,
314313
getLanguage().procShape);
315314
AllocationTracing.trace(composedProc, this);
@@ -322,8 +321,8 @@ public abstract static class ProcSymbolToProcSymbolNode extends PrimitiveArrayAr
322321

323322
@Specialization
324323
protected Object symbolToProcSymbol(RubyProc proc) {
325-
if (proc.sharedMethodInfo.getArity() == SymbolNodes.ToProcNode.ARITY) {
326-
return getSymbol(proc.sharedMethodInfo.getBacktraceName());
324+
if (proc.arity == SymbolNodes.ToProcNode.ARITY) {
325+
return getSymbol(proc.getSharedMethodInfo().getBacktraceName());
327326
} else {
328327
return nil;
329328
}
@@ -364,7 +363,7 @@ protected Object singleBlockArg(VirtualFrame frame,
364363
public abstract static class ProcRuby2KeywordsNode extends PrimitiveArrayArgumentsNode {
365364
@Specialization
366365
protected Object ruby2Keywords(RubyProc proc) {
367-
return MethodRuby2KeywordsNode.ruby2Keywords(proc.sharedMethodInfo, proc.callTarget);
366+
return MethodRuby2KeywordsNode.ruby2Keywords(proc.getSharedMethodInfo(), proc.callTarget);
368367
}
369368
}
370369
}

src/main/java/org/truffleruby/core/proc/ProcOperations.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import com.oracle.truffle.api.RootCallTarget;
2626
import com.oracle.truffle.api.frame.MaterializedFrame;
2727

28+
import static org.truffleruby.language.RubyBaseNode.nil;
29+
2830
public abstract class ProcOperations {
2931

3032
private static Object[] packArguments(RubyProc proc, ArgumentsDescriptor descriptor, Object... args) {
@@ -34,7 +36,7 @@ private static Object[] packArguments(RubyProc proc, ArgumentsDescriptor descrip
3436
proc.method,
3537
proc.frameOnStackMarker,
3638
getSelf(proc),
37-
proc.block,
39+
nil,
3840
descriptor,
3941
args);
4042
}
@@ -61,7 +63,6 @@ public static RubyProc createRubyProc(
6163
MaterializedFrame declarationFrame,
6264
SpecialVariableStorage variables,
6365
InternalMethod method,
64-
Object block,
6566
FrameOnStackMarker frameOnStackMarker,
6667
DeclarationContext declarationContext) {
6768

@@ -82,13 +83,13 @@ public static RubyProc createRubyProc(
8283
rubyClass,
8384
procShape,
8485
type,
85-
sharedMethodInfo,
86+
sharedMethodInfo.getArity(),
87+
sharedMethodInfo.getRawArgumentDescriptors(),
8688
holder,
8789
callTargetForType,
8890
declarationFrame,
8991
variables,
9092
method,
91-
block,
9293
frameOnStackMarker,
9394
declarationContext);
9495

@@ -101,12 +102,11 @@ public static RubyProc convertBlock(RubyContext context, RubyLanguage language,
101102
context.getCoreLibrary().procClass,
102103
language.procShape,
103104
type,
104-
block.sharedMethodInfo,
105+
block.getSharedMethodInfo(),
105106
block.callTargets,
106107
block.declarationFrame,
107108
block.declarationVariables,
108109
block.method,
109-
block.block,
110110
type == ProcType.PROC ? block.frameOnStackMarker : null,
111111
block.declarationContext);
112112
}

0 commit comments

Comments
 (0)