diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java index 72d66dead0aad614ce8eb90e21de016588c6dd5b..a7a17f8209246e587408d1f6731774faf9faf28b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java @@ -39,6 +39,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; @@ -62,7 +63,7 @@ import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; -import com.oracle.truffle.r.runtime.SetNeedsCallerFrameClosure; +import com.oracle.truffle.r.runtime.CallerFrameClosure; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -260,7 +261,7 @@ public class GetFunctions { @Child private CallRFunctionCachedNode callCache = CallRFunctionCachedNodeGen.create(2); private final Assumption needsNoCallerFrame = Truffle.getRuntime().createAssumption("no caller frame"); - private final SetNeedsCallerFrameClosure setNeedsCallerFrameClosure = new SetNeedsCallerFrameFlag(needsNoCallerFrame); + private final CallerFrameClosure setNeedsCallerFrameClosure = new SetNeedsCallerFrameFlag(needsNoCallerFrame); static { Casts casts = new Casts(MGet.class); @@ -403,7 +404,7 @@ public class GetFunctions { return value; } - private class SetNeedsCallerFrameFlag extends SetNeedsCallerFrameClosure { + private class SetNeedsCallerFrameFlag extends CallerFrameClosure { private final Assumption needsNoCallerFrame; @@ -416,6 +417,11 @@ public class GetFunctions { needsNoCallerFrame.invalidate(); } + @Override + public MaterializedFrame getMaterializedCallerFrame() { + return null; + } + } } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java index 52907520278ae691705c7cff9046b2747f0bff79..a217ccfdb3038dc7935044633c912fb8466c7c91 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java @@ -49,7 +49,7 @@ import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSerialize; -import com.oracle.truffle.r.runtime.SetNeedsCallerFrameClosure; +import com.oracle.truffle.r.runtime.CallerFrameClosure; import com.oracle.truffle.r.runtime.SubstituteVirtualFrame; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.context.RContext; @@ -254,7 +254,7 @@ public class HiddenInternalFunctions { RSerialize.CallHook callHook = new RSerialize.CallHook() { @Override public Object eval(Object arg) { - return callCache.execute(SubstituteVirtualFrame.create(frame), envhook, RCaller.create(frame, getOriginalCall()), SetNeedsCallerFrameClosure.DUMMY, new Object[]{arg}, null); + return callCache.execute(SubstituteVirtualFrame.create(frame), envhook, RCaller.create(frame, getOriginalCall()), new CallerFrameClosure.Dummy(0), new Object[]{arg}, null); } }; String functionName = ReadVariableNode.getSlowPathEvaluationName(); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java index f882af9993d0773fe3658e32d3fb665e738fe44f..c9d12275d3cd53f8f5576e3e264c7a55b4763552 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java @@ -32,7 +32,7 @@ import com.oracle.truffle.r.nodes.function.call.CallRFunctionNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.SetNeedsCallerFrameClosure; +import com.oracle.truffle.r.runtime.CallerFrameClosure; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RFunction; @@ -107,7 +107,7 @@ public abstract class UpdateSlot extends RBuiltinNode.Arg3 { if (cached.profile(currentFunction == checkSlotAssignFunction)) { // TODO: technically, someone could override checkAtAssignment function and access // the caller, but it's rather unlikely - checkAtAssignmentCall.execute(frame, checkSlotAssignFunction, RCaller.createInvalid(frame), SetNeedsCallerFrameClosure.DUMMY, new Object[]{objClass, name, valClass}, SIGNATURE, + checkAtAssignmentCall.execute(frame, checkSlotAssignFunction, RCaller.createInvalid(frame), null, new Object[]{objClass, name, valClass}, SIGNATURE, checkSlotAssignFunction.getEnclosingFrame(), null); } else { // slow path diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java index 5ae4e4a86af8ff26dc0eaa4332c59bf62c733875..ef7648287641e87a826d3734a6f660242ddb6985 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java @@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.RArguments.DispatchArgs; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RVisibility; -import com.oracle.truffle.r.runtime.SetNeedsCallerFrameClosure; +import com.oracle.truffle.r.runtime.CallerFrameClosure; import com.oracle.truffle.r.runtime.builtins.FastPathFactory; import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; @@ -265,7 +265,7 @@ public abstract class CallMatcherNode extends RBaseNode { Supplier<RSyntaxElement> argsSupplier = RCallerHelper.createFromArguments(genFunctionName, preparePermutation, suppliedArguments, suppliedSignature); RCaller caller = genFunctionName == null ? RCaller.createInvalid(frame, parent) : RCaller.create(frame, parent, argsSupplier); try { - return call.execute(frame, cachedFunction, caller, SetNeedsCallerFrameClosure.DUMMY, reorderedArgs, matchedArgs.getSignature(), cachedFunction.getEnclosingFrame(), + return call.execute(frame, cachedFunction, caller, null, reorderedArgs, matchedArgs.getSignature(), cachedFunction.getEnclosingFrame(), dispatchArgs); } finally { visibility.executeAfterCall(frame, caller); @@ -346,7 +346,7 @@ public abstract class CallMatcherNode extends RBaseNode { : RCaller.create(frame, RCallerHelper.createFromArguments(genFunctionName, new RArgsValuesAndNames(reorderedArgs.getArguments(), ArgumentsSignature.empty(reorderedArgs.getLength())))); try { - return call.execute(frame, function, caller, SetNeedsCallerFrameClosure.DUMMY, reorderedArgs.getArguments(), reorderedArgs.getSignature(), function.getEnclosingFrame(), dispatchArgs); + return call.execute(frame, function, caller, new CallerFrameClosure.Dummy(3), reorderedArgs.getArguments(), reorderedArgs.getSignature(), function.getEnclosingFrame(), dispatchArgs); } finally { visibility.executeAfterCall(frame, caller); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java index 5a53eddda2212bc88327f49bdd6872f5dfe8118d..6e4ecf5de1af949aeac0a8f51c6ae19209b49937 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java @@ -31,7 +31,7 @@ import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.SetNeedsCallerFrameClosure; +import com.oracle.truffle.r.runtime.CallerFrameClosure; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.nodes.RBaseNode; @@ -47,15 +47,18 @@ public final class GetCallerFrameNode extends RBaseNode { public MaterializedFrame execute(Frame frame) { Object callerFrameObject = RArguments.getCallerFrame(frame); - if (!(callerFrameObject instanceof MaterializedFrame)) { + if (callerFrameObject instanceof CallerFrameClosure) { + CallerFrameClosure closure = (CallerFrameClosure) callerFrameObject; if (!slowPathInitialized) { CompilerDirectives.transferToInterpreterAndInvalidate(); slowPathInitialized = true; } - notifyCallers(callerFrameObject); - if (slowPathInitialized) { - RError.performanceWarning("slow caller frame access"); + notifyCallers(closure); + MaterializedFrame materializedCallerFrame = closure.getMaterializedCallerFrame(); + if (materializedCallerFrame != null) { + return materializedCallerFrame; } + RError.performanceWarning("slow caller frame access"); // for now, get it on the very slow path Frame callerFrame = Utils.getCallerFrame(frame, FrameAccess.MATERIALIZE); if (callerFrame != null) { @@ -69,10 +72,8 @@ public final class GetCallerFrameNode extends RBaseNode { return (MaterializedFrame) callerFrameObject; } - private static void notifyCallers(Object callerFrameObject) { - if (callerFrameObject instanceof SetNeedsCallerFrameClosure) { - // inform the responsible call node to create a caller frame - ((SetNeedsCallerFrameClosure) callerFrameObject).setNeedsCallerFrame(); - } + private static void notifyCallers(CallerFrameClosure callerFrameObject) { + // inform the responsible call node to create a caller frame + callerFrameObject.setNeedsCallerFrame(); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java index 7b257202f4d403b2e7f517fce403a9c839787d8b..f403228b90cdd8ecd60eed11bd43745ff419bd4f 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java @@ -83,7 +83,7 @@ import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.RVisibility; -import com.oracle.truffle.r.runtime.SetNeedsCallerFrameClosure; +import com.oracle.truffle.r.runtime.CallerFrameClosure; import com.oracle.truffle.r.runtime.SubstituteVirtualFrame; import com.oracle.truffle.r.runtime.builtins.FastPathFactory; import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor; @@ -155,9 +155,10 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS // needed for INTERNAL_GENERIC calls: @Child private FunctionDispatch internalDispatchCall; + // TODO remove; kept just for compatibility private final Assumption needsNoCallerFrame = Truffle.getRuntime().createAssumption("no caller frame"); - private final SetNeedsCallerFrameClosure setNeedsCallerFrameClosure = new InvalidateNoCallerFrame(needsNoCallerFrame); + // TODO remove; kept just for compatibility public boolean setNeedsCallerFrame() { boolean value = !needsNoCallerFrame.isValid(); needsNoCallerFrame.invalidate(); @@ -993,19 +994,25 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS call.getCallNode().cloneCallTarget(); } } - Object callerFrameObject = /* CompilerDirectives.inInterpreter() || */originalCall.needsNoCallerFrame.isValid() ? originalCall.setNeedsCallerFrameClosure : frame.materialize(); - return call.execute(frame, function, originalCall.createCaller(frame, function), callerFrameObject, orderedArguments.getArguments(), orderedArguments.getSignature(), + return call.execute(frame, function, originalCall.createCaller(frame, function), null, orderedArguments.getArguments(), orderedArguments.getSignature(), function.getEnclosingFrame(), s3Args); } } - public static final class InvalidateNoCallerFrame extends SetNeedsCallerFrameClosure { + public static final class InvalidateNoCallerFrame extends CallerFrameClosure { private final Assumption needsNoCallerFrame; + private final MaterializedFrame frame; protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame) { this.needsNoCallerFrame = needsNoCallerFrame; + this.frame = null; + } + + protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame, MaterializedFrame frame) { + this.needsNoCallerFrame = needsNoCallerFrame; + this.frame = frame; } @Override @@ -1013,6 +1020,11 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS needsNoCallerFrame.invalidate(); } + @Override + public MaterializedFrame getMaterializedCallerFrame() { + return frame; + } + } @Override diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java index 8ada74320f87c9d3771663d80faa80066c240897..d8585b338bf6ebe57652bb451e125348009c062a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java @@ -22,7 +22,9 @@ */ package com.oracle.truffle.r.nodes.function.call; +import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; @@ -32,6 +34,7 @@ import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.CallerFrameClosure; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RArguments.DispatchArgs; import com.oracle.truffle.r.runtime.RCaller; @@ -43,6 +46,9 @@ public final class CallRFunctionNode extends Node { @Child private DirectCallNode callNode; @Child private SetVisibilityNode visibility = SetVisibilityNode.create(); + private final Assumption needsNoCallerFrame = Truffle.getRuntime().createAssumption("no caller frame"); + private final CallerFrameClosure invalidateNoCallerFrame = new InvalidateNoCallerFrame(needsNoCallerFrame); + private CallRFunctionNode(CallTarget callTarget) { this.callNode = Truffle.getRuntime().createDirectCallNode(callTarget); } @@ -51,8 +57,9 @@ public final class CallRFunctionNode extends Node { return new CallRFunctionNode(callTarget); } - public Object execute(VirtualFrame frame, RFunction function, RCaller caller, Object callerFrameObject, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, + public Object execute(VirtualFrame frame, RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, MaterializedFrame enclosingFrame, DispatchArgs dispatchArgs) { + Object callerFrameObject = needsNoCallerFrame.isValid() ? getCallerFrameObject(frame) : frame.materialize(); Object[] callArgs = RArguments.create(function, caller, callerFrameObject, evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs); try { return callNode.call(callArgs); @@ -61,16 +68,25 @@ public final class CallRFunctionNode extends Node { } } + private Object getCallerFrameObject(VirtualFrame callerFrame) { + if (CompilerDirectives.inInterpreter()) { + return new InvalidateNoCallerFrame(needsNoCallerFrame, callerFrame.materialize()); + } + return invalidateNoCallerFrame; + } + public DirectCallNode getCallNode() { return callNode; } public static Object executeSlowpath(RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, DispatchArgs dispatchArgs) { + assert callerFrame != null; Object[] callArgs = RArguments.create(function, caller, callerFrame, evaluatedArgs, suppliedSignature, function.getEnclosingFrame(), dispatchArgs); return executeSlowpath(function, caller, callerFrame, callArgs); } public static Object executeSlowpath(RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, DispatchArgs dispatchArgs) { + assert callerFrame != null; Object[] callArgs = RArguments.create(function, caller, callerFrame, evaluatedArgs, dispatchArgs); return executeSlowpath(function, caller, callerFrame, callArgs); } @@ -82,4 +98,31 @@ public final class CallRFunctionNode extends Node { SetVisibilityNode.executeAfterCallSlowPath(callerFrame, caller); } } + + public static final class InvalidateNoCallerFrame extends CallerFrameClosure { + + private final Assumption needsNoCallerFrame; + private final MaterializedFrame frame; + + protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame) { + this.needsNoCallerFrame = needsNoCallerFrame; + this.frame = null; + } + + protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame, MaterializedFrame frame) { + this.needsNoCallerFrame = needsNoCallerFrame; + this.frame = frame; + } + + @Override + public void setNeedsCallerFrame() { + needsNoCallerFrame.invalidate(); + } + + @Override + public MaterializedFrame getMaterializedCallerFrame() { + return frame; + } + + } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java index 6592433bad3d03be5084988a78fc6bd4dc7cf7c4..3a5cbd249e66e858b870df793b35e5a3f99a3779 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java @@ -32,7 +32,6 @@ import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.SetNeedsCallerFrameClosure; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RFunction; @@ -132,7 +131,7 @@ abstract class LoadMethod extends RBaseNode { if (cached.profile(currentFunction == loadMethodFunction)) { // TODO: technically, someone could override loadMethod function and access the // caller, but it's rather unlikely - ret = (RFunction) loadMethodCall.execute(frame, loadMethodFunction, caller, SetNeedsCallerFrameClosure.DUMMY, + ret = (RFunction) loadMethodCall.execute(frame, loadMethodFunction, caller, null, new Object[]{fdef, fname, REnvironment.frameToEnvironment(frame.materialize())}, SIGNATURE, loadMethodFunction.getEnclosingFrame(), null); } else { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/SetNeedsCallerFrameClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/CallerFrameClosure.java similarity index 64% rename from com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/SetNeedsCallerFrameClosure.java rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/CallerFrameClosure.java index 046eef0808745ec45023804609091cdb6864aa61..f642e50181a719ebb39b484a2537349075e57f1b 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/SetNeedsCallerFrameClosure.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/CallerFrameClosure.java @@ -22,17 +22,38 @@ */ package com.oracle.truffle.r.runtime; -public abstract class SetNeedsCallerFrameClosure { - public static final SetNeedsCallerFrameClosure DUMMY = new Dummy(); +import com.oracle.truffle.api.frame.MaterializedFrame; +public abstract class CallerFrameClosure { +// public static final CallerFrameClosure DUMMY = new Dummy(); + + /** + * Inform the call node to subsequently provide the caller frame. + */ public abstract void setNeedsCallerFrame(); - private static class Dummy extends SetNeedsCallerFrameClosure { + /** + * Retrieve the materialized caller frame if available (i.e. interpreter only). + */ + public abstract MaterializedFrame getMaterializedCallerFrame(); + + public static class Dummy extends CallerFrameClosure { + + private final int id; + + public Dummy(int id) { + this.id = id; + } @Override public void setNeedsCallerFrame() { // do nothing } + @Override + public MaterializedFrame getMaterializedCallerFrame() { + return null; + } + } }