From b2d4911ca08f8033430103195622ea2f62f70d7b Mon Sep 17 00:00:00 2001 From: Florian Angerer <florian.angerer@oracle.com> Date: Thu, 31 Aug 2017 12:56:28 +0200 Subject: [PATCH] Moved caller frame materialization to 'CallRFunctionNode'. --- .../r/nodes/builtin/base/GetFunctions.java | 12 +++-- .../builtin/base/HiddenInternalFunctions.java | 4 +- .../r/nodes/builtin/base/UpdateSlot.java | 4 +- .../r/nodes/function/CallMatcherNode.java | 6 +-- .../r/nodes/function/GetCallerFrameNode.java | 21 ++++----- .../truffle/r/nodes/function/RCallNode.java | 22 ++++++--- .../function/call/CallRFunctionNode.java | 45 ++++++++++++++++++- .../truffle/r/nodes/objects/LoadMethod.java | 3 +- ...meClosure.java => CallerFrameClosure.java} | 27 +++++++++-- 9 files changed, 113 insertions(+), 31 deletions(-) rename com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/{SetNeedsCallerFrameClosure.java => CallerFrameClosure.java} (64%) 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 72d66dead0..a7a17f8209 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 5290752027..a217ccfdb3 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 f882af9993..c9d12275d3 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 5ae4e4a86a..ef76482876 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 5a53eddda2..6e4ecf5de1 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 7b257202f4..f403228b90 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 8ada74320f..d8585b338b 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 6592433bad..3a5cbd249e 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 046eef0808..f642e50181 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; + } + } } -- GitLab