diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso
index df85c99c32bc..af4675d0fdd3 100644
--- a/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso
+++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso
@@ -474,7 +474,7 @@ is_unresolved_symbol value = @Builtin_Method "Meta.is_unresolved_symbol"
    used carefully.
 get_source_location : Integer -> Text
 get_source_location skip_frames =
-    get_source_location_builtin skip_frames+1
+    get_source_location_builtin skip_frames
 
 ## PRIVATE
 
diff --git a/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala b/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala
index 1c1e39010524..32f36c73476b 100644
--- a/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala
+++ b/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala
@@ -3058,7 +3058,6 @@ class RuntimeServerTest
       )
     )
     context.receiveN(4) should contain theSameElementsAs Seq(
-      Api.Response(Api.BackgroundJobsStartedNotification()),
       Api.Response(requestId, Api.PushContextResponse(contextId)),
       Api.Response(
         Api.ExecutionUpdate(
@@ -3066,11 +3065,10 @@ class RuntimeServerTest
           Seq(
             Api.ExecutionResult.Diagnostic.error(
               "Type error: expected `str` to be Text, but got 2 (Integer).",
-              None,
-              None,
+              Some(mainFile),
+              Some(model.Range(model.Position(2, 10), model.Position(2, 15))),
               None,
               Vector(
-                Api.StackTraceElement("Text.+", None, None, None),
                 Api.StackTraceElement(
                   "Main.bar",
                   Some(mainFile),
@@ -3092,6 +3090,7 @@ class RuntimeServerTest
           )
         )
       ),
+      Api.Response(Api.BackgroundJobsStartedNotification()),
       context.executionComplete(contextId)
     )
   }
@@ -3216,7 +3215,6 @@ class RuntimeServerTest
       )
     )
     context.receiveN(4) should contain theSameElementsAs Seq(
-      Api.Response(Api.BackgroundJobsStartedNotification()),
       Api.Response(requestId, Api.PushContextResponse(contextId)),
       Api.Response(
         Api.ExecutionUpdate(
@@ -3224,11 +3222,10 @@ class RuntimeServerTest
           Seq(
             Api.ExecutionResult.Diagnostic.error(
               "Type error: expected `that` to be Number, but got quux (Unresolved_Symbol).",
-              None,
-              None,
+              Some(mainFile),
+              Some(model.Range(model.Position(10, 8), model.Position(10, 17))),
               None,
               Vector(
-                Api.StackTraceElement("Small_Integer.+", None, None, None),
                 Api.StackTraceElement(
                   "Main.baz",
                   Some(mainFile),
@@ -3266,6 +3263,7 @@ class RuntimeServerTest
           )
         )
       ),
+      Api.Response(Api.BackgroundJobsStartedNotification()),
       context.executionComplete(contextId)
     )
   }
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
new file mode 100644
index 000000000000..37a69a779151
--- /dev/null
+++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/IfVsCaseBenchmarks.java
@@ -0,0 +1,187 @@
+package org.enso.interpreter.bench.benchmarks.semantic;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import org.enso.interpreter.test.TestBase;
+import org.enso.polyglot.MethodNames.Module;
+import org.graalvm.polyglot.Context;
+import org.graalvm.polyglot.Source;
+import org.graalvm.polyglot.Value;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.infra.BenchmarkParams;
+
+@BenchmarkMode(Mode.AverageTime)
+@Fork(1)
+@Warmup(iterations = 5, time = 1)
+@Measurement(iterations = 3, time = 3)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@State(Scope.Benchmark)
+public class IfVsCaseBenchmarks extends TestBase {
+  private static final int INPUT_VEC_SIZE = 100_000;
+  private Context ctx;
+  private Value ifBench3;
+  private Value caseBench3;
+  private Value ifBench6;
+  private Value caseBench6;
+  private Value createVec;
+  private Value inputVec;
+  private OutputStream out = new ByteArrayOutputStream();
+
+  @Setup
+  public void initializeBench(BenchmarkParams params) throws IOException {
+    ctx = Context.newBuilder("enso")
+        .allowAllAccess(true)
+        .logHandler(out)
+        .out(out)
+        .err(out)
+        .allowIO(true)
+        .allowExperimentalOptions(true)
+        .option(
+            "enso.languageHomeOverride",
+            Paths.get("../../distribution/component").toFile().getAbsolutePath()
+        )
+        .option("engine.MultiTier", "true")
+        .option("engine.BackgroundCompilation", "true")
+        .build();
+
+    var code = """
+        from Standard.Base import all
+
+        type My_Type
+            Value f1 f2 f3 f4 f5 f6
+
+        if_bench_3 : Vector My_Type -> Integer
+        if_bench_3 vec =
+            vec.fold 0 acc-> curr->
+                if curr.f1.not then acc else
+                    if curr.f2.not then acc else
+                        if curr.f3.not then acc else
+                            acc + 1
+
+        case_bench_3 : Vector My_Type -> Integer
+        case_bench_3 vec =
+            vec.fold 0 acc-> curr->
+                case curr.f1 of
+                    False -> acc
+                    True -> case curr.f2 of
+                        False -> acc
+                        True -> case curr.f3 of
+                            False -> acc
+                            True -> acc + 1
+
+        if_bench_6 : Vector My_Type -> Integer
+        if_bench_6 vec =
+            vec.fold 0 acc-> curr->
+                if curr.f1.not then acc else
+                    if curr.f2.not then acc else
+                        if curr.f3.not then acc else
+                            if curr.f4.not then acc else
+                                if curr.f5.not then acc else
+                                    if curr.f6.not then acc else
+                                        acc + 1
+
+        case_bench_6 : Vector My_Type -> Integer
+        case_bench_6 vec =
+            vec.fold 0 acc-> curr->
+                case curr.f1 of
+                    False -> acc
+                    True -> case curr.f2 of
+                        False -> acc
+                        True -> case curr.f3 of
+                            False -> acc
+                            True -> case curr.f4 of
+                                False -> acc
+                                True -> case curr.f5 of
+                                    False -> acc
+                                    True -> case curr.f6 of
+                                        False -> acc
+                                        True -> acc + 1
+
+        create_vec polyglot_vec =
+            Vector.from_polyglot_array polyglot_vec . map elem->
+                My_Type.Value (elem.at 0) (elem.at 1) (elem.at 2) (elem.at 3) (elem.at 4) (elem.at 5)
+
+        """;
+
+    var file = File.createTempFile("if_case", ".enso");
+    try (var w = new FileWriter(file)) {
+      w.write(code);
+    }
+    var src = Source.newBuilder("enso", file).build();
+    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"));
+    ifBench6 = Objects.requireNonNull(module.invokeMember(Module.EVAL_EXPRESSION, "if_bench_6"));
+    caseBench6 = Objects.requireNonNull(module.invokeMember(Module.EVAL_EXPRESSION, "case_bench_6"));
+    createVec = Objects.requireNonNull(module.invokeMember(Module.EVAL_EXPRESSION, "create_vec"));
+    // So far, input is a vector of My_Type.Value with all fields set to True
+    inputVec = createMyTypeAllTrue(INPUT_VEC_SIZE);
+  }
+
+  @TearDown
+  public void tearDown() {
+    ctx.close();
+  }
+
+  /**
+   * Iterates over a vector of {@code My_Type} values with True only fields.
+   */
+  @Benchmark
+  public void ifBench3() {
+    Value res = ifBench3.execute(inputVec);
+    checkResult(res);
+  }
+
+  @Benchmark
+  public void ifBench6() {
+    Value res = ifBench6.execute(inputVec);
+    checkResult(res);
+  }
+
+  @Benchmark
+  public void caseBench3() {
+    Value res = caseBench3.execute(inputVec);
+    checkResult(res);
+  }
+
+  @Benchmark
+  public void caseBench6() {
+    Value res = caseBench6.execute(inputVec);
+    checkResult(res);
+  }
+
+  private static void checkResult(Value res) {
+    if (res.asInt() != INPUT_VEC_SIZE) {
+      throw new AssertionError("Expected result: " + INPUT_VEC_SIZE + ", got: " + res.asInt());
+    }
+  }
+
+  /**
+   * Creates a vector of {@code My_Type} with all True fields
+   */
+  private Value createMyTypeAllTrue(int size) {
+    List<List<Boolean>> inputPolyVec = new ArrayList<>();
+    for (int i = 0; i < size; i++) {
+      inputPolyVec.add(List.of(true, true, true, true, true, true));
+    }
+    return createVec.execute(inputPolyVec);
+  }
+}
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
new file mode 100644
index 000000000000..d660aad64bfe
--- /dev/null
+++ b/engine/runtime/src/main/java/org/enso/interpreter/node/InlineableRootNode.java
@@ -0,0 +1,56 @@
+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 35c2624f0682..c734cbd3a5c1 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
@@ -8,6 +8,7 @@
 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.runtime.callable.CallerInfo;
 import org.enso.interpreter.runtime.callable.function.Function;
 
@@ -52,11 +53,15 @@ protected Object callDirect(
       Object state,
       Object[] arguments,
       @Cached("function.getCallTarget()") RootCallTarget cachedTarget,
-      @Cached("create(cachedTarget)") DirectCallNode callNode) {
+      @Cached("createCallNode(cachedTarget)") DirectCallNode callNode) {
     return callNode.call(
         Function.ArgumentsHelper.buildArguments(function, callerInfo, state, arguments));
   }
 
+  static DirectCallNode createCallNode(RootCallTarget t) {
+    return InlineableRootNode.create(t);
+  }
+
   /**
    * Calls the function with a lookup.
    *
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 4d7fd660506a..c36cd40d4d88 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,13 +1,18 @@
 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.EnsoLanguage;
+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 {
+public abstract class BuiltinRootNode extends RootNode implements InlineableRootNode {
   protected BuiltinRootNode(EnsoLanguage language) {
     super(language);
   }
@@ -28,4 +33,64 @@ 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() {
+    return DirectCallNode.create(getCallTarget());
+  }
+
+  /**
+   * 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 <E> extra data to keep in the node
+   * @param <N> node to delegate to from {@link #call(java.lang.Object...)} method
+   */
+  protected abstract static class InlinedCallNode<E, N extends Node> extends DirectCallNode {
+    protected final E extra;
+    @Child protected N body;
+
+    protected InlinedCallNode(E extra, N body) {
+      super(null);
+      this.extra = extra;
+      this.body = body;
+    }
+
+    @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 null;
+    }
+  }
 }
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 f6150ee5ac2c..6f29ff4edddb 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
@@ -12,12 +12,13 @@
     type = "Boolean",
     name = "if_then_else",
     description = "Performs the standard if-then-else control flow operation.")
-public class IfThenElseNode extends Node {
+public final class IfThenElseNode extends Node {
   private @Child ThunkExecutorNode leftThunkExecutorNode = ThunkExecutorNode.build();
   private @Child ThunkExecutorNode rightThunkExecutorNode = ThunkExecutorNode.build();
   private final ConditionProfile condProfile = ConditionProfile.createCountingProfile();
 
-  Object execute(State state, boolean self, @Suspend Object if_true, @Suspend Object if_false) {
+  public Object execute(
+      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);
     } else {
diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/debug/DebugEvalNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/debug/DebugEvalNode.java
index 8437f4c18ea6..bcf9a54e849c 100644
--- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/debug/DebugEvalNode.java
+++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/debug/DebugEvalNode.java
@@ -1,5 +1,6 @@
 package org.enso.interpreter.node.expression.builtin.debug;
 
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import org.enso.interpreter.dsl.BuiltinMethod;
 import org.enso.interpreter.node.BaseNode;
@@ -22,7 +23,8 @@ public class DebugEvalNode extends Node {
     evalNode.setTailStatus(BaseNode.TailStatus.TAIL_DIRECT);
   }
 
-  Object execute(CallerInfo callerInfo, State state, Object expression) {
+  Object execute(
+      VirtualFrame requestOwnStackFrame, CallerInfo callerInfo, State state, Object expression) {
     return evalNode.execute(callerInfo, state, expectTextNode.execute(expression));
   }
 }
diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/ThrowErrorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/ThrowErrorNode.java
index 6d11c466f2ce..12ebeb6d4143 100644
--- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/ThrowErrorNode.java
+++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/ThrowErrorNode.java
@@ -1,5 +1,6 @@
 package org.enso.interpreter.node.expression.builtin.error;
 
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import org.enso.interpreter.dsl.BuiltinMethod;
 import org.enso.interpreter.runtime.error.DataflowError;
@@ -9,7 +10,7 @@
     name = "throw",
     description = "Returns a new value error with given payload.")
 public class ThrowErrorNode extends Node {
-  public Object execute(Object payload) {
+  public Object execute(VirtualFrame giveMeAStackFrame, Object payload) {
     return DataflowError.withoutTrace(payload, this);
   }
 }
diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/ThrowPanicNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/ThrowPanicNode.java
index e04a1e5ad174..be8726355ec3 100644
--- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/ThrowPanicNode.java
+++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/ThrowPanicNode.java
@@ -3,6 +3,7 @@
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 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.UnsupportedMessageException;
 import com.oracle.truffle.api.library.CachedLibrary;
@@ -24,7 +25,7 @@ static ThrowPanicNode build() {
     return ThrowPanicNodeGen.create();
   }
 
-  abstract Object execute(Object payload);
+  abstract Object execute(VirtualFrame giveMeAStackFrame, Object payload);
 
   EnsoContext getContext() {
     return EnsoContext.get(this);
@@ -35,6 +36,7 @@ EnsoContext getContext() {
         "payload.getConstructor().getType() == getContext().getBuiltins().caughtPanic().getType()"
       })
   Object doCaughtPanic(
+      VirtualFrame frame,
       Atom payload,
       @CachedLibrary(limit = "5") InteropLibrary interopLibrary,
       @CachedLibrary(limit = "5") StructsLibrary structs,
diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/GetStackTraceNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/GetStackTraceNode.java
index e9b9ed0d44d3..17f1d7ad17a6 100644
--- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/GetStackTraceNode.java
+++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/GetStackTraceNode.java
@@ -2,6 +2,7 @@
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.TruffleStackTrace;
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import org.enso.interpreter.dsl.BuiltinMethod;
 import org.enso.interpreter.runtime.data.Array;
@@ -13,7 +14,7 @@
     description = "Gets the current execution stacktrace.",
     autoRegister = false)
 public class GetStackTraceNode extends Node {
-  Array execute() {
+  Array execute(VirtualFrame requestOwnStackFrame) {
     var exception = new PanicException("Stacktrace", this);
     TruffleStackTrace.fillIn(exception);
     return stackTraceToArray(exception);
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 a5589b7dbc93..734a644484ee 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
@@ -159,7 +159,11 @@ private void generateCode(MethodDefinition methodDefinition) throws IOException
       out.println("  description = \"\"\"\n" + methodDefinition.getDescription() + "\"\"\")");
       out.println("public class " + methodDefinition.getClassName() + " extends BuiltinRootNode {");
       out.println("  private @Child " + methodDefinition.getOriginalClassName() + " bodyNode;");
-      out.println("  private final boolean staticOfInstanceMethod;");
+      out.println("  private static final class Internals {");
+      out.println("    Internals(boolean s) {");
+      out.println("      this.staticOfInstanceMethod = s;");
+      out.println("    }");
+      out.println("    private final boolean staticOfInstanceMethod;");
 
       out.println();
 
@@ -167,28 +171,30 @@ private void generateCode(MethodDefinition methodDefinition) throws IOException
         if (arg.shouldCheckErrors()) {
           String condName = mkArgumentInternalVarName(arg) + DATAFLOW_ERROR_PROFILE;
           out.println(
-              "  private final ConditionProfile "
+              "    private final ConditionProfile "
                   + condName
                   + " = ConditionProfile.createCountingProfile();");
         }
 
         if (arg.isPositional() && !arg.isSelf()) {
           String branchName = mkArgumentInternalVarName(arg) + PANIC_SENTINEL_PROFILE;
-          out.println("  private final BranchProfile " + branchName + " = BranchProfile.create();");
+          out.println("    private final BranchProfile " + branchName + " = BranchProfile.create();");
         }
 
         if (arg.shouldCheckWarnings()) {
           String warningName = mkArgumentInternalVarName(arg) + WARNING_PROFILE;
           out.println(
-              "  private final BranchProfile " + warningName + " = BranchProfile.create();");
+              "    private final BranchProfile " + warningName + " = BranchProfile.create();");
         }
       }
-      out.println("  private final BranchProfile anyWarningsProfile = BranchProfile.create();");
+      out.println("    private final BranchProfile anyWarningsProfile = BranchProfile.create();");
+      out.println("  }");
+      out.println("  private final Internals internals;");
 
       out.println("  private " + methodDefinition.getClassName() + "(EnsoLanguage language, boolean staticOfInstanceMethod) {");
       out.println("    super(language);");
       out.println("    this.bodyNode = " + methodDefinition.getConstructorExpression() + ";");
-      out.println("    this.staticOfInstanceMethod = staticOfInstanceMethod;");
+      out.println("    this.internals = new Internals(staticOfInstanceMethod);");
       out.println("  }");
 
       out.println();
@@ -223,17 +229,35 @@ private void generateCode(MethodDefinition methodDefinition) throws IOException
       out.println("  }");
 
       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(extra, body, args);");
+        out.println("      }");
+        out.println("    };");
+        out.println("  }");
+      }
 
       out.println("  @Override");
       out.println("  public Object execute(VirtualFrame frame) {");
-      out.println("    State state = Function.ArgumentsHelper.getState(frame.getArguments());");
+      if (methodDefinition.needsFrame()) {
+        out.println("    var args = frame.getArguments();");
+      } else {
+        out.println("    return handleExecute(this.internals, bodyNode, frame.getArguments());");
+        out.println("  }");
+        out.println("  private static Object handleExecute(Internals internals, " + methodDefinition.getOriginalClassName() + " bodyNode, Object[] args) {");
+      }
+      out.println("    var prefix = internals.staticOfInstanceMethod ? 1 : 0;");
+      out.println("    State state = Function.ArgumentsHelper.getState(args);");
       if (methodDefinition.needsCallerInfo()) {
         out.println(
-            "    CallerInfo callerInfo = Function.ArgumentsHelper.getCallerInfo(frame.getArguments());");
+            "    CallerInfo callerInfo = Function.ArgumentsHelper.getCallerInfo(args);");
       }
       out.println(
-          "    Object[] arguments = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());");
-      out.println("    int prefix = this.staticOfInstanceMethod ? 1 : 0;");
+          "    Object[] arguments = Function.ArgumentsHelper.getPositionalArguments(args);");
       List<String> callArgNames = new ArrayList<>();
       for (MethodDefinition.ArgumentDefinition arg :
               methodDefinition.getArguments()) {
@@ -260,7 +284,7 @@ private void generateCode(MethodDefinition methodDefinition) throws IOException
       String executeCall = "bodyNode.execute(" + String.join(", ", callArgNames) + ")";
       if (warningsPossible) {
         out.println("    if (anyWarnings) {");
-        out.println("      anyWarningsProfile.enter();");
+        out.println("      internals.anyWarningsProfile.enter();");
         out.println("      Object result = " + executeCall + ";");
         out.println("      return WithWarnings.appendTo(result, gatheredWarnings);");
         out.println("    } else {");
@@ -296,7 +320,7 @@ private void generateCode(MethodDefinition methodDefinition) throws IOException
 
       out.println("  @Override");
       out.println("  protected RootNode cloneUninitialized() {");
-      out.println("    return new " + methodDefinition.getClassName() + "(EnsoLanguage.get(this), this.staticOfInstanceMethod);");
+      out.println("    return new " + methodDefinition.getClassName() + "(EnsoLanguage.get(this), internals.staticOfInstanceMethod);");
       out.println("  }");
 
       out.println();
@@ -334,7 +358,7 @@ private void generateArgumentRead(
     if (arg.shouldCheckErrors()) {
       String condProfile = mkArgumentInternalVarName(arg) + DATAFLOW_ERROR_PROFILE;
       out.println(
-          "    if ("
+          "    if (internals."
               + condProfile
               + ".profile(TypesGen.isDataflowError("
               + argReference
@@ -350,7 +374,7 @@ private void generateArgumentRead(
           "    if (TypesGen.isPanicSentinel("
               + argReference
               + ")) {\n"
-              + "      "
+              + "      internals."
               + branchProfile
               + ".enter();\n"
               + "      throw TypesGen.asPanicSentinel("
@@ -432,7 +456,7 @@ private void generateCheckedArgumentRead(
         "      " + varName + " = " + castName + "(" + argsArray + "[arg" + arg.getPosition() + "Idx]);");
     out.println("    } catch (UnexpectedResultException e) {");
     out.println("      com.oracle.truffle.api.CompilerDirectives.transferToInterpreter();");
-    out.println("      var builtins = EnsoContext.get(this).getBuiltins();");
+    out.println("      var builtins = EnsoContext.get(bodyNode).getBuiltins();");
     out.println("      var ensoTypeName = org.enso.interpreter.runtime.type.ConstantsGen.getEnsoTypeName(\"" + builtinName + "\");");
     out.println("      var error = (ensoTypeName != null)");
     out.println("        ? builtins.error().makeTypeError(builtins.fromTypeSystem(ensoTypeName), arguments[arg"
@@ -447,7 +471,7 @@ private void generateCheckedArgumentRead(
                       + " expected a "
                       + builtinName
                       + "\");");
-    out.println("      throw new PanicException(error,this);");
+    out.println("      throw new PanicException(error, bodyNode);");
     out.println("    }");
   }
 
@@ -467,7 +491,7 @@ private boolean generateWarningsCheck(
             "    if ("
                 + arrayRead(argumentsArray, arg.getPosition())
                 + " instanceof WithWarnings) {");
-        out.println("      " + mkArgumentInternalVarName(arg) + WARNING_PROFILE + ".enter();");
+        out.println("      internals." + mkArgumentInternalVarName(arg) + WARNING_PROFILE + ".enter();");
         out.println("      anyWarnings = true;");
         out.println(
             "      WithWarnings withWarnings = (WithWarnings) "
@@ -478,7 +502,7 @@ private boolean generateWarningsCheck(
                 + arrayRead(argumentsArray, arg.getPosition())
                 + " = withWarnings.getValue();");
         out.println(
-            "      gatheredWarnings = gatheredWarnings.prepend(withWarnings.getReassignedWarnings(this));");
+            "      gatheredWarnings = gatheredWarnings.prepend(withWarnings.getReassignedWarnings(bodyNode));");
         out.println("    }");
       }
       return true;
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 b5faa71b379b..812a2bd5388e 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
@@ -25,6 +25,7 @@ public class MethodDefinition {
   private final List<ArgumentDefinition> arguments;
   private final Set<String> imports;
   private final boolean needsCallerInfo;
+  private final boolean needsFrame;
   private final String constructorExpression;
 
   /**
@@ -45,6 +46,7 @@ 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.constructorExpression = initConstructor(element);
   }
 
@@ -194,6 +196,11 @@ public boolean needsCallerInfo() {
     return needsCallerInfo;
   }
 
+  /** @return whether this method requires virtual frame. */
+  public boolean needsFrame() {
+    return needsFrame;
+  }
+
   public String getConstructorExpression() {
     return constructorExpression;
   }
diff --git a/test/Tests/src/Semantic/Warnings_Spec.enso b/test/Tests/src/Semantic/Warnings_Spec.enso
index d94fa98f64ae..e9096c541b63 100644
--- a/test/Tests/src/Semantic/Warnings_Spec.enso
+++ b/test/Tests/src/Semantic/Warnings_Spec.enso
@@ -154,7 +154,7 @@ spec = Test.group "Dataflow Warnings" <|
         r = reassign_test x
         warn = Warning.get_all r . first
         reassignments = warn.reassignments.map .name
-        reassignments.should_equal ['Warnings_Spec.poly_sum', 'Small_Integer.+', 'Warnings_Spec.get_foo', 'Wrap.Value', 'Warnings_Spec.unwrap', 'Warnings_Spec.rewrap', 'Wrap.Value']
+        reassignments.should_equal ['Warnings_Spec.poly_sum', 'Warnings_Spec.reassign_test', 'Warnings_Spec.get_foo', 'Wrap.Value', 'Warnings_Spec.unwrap', 'Warnings_Spec.rewrap', 'Wrap.Value']
 
     Test.specify "should allow to set all warnings" <|
         warned = Warning.attach 1 <| Warning.attach 2 <| Warning.attach 3 <| Warning.attach 4 "foo"