From b169e498ab4cc7e39825d9cef020dc45e2293def Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 26 Apr 2023 18:41:39 +0200 Subject: [PATCH 01/13] Introducing @BuildinMethod.needsFrame that can overide the default --- .../node/callable/ExecuteCallNode.java | 14 ++++++++++--- .../callable/dispatch/CallOptimiserNode.java | 8 +++++++- .../node/callable/dispatch/CurryNode.java | 10 +++++----- .../callable/dispatch/IndirectCurryNode.java | 10 ++++++---- .../dispatch/LoopingCallOptimiserNode.java | 4 ++-- .../dispatch/SimpleCallOptimiserNode.java | 12 ++++++++--- .../callable/thunk/ThunkExecutorNode.java | 4 ++-- .../expression/builtin/BuiltinRootNode.java | 6 +++++- .../builtin/function/ApplicationOperator.java | 3 ++- .../builtin/ordering/SortVectorNode.java | 6 +++--- .../org/enso/interpreter/runtime/Module.java | 1 + .../interpreter/test/semantic/EvalTest.scala | 14 +++++++++++++ .../org/enso/interpreter/dsl/Builtin.java | 14 +++++++++++++ .../enso/interpreter/dsl/BuiltinMethod.java | 16 +++++++++++++-- .../interpreter/dsl/BuiltinsProcessor.java | 20 ++++++++++++++++--- .../enso/interpreter/dsl/MethodProcessor.java | 16 +++++++++------ .../builtins/MethodNodeClassGenerator.java | 6 +++++- .../dsl/model/MethodDefinition.java | 8 ++++++-- 18 files changed, 133 insertions(+), 39 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java index c734cbd3a5c1..b5a8d714d102 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java @@ -4,11 +4,13 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import org.enso.interpreter.node.InlineableRootNode; +import org.enso.interpreter.node.expression.builtin.BuiltinRootNode; import org.enso.interpreter.runtime.callable.CallerInfo; import org.enso.interpreter.runtime.callable.function.Function; @@ -48,14 +50,19 @@ public static ExecuteCallNode build() { */ @Specialization(guards = "function.getCallTarget() == cachedTarget") protected Object callDirect( + VirtualFrame frame, Function function, CallerInfo callerInfo, Object state, Object[] arguments, @Cached("function.getCallTarget()") RootCallTarget cachedTarget, @Cached("createCallNode(cachedTarget)") DirectCallNode callNode) { - return callNode.call( - Function.ArgumentsHelper.buildArguments(function, callerInfo, state, arguments)); + var args = Function.ArgumentsHelper.buildArguments(function, callerInfo, state, arguments); + if (callNode instanceof BuiltinRootNode.InlinedCallNode in) { + return in.callWithFrame(frame, args); + } else { + return callNode.call(args); + } } static DirectCallNode createCallNode(RootCallTarget t) { @@ -90,6 +97,7 @@ protected Object callIndirect( /** * Executes the function call. * + * @param frame the caller's frame * @param function the function to execute * @param callerInfo the caller info to pass to the function * @param state the state value to pass to the function @@ -97,5 +105,5 @@ protected Object callIndirect( * @return the result of executing {@code function} on {@code arguments} */ public abstract Object executeCall( - Function function, CallerInfo callerInfo, Object state, Object[] arguments); + VirtualFrame frame, Function function, CallerInfo callerInfo, Object state, Object[] arguments); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/CallOptimiserNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/CallOptimiserNode.java index ada785524bb6..3d0422ea134a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/CallOptimiserNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/CallOptimiserNode.java @@ -1,5 +1,6 @@ package org.enso.interpreter.node.callable.dispatch; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import org.enso.interpreter.runtime.callable.CallerInfo; @@ -27,6 +28,7 @@ public static CallOptimiserNode build() { /** * Calls the provided {@code callable} using the provided {@code arguments}. * + * @param frame frame of the caller * @param callable the callable to execute * @param callerInfo the caller info to pass to the function * @param state the state to pass to the function @@ -34,5 +36,9 @@ public static CallOptimiserNode build() { * @return the result of executing {@code callable} using {@code arguments} */ public abstract Object executeDispatch( - Function callable, CallerInfo callerInfo, State state, Object[] arguments); + VirtualFrame frame, + Function callable, + CallerInfo callerInfo, + State state, + Object[] arguments); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/CurryNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/CurryNode.java index 4a2b022bb5ee..8803831db1c9 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/CurryNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/CurryNode.java @@ -105,7 +105,7 @@ public Object execute( Object[] oversaturatedArguments) { if (appliesFully) { if (!postApplicationSchema.hasOversaturatedArgs()) { - var value = doCall(function, callerInfo, state, arguments); + var value = doCall(frame, function, callerInfo, state, arguments); if (defaultsExecutionMode.isExecute() && (value instanceof Function || (value instanceof AtomConstructor cons && cons.getConstructorFunction().getSchema().isFullyApplied()))) { @@ -133,7 +133,7 @@ public Object execute( return value; } } else { - var evaluatedVal = loopingCall.executeDispatch(function, callerInfo, state, arguments); + var evaluatedVal = loopingCall.executeDispatch(frame, function, callerInfo, state, arguments); return this.oversaturatedCallableNode.execute( evaluatedVal, frame, state, oversaturatedArguments); @@ -150,11 +150,11 @@ public Object execute( } private Object doCall( - Function function, CallerInfo callerInfo, State state, Object[] arguments) { + VirtualFrame frame, Function function, CallerInfo callerInfo, State state, Object[] arguments) { return switch (getTailStatus()) { - case TAIL_DIRECT -> directCall.executeCall(function, callerInfo, state, arguments); + case TAIL_DIRECT -> directCall.executeCall(frame, function, callerInfo, state, arguments); case TAIL_LOOP -> throw new TailCallException(function, callerInfo, arguments); - default -> loopingCall.executeDispatch(function, callerInfo, state, arguments); + default -> loopingCall.executeDispatch(frame, function, callerInfo, state, arguments); }; } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/IndirectCurryNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/IndirectCurryNode.java index 839e92e50ce7..489139633460 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/IndirectCurryNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/IndirectCurryNode.java @@ -4,6 +4,7 @@ import com.oracle.truffle.api.dsl.GenerateUncached; 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.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import org.enso.interpreter.node.BaseNode; @@ -74,7 +75,7 @@ Object doCurry( if (appliesFully) { if (!postApplicationSchema.hasOversaturatedArgs()) { var value = - doCall(function, callerInfo, state, arguments, isTail, directCall, loopingCall); + doCall(frame, function, callerInfo, state, arguments, isTail, directCall, loopingCall); if (defaultsExecutionMode.isExecute() && (value instanceof Function || (value instanceof AtomConstructor cons && cons.getConstructorFunction().getSchema().isFullyApplied()))) { @@ -91,7 +92,7 @@ Object doCurry( return value; } } else { - var evaluatedVal = loopingCall.executeDispatch(function, callerInfo, state, arguments); + var evaluatedVal = loopingCall.executeDispatch(frame, function, callerInfo, state, arguments); return oversaturatedCallableNode.execute( evaluatedVal, @@ -114,6 +115,7 @@ Object doCurry( } private Object doCall( + VirtualFrame frame, Function function, CallerInfo callerInfo, State state, @@ -123,11 +125,11 @@ private Object doCall( CallOptimiserNode loopingCall) { switch (isTail) { case TAIL_DIRECT: - return directCall.executeCall(function, callerInfo, state, arguments); + return directCall.executeCall(frame, function, callerInfo, state, arguments); case TAIL_LOOP: throw new TailCallException(function, callerInfo, arguments); default: - return loopingCall.executeDispatch(function, callerInfo, state, arguments); + return loopingCall.executeDispatch(frame, function, callerInfo, state, arguments); } } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/LoopingCallOptimiserNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/LoopingCallOptimiserNode.java index 4fd7ccb5bc51..9d1b48077724 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/LoopingCallOptimiserNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/LoopingCallOptimiserNode.java @@ -79,7 +79,7 @@ public Object uncachedDispatch( @Cached ExecuteCallNode executeCallNode) { while (true) { try { - return executeCallNode.executeCall(function, callerInfo, state, arguments); + return executeCallNode.executeCall(null, function, callerInfo, state, arguments); } catch (TailCallException e) { function = e.getFunction(); callerInfo = e.getCallerInfo(); @@ -211,7 +211,7 @@ public boolean executeRepeating(VirtualFrame frame) { Object[] arguments = getNextArgs(frame); CallerInfo callerInfo = getCallerInfo(frame); frame.setObject( - resultSlotIdx, dispatchNode.executeCall(function, callerInfo, state, arguments)); + resultSlotIdx, dispatchNode.executeCall(frame, function, callerInfo, state, arguments)); return false; } catch (TailCallException e) { setNextCall(frame, e.getFunction(), e.getCallerInfo(), e.getArguments()); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/SimpleCallOptimiserNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/SimpleCallOptimiserNode.java index 97f0ca21d0c7..594e6b1522d7 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/SimpleCallOptimiserNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/SimpleCallOptimiserNode.java @@ -1,6 +1,7 @@ package org.enso.interpreter.node.callable.dispatch; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInfo; import org.enso.interpreter.node.callable.ExecuteCallNode; import org.enso.interpreter.node.callable.ExecuteCallNodeGen; @@ -44,9 +45,13 @@ public static SimpleCallOptimiserNode build() { */ @Override public Object executeDispatch( - Function function, CallerInfo callerInfo, State state, Object[] arguments) { + VirtualFrame frame, + Function function, + CallerInfo callerInfo, + State state, + Object[] arguments) { try { - return executeCallNode.executeCall(function, callerInfo, state, arguments); + return executeCallNode.executeCall(frame, function, callerInfo, state, arguments); } catch (TailCallException e) { if (next == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -60,7 +65,8 @@ public Object executeDispatch( lock.unlock(); } } - return next.executeDispatch(e.getFunction(), e.getCallerInfo(), state, e.getArguments()); + return next.executeDispatch( + null, e.getFunction(), e.getCallerInfo(), state, e.getArguments()); } } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ThunkExecutorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ThunkExecutorNode.java index 8552a3b3fe27..d3b24aa579b0 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ThunkExecutorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ThunkExecutorNode.java @@ -63,7 +63,7 @@ Object doCached( return callNode.call(Function.ArgumentsHelper.buildArguments(function, state)); } catch (TailCallException e) { return loopingCallOptimiserNode.executeDispatch( - e.getFunction(), e.getCallerInfo(), state, e.getArguments()); + null, e.getFunction(), e.getCallerInfo(), state, e.getArguments()); } } } @@ -84,7 +84,7 @@ Object doUncached( function.getCallTarget(), Function.ArgumentsHelper.buildArguments(function, state)); } catch (TailCallException e) { return loopingCallOptimiserNode.executeDispatch( - e.getFunction(), e.getCallerInfo(), state, e.getArguments()); + null, e.getFunction(), e.getCallerInfo(), state, e.getArguments()); } } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java index 52d8b83d01c5..8c29eec6f460 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java @@ -54,7 +54,7 @@ public DirectCallNode createDirectCallNode() { * @param extra data to keep in the node * @param node to delegate to from {@link #call(java.lang.Object...)} method */ - protected abstract static class InlinedCallNode extends DirectCallNode { + public abstract static class InlinedCallNode extends DirectCallNode { protected final E extra; @Child protected N body; @@ -64,6 +64,10 @@ protected InlinedCallNode(E extra, N body) { this.body = body; } + public Object callWithFrame(VirtualFrame frame, Object... arguments) { + return call(arguments); + } + @Override public abstract Object call(Object... arguments); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/function/ApplicationOperator.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/function/ApplicationOperator.java index ad5d39967321..63a3c790f1cf 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/function/ApplicationOperator.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/function/ApplicationOperator.java @@ -12,7 +12,8 @@ @BuiltinMethod( type = "Function", name = "<|", - description = "Takes a function and an argument and applies the function to the argument.") + description = "Takes a function and an argument and applies the function to the argument.", + needsFrame = false) public class ApplicationOperator extends Node { private @Child InvokeCallableNode invokeCallableNode; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java index d23ee524e04c..49dfbe35c76b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java @@ -806,8 +806,8 @@ public int compare(Object x, Object y) { Object yConverted; if (hasCustomOnFunc) { // onFunc cannot have `self` argument, we assume it has just one argument. - xConverted = callNode.executeDispatch(onFunc.get(x), null, state, new Object[]{x}); - yConverted = callNode.executeDispatch(onFunc.get(y), null, state, new Object[]{y}); + xConverted = callNode.executeDispatch(null, onFunc.get(x), null, state, new Object[]{x}); + yConverted = callNode.executeDispatch(null, onFunc.get(y), null, state, new Object[]{y}); } else { xConverted = x; yConverted = y; @@ -818,7 +818,7 @@ public int compare(Object x, Object y) { } else { args = new Object[] {xConverted, yConverted}; } - Object res = callNode.executeDispatch(compareFunc.get(xConverted), null, state, args); + Object res = callNode.executeDispatch(null, compareFunc.get(xConverted), null, state, args); if (res == less) { return ascending ? -1 : 1; } else if (res == equal) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java index 1c2d94019d15..18667b30a151 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java @@ -626,6 +626,7 @@ private static Object evalExpression( .orElseThrow(); CallerInfo callerInfo = new CallerInfo(null, LocalScope.root(), scope); return callOptimiserNode.executeDispatch( + null, eval.getFunction(), callerInfo, context.emptyState(), diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/EvalTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/EvalTest.scala index 07a568a09505..6828ec06277c 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/EvalTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/EvalTest.scala @@ -36,6 +36,20 @@ class EvalTest extends InterpreterTest { consumeOut shouldEqual List("Hello World!") } + "have access to the caller scope with <|" in { + val code = + s"""import Standard.Base.Runtime.Debug + |import Standard.Base.IO + | + |main = + | x = "Hello World!" + | Debug.eval <| $rawTQ + | IO.println x + |""".stripMargin + eval(code) + consumeOut shouldEqual List("Hello World!") + } + "have access to the caller module scope" in { val code = s"""import Standard.Base.Runtime.Debug diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/Builtin.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/Builtin.java index 81a91a84e2ae..0c3e585fbd92 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/Builtin.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/Builtin.java @@ -160,6 +160,20 @@ * type. Auto-registered methods do not have to be declared explicitly. */ boolean autoRegister() default true; + + /** + * Needs own frame or not. This argument doesn't need to be specified. If it is missing, its + * effective value is derived from the arguments of the annotated method. When the + * {@code execute} method requires {@link VirtualFrame} as one of its arguments the value of + * unspecified {@link #needsFrame()} is {@code true}. When no {@link VirtualFrame} is needed, + * the value is assumed to be {@code false}. + * + * @return explicitly specify whether the builtin needs its own {@link VirtualFrame} or can + * share the one of a caller. + * @see BuiltinMethod + * @see BuiltinMethod#needsFrame + */ + boolean needsFrame() default false; } /** diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinMethod.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinMethod.java index c5163ae96f92..075b83cb3949 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinMethod.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinMethod.java @@ -9,8 +9,8 @@ * An annotation denoting a node that should be wrapped for standard library export. A subclass of * {@code BuiltinRootNode} is generated with implementation of {@code * InlineableRootNode#createDirectCallNode()} that either delegates to regular {@link - * DirectCallNode} (when the {@code execute} method requires {@code VirtualFrame} as one of its - * arguments) or provides a special implementation, if no {@code VirtualFrame} is needed. + * DirectCallNode} or provides a special and faster implementation depending on implicit or explicit + * value of {@link #needsFrame()} attribute. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) @@ -29,4 +29,16 @@ /** @return whether a method should be registered automatically with a type */ boolean autoRegister() default true; + + /** + * Needs own frame or not. This argument doesn't need to be specified. If it is missing, its + * effective value is derived from the arguments of the annotated method. When the {@code + * execute} method requires {@code VirtualFrame} as one of its arguments the value of unspecified + * {@link #needsFrame()} is {@code true}. When no {@code VirtualFrame} is needed, the value is + * assumed to be {@code false}. + * + * @return explicitly specify whether the builtin needs its own {@link VirtualFrame} or can share + * the one of a caller. + */ + boolean needsFrame() default false; } diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinsProcessor.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinsProcessor.java index 8743a09ab7db..2767b0b3cd0c 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinsProcessor.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinsProcessor.java @@ -149,6 +149,7 @@ public void handleMethodElement(Element element, RoundEnvironment roundEnv) thro PackageElement pkgElement = (PackageElement) ownerTpeElement.getEnclosingElement(); Builtin.Method annotation = element.getAnnotation(Builtin.Method.class); + Boolean needsFrame = checkNeedsFrame(element); boolean isConstructor = method.getKind() == ElementKind.CONSTRUCTOR; if (annotation.expandVarargs() != 0) { @@ -183,7 +184,7 @@ public void handleMethodElement(Element element, RoundEnvironment roundEnv) thro methodName, annotation.description(), method.getSimpleName().toString(), - annotation.autoRegister()); + annotation.autoRegister(), needsFrame); } catch (IOException ioe) { throw new RuntimeException(ioe); } @@ -237,7 +238,7 @@ public void handleMethodElement(Element element, RoundEnvironment roundEnv) thro builtinMethodName, annotation.description(), method.getSimpleName().toString(), - annotation.autoRegister()); + annotation.autoRegister(), needsFrame); } } else { MethodNodeClassGenerator classGenerator = @@ -248,7 +249,7 @@ public void handleMethodElement(Element element, RoundEnvironment roundEnv) thro builtinMethodName, annotation.description(), method.getSimpleName().toString(), - annotation.autoRegister()); + annotation.autoRegister(), needsFrame); } } } else { @@ -256,6 +257,19 @@ public void handleMethodElement(Element element, RoundEnvironment roundEnv) thro } } + static Boolean checkNeedsFrame(Element element) { + Boolean needsFrame = null; + for (var m : element.getAnnotationMirrors()) { + for (var entry : m.getElementValues().entrySet()) { + var name = entry.getKey().getSimpleName().toString(); + if (name.equals("needsFrame")) { + needsFrame = (Boolean) entry.getValue().getValue(); + } + } + } + return needsFrame; + } + /** * Count the number of @Specialization or @Fallback annotations for a given method name. * diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java index 734a644484ee..5f018a84acf3 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java @@ -54,7 +54,8 @@ public boolean handleProcess(Set annotations, RoundEnviro for (Element elt : annotatedElements) { if (elt.getKind() == ElementKind.CLASS) { try { - handleTypeELement((TypeElement) elt, roundEnv); + var needsFrame = BuiltinsProcessor.checkNeedsFrame(elt); + handleTypeELement((TypeElement) elt, roundEnv, needsFrame); } catch (IOException e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage()); } @@ -71,7 +72,7 @@ public boolean handleProcess(Set annotations, RoundEnviro return true; } - private void handleTypeELement(TypeElement element, RoundEnvironment roundEnv) + private void handleTypeELement(TypeElement element, RoundEnvironment roundEnv, Boolean needsFrame) throws IOException { ExecutableElement executeMethod = element.getEnclosedElements().stream() @@ -94,7 +95,7 @@ private void handleTypeELement(TypeElement element, RoundEnvironment roundEnv) String pkgName = processingEnv.getElementUtils().getPackageOf(element).getQualifiedName().toString(); - MethodDefinition def = new MethodDefinition(pkgName, element, executeMethod); + MethodDefinition def = new MethodDefinition(pkgName, element, executeMethod, needsFrame); if (!def.validate(processingEnv)) { return; } @@ -235,7 +236,10 @@ private void generateCode(MethodDefinition methodDefinition) throws IOException out.println(" var n = " + methodDefinition.getConstructorExpression() + ";"); out.println(" return new InlinedCallNode<>(new Internals(internals.staticOfInstanceMethod), n) {"); out.println(" public Object call(Object[] args) {"); - out.println(" return handleExecute(extra, body, args);"); + out.println(" return handleExecute(null, extra, body, args);"); + out.println(" }"); + out.println(" public Object callWithFrame(VirtualFrame frame, Object[] args) {"); + out.println(" return handleExecute(frame, extra, body, args);"); out.println(" }"); out.println(" };"); out.println(" }"); @@ -246,9 +250,9 @@ private void generateCode(MethodDefinition methodDefinition) throws IOException if (methodDefinition.needsFrame()) { out.println(" var args = frame.getArguments();"); } else { - out.println(" return handleExecute(this.internals, bodyNode, frame.getArguments());"); + out.println(" return handleExecute(frame, this.internals, bodyNode, frame.getArguments());"); out.println(" }"); - out.println(" private static Object handleExecute(Internals internals, " + methodDefinition.getOriginalClassName() + " bodyNode, Object[] args) {"); + out.println(" private static Object handleExecute(VirtualFrame frame, Internals internals, " + methodDefinition.getOriginalClassName() + " bodyNode, Object[] args) {"); } out.println(" var prefix = internals.staticOfInstanceMethod ? 1 : 0;"); out.println(" State state = Function.ArgumentsHelper.getState(args);"); diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/builtins/MethodNodeClassGenerator.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/builtins/MethodNodeClassGenerator.java index 1713abb68076..ced89aacd9b8 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/builtins/MethodNodeClassGenerator.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/builtins/MethodNodeClassGenerator.java @@ -39,7 +39,8 @@ public void generate( String methodName, String description, String ownerMethodName, - boolean isAutoRegister) + boolean isAutoRegister, + Boolean needsFrame) throws IOException { JavaFileObject gen = processingEnv.getFiler().createSourceFile(builtinNode.jvmFriendlyFullyQualifiedName()); @@ -58,6 +59,9 @@ public void generate( if (!isAutoRegister) { moduleOwnerInfo = ", autoRegister = " + isAutoRegister; } + if (needsFrame != null) { + moduleOwnerInfo = moduleOwnerInfo + ", needsFrame = " + needsFrame; + } out.println( "@BuiltinMethod(type = \"" + ensoTypeName diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/model/MethodDefinition.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/model/MethodDefinition.java index cdc618db0038..c9835cd4eca9 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/model/MethodDefinition.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/model/MethodDefinition.java @@ -34,8 +34,11 @@ public class MethodDefinition { * @param packageName the name of the package this method is declared in. * @param element the element (class) declaring this method. * @param execute the element (method) containing the logic. + * @param needsFrame optionally specify if we need own frame, if {@code null} the value is derived + * from presence/absence of {@code VirtualFrame} argument */ - public MethodDefinition(String packageName, TypeElement element, ExecutableElement execute) { + public MethodDefinition( + String packageName, TypeElement element, ExecutableElement execute, Boolean needsFrame) { this.annotation = element.getAnnotation(BuiltinMethod.class); this.element = element; this.executeMethod = execute; @@ -46,7 +49,8 @@ public MethodDefinition(String packageName, TypeElement element, ExecutableEleme this.arguments = initArguments(execute); this.imports = initImports(); this.needsCallerInfo = arguments.stream().anyMatch(ArgumentDefinition::isCallerInfo); - this.needsFrame = arguments.stream().anyMatch(ArgumentDefinition::isFrame); + this.needsFrame = + needsFrame != null ? needsFrame : arguments.stream().anyMatch(ArgumentDefinition::isFrame); this.constructorExpression = initConstructor(element); } From 00e70fe7077b175d94d28c3b630465fa1fd5bb93 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 27 Apr 2023 06:49:38 +0200 Subject: [PATCH 02/13] Propagating frame via more nodes --- .../callable/IndirectInvokeCallableNode.java | 2 +- .../node/callable/IndirectInvokeMethodNode.java | 3 ++- .../node/callable/InvokeCallableNode.java | 6 +++--- .../node/callable/InvokeMethodNode.java | 2 +- .../callable/argument/ArgumentSorterNode.java | 10 ++++++---- .../argument/IndirectArgumentSorterNode.java | 10 ++++++++-- .../dispatch/IndirectInvokeFunctionNode.java | 1 + .../callable/dispatch/InvokeFunctionNode.java | 3 ++- .../dispatch/LoopingCallOptimiserNode.java | 4 +++- .../dispatch/SimpleCallOptimiserNode.java | 2 +- .../node/callable/thunk/ForceNode.java | 2 +- .../node/callable/thunk/ThunkExecutorNode.java | 11 ++++++++--- .../node/expression/builtin/bool/AndNode.java | 9 ++++++--- .../expression/builtin/bool/IfThenElseNode.java | 16 ++++++++++++---- .../node/expression/builtin/bool/IfThenNode.java | 11 +++++++---- .../node/expression/builtin/bool/OrNode.java | 9 ++++++--- .../expression/builtin/error/CatchPanicNode.java | 2 +- .../builtin/meta/GetAnnotationNode.java | 4 ++-- .../expression/builtin/resource/BracketNode.java | 2 +- .../expression/builtin/runtime/NoInlineNode.java | 10 ++++++++-- .../runtime/RuntimeWithDisabledContextNode.java | 9 ++++++--- .../runtime/RuntimeWithEnabledContextNode.java | 9 ++++++--- .../builtin/special/RunThreadNode.java | 8 +++++--- .../expression/builtin/state/RunStateNode.java | 15 +++++++++++---- .../builtin/thread/WithInterruptHandlerNode.java | 12 ++++++++---- .../node/expression/debug/EvalNode.java | 4 ++-- .../runtime/data/hash/HashMapGetNode.java | 16 ++++++++++------ 27 files changed, 128 insertions(+), 64 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeCallableNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeCallableNode.java index 8fd86f6487a7..969d41d4db74 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeCallableNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeCallableNode.java @@ -182,7 +182,7 @@ public Object invokeDynamicSymbol( if (canApplyThis) { Object self = arguments[thisArgumentPosition]; if (argumentsExecutionMode.shouldExecute()) { - self = thisExecutor.executeThunk(self, state, BaseNode.TailStatus.NOT_TAIL); + self = thisExecutor.executeThunk(callerFrame, self, state, BaseNode.TailStatus.NOT_TAIL); arguments[thisArgumentPosition] = self; } return invokeMethodNode.execute( diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java index 6a22a01234e8..df04851a558f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java @@ -178,7 +178,8 @@ Object doPolyglot( @Cached HostMethodCallNode hostMethodCallNode) { Object[] args = new Object[arguments.length - 1]; for (int i = 0; i < arguments.length - 1; i++) { - var r = argExecutor.executeThunk(arguments[i + 1], state, BaseNode.TailStatus.NOT_TAIL); + var r = + argExecutor.executeThunk(frame, arguments[i + 1], state, BaseNode.TailStatus.NOT_TAIL); if (r instanceof DataflowError) { return r; } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java index 8916c6a26f29..69b6f47e7c18 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java @@ -215,8 +215,8 @@ public Object invokeConversion( lock.unlock(); } } - selfArgument = thisExecutor.executeThunk(selfArgument, state, TailStatus.NOT_TAIL); - thatArgument = thatExecutor.executeThunk(thatArgument, state, TailStatus.NOT_TAIL); + selfArgument = thisExecutor.executeThunk(callerFrame, selfArgument, state, TailStatus.NOT_TAIL); + thatArgument = thatExecutor.executeThunk(callerFrame, thatArgument, state, TailStatus.NOT_TAIL); arguments[thisArgumentPosition] = selfArgument; arguments[thatArgumentPosition] = thatArgument; @@ -248,7 +248,7 @@ public Object invokeDynamicSymbol( lock.unlock(); } } - selfArgument = thisExecutor.executeThunk(selfArgument, state, TailStatus.NOT_TAIL); + selfArgument = thisExecutor.executeThunk(callerFrame, selfArgument, state, TailStatus.NOT_TAIL); arguments[thisArgumentPosition] = selfArgument; } return invokeMethodNode.execute(callerFrame, state, symbol, selfArgument, arguments); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java index 74a672bd9fa8..aaf574b1b66f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java @@ -307,7 +307,7 @@ Object doPolyglot( boolean anyWarnings = false; ArrayRope accumulatedWarnings = new ArrayRope<>(); for (int i = 0; i < argExecutors.length; i++) { - var r = argExecutors[i].executeThunk(arguments[i + 1], state, TailStatus.NOT_TAIL); + var r = argExecutors[i].executeThunk(frame, arguments[i + 1], state, TailStatus.NOT_TAIL); if (r instanceof DataflowError) { profiles[i].enter(); return r; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ArgumentSorterNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ArgumentSorterNode.java index cbad564b3a77..2b6fa645ee2e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ArgumentSorterNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ArgumentSorterNode.java @@ -1,6 +1,7 @@ package org.enso.interpreter.node.callable.argument; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.NodeInfo; import org.enso.interpreter.node.BaseNode; @@ -66,7 +67,7 @@ private void initArgumentExecutors() { } @ExplodeLoop - private void executeArguments(Object[] arguments, State state) { + private void executeArguments(VirtualFrame frame, Object[] arguments, State state) { if (executors == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); Lock lock = getLock(); @@ -81,7 +82,7 @@ private void executeArguments(Object[] arguments, State state) { } for (int i = 0; i < mapping.getArgumentShouldExecute().length; i++) { if (executors[i] != null) { - arguments[i] = executors[i].executeThunk(arguments[i], state, TailStatus.NOT_TAIL); + arguments[i] = executors[i].executeThunk(frame, arguments[i], state, TailStatus.NOT_TAIL); } } } @@ -94,9 +95,10 @@ private void executeArguments(Object[] arguments, State state) { * @param arguments the arguments to reorder * @return the provided {@code arguments} in the order expected by the cached {@link Function} */ - public MappedArguments execute(Function function, State state, Object[] arguments) { + public MappedArguments execute( + VirtualFrame frame, Function function, State state, Object[] arguments) { if (argumentsExecutionMode.shouldExecute()) { - executeArguments(arguments, state); + executeArguments(frame, arguments, state); } Object[] mappedAppliedArguments = prepareArguments( diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/IndirectArgumentSorterNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/IndirectArgumentSorterNode.java index 5f0e1ee2ebc3..dd8255172796 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/IndirectArgumentSorterNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/IndirectArgumentSorterNode.java @@ -3,6 +3,7 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; @@ -35,6 +36,7 @@ public static IndirectArgumentSorterNode build() { @ExplodeLoop private void executeArguments( + VirtualFrame frame, ArgumentMapping mapping, Object[] arguments, State state, @@ -42,7 +44,8 @@ private void executeArguments( for (int i = 0; i < mapping.getArgumentShouldExecute().length; i++) { if (mapping.getArgumentShouldExecute()[i]) { arguments[i] = - thunkExecutorNode.executeThunk(arguments[i], state, BaseNode.TailStatus.NOT_TAIL); + thunkExecutorNode.executeThunk( + frame, arguments[i], state, BaseNode.TailStatus.NOT_TAIL); } } } @@ -50,6 +53,7 @@ private void executeArguments( /** * Reorders and executes the provided arguments in a way suitable for the called function. * + * @param frame current frame * @param preApplicationSchema the function schema before applying the arguments * @param mapping the pre-computed argument mapping for the function * @param argumentsExecutionMode whether arguments should be executed or not @@ -59,6 +63,7 @@ private void executeArguments( * @return the provided {@code arguments} in the order expected by the cached {@link Function} */ public abstract ArgumentSorterNode.MappedArguments execute( + VirtualFrame frame, FunctionSchema preApplicationSchema, ArgumentMapping mapping, InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode, @@ -68,6 +73,7 @@ public abstract ArgumentSorterNode.MappedArguments execute( @Specialization ArgumentSorterNode.MappedArguments doExecute( + VirtualFrame frame, FunctionSchema preApplicationSchema, ArgumentMapping mapping, InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode, @@ -77,7 +83,7 @@ ArgumentSorterNode.MappedArguments doExecute( @Cached ThunkExecutorNode thunkExecutorNode) { FunctionSchema postApplicationSchema = mapping.getPostApplicationSchema(); if (argumentsExecutionMode.shouldExecute()) { - executeArguments(mapping, arguments, state, thunkExecutorNode); + executeArguments(frame, mapping, arguments, state, thunkExecutorNode); } Object[] mappedAppliedArguments = ArgumentSorterNode.prepareArguments( diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/IndirectInvokeFunctionNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/IndirectInvokeFunctionNode.java index d3fb301ac277..c72642a09657 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/IndirectInvokeFunctionNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/IndirectInvokeFunctionNode.java @@ -66,6 +66,7 @@ Object invokeUncached( ArgumentSorterNode.MappedArguments mappedArguments = mappingNode.execute( + callerFrame, function.getSchema(), argumentMapping, argumentsExecutionMode, diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/InvokeFunctionNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/InvokeFunctionNode.java index 151c32cccbee..cd5acd0f17a0 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/InvokeFunctionNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/InvokeFunctionNode.java @@ -82,7 +82,7 @@ Object invokeCached( "build(argumentMapping, getDefaultsExecutionMode(), getArgumentsExecutionMode(), getTailStatus())") CurryNode curryNode) { ArgumentSorterNode.MappedArguments mappedArguments = - mappingNode.execute(function, state, arguments); + mappingNode.execute(callerFrame, function, state, arguments); CallerInfo callerInfo = null; if (cachedSchema.getCallerFrameAccess().shouldFrameBePassed()) { callerInfo = captureCallerInfoNode.execute(callerFrame.materialize()); @@ -121,6 +121,7 @@ Object invokeUncached( ArgumentSorterNode.MappedArguments mappedArguments = mappingNode.execute( + callerFrame, function.getSchema(), argumentMapping, getArgumentsExecutionMode(), diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/LoopingCallOptimiserNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/LoopingCallOptimiserNode.java index 9d1b48077724..b78a94eb3a63 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/LoopingCallOptimiserNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/LoopingCallOptimiserNode.java @@ -7,6 +7,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.FrameSlotKind; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @@ -72,6 +73,7 @@ public Object dispatch( @Specialization(replaces = "dispatch") @CompilerDirectives.TruffleBoundary public Object uncachedDispatch( + MaterializedFrame frame, Function function, CallerInfo callerInfo, State state, @@ -79,7 +81,7 @@ public Object uncachedDispatch( @Cached ExecuteCallNode executeCallNode) { while (true) { try { - return executeCallNode.executeCall(null, function, callerInfo, state, arguments); + return executeCallNode.executeCall(frame, function, callerInfo, state, arguments); } catch (TailCallException e) { function = e.getFunction(); callerInfo = e.getCallerInfo(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/SimpleCallOptimiserNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/SimpleCallOptimiserNode.java index 594e6b1522d7..877ff2bced9d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/SimpleCallOptimiserNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/SimpleCallOptimiserNode.java @@ -66,7 +66,7 @@ public Object executeDispatch( } } return next.executeDispatch( - null, e.getFunction(), e.getCallerInfo(), state, e.getArguments()); + frame, e.getFunction(), e.getCallerInfo(), state, e.getArguments()); } } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ForceNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ForceNode.java index b39319df53af..e51285a56aff 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ForceNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ForceNode.java @@ -30,6 +30,6 @@ public static ForceNode build(ExpressionNode target) { Object passToExecutorNode( VirtualFrame frame, Object thunk, @Cached("build()") ThunkExecutorNode thunkExecutorNode) { State state = Function.ArgumentsHelper.getState(frame.getArguments()); - return thunkExecutorNode.executeThunk(thunk, state, getTailStatus()); + return thunkExecutorNode.executeThunk(frame, thunk, state, getTailStatus()); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ThunkExecutorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ThunkExecutorNode.java index d3b24aa579b0..114e9fda306b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ThunkExecutorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/thunk/ThunkExecutorNode.java @@ -2,6 +2,7 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; @@ -35,12 +36,14 @@ public static ThunkExecutorNode build() { /** * Forces the thunk to its resulting value. * + * @param frame the current frame * @param thunk the thunk to force * @param state the state to pass to the thunk * @param isTail is the execution happening in a tail-call position * @return the return value of this thunk */ - public abstract Object executeThunk(Object thunk, State state, BaseNode.TailStatus isTail); + public abstract Object executeThunk( + VirtualFrame frame, Object thunk, State state, BaseNode.TailStatus isTail); boolean sameCallTarget(DirectCallNode callNode, Function function) { return function.getCallTarget() == callNode.getCallTarget(); @@ -50,6 +53,7 @@ boolean sameCallTarget(DirectCallNode callNode, Function function) { guards = {"function.isThunk()", "sameCallTarget(callNode, function)"}, limit = Constants.CacheSizes.THUNK_EXECUTOR_NODE) Object doCached( + VirtualFrame frame, Function function, State state, BaseNode.TailStatus isTail, @@ -63,13 +67,14 @@ Object doCached( return callNode.call(Function.ArgumentsHelper.buildArguments(function, state)); } catch (TailCallException e) { return loopingCallOptimiserNode.executeDispatch( - null, e.getFunction(), e.getCallerInfo(), state, e.getArguments()); + frame, e.getFunction(), e.getCallerInfo(), state, e.getArguments()); } } } @Specialization(replaces = "doCached", guards = "function.isThunk()") Object doUncached( + VirtualFrame frame, Function function, State state, BaseNode.TailStatus isTail, @@ -84,7 +89,7 @@ Object doUncached( function.getCallTarget(), Function.ArgumentsHelper.buildArguments(function, state)); } catch (TailCallException e) { return loopingCallOptimiserNode.executeDispatch( - null, e.getFunction(), e.getCallerInfo(), state, e.getArguments()); + frame, e.getFunction(), e.getCallerInfo(), state, e.getArguments()); } } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/AndNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/AndNode.java index 99313580807a..af5f7c0f9712 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/AndNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/AndNode.java @@ -2,6 +2,7 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; import org.enso.interpreter.dsl.BuiltinMethod; @@ -13,7 +14,8 @@ @BuiltinMethod( type = "Boolean", name = "&&", - description = "Computes the logical conjunction of two booleans") + description = "Computes the logical conjunction of two booleans", + needsFrame = false) public abstract class AndNode extends Node { private final ConditionProfile conditionProfile = ConditionProfile.createCountingProfile(); @@ -22,10 +24,11 @@ public static AndNode build() { return AndNodeGen.create(); } - abstract Object execute(State state, boolean self, @Suspend Object that); + abstract Object execute(VirtualFrame frame, State state, boolean self, @Suspend Object that); @Specialization Object executeBool( + VirtualFrame frame, State state, boolean self, Object that, @@ -33,6 +36,6 @@ Object executeBool( if (conditionProfile.profile(!self)) { return false; } - return rhsThunkExecutorNode.executeThunk(that, state, BaseNode.TailStatus.TAIL_DIRECT); + return rhsThunkExecutorNode.executeThunk(frame, that, state, BaseNode.TailStatus.TAIL_DIRECT); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenElseNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenElseNode.java index 6f29ff4edddb..59da9196f998 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenElseNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenElseNode.java @@ -1,5 +1,6 @@ package org.enso.interpreter.node.expression.builtin.bool; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; import org.enso.interpreter.dsl.BuiltinMethod; @@ -11,18 +12,25 @@ @BuiltinMethod( type = "Boolean", name = "if_then_else", - description = "Performs the standard if-then-else control flow operation.") + description = "Performs the standard if-then-else control flow operation.", + needsFrame = false) public final class IfThenElseNode extends Node { private @Child ThunkExecutorNode leftThunkExecutorNode = ThunkExecutorNode.build(); private @Child ThunkExecutorNode rightThunkExecutorNode = ThunkExecutorNode.build(); private final ConditionProfile condProfile = ConditionProfile.createCountingProfile(); public Object execute( - State state, boolean self, @Suspend Object if_true, @Suspend Object if_false) { + VirtualFrame frame, + State state, + boolean self, + @Suspend Object if_true, + @Suspend Object if_false) { if (condProfile.profile(self)) { - return leftThunkExecutorNode.executeThunk(if_true, state, BaseNode.TailStatus.TAIL_DIRECT); + return leftThunkExecutorNode.executeThunk( + frame, if_true, state, BaseNode.TailStatus.TAIL_DIRECT); } else { - return rightThunkExecutorNode.executeThunk(if_false, state, BaseNode.TailStatus.TAIL_DIRECT); + return rightThunkExecutorNode.executeThunk( + frame, if_false, state, BaseNode.TailStatus.TAIL_DIRECT); } } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenNode.java index e88986973fe7..12b3e0cf77e4 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenNode.java @@ -1,6 +1,7 @@ package org.enso.interpreter.node.expression.builtin.bool; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; import org.enso.interpreter.dsl.BuiltinMethod; @@ -13,7 +14,8 @@ @BuiltinMethod( type = "Boolean", name = "if_then", - description = "Performs the standard if-then control flow operation.") + description = "Performs the standard if-then control flow operation.", + needsFrame = false) public abstract class IfThenNode extends Node { private @Child ThunkExecutorNode leftThunkExecutorNode = ThunkExecutorNode.build(); private final ConditionProfile condProfile = ConditionProfile.createCountingProfile(); @@ -22,12 +24,13 @@ static IfThenNode build() { return IfThenNodeGen.create(); } - abstract Object execute(State state, boolean self, @Suspend Object if_true); + abstract Object execute(VirtualFrame frame, State state, boolean self, @Suspend Object if_true); @Specialization - Object doExecute(State state, boolean self, Object if_true) { + Object doExecute(VirtualFrame frame, State state, boolean self, Object if_true) { if (condProfile.profile(self)) { - return leftThunkExecutorNode.executeThunk(if_true, state, BaseNode.TailStatus.TAIL_DIRECT); + return leftThunkExecutorNode.executeThunk( + frame, if_true, state, BaseNode.TailStatus.TAIL_DIRECT); } else { return EnsoContext.get(this).getNothing(); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/OrNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/OrNode.java index ba6b77c533e9..201280186901 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/OrNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/OrNode.java @@ -2,6 +2,7 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; import org.enso.interpreter.dsl.BuiltinMethod; @@ -13,7 +14,8 @@ @BuiltinMethod( type = "Boolean", name = "||", - description = "Computes the logical disjunction of two booleans") + description = "Computes the logical disjunction of two booleans", + needsFrame = false) public abstract class OrNode extends Node { private final ConditionProfile conditionProfile = ConditionProfile.createCountingProfile(); @@ -22,10 +24,11 @@ public static OrNode build() { return OrNodeGen.create(); } - abstract Object execute(State state, boolean self, @Suspend Object that); + abstract Object execute(VirtualFrame frame, State state, boolean self, @Suspend Object that); @Specialization Object executeBool( + VirtualFrame frame, State state, boolean self, Object that, @@ -33,6 +36,6 @@ Object executeBool( if (conditionProfile.profile(self)) { return true; } - return rhsThunkExecutorNode.executeThunk(that, state, BaseNode.TailStatus.TAIL_DIRECT); + return rhsThunkExecutorNode.executeThunk(frame, that, state, BaseNode.TailStatus.TAIL_DIRECT); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/CatchPanicNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/CatchPanicNode.java index ac7a37d8e042..28822e1bbfd5 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/CatchPanicNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/CatchPanicNode.java @@ -60,7 +60,7 @@ Object doExecute( @Cached BranchProfile otherExceptionBranchProfile, @CachedLibrary(limit = "3") InteropLibrary interop) { try { - return thunkExecutorNode.executeThunk(action, state, BaseNode.TailStatus.TAIL_DIRECT); + return thunkExecutorNode.executeThunk(frame, action, state, BaseNode.TailStatus.TAIL_DIRECT); } catch (PanicException e) { panicBranchProfile.enter(); Object payload = e.getPayload(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java index edea86d0de32..7b6c2459e3b9 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java @@ -48,7 +48,7 @@ Object doExecute( if (annotation != null) { Function thunk = Function.thunk(annotation.getExpression().getCallTarget(), frame.materialize()); - return thunkExecutorNode.executeThunk(thunk, state, getTailStatus()); + return thunkExecutorNode.executeThunk(frame, thunk, state, getTailStatus()); } } AtomConstructor constructor = getAtomConstructor(targetType, methodName); @@ -59,7 +59,7 @@ Object doExecute( if (annotation != null) { Function thunk = Function.thunk(annotation.getExpression().getCallTarget(), frame.materialize()); - return thunkExecutorNode.executeThunk(thunk, state, getTailStatus()); + return thunkExecutorNode.executeThunk(frame, thunk, state, getTailStatus()); } } return EnsoContext.get(this).getNothing(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/resource/BracketNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/resource/BracketNode.java index a6e48e4ba3b2..d0f49b22da00 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/resource/BracketNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/resource/BracketNode.java @@ -65,7 +65,7 @@ Object doBracket( Object action, @Cached BranchProfile initializationFailedWithDataflowErrorProfile) { Object resource = - invokeConstructorNode.executeThunk(constructor, state, BaseNode.TailStatus.NOT_TAIL); + invokeConstructorNode.executeThunk(frame, constructor, state, BaseNode.TailStatus.NOT_TAIL); if (TypesGen.isDataflowError(resource)) { initializationFailedWithDataflowErrorProfile.enter(); return resource; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/NoInlineNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/NoInlineNode.java index 6f96e8040e83..ddbe2c5ca864 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/NoInlineNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/NoInlineNode.java @@ -1,6 +1,8 @@ package org.enso.interpreter.node.expression.builtin.runtime; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.Suspend; @@ -16,8 +18,12 @@ public class NoInlineNode extends Node { private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build(); + Object execute(VirtualFrame frame, State state, @Suspend Object action) { + return executeImpl(frame.materialize(), state, action); + } + @CompilerDirectives.TruffleBoundary - Object execute(State state, @Suspend Object action) { - return thunkExecutorNode.executeThunk(action, state, BaseNode.TailStatus.NOT_TAIL); + private Object executeImpl(MaterializedFrame frame, State state, @Suspend Object action) { + return thunkExecutorNode.executeThunk(frame, action, state, BaseNode.TailStatus.NOT_TAIL); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithDisabledContextNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithDisabledContextNode.java index fe01515010f1..73676a47de5c 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithDisabledContextNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithDisabledContextNode.java @@ -1,5 +1,6 @@ package org.enso.interpreter.node.expression.builtin.runtime; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.Suspend; @@ -13,14 +14,16 @@ type = "Runtime", name = "with_disabled_context_builtin", description = "Disallows context in the specified scope.", - autoRegister = false) + autoRegister = false, + needsFrame = false) public class RuntimeWithDisabledContextNode extends Node { private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build(); private @Child ExpectStringNode expectStringNode = ExpectStringNode.build(); - Object execute(State state, Atom context, Object env_name, @Suspend Object action) { + Object execute( + VirtualFrame frame, State state, Atom context, Object env_name, @Suspend Object action) { String envName = expectStringNode.execute(env_name); return thunkExecutorNode.executeThunk( - action, state.withContextDisabledIn(context, envName), BaseNode.TailStatus.NOT_TAIL); + frame, action, state.withContextDisabledIn(context, envName), BaseNode.TailStatus.NOT_TAIL); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithEnabledContextNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithEnabledContextNode.java index 1d28351c93a1..d2e5b0e8d3cb 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithEnabledContextNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithEnabledContextNode.java @@ -1,5 +1,6 @@ package org.enso.interpreter.node.expression.builtin.runtime; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.Suspend; @@ -13,14 +14,16 @@ type = "Runtime", name = "with_enabled_context_builtin", description = "Allows context in the specified scope.", - autoRegister = false) + autoRegister = false, + needsFrame = false) public class RuntimeWithEnabledContextNode extends Node { private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build(); private @Child ExpectStringNode expectStringNode = ExpectStringNode.build(); - Object execute(State state, Atom context, Object env_name, @Suspend Object action) { + Object execute( + VirtualFrame frame, State state, Atom context, Object env_name, @Suspend Object action) { String envName = expectStringNode.execute(env_name); return thunkExecutorNode.executeThunk( - action, state.withContextEnabledIn(context, envName), BaseNode.TailStatus.NOT_TAIL); + frame, action, state.withContextEnabledIn(context, envName), BaseNode.TailStatus.NOT_TAIL); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/special/RunThreadNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/special/RunThreadNode.java index bd7480eca5c7..fc107706282c 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/special/RunThreadNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/special/RunThreadNode.java @@ -2,6 +2,8 @@ import com.oracle.truffle.api.CompilerDirectives; 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.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.Suspend; @@ -16,11 +18,11 @@ static RunThreadNode build() { return RunThreadNodeGen.create(); } - abstract Thread execute(State state, @Suspend Object self); + abstract Thread execute(VirtualFrame frame, State state, @Suspend Object self); @CompilerDirectives.TruffleBoundary @Specialization - Thread doExecute(State state, Object self) { + Thread doExecute(MaterializedFrame frame, State state, Object self) { EnsoContext ctx = EnsoContext.get(this); Thread thread = ctx.getEnvironment() @@ -29,7 +31,7 @@ Thread doExecute(State state, Object self) { Object p = ctx.getThreadManager().enter(); try { ThunkExecutorNodeGen.getUncached() - .executeThunk(self, state, BaseNode.TailStatus.NOT_TAIL); + .executeThunk(frame, self, state, BaseNode.TailStatus.NOT_TAIL); } finally { ctx.getThreadManager().leave(p); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/state/RunStateNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/state/RunStateNode.java index 8904085b0dbc..ac72a529ca75 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/state/RunStateNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/state/RunStateNode.java @@ -3,6 +3,7 @@ import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.ReportPolymorphism; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObjectLibrary; @@ -16,7 +17,8 @@ type = "State", name = "run", description = "Runs a stateful computation in a local state environment.", - autoRegister = false) + autoRegister = false, + needsFrame = false) @ReportPolymorphism public abstract class RunStateNode extends Node { static RunStateNode build() { @@ -25,10 +27,12 @@ static RunStateNode build() { private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build(); - abstract Object execute(State state, Object key, Object local_state, @Suspend Object computation); + abstract Object execute( + VirtualFrame frame, State state, Object key, Object local_state, @Suspend Object computation); @Specialization(guards = "objects.containsKey(data, key)") Object doExisting( + VirtualFrame frame, State state, Object key, Object local, @@ -38,7 +42,8 @@ Object doExisting( var old = objects.getOrDefault(data, key, null); objects.put(data, key, local); try { - return thunkExecutorNode.executeThunk(computation, state, BaseNode.TailStatus.NOT_TAIL); + return thunkExecutorNode.executeThunk( + frame, computation, state, BaseNode.TailStatus.NOT_TAIL); } finally { objects.put(state.getContainer(), key, old); } @@ -46,6 +51,7 @@ Object doExisting( @Specialization(guards = "!objects.containsKey(data, key)") Object doFresh( + VirtualFrame frame, State state, Object key, Object local, @@ -54,7 +60,8 @@ Object doFresh( @CachedLibrary(limit = "10") DynamicObjectLibrary objects) { objects.put(data, key, local); try { - return thunkExecutorNode.executeThunk(computation, state, BaseNode.TailStatus.NOT_TAIL); + return thunkExecutorNode.executeThunk( + frame, computation, state, BaseNode.TailStatus.NOT_TAIL); } finally { objects.removeKey(data, key); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/thread/WithInterruptHandlerNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/thread/WithInterruptHandlerNode.java index e98c45129426..c5f4066dd71b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/thread/WithInterruptHandlerNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/thread/WithInterruptHandlerNode.java @@ -1,5 +1,6 @@ package org.enso.interpreter.node.expression.builtin.thread; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.Suspend; @@ -12,16 +13,19 @@ type = "Thread", name = "with_interrupt_handler", description = "Runs a computation with a handler for thread interrupts.", - autoRegister = false) + autoRegister = false, + needsFrame = false) public class WithInterruptHandlerNode extends Node { private @Child ThunkExecutorNode actExecutorNode = ThunkExecutorNode.build(); private @Child ThunkExecutorNode handlerExecutorNode = ThunkExecutorNode.build(); - Object execute(State state, @Suspend Object action, @Suspend Object interrupt_handler) { + Object execute( + VirtualFrame frame, State state, @Suspend Object action, @Suspend Object interrupt_handler) { try { - return actExecutorNode.executeThunk(action, state, BaseNode.TailStatus.NOT_TAIL); + return actExecutorNode.executeThunk(frame, action, state, BaseNode.TailStatus.NOT_TAIL); } catch (ThreadInterruptedException e) { - handlerExecutorNode.executeThunk(interrupt_handler, state, BaseNode.TailStatus.NOT_TAIL); + handlerExecutorNode.executeThunk( + frame, interrupt_handler, state, BaseNode.TailStatus.NOT_TAIL); throw e; } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/debug/EvalNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/debug/EvalNode.java index 40b8076a6aba..50d151a20241 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/debug/EvalNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/debug/EvalNode.java @@ -101,7 +101,7 @@ Object doCached( RootCallTarget cachedCallTarget, @Cached("build()") ThunkExecutorNode thunkExecutorNode) { Function thunk = Function.thunk(cachedCallTarget, callerInfo.getFrame()); - return thunkExecutorNode.executeThunk(thunk, state, getTailStatus()); + return thunkExecutorNode.executeThunk(callerInfo.getFrame(), thunk, state, getTailStatus()); } @Specialization @@ -117,6 +117,6 @@ Object doUncached( callerInfo.getModuleScope(), toJavaStringNode.execute(expression)); Function thunk = Function.thunk(callTarget, callerInfo.getFrame()); - return thunkExecutorNode.executeThunk(thunk, state, getTailStatus()); + return thunkExecutorNode.executeThunk(callerInfo.getFrame(), thunk, state, getTailStatus()); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java index ccf2bef3bee3..06f2eefc93ed 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java @@ -4,6 +4,7 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnknownKeyException; import com.oracle.truffle.api.interop.UnsupportedMessageException; @@ -21,7 +22,8 @@ description = """ Gets a value from the map on the specified key, or the given default. """, - autoRegister = false + autoRegister = false, + needsFrame = false ) @GenerateUncached public abstract class HashMapGetNode extends Node { @@ -30,10 +32,12 @@ public static HashMapGetNode build() { return HashMapGetNodeGen.create(); } - public abstract Object execute(State state, Object self, Object key, @Suspend Object defaultValue); + public abstract Object execute(VirtualFrame frame, State state, Object self, Object key, @Suspend Object defaultValue); @Specialization(guards = "interop.hasHashEntries(self)", limit = "3") - Object hashMapGet(State state, Object self, Object key, Object defaultValue, + Object hashMapGet( + VirtualFrame frame, + State state, Object self, Object key, Object defaultValue, @CachedLibrary("self") InteropLibrary interop, @Cached("build()") ThunkExecutorNode thunkExecutorNode) { if (interop.isHashEntryReadable(self, key)) { @@ -43,13 +47,13 @@ Object hashMapGet(State state, Object self, Object key, Object defaultValue, throw new IllegalStateException(e); } } else { - return thunkExecutorNode.executeThunk(defaultValue, state, TailStatus.NOT_TAIL); + return thunkExecutorNode.executeThunk(frame, defaultValue, state, TailStatus.NOT_TAIL); } } @Fallback - Object fallback(State state, Object self, Object key, Object defaultValue, + Object fallback(VirtualFrame frame, State state, Object self, Object key, Object defaultValue, @Cached("build()") ThunkExecutorNode thunkExecutorNode) { - return thunkExecutorNode.executeThunk(defaultValue, state, TailStatus.NOT_TAIL); + return thunkExecutorNode.executeThunk(frame, defaultValue, state, TailStatus.NOT_TAIL); } } From 9b4a4669d585c09514a15f59daa7a7bf958c90de Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 27 Apr 2023 10:00:51 +0200 Subject: [PATCH 03/13] InlineableNode no longer extends DirectCallNode --- .../dsl/test/InliningBuiltinsNeedNotNode.java | 16 ++++ .../dsl/test/InliningBuiltinsNeedsNode.java | 13 +++ .../dsl/test/InliningBuiltinsTest.java | 83 ++++++++++++++++--- .../enso/interpreter/node/InlineableNode.java | 53 ++++++++++++ .../interpreter/node/InlineableRootNode.java | 56 ------------- .../node/callable/ExecuteCallNode.java | 48 ++++++++--- .../expression/builtin/BuiltinRootNode.java | 72 +--------------- 7 files changed, 191 insertions(+), 150 deletions(-) create mode 100644 engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java create mode 100644 engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java create mode 100644 engine/runtime/src/main/java/org/enso/interpreter/node/InlineableNode.java delete mode 100644 engine/runtime/src/main/java/org/enso/interpreter/node/InlineableRootNode.java diff --git a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java new file mode 100644 index 000000000000..080ebe5963b9 --- /dev/null +++ b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java @@ -0,0 +1,16 @@ +package org.enso.interpreter.dsl.test; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import static org.junit.Assert.assertNotNull; + +@BuiltinMethod(type = "InliningBuiltins", name = "need_not", needsFrame = false) +final class InliningBuiltinsNeedNotNode extends Node { + + long execute(VirtualFrame frame, long a, long b) { + assertNotNull("Some frame is still provided", frame); + return a + b; + } + +} diff --git a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java new file mode 100644 index 000000000000..bb124455796f --- /dev/null +++ b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java @@ -0,0 +1,13 @@ +package org.enso.interpreter.dsl.test; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; + +@BuiltinMethod(type = "InliningBuiltins", name = "needs", needsFrame = true) +final class InliningBuiltinsNeedsNode extends Node { + + long execute(long a, long b) { + return a + b; + } + +} diff --git a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsTest.java b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsTest.java index 37f3d7f50030..beb7fe92b02c 100644 --- a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsTest.java +++ b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsTest.java @@ -1,10 +1,13 @@ package org.enso.interpreter.dsl.test; -import org.enso.interpreter.node.InlineableRootNode; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.RootNode; import org.enso.interpreter.runtime.callable.function.Function; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import org.junit.Test; +import org.enso.interpreter.node.InlineableNode; public class InliningBuiltinsTest { @@ -12,13 +15,15 @@ public class InliningBuiltinsTest { @Test public void executeWithoutVirtualFrame() { var fn = InliningBuiltinsInMethodGen.makeFunction(null); - if (fn.getCallTarget().getRootNode() instanceof InlineableRootNode root) { - var call = root.createDirectCallNode(); - var clazz = call.getClass().getSuperclass(); - assertEquals("InlinedCallNode", clazz.getSimpleName()); - assertEquals("BuiltinRootNode", clazz.getEnclosingClass().getSimpleName()); + if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) { + var call = root.createInlineableNode(); + var clazz = call.getClass(); + assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName()); + assertEquals("org.enso.interpreter.node.InlineableNode$Root", clazz.getEnclosingClass().getInterfaces()[0].getName()); - var res = call.call(Function.ArgumentsHelper.buildArguments(null, null, new Object[] { null, 5L, 7L })); + var res = WithFrame.invoke((frame) -> { + return call.call(frame, Function.ArgumentsHelper.buildArguments(null, null, new Object[] { null, 5L, 7L })); + }); assertEquals(12L, res); } else { fail("It is inlineable: " + fn.getCallTarget().getRootNode()); @@ -29,15 +34,73 @@ public void executeWithoutVirtualFrame() { @Test public void executeWithVirtualFrame() { var fn = InliningBuiltinsOutMethodGen.makeFunction(null); - if (fn.getCallTarget().getRootNode() instanceof InlineableRootNode root) { - var call = root.createDirectCallNode(); + if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) { + fail("The node isn't inlineable: " + fn.getCallTarget().getRootNode()); + } else { + var call = DirectCallNode.create(fn.getCallTarget()); var clazz = call.getClass().getSuperclass(); assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName()); - var res = call.call(Function.ArgumentsHelper.buildArguments(null, null, new Object[] { null, 3L, 9L })); + var res = WithFrame.invoke((frame) -> { + return call.call(Function.ArgumentsHelper.buildArguments(null, null, new Object[] { null, 3L, 9L })); + }); + assertEquals(12L, res); + } + } + + /** @see InliningBuiltinsNeedsNode#execute(long, long) */ + @Test + public void executeWhenNeedsVirtualFrame() { + var fn = InliningBuiltinsNeedsMethodGen.makeFunction(null); + if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) { + fail("The node isn't inlineable: " + fn.getCallTarget().getRootNode()); + } else { + var call = DirectCallNode.create(fn.getCallTarget()); + var clazz = call.getClass().getSuperclass(); + assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName()); + + var res = WithFrame.invoke((frame) -> { + return call.call(Function.ArgumentsHelper.buildArguments(null, null, new Object[] { null, 3L, 9L })); + }); + assertEquals(12L, res); + } + } + + /** @see InliningBuiltinsNeedNotNode#execute(com.oracle.truffle.api.frame.VirtualFrame, long, long) */ + @Test + public void executeWhenNeedNotVirtualFrame() { + var fn = InliningBuiltinsNeedNotMethodGen.makeFunction(null); + if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) { + var call = root.createInlineableNode(); + var clazz = call.getClass(); + assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName()); + assertEquals("org.enso.interpreter.node.InlineableNode$Root", clazz.getEnclosingClass().getInterfaces()[0].getName()); + + var res = WithFrame.invoke((frame) -> { + return call.call(frame, Function.ArgumentsHelper.buildArguments(null, null, new Object[] { null, 5L, 7L })); + }); assertEquals(12L, res); } else { fail("It is inlineable: " + fn.getCallTarget().getRootNode()); } } + + private static final class WithFrame extends RootNode { + private final java.util.function.Function fn; + + private WithFrame(java.util.function.Function fn) { + super(null); + this.fn = fn; + } + + @Override + public Object execute(VirtualFrame frame) { + return fn.apply(frame); + } + + @SuppressWarnings("unchecked") + static T invoke(java.util.function.Function fn, Object... args) { + return (T) new WithFrame<>(fn).getCallTarget().call(args); + } + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/InlineableNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/InlineableNode.java new file mode 100644 index 000000000000..3b77df82cf85 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/InlineableNode.java @@ -0,0 +1,53 @@ +package org.enso.interpreter.node; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RootNode; +import org.enso.interpreter.node.callable.ExecuteCallNode; + +/** + * More effective {@link DirectCallNode} alternative. Supports more aggressive inlining needed by + * {@link ExecuteCallNode}. + */ +public abstract class InlineableNode extends Node { + /** + * Invokes the computation represented by the node. + * + * @param frame current frame of the caller + * @param arguments arguments for the functionality + * @return result of the computation + */ + public abstract Object call(VirtualFrame frame, Object[] arguments); + + /** + * Special interface that allows various {@link RootNode} subclasses to provide more effective + * implementation of {@link DirectCallNode} alternative. Used by for example by {@code + * BuiltinRootNode}. + */ + public interface Root { + /** + * Provides access to {@link RootNode}. Usually the object shall inherit from {link RootNode} as + * well as implement the {@link InlineableNode} interface. This method thus usually returns + * {@code this}. + * + * @return {@code this} types as {link RootNode} + */ + public RootNode getRootNode(); + + /** + * Name of the {@link RootNode}. + * + * @return root node name + */ + public String getName(); + + /** + * Override to provide more effective implementation of {@link DirectCallNode} alternative. + * Suited more for Enso aggressive inlining. + * + * @return a node to call the associated {@link RootNode} - may return {@code null} + */ + public InlineableNode createInlineableNode(); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/InlineableRootNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/InlineableRootNode.java deleted file mode 100644 index d660aad64bfe..000000000000 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/InlineableRootNode.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.enso.interpreter.node; - -import com.oracle.truffle.api.CallTarget; -import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.nodes.DirectCallNode; -import com.oracle.truffle.api.nodes.RootNode; - -/** - * Special interface that allows various {@link RootNode} subclasses to provide - * more effective implementation of {@link DirectCallNode}. Used by for example - * by {@code BuiltinRootNode}. - */ -public interface InlineableRootNode { - /** - * Provides access to {@link RootNode}. Usually the object shall inherit from - * {link RootNode} as well as implement the {@link InlineableRootNode} - * interface. This method thus usually returns {@code this}. - * - * @return {@code this} types as {link RootNode} - */ - public RootNode getRootNode(); - - /** - * Name of the {@link RootNode}. - * - * @return root node name - */ - public String getName(); - - /** - * Override to provide more effective implementation of {@link DirectCallNode} - * suited more for Enso aggressive inlining. - * - * @return a node to {@link DirectCallNode#call(java.lang.Object...) call} the - * associated {@link RootNode} - may return {@code null} - */ - public DirectCallNode createDirectCallNode(); - - /** - * * Obtain a {@link DirectCallNode} for given {@link CallTarget}.Either - * delegates to {@link #createDirectCallNode} or uses regular - * {@link DirectCallNode#create(com.oracle.truffle.api.CallTarget)} method. - * Use for example by {@code ExecuteCallNode}. - * - * @param target call target with regular or - * {@link InlineableRootNode} {@link RootCallTarget#getRootNode()} - * @return instance of {@link DirectCallNode} to use to invoke the - * {@link RootNode#execute(com.oracle.truffle.api.frame.VirtualFrame)}. - */ - public static DirectCallNode create(RootCallTarget target) { - if (target.getRootNode() instanceof InlineableRootNode inRoot && inRoot.createDirectCallNode() instanceof DirectCallNode node) { - return node; - } - return DirectCallNode.create(target); - } -} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java index b5a8d714d102..d8cf4f7ea011 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java @@ -9,15 +9,16 @@ import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; -import org.enso.interpreter.node.InlineableRootNode; -import org.enso.interpreter.node.expression.builtin.BuiltinRootNode; import org.enso.interpreter.runtime.callable.CallerInfo; import org.enso.interpreter.runtime.callable.function.Function; +import org.enso.interpreter.node.InlineableNode; /** - * This node is responsible for optimising function calls. - * - *

Where possible, it will make the call as a direct call, with potential for inlining. + * This node is responsible for optimising function calls. Where possible, it will handle the call via: + *

    + *
  • {@link InlineableNode} to force inlining
  • + *
  • {@link DirectCallNode} with potential for inlining
  • + *
*/ @NodeInfo(shortName = "ExecCall", description = "Optimises function calls") @GenerateUncached @@ -40,6 +41,7 @@ public static ExecuteCallNode build() { *

This specialisation comes into play where the call target for the provided function is * already cached. THis means that the call can be made quickly. * + * @param frame current frame * @param function the function to execute * @param callerInfo the caller info to pass to the function * @param state the current state value @@ -48,7 +50,10 @@ public static ExecuteCallNode build() { * @param callNode the cached call node for {@code cachedTarget} * @return the result of executing {@code function} on {@code arguments} */ - @Specialization(guards = "function.getCallTarget() == cachedTarget") + @Specialization(guards = { + "function.getCallTarget() == cachedTarget", + "callNode != null" + }) protected Object callDirect( VirtualFrame frame, Function function, @@ -56,17 +61,34 @@ protected Object callDirect( Object state, Object[] arguments, @Cached("function.getCallTarget()") RootCallTarget cachedTarget, - @Cached("createCallNode(cachedTarget)") DirectCallNode callNode) { + @Cached("createInlineableNode(cachedTarget)") InlineableNode callNode) { var args = Function.ArgumentsHelper.buildArguments(function, callerInfo, state, arguments); - if (callNode instanceof BuiltinRootNode.InlinedCallNode in) { - return in.callWithFrame(frame, args); - } else { - return callNode.call(args); + return callNode.call(frame, args); + } + + @Specialization(guards = { + "function.getCallTarget() == cachedTarget", + }) + protected Object callDirect( + Function function, + CallerInfo callerInfo, + Object state, + Object[] arguments, + @Cached("function.getCallTarget()") RootCallTarget cachedTarget, + @Cached("createDirectCallNode(cachedTarget)") DirectCallNode callNode) { + var args = Function.ArgumentsHelper.buildArguments(function, callerInfo, state, arguments); + return callNode.call(args); + } + + static InlineableNode createInlineableNode(RootCallTarget t) { + if (t.getRootNode() instanceof InlineableNode.Root inlineNodeProvider) { + return inlineNodeProvider.createInlineableNode(); } + return null; } - static DirectCallNode createCallNode(RootCallTarget t) { - return InlineableRootNode.create(t); + static DirectCallNode createDirectCallNode(RootCallTarget t) { + return DirectCallNode.create(t); } /** diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java index 8c29eec6f460..04d674f1fe34 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java @@ -1,18 +1,14 @@ package org.enso.interpreter.node.expression.builtin; -import com.oracle.truffle.api.CallTarget; import org.enso.interpreter.EnsoLanguage; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.DirectCallNode; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.RootNode; -import org.enso.interpreter.node.InlineableRootNode; /** Root node for use by all the builtin functions. */ @NodeInfo(shortName = "BuiltinRoot", description = "Root node for builtin functions.") -public abstract class BuiltinRootNode extends RootNode implements InlineableRootNode { +public abstract class BuiltinRootNode extends RootNode { protected BuiltinRootNode(EnsoLanguage language) { super(language); } @@ -33,70 +29,4 @@ protected BuiltinRootNode(EnsoLanguage language) { */ @Override public abstract String getName(); - - /** - * Factory method creating a {@link DirectCallNode} to invoke this builtin.Defaults to standard - * {@link DirectCallNode#create(com.oracle.truffle.api.CallTarget)} implementation. Subclasses may - * override this with the help of {@link InlinedCallNode}. - * - * @return new node to use to call this builtin - */ - public DirectCallNode createDirectCallNode() { - var callNode = DirectCallNode.create(cloneUninitialized().getCallTarget()); - callNode.forceInlining(); - return callNode; - } - - /** - * Helper class allowing better implementation of {@link #createDirectCallNode}. Subclass, pass in - * {@code extra} and {@code body} and override {@code call} method to do what has to be done. - * - * @param extra data to keep in the node - * @param node to delegate to from {@link #call(java.lang.Object...)} method - */ - public abstract static class InlinedCallNode extends DirectCallNode { - protected final E extra; - @Child protected N body; - - protected InlinedCallNode(E extra, N body) { - super(null); - this.extra = extra; - this.body = body; - } - - public Object callWithFrame(VirtualFrame frame, Object... arguments) { - return call(arguments); - } - - @Override - public abstract Object call(Object... arguments); - - @Override - public final boolean isInlinable() { - return true; - } - - @Override - public final boolean isInliningForced() { - return true; - } - - @Override - public final void forceInlining() {} - - @Override - public final boolean isCallTargetCloningAllowed() { - return false; - } - - @Override - public final boolean cloneCallTarget() { - return false; - } - - @Override - public final CallTarget getClonedCallTarget() { - return getRootNode().getCallTarget(); - } - } } From ea96ab18df72a3a2df1495d9c31e0b902bb7bb56 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 27 Apr 2023 10:25:31 +0200 Subject: [PATCH 04/13] Necessary changes in annotation processor --- .../enso/interpreter/dsl/MethodProcessor.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java index 5f018a84acf3..3818acc3bb52 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java @@ -128,6 +128,7 @@ private void handleTypeELement(TypeElement element, RoundEnvironment roundEnv, B "com.oracle.truffle.api.profiles.ConditionProfile", "java.nio.file.OpenOption", "org.enso.interpreter.EnsoLanguage", + "org.enso.interpreter.node.InlineableNode", "org.enso.interpreter.node.expression.builtin.BuiltinRootNode", "org.enso.interpreter.runtime.callable.argument.ArgumentDefinition", "org.enso.interpreter.runtime.callable.function.Function", @@ -158,7 +159,11 @@ private void generateCode(MethodDefinition methodDefinition) throws IOException out.println("@NodeInfo("); out.println(" shortName = \"" + methodDefinition.getDeclaredName() + "\","); out.println(" description = \"\"\"\n" + methodDefinition.getDescription() + "\"\"\")"); - out.println("public class " + methodDefinition.getClassName() + " extends BuiltinRootNode {"); + if (methodDefinition.needsFrame()) { + out.println("public class " + methodDefinition.getClassName() + " extends BuiltinRootNode {"); + } else { + out.println("public class " + methodDefinition.getClassName() + " extends BuiltinRootNode implements InlineableNode.Root {"); + } out.println(" private @Child " + methodDefinition.getOriginalClassName() + " bodyNode;"); out.println(" private static final class Internals {"); out.println(" Internals(boolean s) {"); @@ -232,13 +237,12 @@ private void generateCode(MethodDefinition methodDefinition) throws IOException out.println(); if (!methodDefinition.needsFrame()) { out.println(" @Override"); - out.println(" public final InlinedCallNode createDirectCallNode() {"); - out.println(" var n = " + methodDefinition.getConstructorExpression() + ";"); - out.println(" return new InlinedCallNode<>(new Internals(internals.staticOfInstanceMethod), n) {"); - out.println(" public Object call(Object[] args) {"); - out.println(" return handleExecute(null, extra, body, args);"); - out.println(" }"); - out.println(" public Object callWithFrame(VirtualFrame frame, Object[] args) {"); + out.println(" public final InlineableNode createInlineableNode() {"); + out.println(" return new InlineableNode() {"); + out.println(" private final Internals extra = new Internals(internals.staticOfInstanceMethod);"); + out.println(" private @Child " + methodDefinition.getOriginalClassName() + " body = " + methodDefinition.getConstructorExpression() + ";"); + out.println(" @Override"); + out.println(" public Object call(VirtualFrame frame, Object[] args) {"); out.println(" return handleExecute(frame, extra, body, args);"); out.println(" }"); out.println(" };"); From 59e2ebaa1e1d635465ec97dc9da8519e40ff59bb Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 27 Apr 2023 11:15:02 +0200 Subject: [PATCH 05/13] Include interpreter-dsl-test project in the aggregates --- build.sbt | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sbt b/build.sbt index 599c71b930e0..8d30afaedaa2 100644 --- a/build.sbt +++ b/build.sbt @@ -247,6 +247,7 @@ lazy val enso = (project in file(".")) .settings(version := "0.1") .aggregate( `interpreter-dsl`, + `interpreter-dsl-test`, `json-rpc-server-test`, `json-rpc-server`, `language-server`, From 0ee6900c946805fcb066218d7251c33b76e1ae05 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 27 Apr 2023 11:51:56 +0200 Subject: [PATCH 06/13] javafmtAll on the new interpreter-dsl-test files --- .../org/enso/interpreter/dsl/test/InliningBuiltinsInNode.java | 1 - .../enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java | 1 - .../org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java | 1 - .../org/enso/interpreter/dsl/test/InliningBuiltinsOutNode.java | 1 - 4 files changed, 4 deletions(-) diff --git a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsInNode.java b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsInNode.java index b37ca62a7d18..8b44106e8752 100644 --- a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsInNode.java +++ b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsInNode.java @@ -9,5 +9,4 @@ final class InliningBuiltinsInNode extends Node { long execute(long a, long b) { return a + b; } - } diff --git a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java index 080ebe5963b9..5f1ee718308b 100644 --- a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java +++ b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java @@ -12,5 +12,4 @@ long execute(VirtualFrame frame, long a, long b) { assertNotNull("Some frame is still provided", frame); return a + b; } - } diff --git a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java index bb124455796f..c2836ef47dfa 100644 --- a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java +++ b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java @@ -9,5 +9,4 @@ final class InliningBuiltinsNeedsNode extends Node { long execute(long a, long b) { return a + b; } - } diff --git a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsOutNode.java b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsOutNode.java index 4d3f95006288..7c7133569463 100644 --- a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsOutNode.java +++ b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsOutNode.java @@ -12,5 +12,4 @@ long execute(VirtualFrame frame, long a, long b) { Assert.assertNotNull("VirtualFrame is always provided", frame); return a + b; } - } From c1c81a4054375b78b3227826b0554fc2a6ad71b2 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 27 Apr 2023 14:56:13 +0200 Subject: [PATCH 07/13] inlineable attribute --- .../dsl/test/InliningBuiltinsNeedNotNode.java | 2 +- .../dsl/test/InliningBuiltinsNeedsNode.java | 2 +- .../node/expression/builtin/bool/AndNode.java | 2 +- .../builtin/bool/IfThenElseNode.java | 2 +- .../expression/builtin/bool/IfThenNode.java | 2 +- .../node/expression/builtin/bool/OrNode.java | 2 +- .../builtin/function/ApplicationOperator.java | 2 +- .../RuntimeWithDisabledContextNode.java | 2 +- .../RuntimeWithEnabledContextNode.java | 2 +- .../builtin/state/RunStateNode.java | 2 +- .../thread/WithInterruptHandlerNode.java | 2 +- .../runtime/data/hash/HashMapGetNode.java | 2 +- .../org/enso/interpreter/dsl/Builtin.java | 18 +++++++++--------- .../enso/interpreter/dsl/BuiltinMethod.java | 19 +++++++++---------- .../interpreter/dsl/BuiltinsProcessor.java | 7 +++---- 15 files changed, 33 insertions(+), 35 deletions(-) diff --git a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java index 5f1ee718308b..00a9995eab94 100644 --- a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java +++ b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedNotNode.java @@ -5,7 +5,7 @@ import org.enso.interpreter.dsl.BuiltinMethod; import static org.junit.Assert.assertNotNull; -@BuiltinMethod(type = "InliningBuiltins", name = "need_not", needsFrame = false) +@BuiltinMethod(type = "InliningBuiltins", name = "need_not", inlineable = true) final class InliningBuiltinsNeedNotNode extends Node { long execute(VirtualFrame frame, long a, long b) { diff --git a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java index c2836ef47dfa..751d4b3eb316 100644 --- a/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java +++ b/engine/interpreter-dsl-test/src/test/java/org/enso/interpreter/dsl/test/InliningBuiltinsNeedsNode.java @@ -3,7 +3,7 @@ import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; -@BuiltinMethod(type = "InliningBuiltins", name = "needs", needsFrame = true) +@BuiltinMethod(type = "InliningBuiltins", name = "needs", inlineable = false) final class InliningBuiltinsNeedsNode extends Node { long execute(long a, long b) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/AndNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/AndNode.java index af5f7c0f9712..ca26e8a21e9d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/AndNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/AndNode.java @@ -15,7 +15,7 @@ type = "Boolean", name = "&&", description = "Computes the logical conjunction of two booleans", - needsFrame = false) + inlineable = true) public abstract class AndNode extends Node { private final ConditionProfile conditionProfile = ConditionProfile.createCountingProfile(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenElseNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenElseNode.java index 59da9196f998..95151c9901bd 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenElseNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenElseNode.java @@ -13,7 +13,7 @@ type = "Boolean", name = "if_then_else", description = "Performs the standard if-then-else control flow operation.", - needsFrame = false) + inlineable = true) public final class IfThenElseNode extends Node { private @Child ThunkExecutorNode leftThunkExecutorNode = ThunkExecutorNode.build(); private @Child ThunkExecutorNode rightThunkExecutorNode = ThunkExecutorNode.build(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenNode.java index 12b3e0cf77e4..868dde221304 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/IfThenNode.java @@ -15,7 +15,7 @@ type = "Boolean", name = "if_then", description = "Performs the standard if-then control flow operation.", - needsFrame = false) + inlineable = true) public abstract class IfThenNode extends Node { private @Child ThunkExecutorNode leftThunkExecutorNode = ThunkExecutorNode.build(); private final ConditionProfile condProfile = ConditionProfile.createCountingProfile(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/OrNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/OrNode.java index 201280186901..01d459af3f9b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/OrNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/OrNode.java @@ -15,7 +15,7 @@ type = "Boolean", name = "||", description = "Computes the logical disjunction of two booleans", - needsFrame = false) + inlineable = true) public abstract class OrNode extends Node { private final ConditionProfile conditionProfile = ConditionProfile.createCountingProfile(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/function/ApplicationOperator.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/function/ApplicationOperator.java index 63a3c790f1cf..4b67ea9bde92 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/function/ApplicationOperator.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/function/ApplicationOperator.java @@ -13,7 +13,7 @@ type = "Function", name = "<|", description = "Takes a function and an argument and applies the function to the argument.", - needsFrame = false) + inlineable = true) public class ApplicationOperator extends Node { private @Child InvokeCallableNode invokeCallableNode; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithDisabledContextNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithDisabledContextNode.java index 73676a47de5c..51601b3196dc 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithDisabledContextNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithDisabledContextNode.java @@ -15,7 +15,7 @@ name = "with_disabled_context_builtin", description = "Disallows context in the specified scope.", autoRegister = false, - needsFrame = false) + inlineable = true) public class RuntimeWithDisabledContextNode extends Node { private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build(); private @Child ExpectStringNode expectStringNode = ExpectStringNode.build(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithEnabledContextNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithEnabledContextNode.java index d2e5b0e8d3cb..aaac3a094080 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithEnabledContextNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/RuntimeWithEnabledContextNode.java @@ -15,7 +15,7 @@ name = "with_enabled_context_builtin", description = "Allows context in the specified scope.", autoRegister = false, - needsFrame = false) + inlineable = true) public class RuntimeWithEnabledContextNode extends Node { private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build(); private @Child ExpectStringNode expectStringNode = ExpectStringNode.build(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/state/RunStateNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/state/RunStateNode.java index ac72a529ca75..61854b3e3dee 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/state/RunStateNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/state/RunStateNode.java @@ -18,7 +18,7 @@ name = "run", description = "Runs a stateful computation in a local state environment.", autoRegister = false, - needsFrame = false) + inlineable = true) @ReportPolymorphism public abstract class RunStateNode extends Node { static RunStateNode build() { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/thread/WithInterruptHandlerNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/thread/WithInterruptHandlerNode.java index c5f4066dd71b..8b18ab402c03 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/thread/WithInterruptHandlerNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/thread/WithInterruptHandlerNode.java @@ -14,7 +14,7 @@ name = "with_interrupt_handler", description = "Runs a computation with a handler for thread interrupts.", autoRegister = false, - needsFrame = false) + inlineable = true) public class WithInterruptHandlerNode extends Node { private @Child ThunkExecutorNode actExecutorNode = ThunkExecutorNode.build(); private @Child ThunkExecutorNode handlerExecutorNode = ThunkExecutorNode.build(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java index 06f2eefc93ed..8004337561c5 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java @@ -23,7 +23,7 @@ Gets a value from the map on the specified key, or the given default. """, autoRegister = false, - needsFrame = false + inlineable = true ) @GenerateUncached public abstract class HashMapGetNode extends Node { diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/Builtin.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/Builtin.java index 0c3e585fbd92..5f07bb8e274b 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/Builtin.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/Builtin.java @@ -162,18 +162,18 @@ boolean autoRegister() default true; /** - * Needs own frame or not. This argument doesn't need to be specified. If it is missing, its - * effective value is derived from the arguments of the annotated method. When the - * {@code execute} method requires {@link VirtualFrame} as one of its arguments the value of - * unspecified {@link #needsFrame()} is {@code true}. When no {@link VirtualFrame} is needed, - * the value is assumed to be {@code false}. + * Allow aggressive inlining or not. This argument doesn't need to be specified. If it is + * missing, its effective value is derived from the arguments of the annotated method. + * When the annotated method requires {@link VirtualFrame} as one of its arguments the value of + * unspecified {@link #inlineable()} is {@code false}. When no {@link VirtualFrame} is needed, + * the value is assumed to be {@code true}. * - * @return explicitly specify whether the builtin needs its own {@link VirtualFrame} or can - * share the one of a caller. + * @return explicitly specify whether the builtin can be inline and use caller's {@link + * VirtualFrame} * @see BuiltinMethod - * @see BuiltinMethod#needsFrame + * @see BuiltinMethod#inlineable() */ - boolean needsFrame() default false; + boolean inlineable() default true; } /** diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinMethod.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinMethod.java index 075b83cb3949..67ee13b0bc4e 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinMethod.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinMethod.java @@ -8,9 +8,9 @@ /** * An annotation denoting a node that should be wrapped for standard library export. A subclass of * {@code BuiltinRootNode} is generated with implementation of {@code - * InlineableRootNode#createDirectCallNode()} that either delegates to regular {@link + * InlineableNode.Root.createInlineableNode()} that either delegates to regular {@link * DirectCallNode} or provides a special and faster implementation depending on implicit or explicit - * value of {@link #needsFrame()} attribute. + * value of {@link #inlineable()} attribute. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) @@ -31,14 +31,13 @@ boolean autoRegister() default true; /** - * Needs own frame or not. This argument doesn't need to be specified. If it is missing, its - * effective value is derived from the arguments of the annotated method. When the {@code - * execute} method requires {@code VirtualFrame} as one of its arguments the value of unspecified - * {@link #needsFrame()} is {@code true}. When no {@code VirtualFrame} is needed, the value is - * assumed to be {@code false}. + * Allow aggressive inlining or not. This argument doesn't need to be specified. If it is missing, + * its effective value is derived from the arguments of the annotated method. When the + * {@code execute} method requires {@code VirtualFrame} as one of its arguments the value of + * unspecified {@link #inlineable()} is {@code false}. When no {@code VirtualFrame} is needed, the + * value is assumed to be {@code true}. * - * @return explicitly specify whether the builtin needs its own {@link VirtualFrame} or can share - * the one of a caller. + * @return explicitly specify whether the builtin can share {@link VirtualFrame} with its caller. */ - boolean needsFrame() default false; + boolean inlineable() default true; } diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinsProcessor.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinsProcessor.java index 2767b0b3cd0c..424c76018fed 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinsProcessor.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/BuiltinsProcessor.java @@ -258,16 +258,15 @@ public void handleMethodElement(Element element, RoundEnvironment roundEnv) thro } static Boolean checkNeedsFrame(Element element) { - Boolean needsFrame = null; for (var m : element.getAnnotationMirrors()) { for (var entry : m.getElementValues().entrySet()) { var name = entry.getKey().getSimpleName().toString(); - if (name.equals("needsFrame")) { - needsFrame = (Boolean) entry.getValue().getValue(); + if (name.equals("inlineable")) { + return !(Boolean) entry.getValue().getValue(); } } } - return needsFrame; + return null; } /** From 81102bd189a930841b92fac9f53607d0397b3974 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 27 Apr 2023 15:02:47 +0200 Subject: [PATCH 08/13] Better documentation of callInlineable specialization --- .../node/callable/ExecuteCallNode.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java index d8cf4f7ea011..973a642df038 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java @@ -36,10 +36,7 @@ public static ExecuteCallNode build() { } /** - * Calls the function directly. - * - *

This specialisation comes into play where the call target for the provided function is - * already cached. THis means that the call can be made quickly. + * Inlines the function if its root node implements {@link InlineableNode.Root}. * * @param frame current frame * @param function the function to execute @@ -54,7 +51,7 @@ public static ExecuteCallNode build() { "function.getCallTarget() == cachedTarget", "callNode != null" }) - protected Object callDirect( + protected Object callInlineable( VirtualFrame frame, Function function, CallerInfo callerInfo, @@ -66,6 +63,20 @@ protected Object callDirect( return callNode.call(frame, args); } + /** + * Calls the function directly. + * + *

This specialisation comes into play where the call target for the provided function is + * already cached. This means that the call can be made quickly. + * + * @param function the function to execute + * @param callerInfo the caller info to pass to the function + * @param state the current state value + * @param arguments the arguments passed to {@code function} in the expected positional order + * @param cachedTarget the cached call target for {@code function} + * @param callNode the cached call node for {@code cachedTarget} + * @return the result of executing {@code function} on {@code arguments} + */ @Specialization(guards = { "function.getCallTarget() == cachedTarget", }) From 737a7d2574fbbc6eb480b9f8fb4cdf842ebe7011 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 27 Apr 2023 20:36:35 +0200 Subject: [PATCH 09/13] Cannot compile without allowUncached = true --- .../org/enso/interpreter/node/callable/ExecuteCallNode.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java index 973a642df038..73a198b7f681 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java @@ -57,8 +57,8 @@ protected Object callInlineable( CallerInfo callerInfo, Object state, Object[] arguments, - @Cached("function.getCallTarget()") RootCallTarget cachedTarget, - @Cached("createInlineableNode(cachedTarget)") InlineableNode callNode) { + @Cached(value = "function.getCallTarget()", allowUncached = true) RootCallTarget cachedTarget, + @Cached(value = "createInlineableNode(cachedTarget)", allowUncached = true) InlineableNode callNode) { var args = Function.ArgumentsHelper.buildArguments(function, callerInfo, state, arguments); return callNode.call(frame, args); } From e1d1429b8209779048ae3856552f7589d9723fdf Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Fri, 28 Apr 2023 07:56:46 +0200 Subject: [PATCH 10/13] Use SrcUtil.source consistently --- .../benchmarks/semantic/ArrayProxyBenchmarks.java | 8 +++++--- .../bench/benchmarks/semantic/IfVsCaseBenchmarks.java | 7 ++----- .../bench/benchmarks/semantic/StringBenchmarks.java | 10 +++++++--- .../benchmarks/semantic/TypePatternBenchmarks.java | 9 ++++++--- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ArrayProxyBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ArrayProxyBenchmarks.java index cd7c170894eb..16ca0b0218bb 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ArrayProxyBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ArrayProxyBenchmarks.java @@ -30,7 +30,7 @@ public class ArrayProxyBenchmarks { private final long length = 100000; @Setup - public void initializeBenchmark(BenchmarkParams params) { + public void initializeBenchmark(BenchmarkParams params) throws Exception { Engine eng = Engine.newBuilder() .allowExperimentalOptions(true) @@ -59,13 +59,15 @@ Array_Proxy.new n (i -> 3 + 5*i) make_delegating_vector n = Vector.from_polyglot_array (make_delegating_proxy n) """; - var module = ctx.eval("enso", code); + var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var src = SrcUtil.source(benchmarkName, code); + var module = ctx.eval(src); this.self = module.invokeMember("get_associated_type"); Function getMethod = (name) -> module.invokeMember("get_method", self, name); String test_builder; - switch (params.getBenchmark().replaceFirst(".*\\.", "")) { + switch (benchmarkName) { case "sumOverVector": test_builder = "make_vector"; break; diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/IfVsCaseBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/IfVsCaseBenchmarks.java index c1848d13b87b..eb0402c4e41b 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/IfVsCaseBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/IfVsCaseBenchmarks.java @@ -133,11 +133,8 @@ public void initializeBench(BenchmarkParams params) throws IOException { """; - var file = File.createTempFile("if_case", ".enso"); - try (var w = new FileWriter(file)) { - w.write(code); - } - var src = Source.newBuilder("enso", file).build(); + var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var src = SrcUtil.source(benchmarkName, code); Value module = ctx.eval(src); ifBench3 = Objects.requireNonNull(module.invokeMember(Module.EVAL_EXPRESSION, "if_bench_3")); caseBench3 = Objects.requireNonNull(module.invokeMember(Module.EVAL_EXPRESSION, "case_bench_3")); diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/StringBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/StringBenchmarks.java index 385de3bfb5d5..6bd96c4d7d25 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/StringBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/StringBenchmarks.java @@ -32,7 +32,7 @@ public class StringBenchmarks { private Value allLength; @Setup - public void initializeBenchmark(BenchmarkParams params) { + public void initializeBenchmark(BenchmarkParams params) throws Exception { var ctx = Context.newBuilder() .allowExperimentalOptions(true) .allowIO(true) @@ -42,7 +42,8 @@ public void initializeBenchmark(BenchmarkParams params) { "enso.languageHomeOverride", Paths.get("../../distribution/component").toFile().getAbsolutePath() ).build(); - var module = ctx.eval("enso", """ + + var code =""" from Standard.Base import all all_length v = v.fold 0 (sum -> str -> sum + str.length) @@ -51,7 +52,10 @@ public void initializeBenchmark(BenchmarkParams params) { s = "Long string".repeat rep v = Vector.new len (_ -> s) v - """); + """; + var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var src = SrcUtil.source(benchmarkName, code); + var module = ctx.eval(src); this.self = module.invokeMember("get_associated_type"); Function getMethod = (name) -> module.invokeMember("get_method", self, name); diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/TypePatternBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/TypePatternBenchmarks.java index 34244a328e7c..545a7bb17fb9 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/TypePatternBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/TypePatternBenchmarks.java @@ -25,7 +25,7 @@ public class TypePatternBenchmarks { private Value self; @Setup - public void initializeBenchmark(BenchmarkParams params) { + public void initializeBenchmark(BenchmarkParams params) throws Exception { var ctx = Context.newBuilder() .allowExperimentalOptions(true) .allowIO(true) @@ -35,7 +35,7 @@ public void initializeBenchmark(BenchmarkParams params) { "enso.languageHomeOverride", Paths.get("../../distribution/component").toFile().getAbsolutePath() ).build(); - var module = ctx.eval("enso", """ + var code =""" from Standard.Base import Integer, Vector, Any, Decimal avg arr = @@ -60,7 +60,10 @@ public void initializeBenchmark(BenchmarkParams params) { match_dec = v -> case v of n : Decimal -> n + 1 - """); + """; + var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var src = SrcUtil.source(benchmarkName, code); + var module = ctx.eval(src); this.self = module.invokeMember("get_associated_type"); Function getMethod = (name) -> module.invokeMember("get_method", self, name); From 28e7fb478ed169f501dc7b06d8899333ee6bae86 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Fri, 28 Apr 2023 12:28:50 +0200 Subject: [PATCH 11/13] Give the node class a name --- .../main/java/org/enso/interpreter/dsl/MethodProcessor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java index a5d7b91b302f..cc1c8b6856c4 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java @@ -238,14 +238,15 @@ private void generateCode(MethodDefinition methodDefinition) throws IOException if (!methodDefinition.needsFrame()) { out.println(" @Override"); out.println(" public final InlineableNode createInlineableNode() {"); - out.println(" return new InlineableNode() {"); + out.println(" class Inlineable extends InlineableNode {"); out.println(" private final Internals extra = new Internals(internals.staticOfInstanceMethod);"); out.println(" private @Child " + methodDefinition.getOriginalClassName() + " body = " + methodDefinition.getConstructorExpression() + ";"); out.println(" @Override"); out.println(" public Object call(VirtualFrame frame, Object[] args) {"); out.println(" return handleExecute(frame, extra, body, args);"); out.println(" }"); - out.println(" };"); + out.println(" }"); + out.println(" return new Inlineable();"); out.println(" }"); } From 5297ffb71645df86c1005f716523e1f0f1d44033 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Fri, 28 Apr 2023 12:29:21 +0200 Subject: [PATCH 12/13] callIndirect replaces callDirect as well as callInlineable --- .../org/enso/interpreter/node/callable/ExecuteCallNode.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java index 73a198b7f681..6606f73a5e6a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/ExecuteCallNode.java @@ -57,8 +57,8 @@ protected Object callInlineable( CallerInfo callerInfo, Object state, Object[] arguments, - @Cached(value = "function.getCallTarget()", allowUncached = true) RootCallTarget cachedTarget, - @Cached(value = "createInlineableNode(cachedTarget)", allowUncached = true) InlineableNode callNode) { + @Cached("function.getCallTarget()") RootCallTarget cachedTarget, + @Cached("createInlineableNode(cachedTarget)") InlineableNode callNode) { var args = Function.ArgumentsHelper.buildArguments(function, callerInfo, state, arguments); return callNode.call(frame, args); } @@ -115,7 +115,7 @@ static DirectCallNode createDirectCallNode(RootCallTarget t) { * @param callNode the cached call node for making indirect calls * @return the result of executing {@code function} on {@code arguments} */ - @Specialization(replaces = "callDirect") + @Specialization(replaces = { "callDirect", "callInlineable" }) protected Object callIndirect( Function function, CallerInfo callerInfo, From 61af2a55fa3bbb9261c47e0bd19aa4c96897f069 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Fri, 28 Apr 2023 12:41:19 +0200 Subject: [PATCH 13/13] Unifying into SrcUtil.findName --- .../bench/benchmarks/semantic/ArrayProxyBenchmarks.java | 2 +- .../bench/benchmarks/semantic/CurriedFunctionBenchmarks.java | 2 +- .../bench/benchmarks/semantic/EqualsBenchmarks.java | 2 +- .../bench/benchmarks/semantic/IfVsCaseBenchmarks.java | 2 +- .../bench/benchmarks/semantic/ListBenchmarks.java | 2 +- .../semantic/NestedPatternCompilationBenchmarks.java | 2 +- .../enso/interpreter/bench/benchmarks/semantic/SrcUtil.java | 5 +++++ .../bench/benchmarks/semantic/StringBenchmarks.java | 2 +- .../bench/benchmarks/semantic/TypePatternBenchmarks.java | 4 ++-- .../bench/benchmarks/semantic/VectorBenchmarks.java | 2 +- .../bench/benchmarks/semantic/WarningBenchmarks.java | 2 +- 11 files changed, 16 insertions(+), 11 deletions(-) diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ArrayProxyBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ArrayProxyBenchmarks.java index 16ca0b0218bb..a74fc1b8ff2a 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ArrayProxyBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ArrayProxyBenchmarks.java @@ -59,7 +59,7 @@ Array_Proxy.new n (i -> 3 + 5*i) make_delegating_vector n = Vector.from_polyglot_array (make_delegating_proxy n) """; - var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var benchmarkName = SrcUtil.findName(params); var src = SrcUtil.source(benchmarkName, code); var module = ctx.eval(src); diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/CurriedFunctionBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/CurriedFunctionBenchmarks.java index 0ba34c00a9e6..bdb9c4824f2d 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/CurriedFunctionBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/CurriedFunctionBenchmarks.java @@ -42,7 +42,7 @@ public void initializeBenchmark(BenchmarkParams params) throws Exception { Paths.get("../../distribution/component").toFile().getAbsolutePath() ).build(); - var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var benchmarkName = SrcUtil.findName(params); var code = """ avg fn len = sum acc i = if i == len then acc else diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/EqualsBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/EqualsBenchmarks.java index 2021799ca46a..10eb026eb964 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/EqualsBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/EqualsBenchmarks.java @@ -68,7 +68,7 @@ public void initializeBenchmark(BenchmarkParams params) throws Exception { Paths.get("../../distribution/component").toFile().getAbsolutePath() ).build(); - var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var benchmarkName = SrcUtil.findName(params); var codeBuilder = new StringBuilder(""" import Standard.Base.Data.Range.Extensions diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/IfVsCaseBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/IfVsCaseBenchmarks.java index eb0402c4e41b..ac938e7d825b 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/IfVsCaseBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/IfVsCaseBenchmarks.java @@ -133,7 +133,7 @@ public void initializeBench(BenchmarkParams params) throws IOException { """; - var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var benchmarkName = SrcUtil.findName(params); var src = SrcUtil.source(benchmarkName, code); Value module = ctx.eval(src); ifBench3 = Objects.requireNonNull(module.invokeMember(Module.EVAL_EXPRESSION, "if_bench_3")); diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ListBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ListBenchmarks.java index ef8b748ab812..c9db1bc92550 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ListBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/ListBenchmarks.java @@ -46,7 +46,7 @@ public void initializeBenchmark(BenchmarkParams params) throws Exception { Paths.get("../../distribution/component").toFile().getAbsolutePath() ).build(); - var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var benchmarkName = SrcUtil.findName(params); var code = """ from Standard.Base.Data.List.List import Cons, Nil import Standard.Base.IO diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/NestedPatternCompilationBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/NestedPatternCompilationBenchmarks.java index 7d2eca3b2e4a..0cb7b76ecb64 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/NestedPatternCompilationBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/NestedPatternCompilationBenchmarks.java @@ -46,7 +46,7 @@ public void initializeBenchmark(BenchmarkParams params) throws Exception { Paths.get("../../distribution/component").toFile().getAbsolutePath() ).build(); - benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + benchmarkName = SrcUtil.findName(params); code = """ type List Cons a b diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/SrcUtil.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/SrcUtil.java index 95f6d1c5805c..3b2e24446a26 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/SrcUtil.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/SrcUtil.java @@ -4,11 +4,16 @@ import java.io.FileWriter; import java.io.IOException; import org.graalvm.polyglot.Source; +import org.openjdk.jmh.infra.BenchmarkParams; final class SrcUtil { private SrcUtil() { } + static String findName(BenchmarkParams params) { + return params.getBenchmark().replaceFirst(".*\\.", ""); + } + static Source source(String benchmarkName, String code) throws IOException { var d = new File(new File(new File("."), "target"), "bench-data"); d.mkdirs(); diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/StringBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/StringBenchmarks.java index 6bd96c4d7d25..77c2b3fa30a2 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/StringBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/StringBenchmarks.java @@ -53,7 +53,7 @@ public void initializeBenchmark(BenchmarkParams params) throws Exception { v = Vector.new len (_ -> s) v """; - var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var benchmarkName = SrcUtil.findName(params); var src = SrcUtil.source(benchmarkName, code); var module = ctx.eval(src); diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/TypePatternBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/TypePatternBenchmarks.java index 545a7bb17fb9..0dc4e2a38d23 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/TypePatternBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/TypePatternBenchmarks.java @@ -61,7 +61,7 @@ public void initializeBenchmark(BenchmarkParams params) throws Exception { match_dec = v -> case v of n : Decimal -> n + 1 """; - var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var benchmarkName = SrcUtil.findName(params); var src = SrcUtil.source(benchmarkName, code); var module = ctx.eval(src); @@ -70,7 +70,7 @@ public void initializeBenchmark(BenchmarkParams params) throws Exception { var length = 100; this.vec = getMethod.apply("gen_vec").execute(self, length, 1.1); - switch (params.getBenchmark().replaceFirst(".*\\.", "")) { + switch (SrcUtil.findName(params)) { case "matchOverAny": this.patternMatch = getMethod.apply("match_any"); break; diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java index 2213245e1857..ae62b8b0b163 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java @@ -44,7 +44,7 @@ public void initializeBenchmark(BenchmarkParams params) throws Exception { Paths.get("../../distribution/component").toFile().getAbsolutePath() ).build(); - var benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + var benchmarkName = SrcUtil.findName(params); var code = """ import Standard.Base.Data.Vector.Vector import Standard.Base.Data.Array_Proxy.Array_Proxy diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java index da08d9e081b6..58e42fb2d6d1 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java @@ -46,7 +46,7 @@ public class WarningBenchmarks extends TestBase { public void initializeBench(BenchmarkParams params) throws IOException { ctx = createDefaultContext(); - benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + benchmarkName = SrcUtil.findName(params); var code = """ from Standard.Base import all