Repository navigation
v1.3.0
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/Callablethread 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)