Package org.codehaus.groovy.classgen.asm

# Class StatementWriter

java.lang.Object
org.codehaus.groovy.classgen.asm.StatementWriter

Direct Known Subclasses:
  `OptimizingStatementWriter`, `StaticTypesStatementWriter`

public class StatementWriter extends Object
Generates bytecode for Groovy statements by visiting AST statement nodes and emitting corresponding JVM instructions via the `WriterController`. Handles control flow (loops, branches, try/catch), synchronization, assertions, and expression statements.

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `protected final WriterController`
  `controller`
  The controller coordinating all bytecode writers for the current class.

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `StatementWriter(WriterController controller)`
  Creates a statement writer backed by the given controller.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `protected final BytecodeVariable`
  `defineLoopIndexVariable(ForStatement statement)`
  `protected final void`
  `incrementForLoopIndexVariable(BytecodeVariable indexVariable)`
  Increments the for-in index variable by one.
  `protected final void`
  `storeForLoopVariable(BytecodeVariable variable)`
  Stores the top-of-stack value into a for-in loop variable slot.
  `void`
  `writeAssert(AssertStatement statement)`
  Generates bytecode for an assert statement.
  `void`
  `writeBlockStatement(BlockStatement block)`
  Generates bytecode for a block statement by visiting each contained statement.
  `void`
  `writeBreak(BreakStatement statement)`
  Generates bytecode for a break statement, applying any intervening finally blocks before the jump.
  `void`
  `writeContinue(ContinueStatement statement)`
  Generates bytecode for a continue statement, applying any intervening finally blocks before the jump.
  `void`
  `writeDoWhileLoop(DoWhileStatement statement)`
  Generates bytecode for a do-while loop.
  `void`
  `writeExpressionStatement(ExpressionStatement statement)`
  Generates bytecode for an expression statement.
  `protected void`
  `writeForInLoop(ForStatement statement)`
  Generates bytecode for a for-in loop by calling `iterator()` on the collection expression and delegating loop control to `writeForInLoopControlAndBlock(org.codehaus.groovy.ast.stmt.ForStatement)`.
  `protected void`
  `writeForInLoopControlAndBlock(ForStatement statement)`
  Emits the loop-control structure and body for a for-in loop.
  `protected void`
  `writeForLoopWithClosureList(ForStatement statement)`
  Generates bytecode for a C-style `for(init; cond; incr)` loop.
  `void`
  `writeForStatement(ForStatement statement)`
  Generates bytecode for a for statement.
  `void`
  `writeIfElse(IfStatement statement)`
  Generates bytecode for an if/else statement.
  `protected void`
  `writeIteratorHasNext(org.objectweb.asm.MethodVisitor mv)`
  Emits the `Iterator.hasNext()` call via the given visitor.
  `protected void`
  `writeIteratorNext(org.objectweb.asm.MethodVisitor mv)`
  Emits the `Iterator.next()` call via the given visitor.
  `protected final void`
  `writeLoopBackEdge(org.objectweb.asm.Label continueLabel, boolean bodyMayReachContinue)`
  `void`
  `writeReturn(ReturnStatement statement)`
  Generates bytecode for a return statement.
  `protected void`
  `writeStatementLabel(Statement statement)`
  Emits bytecode labels for any statement labels attached to `statement`.
  `void`
  `writeSwitch(SwitchStatement statement)`
  Generates bytecode for a switch statement.
  `void`
  `writeSynchronized(SynchronizedStatement statement)`
  Generates bytecode for a synchronized statement.
  `void`
  `writeThrow(ThrowStatement statement)`
  Generates bytecode for a throw statement.
  `void`
  `writeTryCatchFinally(TryCatchStatement statement)`
  Generates bytecode for a try/catch/finally statement.
  `void`
  `writeWhileLoop(WhileStatement statement)`
  Generates bytecode for a while loop.

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Field Details

  - ### controller

    protected final WriterController controller
    The controller coordinating all bytecode writers for the current class.

- ## Constructor Details

  - ### StatementWriter

    public StatementWriter(WriterController controller)
    Creates a statement writer backed by the given controller.
    Parameters:
      `controller` - the writer controller for the current compilation

- ## Method Details

  - ### writeStatementLabel

    protected void writeStatementLabel(Statement statement)
    Emits bytecode labels for any statement labels attached to `statement`. Called before emitting the body of every statement so that named labels (`break foo` / `continue foo`) resolve correctly.
    Parameters:
      `statement` - the statement whose labels should be emitted

  - ### writeBlockStatement

    public void writeBlockStatement(BlockStatement block)
    Generates bytecode for a block statement by visiting each contained statement. Pushes the block's variable scope, emits the statements, and pops afterward. Named labels on the block create a breakable region so that `break label` within the block jumps to the end of it.
    Parameters:
      `block` - the block statement to compile

  - ### writeForStatement

    public void writeForStatement(ForStatement statement)
    Generates bytecode for a for statement. Delegates to `writeForLoopWithClosureList(org.codehaus.groovy.ast.stmt.ForStatement)` for C-style loops (using a `ClosureListExpression`), or to `writeForInLoop(org.codehaus.groovy.ast.stmt.ForStatement)` for for-in loops.
    Parameters:
      `statement` - the for statement to compile

  - ### writeForInLoop

    protected void writeForInLoop(ForStatement statement)
    Generates bytecode for a for-in loop by calling `iterator()` on the collection expression and delegating loop control to `writeForInLoopControlAndBlock(org.codehaus.groovy.ast.stmt.ForStatement)`.
    Parameters:
      `statement` - the for-in statement to compile

  - ### writeForInLoopControlAndBlock

    protected void writeForInLoopControlAndBlock(ForStatement statement)
    Emits the loop-control structure and body for a for-in loop. Assumes the iterator object is already on the operand stack. Declares loop variables, emits the `hasNext`/`next` check-and-advance, generates the loop body, and handles index-variable increment when present.
    Parameters:
      `statement` - the for-in statement whose control and body should be emitted

  - ### storeForLoopVariable

    protected final void storeForLoopVariable(BytecodeVariable variable)
    Stores the top-of-stack value into a for-in loop variable slot.

    Applies the for-in per-iteration capture policy (`WriterController.isForInPerIterationCaptureEnabled()`, GROOVY-11792): when enabled, a shared (holder) loop variable receives a fresh `Reference` so deferred closures, lambdas, and anonymous inner classes observe this iteration's value. When disabled, the historical in-place `Reference#set` path is used. Non-holder variables always take the plain store path.

    Bytecode emission is delegated to `CompileStack.storeVar(BytecodeVariable, boolean)`.

    Parameters:
      `variable` - the for-in value (or similarly stored) loop variable

  - ### incrementForLoopIndexVariable

    protected final void incrementForLoopIndexVariable(BytecodeVariable indexVariable)
    Increments the for-in index variable by one.

    Plain (non-shared) indexes use `IINC`. Shared indexes are loaded from their `Reference`, unboxed, incremented, then stored via `storeForLoopVariable(BytecodeVariable)` so the same per-iteration capture policy applies as for value variables (GROOVY-11751, GROOVY-11792).

    Parameters:
      `indexVariable` - the for-in index variable; must not be `null`

  - ### defineLoopIndexVariable

    protected final BytecodeVariable defineLoopIndexVariable(ForStatement statement)

  - ### writeLoopBackEdge

    protected final void writeLoopBackEdge(org.objectweb.asm.Label continueLabel, boolean bodyMayReachContinue)

  - ### writeIteratorHasNext

    protected void writeIteratorHasNext(org.objectweb.asm.MethodVisitor mv)
    Emits the `Iterator.hasNext()` call via the given visitor. Overrideable so subclasses can substitute a specialized or inlined variant.
    Parameters:
      `mv` - the method visitor to write to

  - ### writeIteratorNext

    protected void writeIteratorNext(org.objectweb.asm.MethodVisitor mv)
    Emits the `Iterator.next()` call via the given visitor. Overrideable so subclasses can substitute a specialized or inlined variant.
    Parameters:
      `mv` - the method visitor to write to

  - ### writeForLoopWithClosureList

    protected void writeForLoopWithClosureList(ForStatement statement)
    Generates bytecode for a C-style `for(init; cond; incr)` loop. The collection expression is a `ClosureListExpression` whose middle element is the boolean condition, lower elements are initializers, and upper elements are incrementors.
    Parameters:
      `statement` - the for statement with a `ClosureListExpression` collection

  - ### writeWhileLoop

    public void writeWhileLoop(WhileStatement statement)
    Generates bytecode for a while loop.
    Parameters:
      `statement` - the while statement to compile

  - ### writeDoWhileLoop

    public void writeDoWhileLoop(DoWhileStatement statement)
    Generates bytecode for a do-while loop.
    Parameters:
      `statement` - the do-while statement to compile

  - ### writeIfElse

    public void writeIfElse(IfStatement statement)
    Generates bytecode for an if/else statement.

    GROOVY-7463: a labeled `if` registers a breakable frame around the then arm only (same region as before GROOVY-12242). The else arm runs after that frame is popped so labeled-break scoping for the then arm is unchanged. Named break labels remain registered for the method (CompileStack does not un-register them on pop).

    GROOVY-12242 / JEP 394: pattern slots are allocated on the outer frame during the condition (needed for short-circuit `&&` RHS). Each arm then uses `CompileStack.pushState()`/`CompileStack.hidePatternVariablesExcept(java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>)`/ `CompileStack.pop()` so only path-live names are visible. Path-live names come from `VariableScopeVisitor.InstanceofFlowBindings` metadata attached by `VariableScopeVisitor` — classgen does not re-run the flow analysis. After both arms, non-survivors are permanently hidden on the outer frame (JLS §6.3.2.2-200-C).

    Parameters:
      `statement` - the if statement to compile

  - ### writeTryCatchFinally

    public void writeTryCatchFinally(TryCatchStatement statement)
    Generates bytecode for a try/catch/finally statement.

    A `CompileStack.BlockRecorder` is always registered for the try (and catch) regions so that:

    - a non-empty finally is inlined on every abrupt exit (`return`/`break`/`continue`);
    - exception-table ranges are closed before any enclosing finally is inlined (required when an inner try/catch without its own finally sits inside an outer try/finally — see GROOVY-8229);
    - GROOVY-9805 stack-map casts remain active for assignments in the region (`CompileStack.hasBlockRecorder()`).
    When the finally clause is empty (plain `try`/`catch`), the catch-all identity rethrow and the empty shared-finally block are omitted so the shape matches javac more closely and stays more JIT-friendly.
    Parameters:
      `statement` - the try/catch/finally statement to compile

  - ### writeSwitch

    public void writeSwitch(SwitchStatement statement)
    Generates bytecode for a switch statement. Each `case` expression is compared using Groovy's `isCase` operator, so non-integer switch expressions are supported.
    Parameters:
      `statement` - the switch statement to compile

  - ### writeBreak

    public void writeBreak(BreakStatement statement)
    Generates bytecode for a break statement, applying any intervening finally blocks before the jump.
    Parameters:
      `statement` - the break statement to compile

  - ### writeContinue

    public void writeContinue(ContinueStatement statement)
    Generates bytecode for a continue statement, applying any intervening finally blocks before the jump.
    Parameters:
      `statement` - the continue statement to compile

  - ### writeSynchronized

    public void writeSynchronized(SynchronizedStatement statement)
    Generates bytecode for a synchronized statement. Stores the monitor object in a local variable, emits `MONITORENTER`/`MONITOREXIT` guards, and registers a catch-all exception handler that exits the monitor before rethrowing.
    Parameters:
      `statement` - the synchronized statement to compile

  - ### writeAssert

    public void writeAssert(AssertStatement statement)
    Generates bytecode for an assert statement.
    Parameters:
      `statement` - the assert statement to compile

  - ### writeThrow

    public void writeThrow(ThrowStatement statement)
    Generates bytecode for a throw statement. Casts the expression to `Throwable` and emits `ATHROW`.
    Parameters:
      `statement` - the throw statement to compile

  - ### writeReturn

    public void writeReturn(ReturnStatement statement)
    Generates bytecode for a return statement. For void methods emits `RETURN` after applying any finally blocks. For value-returning methods evaluates the expression, casts it to the declared return type, and emits the appropriate typed return instruction.
    Parameters:
      `statement` - the return statement to compile

  - ### writeExpressionStatement

    public void writeExpressionStatement(ExpressionStatement statement)
    Generates bytecode for an expression statement. Evaluates the expression and discards any value left on the operand stack. Marks method-call and binary expressions so that unused return values are elided rather than boxed.

    GROOVY-12242: non-declaration statements that contain an `instanceof` type pattern run in a nested CompileStack state (`pushState`/`pop`) so pattern locals defined during evaluation cannot leak past the statement.

    Parameters:
      `statement` - the expression statement to compile