Package org.codehaus.groovy.runtime

# Class PackedClosure

java.lang.Object
groovy.lang.GroovyObjectSupport
groovy.lang.Closure<Object>
org.codehaus.groovy.runtime.PackedClosure

All Implemented Interfaces:
  `GroovyCallable<Object>`, `GroovyObject`, `Serializable`, `Cloneable`, `Runnable`, `Callable<Object>`

Direct Known Subclasses:
  `PackedClosure.Fixed0`, `PackedClosure.Fixed1`, `PackedClosure.Fixed2`, `PackedClosure.Fixed3`, `PackedClosure.Fixed4`, `PackedClosure.FixedIt`, `PackedClosure.FixedN`

public abstract class PackedClosure extends Closure<Object>
The shared `Closure` adapter family for `@PackedClosures` compact closure compilation.

Normally the Groovy compiler generates one inner class per closure literal (e.g. `Owner$_method_closure1`). Under `@PackedClosures` an eligible closure body is instead hoisted into a synthetic method on the enclosing ("owner") class, and the closure literal is replaced by an instance of the fixed-arity family member matching its declared parameter count (`PackedClosure.Fixed0`..`PackedClosure.Fixed4`, `PackedClosure.FixedIt` for implicit-parameter literals, `PackedClosure.FixedN` for higher and vararg arities), which dispatches back to that method. This removes the per-closure generated class (and the deeply-nested `$_closure1$_closure2$_closure3` name explosion) while still yielding a real `groovy.lang.Closure` instance, so features that operate through `call()` (iteration, `curry`, `memoize`, `trampoline`) continue to work — and the family member's declared `doCall` signature(s) give class-level introspection (SAM-overload selection, MOP method selection) exactly the view a generated closure class would present.

Dispatch goes through the hosting class's `GeneratedDispatcher` tables: the adapter holds the class's shared dispatchers, the hoisted method's compile-time id, and its own dispatch receiver (captured at construction, so `dehydrate()`/`rehydrate()` leave the closure callable). A target taking one or two values beyond the receiver — the overwhelmingly common closure shapes — dispatches through the array-free per-arity tables, passing the receiver, captured values and arguments as plain parameters; anything else packs `[receiver, captured..., args...]` into one array for the general table. Either way the chain is ordinary, JIT-friendly bytecode — no reflection, and no per-instance `MethodHandle` (which the JIT cannot constant-fold, making its invoker path many times slower than a direct call). The id binds the exact hoisted method, so an inherited packed closure can never misdispatch to a same-named method a subclass happens to declare. Argument adaptation on every route replicates metaclass dispatch on a generated closure class: arity mismatches raise `MissingMethodException`, a single `List` destructures across a non-one-parameter signature, trailing-array parameters vararg-collect, and per-parameter coercion follows the metaclass compatibility rules (including `Closure`-to-SAM).

See Also:
  - Serialized Form

- ## Nested Class Summary

  Nested Classes
  Modifier and Type
  Class
  Description
  `static final class`
  `PackedClosure.Fixed0`
  Fixed-arity members of the adapter family: the compiler instantiates the member matching the literal's declared parameter count (`PackedClosure.FixedN` serves higher arities), so a packed closure's arity is visible to class-level introspection exactly as on a generated closure class — notably `MetaClassHelper`'s SAM-overload disambiguation, which reflects the argument class's declared `doCall` and cannot consult the instance.
  `static final class`
  `PackedClosure.Fixed1`
  `static final class`
  `PackedClosure.Fixed2`
  `static final class`
  `PackedClosure.Fixed3`
  `static final class`
  `PackedClosure.Fixed4`
  `static final class`
  `PackedClosure.FixedIt`
  The implicit-parameter literal (`{ it * 2 }`): a generated closure class declares both `doCall()` and `doCall(Object)` for it, which class-level introspection reads as the fuzzy "0 or 1" arity that lets the closure match both zero- and one-parameter SAM overloads (GROOVY-10905) — so this member declares the same pair.
  `static final class`
  `PackedClosure.FixedN`
  Arities above four (rare) and vararg-shaped literals (trailing array parameter, e.g.

- ## Field Summary

  ### Fields inherited from class groovy.lang.Closure

  `DELEGATE_FIRST, DELEGATE_ONLY, DONE, IDENTITY, maximumNumberOfParameters, OWNER_FIRST, OWNER_ONLY, parameterTypes, SKIP, TO_SELF`

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `PackedClosure(Object owner, GeneratedDispatcher.Bundle dispatchers, int id, String method, Object[] captured, Class[] visibleTypes, boolean strict)`

- ## Method Summary

  Modifier and Type
  Method
  Description
  `final Object`
  `call(Object arguments)`
  Invokes the closure with given argument(s), returning any value if applicable.
  `final Object`
  `call(Object... args)`
  Invokes the closure with given argument(s), returning any value if applicable.
  `static PackedClosure`
  `create(Object owner, GeneratedDispatcher.Bundle dispatchers, int id, String method, Object[] captured, Class[] visibleTypes, boolean strict, boolean implicit, boolean vararg)`
  The single entry point for creating a packed closure, reached from generated bytecode via `ScriptBytecodeAdapter.packedClosure(java.lang.Object, java.lang.Object, int, java.lang.String, java.lang.Object[], java.lang.Class[], boolean, boolean, boolean)` (so neither this class nor the fixed-arity family members appear on the emitted-bytecode surface).
  `final Object`
  `dispatchAll(Object[] args)`
  The single dispatch entry every route funnels into: the `call` lanes, the `Fixed*` subclasses' arity-true `doCall`s, and the `PackedClosureMetaClass` short-circuit.
  `void`
  `setDelegate(Object delegate)`
  Allows the delegate to be changed such as when performing markup building
  `void`
  `setResolveStrategy(int resolveStrategy)`
  Sets the strategy which the closure uses to resolve property references and methods.
  `String`
  `toString()`
  Names the hoisted body, so diagnostics identify the literal the way a generated class's name would (`Script$_run_closure1` becomes `Script.$packed$closure$0`).

  ### Methods inherited from class groovy.lang.Closure

  `andThen, andThenSelf, andThenSelf, asWritable, call, checkForReferenceCycle, clone, compose, composeSelf, composeSelf, curry, curry, dehydrate, getDelegate, getDirective, getMaximumNumberOfParameters, getOwner, getParameterTypes, getProperty, getResolveStrategy, getThisObject, isCase, leftShift, leftShift, memoize, memoizeAtLeast, memoizeAtMost, memoizeBetween, mopUnperturbed, ncurry, ncurry, rcurry, rcurry, rehydrate, rightShift, run, setDirective, setMetaClass, setProperty, throwRuntimeException, trampoline, trampoline`

  ### Methods inherited from class groovy.lang.GroovyObjectSupport

  `getMetaClass`

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

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

  ### Methods inherited from interface groovy.lang.GroovyObject

  `invokeMethod`

- ## Constructor Details

  - ### PackedClosure

    public PackedClosure(Object owner, GeneratedDispatcher.Bundle dispatchers, int id, String method, Object[] captured, Class[] visibleTypes, boolean strict)
    Parameters:
      `owner` - the enclosing instance the hoisted method lives on (also used as thisObject; the enclosing class itself for a hoisted method in a static context)
      `dispatchers` - the hosting class's shared dispatch tables (see `GeneratedDispatcher`)
      `id` - the hoisted method's compile-time-assigned index in those tables
      `method` - the name of the hoisted synthetic method (kept for diagnostics only)
      `captured` - values captured from the enclosing scope, passed before the call arguments on every dispatch (a written capture passes its shared `groovy.lang.Reference` unchanged, so writes still propagate)
      `visibleTypes` - the closure's declared parameter types, so callers that key behaviour on `getParameterTypes()` (DGM arity/type decisions) and argument adaptation (vararg collection into a trailing array parameter) behave exactly as with a generated closure class
      `strict` - whether the delegate guard throws. `true` for the dynamic trust path (an unverifiable `@PackedClosures` assertion must fail fast on misuse); `false` when the type checker PROVED every free name owner-resolved.

- ## Method Details

  - ### create

    public static PackedClosure create(Object owner, GeneratedDispatcher.Bundle dispatchers, int id, String method, Object[] captured, Class[] visibleTypes, boolean strict, boolean implicit, boolean vararg)
    The single entry point for creating a packed closure, reached from generated bytecode via `ScriptBytecodeAdapter.packedClosure(java.lang.Object, java.lang.Object, int, java.lang.String, java.lang.Object[], java.lang.Class[], boolean, boolean, boolean)` (so neither this class nor the fixed-arity family members appear on the emitted-bytecode surface). The runtime shape switch is negligible against the object-creation cost. `implicit` marks an implicit-`it` literal (fuzzy 0/1 arity), `vararg` a trailing-array parameter; both need the varargs `doCall` that only `FixedIt`/`FixedN` declare.

  - ### setDelegate

    public void setDelegate(Object delegate)
    Description copied from class: `Closure`
    Allows the delegate to be changed such as when performing markup building
    Overrides:
      `setDelegate` in class `Closure<Object>`
    Parameters:
      `delegate` - the new delegate

  - ### setResolveStrategy

    public void setResolveStrategy(int resolveStrategy)
    Description copied from class: `Closure`
    Sets the strategy which the closure uses to resolve property references and methods. The default is Closure.OWNER_FIRST
    Overrides:
      `setResolveStrategy` in class `Closure<Object>`
    Parameters:
      `resolveStrategy` - The resolve strategy to set
    See Also:
      - `Closure.DELEGATE_FIRST`
      - `Closure.DELEGATE_ONLY`
      - `Closure.OWNER_FIRST`
      - `Closure.OWNER_ONLY`
      - `Closure.TO_SELF`

  - ### toString

    public String toString()
    Names the hoisted body, so diagnostics identify the literal the way a generated class's name would (`Script$_run_closure1` becomes `Script.$packed$closure$0`).
    Overrides:
      `toString` in class `Object`

  - ### call

    public final Object call(Object... args)
    Description copied from class: `Closure`
    Invokes the closure with given argument(s), returning any value if applicable.
    Overrides:
      `call` in class `Closure<Object>`
    Returns:
      The value if applicable or null if there is no return statement in the closure.

  - ### call

    public final Object call(Object arguments)
    Description copied from class: `Closure`
    Invokes the closure with given argument(s), returning any value if applicable.
    Overrides:
      `call` in class `Closure<Object>`
    Parameters:
      `arguments` - could be a single value or a List of values
    Returns:
      The value if applicable or null if there is no return statement in the closure.

  - ### dispatchAll

    public final Object dispatchAll(Object[] args)
    The single dispatch entry every route funnels into: the `call` lanes, the `Fixed*` subclasses' arity-true `doCall`s, and the `PackedClosureMetaClass` short-circuit. Deliberately NOT named `doCall`: a public varargs `doCall(Object[])` inherited by every family member would, under MOP-routed dispatch, exact-match a single `Object[]` argument, beat `doCall(Object)`, and spread the array — a generated closure class declares no such method, so a classed closure never spreads.