Package: org.codehaus.groovy.runtime

## [Java] Class PackedClosure

- org.codehaus.groovy.runtime.PackedClosure

-     public abstract class PackedClosure
      extends Closure

  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 (Fixed0..Fixed4, FixedIt for implicit-parameter literals, 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).

- - ### Nested Class Summary

    Nested classes
    Modifiers | Name | Description
    --- | --- | ---
    `static class` | `PackedClosure.Fixed0` | Fixed-arity members of the adapter family: the compiler instantiates the member matching the literal's declared parameter count (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 class` | `PackedClosure.Fixed1` |
    `static class` | `PackedClosure.Fixed2` |
    `static class` | `PackedClosure.Fixed3` |
    `static class` | `PackedClosure.Fixed4` |
    `static 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 class` | `PackedClosure.FixedN` | Arities above four (rare) and vararg-shaped literals (trailing array parameter, e.g.

  - Inherited fields
    Fields inherited from class | Fields
    --- | ---
    `class Closure` | `DELEGATE_FIRST, DELEGATE_ONLY, DONE, IDENTITY, OWNER_FIRST, OWNER_ONLY, TO_SELF, maximumNumberOfParameters, parameterTypes`

  - ### Constructor Summary

    Constructors
    Constructor and description
    `PackedClosure(Object owner, 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)

  - ### Methods Summary

    Methods
    Type Params | Return Type | Name and description
    --- | --- | ---
    `` | `public final Object` | `call(Object args)`
    `` | `public final Object` | `call(Object arguments)`
    `` | `public static PackedClosure` | `create(Object owner, 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 (so neither this class nor the fixed-arity family members appear on the emitted-bytecode surface).
    `` | `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.
    `` | `public void` | `setDelegate(Object delegate)`
    `` | `public void` | `setResolveStrategy(int resolveStrategy)`
    `` | `public String` | `toString()` Names the hoisted body, so diagnostics identify the literal the way a generated class's name would (`Script$_run_closure1` becomes {@code Script.

  - ### Inherited Methods Summary

    Inherited Methods
    Methods inherited from class | Name
    --- | ---
    `class Closure` | `andThen, andThenSelf, andThenSelf, asWritable, call, call, 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, setDelegate, setDirective, setMetaClass, setProperty, setResolveStrategy, throwRuntimeException, trampoline, trampoline`
    `class GroovyObjectSupport` | `getMetaClass, setMetaClass`

- - ### Constructor Detail

    - #### public PackedClosure(Object owner, 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 Detail

    - #### public final Object call(Object args)

    - #### public final Object call(Object arguments)

    - #### public static PackedClosure create(Object owner, 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 (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.

    - #### 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.

    - #### public void setDelegate(Object delegate)

    - #### public void setResolveStrategy(int resolveStrategy)

    - #### 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`).