Package org.codehaus.groovy.classgen.asm
Class ClosureWriter
java.lang.Object
org.codehaus.groovy.classgen.asm.ClosureWriter
- Direct Known Subclasses:
LambdaWriter,StaticTypesClosureWriter
Generates bytecode for closure expressions.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprotected static classVisitor that rewritesVariableExpressionnodes whose accessed variable is aFieldNodein an outer class to instead reference the corresponding field in the generated closure inner class.protected static interfaceMarker interface for using existing reference. -
Field Summary
FieldsModifier and TypeFieldDescriptionprotected final WriterControllerThe controller coordinating all bytecode writers for the current class.static final StringNode metadata key set on aClosureExpressiononce it has been compiled to a generated closure class, holding that class's name.static final StringField name for the outer instance reference.static final StringName prefix of hoisted packed-closure bodies (also consulted by the static call-site writer).static final StringField name for the this object reference. -
Constructor Summary
ConstructorsConstructorDescriptionClosureWriter(WriterController controller) Creates a closure writer with the given controller. -
Method Summary
Modifier and TypeMethodDescriptionprotected ConstructorNodeaddConstructor(ClosureExpression expression, Parameter[] localVariableParams, InnerClassNode answer, BlockStatement block) Adds a syntheticpublicconstructor to the closure inner class that accepts the outer instance,thisobject, and all captured local variable references.protected voidaddFieldsForLocalVariables(InnerClassNode closureClass, Parameter[] localVariableParams) Adds synthetic private fields to the closure inner class for each captured local variable parameter, promoting them toReferenceholders.booleanEmits asuper(outerInstance, thisObject)constructor call for a generated closure class.protected voidaddSerialVersionUIDField(ClassNode classNode) Adds a syntheticserialVersionUIDfield to the closure class, derived from a hash of the class name.protected BlockStatementcreateBlockStatementForConstructor(ClosureExpression expression, ClassNode outerClass, ClassNode thisClassNode) Creates the block statement for the closure's synthetic constructor, setting up thesuper(outerInstance, thisObject)call and captured variable references.protected ClassNodecreateClosureClass(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 ofParameters, 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 booleanisPackTriggered(ClosureExpression expression, boolean annotated) Whether a packable, non-escaping closure literal should actually be packed.static voidloadReference(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 voidloadThis()Loads the effectivethisreference onto the operand stack — either the actual receiver for a regular method, or the result ofgetThisObject()for a generated closure/lambda.protected voidmarkHoistedBody(MethodNode hoisted) Marks the hoisted body's compilation mode; the static writer overrides this to compile it statically.protected booleanWhether the packed adapter installs the runtime delegate guard.protected ClassNodereadOnlyCaptureType(String name, ClassNode declaredType, Variable variable) The declared type of a read-only (by-value) capture parameter on the hoisted method.protected static voidremoveInitialValues(Parameter[] params) Strips initial-value expressions from parameters that are closure-shared, ensuring the closure constructor is not duplicated.protected StringtriggerDeclineReason(ClosureExpression expression) A trigger-specific decline reason fordeclineReason(org.codehaus.groovy.ast.expr.ClosureExpression), ornullif the trigger did not decline this closure.voidwriteClosure(ClosureExpression expression) Generates bytecode for a closure expression.voidEmits 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 casekcasts the packed argument array ([owner, captured..., args...]) to targetk'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 singleinvokedynamicsite links all three throughIndyInterface.packedDispatchers(delegating toGeneratedDispatcher.bootstrap) into one constant bundle, lazily on first adapter creation.
-
Field Details
-
OUTER_INSTANCE
Field name for the outer instance reference.- See Also:
-
THIS_OBJECT
Field name for the this object reference.- See Also:
-
controller
The controller coordinating all bytecode writers for the current class. -
PACKED_METHOD_PREFIX
Name prefix of hoisted packed-closure bodies (also consulted by the static call-site writer).- See Also:
-
GENERATED_CLOSURE_CLASS
Node metadata key set on aClosureExpressiononce 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
Creates a closure writer with the given controller.- Parameters:
controller- the writer controller
-
-
Method Details
-
writeClosure
Generates bytecode for a closure expression.- Parameters:
expression- the closure expression
-
isPackTriggered
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@PackedClosurestrust assertion;StaticTypesClosureWriteroverrides this to add thegroovy.target.closure.packflag and the delegate-independence proof.- Parameters:
annotated- whether a non-DISABLED@PackedClosuresis in scope
-
triggerDeclineReason
A trigger-specific decline reason fordeclineReason(org.codehaus.groovy.ast.expr.ClosureExpression), ornullif 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
The declared type of a read-only (by-value) capture parameter on the hoisted method. The dynamic writer types it asObject; 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
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 tofalseand 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 casekcasts the packed argument array ([owner, captured..., args...]) to targetk'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 singleinvokedynamicsite links all three throughIndyInterface.packedDispatchers(delegating toGeneratedDispatcher.bootstrap) into one constant bundle, lazily on first adapter creation. A no-op for classes that packed nothing. -
loadReference
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 loadcontroller- the writer controller for the enclosing class
-
getOrAddClosureClass
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 classmodifiers- the access modifiers for the generated class- Returns:
- the generated closure class node
-
createClosureClass
Creates a new inner class node representing the compiled form of a closure expression.- Parameters:
expression- the closure expression to compilemodifiers- the access modifiers for the generated class- Returns:
- the newly created closure class node
-
addSerialVersionUIDField
Adds a syntheticserialVersionUIDfield 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 syntheticpublicconstructor to the closure inner class that accepts the outer instance,thisobject, and all captured local variable references.- Parameters:
expression- the closure expressionlocalVariableParams- parameters for closure-shared local variablesanswer- the closure inner class nodeblock- 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 toReferenceholders.- Parameters:
closureClass- the closure inner class nodelocalVariableParams- 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 thesuper(outerInstance, thisObject)call and captured variable references.- Parameters:
expression- the closure expressionouterClass- the class declaring the closurethisClassNode- thethistype in scope at the closure declaration site- Returns:
- the block statement for the constructor body
-
removeInitialValues
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
Emits asuper(outerInstance, thisObject)constructor call for a generated closure class. Returnsfalseif the current class is not a generated closure.- Parameters:
call- the constructor call expression representingsuper(...)- Returns:
trueif the closure constructor call was emitted
-
loadThis
protected void loadThis()Loads the effectivethisreference onto the operand stack — either the actual receiver for a regular method, or the result ofgetThisObject()for a generated closure/lambda.
-