Annotation Interface CompilerDirectives.EarlyEscapeAnalysis

Enclosing class:
CompilerDirectives

@Retention(RUNTIME) @Target({METHOD,CONSTRUCTOR}) public static @interface CompilerDirectives.EarlyEscapeAnalysis
Requests the Truffle compiler to run escape analysis on this method before partial evaluation.

When a method or constructor is annotated with @EarlyEscapeAnalysis, a dedicated partial escape analysis phase is executed for that method before partial evaluation. This allows allocations that do not escape the method to be virtualized or eliminated, and their fields to be treated as partial-evaluation-time constants where possible.

Typical use cases

  • Methods that allocate temporary objects whose fields are used only locally and are expected to become constants after partial evaluation.
  • Interpreters that keep loop state in a small object (for example a bytecode index), in combination with ExplodeLoop and CompilerDirectives.EarlyInline, so that the state object can be fully scalar replaced.

Example: non-escaping temporary object

@EarlyEscapeAnalysis
private static int computeConstant() {
    TestEscape v = new TestEscape(42);
    CompilerAsserts.partialEvaluationConstant(v.value);
    // After early escape analysis and partial evaluation this method reduces to "return 42".
    return v.value;
}

static final class TestEscape {
    int value;

    TestEscape(int value) {
        this.value = value;
    }
}

Example: loop state object in a merge-exploded interpreter


static final class BytecodeIndex {
    int bci;
}

@CompilationFinal(dimensions = 1) private final byte[] bytecodes = new byte[]{0, 1, 4, 2, 3};

@ExplodeLoop(kind = LoopExplosionKind.MERGE_EXPLODE)
@EarlyEscapeAnalysis
int execute(Boolean v) {
    byte[] bc = this.bytecodes;
    BytecodeIndex index = new BytecodeIndex();
    while (true) {
        CompilerAsserts.partialEvaluationConstant(index.bci);
        switch (bc[index.bci]) {
            case 0:
                index.bci++;
                break;
            case 1:
                // {@code branchTrue} is early inlined and sees the virtual {@code index}
                // object.
                branchTrue(bc, index, v);
                break;
            case 2:
                return 41;
            case 3:
                return 42;
            case 4:
                throw CompilerDirectives.shouldNotReachHere();
        }
    }
}

@EarlyInline
private static void branchTrue(byte[] bc, BytecodeIndex index, Boolean v) {
    if (v) {
        index.bci = bc[index.bci + 1];
    } else {
        index.bci = index.bci + 2;
    }
}

Since:
25.1