Skip to content

v1.3.0

Choose a tag to compare

@hooji hooji released this 26 Mar 10:43
· 108 commits to main since this release
191efc5

What's New in v1.3.0

Lambda frame support

Lambdas on the call stack are now fully supported for freeze/restore. Previously, any $$Lambda frame threw LambdaFrameException. Now the library transparently handles them.

Supported patterns:

  • Lambda as Runnable / Callable thread target
  • Lambda with captured variables from enclosing scope
  • Lambda passed as a callback to user methods
  • Method references (this::method) as functional interfaces

How it works: The library skips $$Lambda dispatch frames during freeze, detects the functional interface via JDI, and creates a java.lang.reflect.Proxy bridge at restore time. The proxy delegates to the compiler-generated synthetic method (e.g., Foo.lambda$doWork$0), whose replay prologue takes over. Captured variables — which become parameters of the synthetic method — are restored by JDI in the single-pass restore.

Not supported: Stream pipelines (stream().filter().map().collect()) and deeply-chained functional APIs.

invokedynamic instrumentation fix

Fixed VerifyError in methods that create lambdas (e.g., new Thread(() -> work(), "name")). The operand stack simulator now tracks NEW as an uninitialized reference type. Invokes whose sub-stack contains uninitialized refs (between NEW and <init>) get no-op stubs instead of invalid bytecode merge paths.

Also removed legacy invokedynamic workarounds — stubs now uniformly jump to BEFORE_INVOKE for all invoke types.

Test results

  • 131 unit tests: all pass
  • 40 E2E integration tests: all pass (4 new lambda tests)