Package: org.codehaus.groovy.classgen.asm

## [Java] Class ClosureWriter

- org.codehaus.groovy.classgen.asm.ClosureWriter

-     public class ClosureWriter
      extends Object

  Generates bytecode for closure expressions.

- - ### Nested Class Summary

    Nested classes
    Modifiers | Name | Description
    --- | --- | ---
    `protected static class` | `ClosureWriter.CorrectAccessedVariableVisitor` | Visitor that rewrites VariableExpression nodes whose accessed variable is a FieldNode in an outer class to instead reference the corresponding field in the generated closure inner class.
    `protected interface` | `ClosureWriter.UseExistingReference` | Marker interface for using existing reference.

  - ### Field Summary

    Fields
    Modifiers | Name | Description
    --- | --- | ---
    `static String` | `GENERATED_CLOSURE_CLASS` | Node metadata key set on a ClosureExpression once it has been compiled to a generated closure class, holding that class's name.
    `static String` | `OUTER_INSTANCE` | Field name for the outer instance reference.
    `static String` | `PACKED_METHOD_PREFIX` | Name prefix of hoisted packed-closure bodies (also consulted by the static call-site writer).
    `static String` | `THIS_OBJECT` | Field name for the this object reference.
    `protected WriterController` | `controller` | The controller coordinating all bytecode writers for the current class.

  - ### Constructor Summary

    Constructors
    Constructor and description
    `ClosureWriter(WriterController controller)` Creates a closure writer with the given controller.

  - ### Methods Summary

    Methods
    Type Params | Return Type | Name and description
    --- | --- | ---
    `` | `protected ConstructorNode` | `addConstructor(ClosureExpression expression, Parameter[] localVariableParams, InnerClassNode answer, BlockStatement block)` Adds a synthetic `public` constructor to the closure inner class that accepts the outer instance, `this` object, and all captured local variable references.
    `` | `protected void` | `addFieldsForLocalVariables(InnerClassNode closureClass, Parameter[] localVariableParams)` Adds synthetic private fields to the closure inner class for each captured local variable parameter, promoting them to `Reference` holders.
    `` | `public boolean` | `addGeneratedClosureConstructorCall(ConstructorCallExpression call)` Emits a `super(outerInstance, thisObject)` constructor call for a generated closure class.
    `` | `protected void` | `addSerialVersionUIDField(ClassNode classNode)` Adds a synthetic `serialVersionUID` field to the closure class, derived from a hash of the class name.
    `` | `protected BlockStatement` | `createBlockStatementForConstructor(ClosureExpression expression, ClassNode outerClass, ClassNode thisClassNode)` Creates the block statement for the closure's synthetic constructor, setting up the `super(outerInstance, thisObject)` call and captured variable references.
    `` | `protected ClassNode` | `createClosureClass(ClosureExpression expression, int modifiers)` Creates a new inner class node representing the compiled form of a closure expression.
    `` | `protected Parameter[]` | `getClosureSharedVariables(ClosureExpression expression)` Collects the closure-shared local variables referenced by a closure expression as an array of Parameters, using the type chooser to infer each variable's type.
    `` | `public ClassNode` | `getOrAddClosureClass(ClosureExpression expression, int modifiers)` Returns the existing generated class for a closure expression, or creates and registers a new one if none exists yet.
    `` | `protected boolean` | `isPackTriggered(ClosureExpression expression, boolean annotated)` Whether a packable, non-escaping closure literal should actually be packed.
    `` | `public static void` | `loadReference(String name, WriterController controller)` Loads a closure-shared variable reference onto the operand stack, looking it up as a field, local variable, or outer closure field as appropriate.
    `` | `protected void` | `loadThis()` Loads the effective `this` reference onto the operand stack — either the actual receiver for a regular method, or the result of `getThisObject()` for a generated closure/lambda.
    `` | `protected void` | `markHoistedBody(MethodNode hoisted)` Marks the hoisted body's compilation mode; the static writer overrides this to compile it statically.
    `` | `protected boolean` | `packedClosureUsesDelegateGuard()` Whether the packed adapter installs the runtime delegate guard.
    `` | `protected ClassNode` | `readOnlyCaptureType(String name, ClassNode declaredType, Variable variable)` The declared type of a read-only (by-value) capture parameter on the hoisted method.
    `` | `protected static void` | `removeInitialValues(Parameter[] params)` Strips initial-value expressions from parameters that are closure-shared, ensuring the closure constructor is not duplicated.
    `` | `protected String` | `triggerDeclineReason(ClosureExpression expression)` A trigger-specific decline reason for declineReason, or `null` if the trigger did not decline this closure.
    `` | `public void` | `writeClosure(ClosureExpression expression)` Generates bytecode for a closure expression.
    `` | `public void` | `writePackedDispatcher()` Emits the class's packed-closure dispatch machinery, once per class at the end of class generation (so every hoisted body — including one a hoisted body itself hoisted — has claimed its id): the `$packedDispatch$(int, Object[])` table, whose case `k` casts the packed argument array (`[owner, captured..., args...]`) to target `k`'s declared parameter types and invokes it directly; the array-free per-arity tables (`$packedDispatch1$`/`$packedDispatch2$`) doing the same from plain parameter slots for the hot one/two-value shapes; and the `$getPackedDispatchers$()` accessor, whose single `invokedynamic` site links all three through `IndyInterface.packedDispatchers` (delegating to `GeneratedDispatcher.bootstrap`) into one constant bundle, lazily on first adapter creation.

  - ### Inherited Methods Summary

    Inherited Methods
    Methods inherited from class | Name
    --- | ---
    `class Object` | `equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Field Detail

    - #### public static final String GENERATED_CLOSURE_CLASS

      Node metadata key set on a ClosureExpression once it has been compiled to a generated closure class, holding that class's name. Tooling such as the AST browser can read it to show which synthetic class a closure literal became; the compiler itself never consults it. The mark only becomes available after the class-generation phase, since that is when the class is made.

    - #### public static final String OUTER_INSTANCE

      Field name for the outer instance reference.

    - #### public static final String PACKED_METHOD_PREFIX

      Name prefix of hoisted packed-closure bodies (also consulted by the static call-site writer).

    - #### public static final String THIS_OBJECT

      Field name for the this object reference.

    - #### protected final WriterController controller

      The controller coordinating all bytecode writers for the current class.

  - ### Constructor Detail

    - #### public ClosureWriter(WriterController controller)

      Creates a closure writer with the given controller.

      Parameters:
        `controller` - the writer controller

  - ### Method Detail

    - #### protected ConstructorNode addConstructor(ClosureExpression expression, Parameter[] localVariableParams, InnerClassNode answer, BlockStatement block)

      Adds a synthetic `public` constructor to the closure inner class that accepts the outer instance, `this` object, and all captured local variable references.

      Parameters:
        `expression` - the closure expression
        `localVariableParams` - parameters for closure-shared local variables
        `answer` - the closure inner class node
        `block` - the constructor body
      Returns:
        the created constructor node

    - #### protected void addFieldsForLocalVariables(InnerClassNode closureClass, Parameter[] localVariableParams)

      Adds synthetic private fields to the closure inner class for each captured local variable parameter, promoting them to `Reference` holders.

      Parameters:
        `closureClass` - the closure inner class node
        `localVariableParams` - the closure-shared local variable parameters

    - #### public boolean addGeneratedClosureConstructorCall(ConstructorCallExpression call)

      Emits a `super(outerInstance, thisObject)` constructor call for a generated closure class. Returns `false` if the current class is not a generated closure.

      Parameters:
        `call` - the constructor call expression representing `super(...)`
      Returns:
        `true` if the closure constructor call was emitted

    - #### protected void addSerialVersionUIDField(ClassNode classNode)

      Adds a synthetic `serialVersionUID` field to the closure class, derived from a hash of the class name.

      Parameters:
        `classNode` - the closure class node to add the field to

    - #### protected BlockStatement createBlockStatementForConstructor(ClosureExpression expression, ClassNode outerClass, ClassNode thisClassNode)

      Creates the block statement for the closure's synthetic constructor, setting up the `super(outerInstance, thisObject)` call and captured variable references.

      Parameters:
        `expression` - the closure expression
        `outerClass` - the class declaring the closure
        `thisClassNode` - the `this` type in scope at the closure declaration site
      Returns:
        the block statement for the constructor body

    - #### protected ClassNode createClosureClass(ClosureExpression expression, int modifiers)

      Creates a new inner class node representing the compiled form of a closure expression.

      Parameters:
        `expression` - the closure expression to compile
        `modifiers` - the access modifiers for the generated class
      Returns:
        the newly created closure class node

    - #### protected Parameter[] getClosureSharedVariables(ClosureExpression expression)

      Collects the closure-shared local variables referenced by a closure expression as an array of Parameters, using the type chooser to infer each variable's type.

      Parameters:
        `expression` - the closure expression
      Returns:
        the array of parameters representing captured shared variables

    - #### public ClassNode getOrAddClosureClass(ClosureExpression expression, int modifiers)

      Returns the existing generated class for a closure expression, or creates and registers a new one if none exists yet.

      Parameters:
        `expression` - the closure expression to compile as an inner class
        `modifiers` - the access modifiers for the generated class
      Returns:
        the generated closure class node

    - #### protected boolean isPackTriggered(ClosureExpression expression, boolean annotated)

      Whether a packable, non-escaping closure literal should actually be packed. Dynamic compilation has no proof of delegate-independence, so the only trigger is the `@PackedClosures` trust assertion; `StaticTypesClosureWriter` overrides this to add the `groovy.target.closure.pack` flag and the delegate-independence proof.

      Parameters:
        `annotated` - whether a non-DISABLED `@PackedClosures` is in scope

    - #### public static void loadReference(String name, WriterController controller)

      Loads a closure-shared variable reference onto the operand stack, looking it up as a field, local variable, or outer closure field as appropriate.

      Parameters:
        `name` - the variable name to load
        `controller` - the writer controller for the enclosing class

    - #### protected void loadThis()

      Loads the effective `this` reference onto the operand stack — either the actual receiver for a regular method, or the result of `getThisObject()` for a generated closure/lambda.

    - #### protected void markHoistedBody(MethodNode hoisted)

      Marks the hoisted body's compilation mode; the static writer overrides this to compile it statically.

    - #### protected boolean packedClosureUsesDelegateGuard()

      Whether the packed adapter installs the runtime delegate guard. The dynamic trust path needs it (an unverifiable assertion must fail fast on misuse); the static writer proved independence, so it overrides this to `false` and a caller-set delegate is then stored and ignored.

    - #### protected ClassNode readOnlyCaptureType(String name, ClassNode declaredType, Variable variable)

      The declared type of a read-only (by-value) capture parameter on the hoisted method. The dynamic writer types it as `Object`; the static writer overrides this to the capture's declared/flow-inferred type so the body compiles with static dispatch. This is the seam that keeps @CompileStatic-specific typing out of the general (dynamic) emitter.

    - #### protected static void removeInitialValues(Parameter[] params)

      Strips initial-value expressions from parameters that are closure-shared, ensuring the closure constructor is not duplicated.

      Parameters:
        `params` - the parameters to mutate in-place

    - #### protected String triggerDeclineReason(ClosureExpression expression)

      A trigger-specific decline reason for declineReason, or `null` if the trigger did not decline this closure. Only the static writer has one (a delegate-resolved body); the dynamic path trusts the annotation and never declines on trigger grounds.

    - #### public void writeClosure(ClosureExpression expression)

      Generates bytecode for a closure expression.

      Parameters:
        `expression` - the closure expression

    - #### public void writePackedDispatcher()

      Emits the class's packed-closure dispatch machinery, once per class at the end of class generation (so every hoisted body — including one a hoisted body itself hoisted — has claimed its id): the `$packedDispatch$(int, Object[])` table, whose case `k` casts the packed argument array (`[owner, captured..., args...]`) to target `k`'s declared parameter types and invokes it directly; the array-free per-arity tables (`$packedDispatch1$`/`$packedDispatch2$`) doing the same from plain parameter slots for the hot one/two-value shapes; and the `$getPackedDispatchers$()` accessor, whose single `invokedynamic` site links all three through `IndyInterface.packedDispatchers` (delegating to `GeneratedDispatcher.bootstrap`) into one constant bundle, lazily on first adapter creation. A no-op for classes that packed nothing.