45
45
import org .truffleruby .language .control .RaiseException ;
46
46
import org .truffleruby .language .methods .CallInternalMethodNode ;
47
47
import org .truffleruby .language .methods .InternalMethod ;
48
+ import org .truffleruby .language .methods .SharedMethodInfo ;
48
49
import org .truffleruby .language .objects .AllocationTracing ;
49
50
import org .truffleruby .language .objects .MetaClassNode ;
50
51
import org .truffleruby .language .threadlocal .SpecialVariableStorage ;
@@ -135,10 +136,16 @@ public abstract static class CallNode extends AlwaysInlinedMethodNode {
135
136
protected Object call (Frame callerFrame , RubyMethod method , Object [] rubyArgs , RootCallTarget target ,
136
137
@ Cached CallInternalMethodNode callInternalMethodNode ) {
137
138
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 );
139
146
RubyArguments .setMethod (newArgs , internalMethod );
140
147
assert RubyArguments .assertFrameArguments (newArgs );
141
- return callInternalMethodNode .execute (callerFrame , internalMethod , method . receiver , newArgs , null );
148
+ return callInternalMethodNode .execute (frame , internalMethod , receiver , newArgs , null );
142
149
}
143
150
}
144
151
@@ -273,28 +280,29 @@ protected RubyUnboundMethod unbind(RubyMethod method) {
273
280
@ CoreMethod (names = "to_proc" )
274
281
public abstract static class ToProcNode extends CoreMethodArrayArgumentsNode {
275
282
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 ,
278
286
@ Cached ("methodObject" ) RubyMethod cachedMethodObject ,
279
287
@ Cached ("toProcUncached(cachedMethodObject)" ) RubyProc proc ) {
280
288
return proc ;
281
289
}
282
290
283
291
@ Specialization (
284
- guards = "cachedMethod == methodObject.method " ,
292
+ guards = "methodObject.method.getCallTarget() == methodCallTarget " ,
285
293
limit = "getCacheLimit()" ,
286
- replaces = "toProcCached " )
294
+ replaces = "toProcCachedSingleContext " )
287
295
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 );
291
299
}
292
300
293
- @ Specialization
301
+ @ Specialization ( replaces = { "toProcCachedSingleContext" , "toProcCachedTarget" })
294
302
protected RubyProc toProcUncached (RubyMethod methodObject ) {
295
303
final InternalMethod method = methodObject .method ;
296
- final RootCallTarget callTarget = methodCallTarget (method );
297
304
final Object receiver = methodObject .receiver ;
305
+ final RootCallTarget callTarget = procCallTargetToCallRubyMethod (method .getCallTarget ());
298
306
return createProc (callTarget , method , receiver );
299
307
}
300
308
@@ -312,55 +320,48 @@ private RubyProc createProc(RootCallTarget callTarget, InternalMethod method, Ob
312
320
declarationFrame ,
313
321
variables ,
314
322
method ,
315
- nil ,
316
323
null ,
317
324
method .getDeclarationContext ());
318
325
}
319
326
320
327
@ TruffleBoundary
321
- protected RootCallTarget methodCallTarget ( InternalMethod method ) {
328
+ protected RootCallTarget procCallTargetToCallRubyMethod ( RootCallTarget callTarget ) {
322
329
// translate to something like:
323
330
// lambda { |same args list| method.call(args) }
324
331
// We need to preserve the method receiver and we want to have the same argument list.
325
332
// We create a new CallTarget for the Proc that calls the method CallTarget and passes the correct receiver.
326
333
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 ( );
329
336
330
- final SetReceiverNode setReceiverNode = new SetReceiverNode ( method );
337
+ var callWithRubyMethodReceiverNode = new CallWithRubyMethodReceiverNode ( );
331
338
final RubyLambdaRootNode wrapRootNode = new RubyLambdaRootNode (
332
339
getLanguage (),
333
- sourceSection ,
340
+ sharedMethodInfo . getSourceSection () ,
334
341
methodRootNode .getFrameDescriptor (),
335
- method . getSharedMethodInfo () ,
336
- setReceiverNode ,
342
+ sharedMethodInfo ,
343
+ callWithRubyMethodReceiverNode ,
337
344
methodRootNode .getSplit (),
338
345
methodRootNode .returnID ,
339
346
BreakID .INVALID ,
340
- method . getSharedMethodInfo () .getArity ());
347
+ sharedMethodInfo .getArity ());
341
348
return wrapRootNode .getCallTarget ();
342
349
}
343
350
344
351
protected int getCacheLimit () {
345
352
return getLanguage ().options .METHOD_TO_PROC_CACHE ;
346
353
}
347
354
348
- }
355
+ private static class CallWithRubyMethodReceiverNode extends RubyContextSourceNode {
356
+ @ Child private CallInternalMethodNode callInternalMethodNode = CallInternalMethodNode .create ();
349
357
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
+ }
364
365
}
365
366
}
366
367
0 commit comments