Skip to content

v1.3.5

Choose a tag to compare

@hooji hooji released this 29 Mar 01:06
· 35 commits to main since this release
ad5a250

v1.3.5 — Major Refactoring, Audit Fixes, and Robustness Improvements

Architecture Refactoring

ThreadRestorer decomposition (Stages 1–4):

  • Extract SnapshotValidator — bytecode/structure hash validation (Stage 1)
  • Extract ReflectionHelpers — method lookup, descriptor matching, bottom frame invocation (Stage 2a–2e)
  • Extract JdiValueConverter — stateless snapshot ObjectRef → JDI Value conversion (Stage 3)
  • Extract JdiLocalSetter — JDI local variable setting with frame matching, GC pinning, class preloading (Stage 4a–4c)
  • ThreadRestorer reduced from ~1150 lines to ~375 lines

PrologueInjector decomposition (v1.3.1):

  • Extract OperandStackSimulator — JVM operand stack simulation for type tracking
  • Extract PrologueEmitter — replay prologue bytecode emission
  • Extract PrologueTypes — shared data types
  • PrologueInjector reduced from ~1300 lines to ~280 lines

Bug Fixes

  • FrameSnapshot equals/hashCode/toString — lambdaBridgeInterface field was missing from all three methods, causing two snapshots differing only in lambda bridge interface to compare as equal
  • Snapshot handler deadlock — moved handler.accept() after threadRef.resume() so the handler no longer runs while the frozen thread is JDI-suspended; eliminates deadlock if handler acquires locks held by the frozen thread
  • FreezeFlag thread ID reuse — replaced Set<Long> (thread IDs) with Set<Thread> using IdentityHashMap; eliminates false positives from JVM thread ID recycling
  • Broken slot reflection — captureLocals used getMethod("slot") on a package-private method, which always threw NoSuchMethodException and silently defaulted every variable's slot to 0; removed the dead reflection entirely (restore matches by name, not slot)

Dead Code Removal

  • Removed 4 dead catch(Exception ignored) blocks in ThreadFreezer that were confirmed to never fire by running all 258 tests without them
  • Removed dead if/else branch in HeapRestorer.populateArray (both branches identical)
  • Removed unused isInfrastructureFrame static import from ThreadRestorer

Enterprise Improvements

  • Configurable timeouts via system properties:
    • durable.freeze.timeout.ms (default 30s) — caller thread wait for freeze worker
    • durable.jdi.wait.timeout.ms (default 30s) — JDI worker wait for replay thread
    • durable.restore.timeout.seconds (default 300s) — go-latch wait (existing)

CI

  • Removed ubuntu JDK 10 from matrix (intermittent Zulu failures unrelated to our code)
  • Bumped actions/checkout, actions/setup-java, actions/cache from v4 to v5 (Node.js 24)

Tests

All 258 tests pass (215 unit + 43 E2E) across JDK 8–25 on Linux, macOS, and Windows.