Class ClosureWriter

java.lang.Object
org.codehaus.groovy.classgen.asm.ClosureWriter
Direct Known Subclasses:
LambdaWriter, StaticTypesClosureWriter

public class ClosureWriter extends Object
Generates bytecode for closure expressions.
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    protected static class 
    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 static interface 
    Marker interface for using existing reference.
  • Field Summary

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

    Constructors
    Constructor
    Description
    Creates a closure writer with the given controller.
  • Method Summary

    Modifier and Type
    Method
    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.
    boolean
    Emits a super(outerInstance, thisObject) constructor call for a generated closure class.
    protected void
    Adds a synthetic serialVersionUID field to the closure class, derived from a hash of the class name.
    protected BlockStatement
    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[]
    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.
    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.
    static void
    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
    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
    Marks the hoisted body's compilation mode; the static writer overrides this to compile it statically.
    protected boolean
    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
    Strips initial-value expressions from parameters that are closure-shared, ensuring the closure constructor is not duplicated.
    protected String
    A trigger-specific decline reason for declineReason(org.codehaus.groovy.ast.expr.ClosureExpression), or null if the trigger did not decline this closure.
    void
    Generates bytecode for a closure expression.
    void
    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.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • OUTER_INSTANCE

      public static final String OUTER_INSTANCE
      Field name for the outer instance reference.
      See Also:
    • THIS_OBJECT

      public static final String THIS_OBJECT
      Field name for the this object reference.
      See Also:
    • controller

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

      public static final String PACKED_METHOD_PREFIX
      Name prefix of hoisted packed-closure bodies (also consulted by the static call-site writer).
      See Also:
    • GENERATED_CLOSURE_CLASS

      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.
  • Constructor Details

    • ClosureWriter

      public ClosureWriter(WriterController controller)
      Creates a closure writer with the given controller.
      Parameters:
      controller - the writer controller
  • Method Details

    • writeClosure

      public void writeClosure(ClosureExpression expression)
      Generates bytecode for a closure expression.
      Parameters:
      expression - the closure expression
    • isPackTriggered

      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
    • triggerDeclineReason

      protected String triggerDeclineReason(ClosureExpression expression)
      A trigger-specific decline reason for declineReason(org.codehaus.groovy.ast.expr.ClosureExpression), 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.
    • readOnlyCaptureType

      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.
    • markHoistedBody

      protected void markHoistedBody(MethodNode hoisted)
      Marks the hoisted body's compilation mode; the static writer overrides this to compile it statically.
    • packedClosureUsesDelegateGuard

      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.
    • writePackedDispatcher

      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.
    • loadReference

      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
    • getOrAddClosureClass

      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
    • createClosureClass

      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
    • addSerialVersionUIDField

      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
    • addConstructor

      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
    • addFieldsForLocalVariables

      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
    • createBlockStatementForConstructor

      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
    • removeInitialValues

      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
    • addGeneratedClosureConstructorCall

      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
    • getClosureSharedVariables

      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
    • loadThis

      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.