Skip to content

Commit

Permalink
[GR-28711] Make the CallTarget for Method#to_proc context-independent
Browse files Browse the repository at this point in the history
PullRequest: truffleruby/3354
  • Loading branch information
eregon committed May 17, 2022
2 parents 606438b + 1ea6310 commit e2f62b8
Show file tree
Hide file tree
Showing 16 changed files with 113 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ protected Object instanceExec(VirtualFrame frame, Object receiver, Object[] argu
block.declarationContext.getRefinements());
var descriptor = RubyArguments.getDescriptor(frame);
return callBlockNode.executeCallBlock(
declarationContext, block, receiver, block.block, descriptor, arguments, null);
declarationContext, block, receiver, nil, descriptor, arguments, null);
}

@Specialization
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/truffleruby/core/fiber/FiberManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public FiberManager(RubyLanguage language, RubyContext context) {
}

public void initialize(RubyFiber fiber, boolean blocking, RubyProc block, Node currentNode) {
final SourceSection sourceSection = block.sharedMethodInfo.getSourceSection();
final SourceSection sourceSection = block.getSharedMethodInfo().getSourceSection();
fiber.sourceLocation = RubyLanguage.fileLine(sourceSection);
fiber.blocking = blocking;

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ protected Object yieldPair(RubyProc block, Object key, Object value,
@Cached ConditionProfile arityMoreThanOne) {
// MRI behavior, see rb_hash_each_pair()
// We use getMethodArityNumber() here since for non-lambda the semantics are the same for both branches
if (arityMoreThanOne.profile(block.sharedMethodInfo.getArity().getMethodArityNumber() > 1)) {
if (arityMoreThanOne.profile(block.arity.getMethodArityNumber() > 1)) {
return yieldNode.yield(block, key, value);
} else {
return yieldNode.yield(block, createArray(new Object[]{ key, value }));
Expand Down
71 changes: 36 additions & 35 deletions src/main/java/org/truffleruby/core/method/MethodNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.truffleruby.language.control.RaiseException;
import org.truffleruby.language.methods.CallInternalMethodNode;
import org.truffleruby.language.methods.InternalMethod;
import org.truffleruby.language.methods.SharedMethodInfo;
import org.truffleruby.language.objects.AllocationTracing;
import org.truffleruby.language.objects.MetaClassNode;
import org.truffleruby.language.threadlocal.SpecialVariableStorage;
Expand Down Expand Up @@ -135,10 +136,16 @@ public abstract static class CallNode extends AlwaysInlinedMethodNode {
protected Object call(Frame callerFrame, RubyMethod method, Object[] rubyArgs, RootCallTarget target,
@Cached CallInternalMethodNode callInternalMethodNode) {
final InternalMethod internalMethod = method.method;
final Object[] newArgs = RubyArguments.repack(rubyArgs, method.receiver);
final Object receiver = method.receiver;
return callBoundMethod(callerFrame, internalMethod, receiver, rubyArgs, callInternalMethodNode);
}

static Object callBoundMethod(Frame frame, InternalMethod internalMethod, Object receiver,
Object[] callerRubyArgs, CallInternalMethodNode callInternalMethodNode) {
final Object[] newArgs = RubyArguments.repack(callerRubyArgs, receiver);
RubyArguments.setMethod(newArgs, internalMethod);
assert RubyArguments.assertFrameArguments(newArgs);
return callInternalMethodNode.execute(callerFrame, internalMethod, method.receiver, newArgs, null);
return callInternalMethodNode.execute(frame, internalMethod, receiver, newArgs, null);
}
}

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

@Specialization(guards = "methodObject == cachedMethodObject", limit = "getCacheLimit()")
protected RubyProc toProcCached(RubyMethod methodObject,
@Specialization(guards = { "isSingleContext()", "methodObject == cachedMethodObject" },
limit = "getCacheLimit()")
protected RubyProc toProcCachedSingleContext(RubyMethod methodObject,
@Cached("methodObject") RubyMethod cachedMethodObject,
@Cached("toProcUncached(cachedMethodObject)") RubyProc proc) {
return proc;
}

@Specialization(
guards = "cachedMethod == methodObject.method",
guards = "methodObject.method.getCallTarget() == methodCallTarget",
limit = "getCacheLimit()",
replaces = "toProcCached")
replaces = "toProcCachedSingleContext")
protected RubyProc toProcCachedTarget(RubyMethod methodObject,
@Cached("methodObject.method") InternalMethod cachedMethod,
@Cached("methodCallTarget(cachedMethod)") RootCallTarget callTarget) {
return createProc(callTarget, cachedMethod, methodObject.receiver);
@Cached("methodObject.method.getCallTarget()") RootCallTarget methodCallTarget,
@Cached("procCallTargetToCallRubyMethod(methodCallTarget)") RootCallTarget procCallTarget) {
return createProc(procCallTarget, methodObject.method, methodObject.receiver);
}

@Specialization
@Specialization(replaces = { "toProcCachedSingleContext", "toProcCachedTarget" })
protected RubyProc toProcUncached(RubyMethod methodObject) {
final InternalMethod method = methodObject.method;
final RootCallTarget callTarget = methodCallTarget(method);
final Object receiver = methodObject.receiver;
final RootCallTarget callTarget = procCallTargetToCallRubyMethod(method.getCallTarget());
return createProc(callTarget, method, receiver);
}

Expand All @@ -312,55 +320,48 @@ private RubyProc createProc(RootCallTarget callTarget, InternalMethod method, Ob
declarationFrame,
variables,
method,
nil,
null,
method.getDeclarationContext());
}

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

final SourceSection sourceSection = method.getSharedMethodInfo().getSourceSection();
final RubyRootNode methodRootNode = RubyRootNode.of(method.getCallTarget());
final RubyRootNode methodRootNode = RubyRootNode.of(callTarget);
final SharedMethodInfo sharedMethodInfo = methodRootNode.getSharedMethodInfo();

final SetReceiverNode setReceiverNode = new SetReceiverNode(method);
var callWithRubyMethodReceiverNode = new CallWithRubyMethodReceiverNode();
final RubyLambdaRootNode wrapRootNode = new RubyLambdaRootNode(
getLanguage(),
sourceSection,
sharedMethodInfo.getSourceSection(),
methodRootNode.getFrameDescriptor(),
method.getSharedMethodInfo(),
setReceiverNode,
sharedMethodInfo,
callWithRubyMethodReceiverNode,
methodRootNode.getSplit(),
methodRootNode.returnID,
BreakID.INVALID,
method.getSharedMethodInfo().getArity());
sharedMethodInfo.getArity());
return wrapRootNode.getCallTarget();
}

protected int getCacheLimit() {
return getLanguage().options.METHOD_TO_PROC_CACHE;
}

}
private static class CallWithRubyMethodReceiverNode extends RubyContextSourceNode {
@Child private CallInternalMethodNode callInternalMethodNode = CallInternalMethodNode.create();

private static class SetReceiverNode extends RubyContextSourceNode {
private final InternalMethod method;
@Child private CallInternalMethodNode callInternalMethodNode = CallInternalMethodNode.create();

public SetReceiverNode(InternalMethod method) {
this.method = method;
}

@Override
public Object execute(VirtualFrame frame) {
final Object originalBoundMethodReceiver = RubyArguments.getSelf(RubyArguments.getDeclarationFrame(frame));
Object[] rubyArgs = RubyArguments.repack(frame.getArguments(), originalBoundMethodReceiver);
RubyArguments.setMethod(rubyArgs, method);
return callInternalMethodNode.execute(frame, method, originalBoundMethodReceiver, rubyArgs, null);
@Override
public Object execute(VirtualFrame frame) {
final MaterializedFrame declarationFrame = RubyArguments.getDeclarationFrame(frame);
final Object receiver = RubyArguments.getSelf(declarationFrame);
final InternalMethod method = RubyArguments.getMethod(declarationFrame);
return CallNode.callBoundMethod(frame, method, receiver, frame.getArguments(), callInternalMethodNode);
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/truffleruby/core/module/ModuleNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ public Object classExec(ArgumentsDescriptor descriptor, RubyModule self, Object[
new FixedDefaultDefinee(self),
block.declarationContext.getRefinements());

return callBlockNode.executeCallBlock(declarationContext, block, self, block.block, descriptor, args, null);
return callBlockNode.executeCallBlock(declarationContext, block, self, nil, descriptor, args, null);
}
}

Expand Down Expand Up @@ -1334,7 +1334,7 @@ private RubySymbol defineMethod(RubyModule module, String name, RubyProc proc,
MaterializedFrame callerFrame) {
final RootCallTarget callTargetForLambda = proc.callTargets.getCallTargetForLambda();
final RubyLambdaRootNode rootNode = RubyLambdaRootNode.of(callTargetForLambda);
final SharedMethodInfo info = proc.sharedMethodInfo.forDefineMethod(module, name);
final SharedMethodInfo info = proc.getSharedMethodInfo().forDefineMethod(module, name);
final RubyNode body = rootNode.copyBody();
final RubyNode newBody = new CallMethodWithLambdaBody(isSingleContext() ? proc : null,
callTargetForLambda, body);
Expand Down Expand Up @@ -2289,7 +2289,7 @@ protected RubyModule refine(RubyModule namespace, RubyModule moduleToRefine, Rub
declarationContext,
block,
refinement,
block.block,
nil,
EmptyArgumentsDescriptor.INSTANCE,
EMPTY_ARGUMENTS,
null);
Expand Down
33 changes: 16 additions & 17 deletions src/main/java/org/truffleruby/core/proc/ProcNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import org.truffleruby.language.dispatch.DispatchNode;
import org.truffleruby.language.locals.FindDeclarationVariableNodes.FindAndReadDeclarationVariableNode;
import org.truffleruby.language.methods.Arity;
import org.truffleruby.language.methods.SharedMethodInfo;
import org.truffleruby.language.objects.AllocationTracing;
import org.truffleruby.language.objects.LogicalClassNode;
import org.truffleruby.language.yield.CallBlockNode;
Expand Down Expand Up @@ -119,13 +118,13 @@ protected RubyProc procSpecial(VirtualFrame frame, RubyClass procClass, Object[]
procClass,
getLanguage().procShape,
block.type,
block.sharedMethodInfo,
block.arity,
block.argumentDescriptors,
block.callTargets,
block.callTarget,
block.declarationFrame,
block.declarationVariables,
block.method,
block.block,
block.frameOnStackMarker,
block.declarationContext);

Expand Down Expand Up @@ -157,13 +156,13 @@ protected RubyProc dup(RubyProc proc) {
logicalClass,
getLanguage().procShape,
proc.type,
proc.sharedMethodInfo,
proc.arity,
proc.argumentDescriptors,
proc.callTargets,
proc.callTarget,
proc.declarationFrame,
proc.declarationVariables,
proc.method,
proc.block,
proc.frameOnStackMarker,
proc.declarationContext);

Expand All @@ -187,7 +186,7 @@ public abstract static class BindingNode extends CoreMethodArrayArgumentsNode {
@Specialization
protected RubyBinding binding(RubyProc proc) {
final MaterializedFrame frame = proc.declarationFrame;
final SourceSection sourceSection = proc.sharedMethodInfo.getSourceSection();
final SourceSection sourceSection = proc.getSharedMethodInfo().getSourceSection();
return BindingNodes.createBinding(getContext(), getLanguage(), frame, sourceSection);
}
}
Expand Down Expand Up @@ -247,7 +246,7 @@ public abstract static class ParametersNode extends CoreMethodArrayArgumentsNode
@TruffleBoundary
@Specialization
protected RubyArray parameters(RubyProc proc) {
final ArgumentDescriptor[] argsDesc = proc.sharedMethodInfo.getArgumentDescriptors();
final ArgumentDescriptor[] argsDesc = proc.getArgumentDescriptors();
final boolean isLambda = proc.type == ProcType.LAMBDA;
return ArgumentDescriptorUtils
.argumentDescriptorsToParameters(getLanguage(), getContext(), argsDesc, isLambda);
Expand All @@ -263,7 +262,7 @@ public abstract static class SourceLocationNode extends CoreMethodArrayArguments
@TruffleBoundary
@Specialization
protected Object sourceLocation(RubyProc proc) {
SourceSection sourceSection = proc.sharedMethodInfo.getSourceSection();
SourceSection sourceSection = proc.getSharedMethodInfo().getSourceSection();

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

@Specialization
protected RubyProc createSameArityProc(RubyProc userProc, RubyProc block) {
final RubyProc composedProc = block.withSharedMethodInfo(
userProc.sharedMethodInfo,
final RubyProc composedProc = block.withArity(
userProc.arity,
userProc.argumentDescriptors,
coreLibrary().procClass,
getLanguage().procShape);
AllocationTracing.trace(composedProc, this);
Expand All @@ -299,17 +299,16 @@ protected RubyProc createSameArityProc(RubyProc userProc, RubyProc block) {
public abstract static class ProcSpecifyArityNode extends PrimitiveArrayArgumentsNode {
@Specialization
protected RubyProc specifyArityProc(RubyProc block, int argc) {
Arity oldArity = block.sharedMethodInfo.getArity();
final Arity newArity;
if (argc <= -1) {
newArity = new Arity(-(argc + 1), 0, true);
} else {
newArity = new Arity(argc, 0, false);
}

SharedMethodInfo newSharedMethodInfo = block.sharedMethodInfo.withArity(newArity);
final RubyProc composedProc = block.withSharedMethodInfo(
newSharedMethodInfo,
final RubyProc composedProc = block.withArity(
newArity,
null,
coreLibrary().procClass,
getLanguage().procShape);
AllocationTracing.trace(composedProc, this);
Expand All @@ -322,8 +321,8 @@ public abstract static class ProcSymbolToProcSymbolNode extends PrimitiveArrayAr

@Specialization
protected Object symbolToProcSymbol(RubyProc proc) {
if (proc.sharedMethodInfo.getArity() == SymbolNodes.ToProcNode.ARITY) {
return getSymbol(proc.sharedMethodInfo.getBacktraceName());
if (proc.arity == SymbolNodes.ToProcNode.ARITY) {
return getSymbol(proc.getSharedMethodInfo().getBacktraceName());
} else {
return nil;
}
Expand Down Expand Up @@ -364,7 +363,7 @@ protected Object singleBlockArg(VirtualFrame frame,
public abstract static class ProcRuby2KeywordsNode extends PrimitiveArrayArgumentsNode {
@Specialization
protected Object ruby2Keywords(RubyProc proc) {
return MethodRuby2KeywordsNode.ruby2Keywords(proc.sharedMethodInfo, proc.callTarget);
return MethodRuby2KeywordsNode.ruby2Keywords(proc.getSharedMethodInfo(), proc.callTarget);
}
}
}
12 changes: 6 additions & 6 deletions src/main/java/org/truffleruby/core/proc/ProcOperations.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.frame.MaterializedFrame;

import static org.truffleruby.language.RubyBaseNode.nil;

public abstract class ProcOperations {

private static Object[] packArguments(RubyProc proc, ArgumentsDescriptor descriptor, Object... args) {
Expand All @@ -34,7 +36,7 @@ private static Object[] packArguments(RubyProc proc, ArgumentsDescriptor descrip
proc.method,
proc.frameOnStackMarker,
getSelf(proc),
proc.block,
nil,
descriptor,
args);
}
Expand All @@ -61,7 +63,6 @@ public static RubyProc createRubyProc(
MaterializedFrame declarationFrame,
SpecialVariableStorage variables,
InternalMethod method,
Object block,
FrameOnStackMarker frameOnStackMarker,
DeclarationContext declarationContext) {

Expand All @@ -82,13 +83,13 @@ public static RubyProc createRubyProc(
rubyClass,
procShape,
type,
sharedMethodInfo,
sharedMethodInfo.getArity(),
sharedMethodInfo.getRawArgumentDescriptors(),
holder,
callTargetForType,
declarationFrame,
variables,
method,
block,
frameOnStackMarker,
declarationContext);

Expand All @@ -101,12 +102,11 @@ public static RubyProc convertBlock(RubyContext context, RubyLanguage language,
context.getCoreLibrary().procClass,
language.procShape,
type,
block.sharedMethodInfo,
block.getSharedMethodInfo(),
block.callTargets,
block.declarationFrame,
block.declarationVariables,
block.method,
block.block,
type == ProcType.PROC ? block.frameOnStackMarker : null,
block.declarationContext);
}
Expand Down
Loading

0 comments on commit e2f62b8

Please sign in to comment.