-
Notifications
You must be signed in to change notification settings - Fork 25
feat: support jit to interpreter fallback #274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 4 commits
f0fb7cf
740c53a
2ef2b13
2505500
e6deef9
27e3d9b
37eeef0
9465748
eb27cf8
66ab6b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| # EVM JIT Fallback Design | ||
|
|
||
| ## Architecture Overview | ||
|
|
||
| The fallback mechanism involves three main components: | ||
|
|
||
| 1. **EVMMirBuilder Fallback Interface**: Generates MIR instructions to capture state and call runtime | ||
| 2. **Runtime Fallback Function**: Transfers execution state and creates interpreter instance | ||
| 3. **Interpreter State Restoration**: Resumes execution from provided EVM state | ||
|
|
||
| ## State Transfer Design | ||
|
|
||
| ### EVM State Components | ||
| The following state must be preserved during fallback: | ||
|
|
||
| - **Program Counter (PC)**: Current bytecode position | ||
| - **Stack State**: Complete evaluation stack contents and size | ||
| - **Memory State**: Memory contents and size | ||
| - **Storage State**: Already handled by EVMInstance (no transfer needed) | ||
| - **Gas State**: Remaining gas and gas costs | ||
| - **Call Context**: Caller, value, calldata (already in EVMInstance) | ||
|
|
||
| ### State Capture Mechanism | ||
|
|
||
| ```cpp | ||
| // In EVMMirBuilder | ||
| void fallbackToInterpreter(uint64_t targetPC) { | ||
| // 1. Save current PC | ||
| // 2. Flush stack state to EVMInstance | ||
| // 3. Sync memory state | ||
| // 4. Call runtime fallback function | ||
| callRuntimeFor(RuntimeFunctions.HandleFallback, targetPC); | ||
| } | ||
| ``` | ||
|
|
||
| ### Runtime Interface Design | ||
|
|
||
| ```cpp | ||
| // New runtime function signature | ||
| using FallbackFn = void (*)(zen::runtime::EVMInstance *, uint64_t); | ||
|
|
||
| // Implementation | ||
| void evmHandleFallback(zen::runtime::EVMInstance *Instance, uint64_t PC); | ||
| ``` | ||
|
|
||
| ## Interpreter Integration | ||
|
|
||
| ### State Restoration | ||
| The interpreter must be enhanced to accept initial state: | ||
|
|
||
| ```cpp | ||
| class EVMInterpreter { | ||
| // New method for state-based execution | ||
| evmc_result executeFromState(EVMInstance* instance, uint64_t startPC); | ||
|
|
||
| // Restore stack from EVMInstance | ||
| void restoreStackState(EVMInstance* instance); | ||
|
|
||
| // Memory is already accessible via EVMInstance | ||
| }; | ||
| ``` | ||
|
|
||
| ### Execution Flow | ||
|
|
||
| 1. **JIT Execution**: Normal compiled execution until fallback trigger | ||
| 2. **State Capture**: EVMMirBuilder saves all volatile state to EVMInstance | ||
| 3. **Runtime Transition**: Call evmHandleFallback with target PC | ||
| 4. **Interpreter Creation**: Runtime creates new interpreter instance | ||
| 5. **State Restoration**: Interpreter loads state from EVMInstance | ||
| 6. **Continued Execution**: Interpreter resumes from specified PC | ||
|
|
||
| ## Implementation Phases | ||
|
|
||
| ### Phase 1: Basic Infrastructure | ||
| - Add fallbackToInterpreter method to EVMMirBuilder | ||
| - Implement evmHandleFallback runtime function | ||
| - Add executeFromState method to interpreter | ||
|
|
||
| ### Phase 2: State Management | ||
| - Implement stack state synchronization | ||
| - Add memory state consistency checks | ||
| - Handle gas accounting across transition | ||
|
|
||
| ### Phase 3: Integration & Testing | ||
| - Add fallback triggers for unsupported opcodes | ||
| - Implement comprehensive test coverage | ||
| - Performance optimization and validation | ||
|
|
||
| ## Error Handling | ||
|
|
||
| ### Fallback Triggers | ||
| - Unsupported opcodes in current JIT implementation | ||
| - Complex control flow that exceeds JIT capabilities | ||
| - Runtime conditions requiring interpreter flexibility | ||
| - Explicit fallback requests for debugging/testing | ||
|
|
||
| ### Error Conditions | ||
| - Invalid PC values (must point to valid instruction boundary) | ||
| - Stack overflow/underflow during state transfer | ||
| - Memory inconsistencies between JIT and interpreter views | ||
| - Gas exhaustion during fallback process | ||
|
|
||
| ## Performance Considerations | ||
|
|
||
| ### Optimization Strategies | ||
| - Minimize state synchronization overhead | ||
| - Use efficient stack flushing mechanisms | ||
| - Avoid unnecessary memory copies | ||
| - Batch state updates when possible | ||
|
|
||
| ### Performance Monitoring | ||
| - Track fallback frequency and triggers | ||
| - Measure state transfer overhead | ||
| - Monitor interpreter performance post-fallback | ||
| - Identify optimization opportunities | ||
|
|
||
| ## Security & Determinism | ||
|
|
||
| ### Deterministic Execution | ||
| - Ensure identical results across JIT/interpreter boundary | ||
| - Maintain consistent gas accounting | ||
| - Preserve exact stack and memory semantics | ||
| - Handle edge cases identically | ||
|
|
||
| ### Security Considerations | ||
| - Validate all transferred state for consistency | ||
| - Prevent state corruption during transition | ||
| - Ensure proper error propagation | ||
| - Maintain execution context isolation | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Add EVM JIT Fallback to Interpreter | ||
|
|
||
| ## Summary | ||
| Add fallback mechanism from EVM JIT compilation to interpreter execution, enabling seamless transition when JIT compilation encounters unsupported operations or runtime conditions. | ||
|
|
||
| ## Motivation | ||
| Currently, EVM JIT compilation is an all-or-nothing approach. When the JIT compiler encounters unsupported opcodes, complex control flow, or runtime conditions that cannot be efficiently compiled, the entire execution must fall back to interpreter mode from the beginning. This results in: | ||
|
|
||
| 1. **Performance degradation**: Losing all JIT optimization benefits for the entire execution | ||
| 2. **Complexity**: Requiring complete re-execution from the start | ||
| 3. **Resource waste**: Discarding partially compiled code and optimization work | ||
|
|
||
| A mid-execution fallback mechanism would allow: | ||
| - Preserving JIT performance benefits for successfully compiled portions | ||
| - Graceful degradation only for problematic code sections | ||
| - Better overall performance for mixed workloads | ||
|
|
||
| ## Goals | ||
| - Enable EVMMirBuilder to generate fallback calls to interpreter | ||
| - Preserve complete EVM execution state (PC, stack, memory) during transition | ||
| - Allow interpreter to resume execution from arbitrary EVM state | ||
| - Maintain deterministic execution semantics across JIT/interpreter boundary | ||
|
|
||
| ## Non-Goals | ||
| - Fallback from interpreter to JIT (one-way transition only) | ||
| - Automatic re-compilation after fallback | ||
| - Cross-function fallback (limited to single function scope) | ||
|
|
||
| ## Success Criteria | ||
| - JIT-compiled EVM code can fallback to interpreter at any instruction boundary | ||
|
||
| - All EVM execution state is correctly preserved and transferred | ||
| - Interpreter can resume execution from transferred state | ||
| - Execution results are identical to pure interpreter or pure JIT execution | ||
| - Performance degradation is minimal for fallback transition overhead | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # evm-execution Specification Delta | ||
|
|
||
| ## MODIFIED Requirements | ||
|
|
||
| ### Requirement: EVM execution mode flexibility | ||
| The system SHALL support seamless transitions between JIT and interpreter execution modes within a single contract execution. | ||
|
|
||
| #### Scenario: Mid-execution mode transition | ||
| - **WHEN** JIT execution encounters a fallback condition | ||
| - **THEN** execution SHALL transition to interpreter mode | ||
| - **AND** the transition SHALL preserve all execution state | ||
| - **AND** execution results SHALL be identical to single-mode execution | ||
|
|
||
| #### Scenario: Fallback trigger conditions | ||
| - **WHEN** JIT encounters unsupported opcodes | ||
| - **OR** complex control flow exceeds JIT capabilities | ||
| - **OR** runtime conditions require interpreter flexibility | ||
| - **THEN** the system SHALL trigger fallback to interpreter | ||
| - **AND** the fallback SHALL be transparent to the calling context | ||
|
|
||
| ### Requirement: Execution state management across modes | ||
| The system SHALL maintain consistent EVM execution state regardless of execution mode transitions. | ||
|
|
||
| #### Scenario: State consistency validation | ||
| - **WHEN** execution mode changes occur | ||
| - **THEN** all EVM state components SHALL be validated for consistency | ||
| - **AND** any state corruption SHALL result in execution failure | ||
| - **AND** deterministic execution SHALL be maintained across transitions | ||
|
|
||
| #### Scenario: Cross-mode gas accounting | ||
| - **WHEN** execution transitions between JIT and interpreter | ||
| - **THEN** gas consumption SHALL be tracked continuously | ||
| - **AND** gas costs SHALL be identical regardless of execution mode | ||
| - **AND** gas exhaustion SHALL be detected consistently |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # evm-jit-fallback Specification Delta | ||
|
|
||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: JIT fallback interface in EVMMirBuilder | ||
| The EVMMirBuilder SHALL provide a fallbackToInterpreter method to transition execution from JIT to interpreter mode. | ||
|
|
||
| #### Scenario: Fallback method interface | ||
| - **WHEN** EVMMirBuilder needs to fallback to interpreter | ||
| - **THEN** it SHALL call fallbackToInterpreter(uint64_t targetPC) | ||
| - **AND** the method SHALL generate MIR instructions to save current execution state | ||
| - **AND** it SHALL call the runtime fallback function via callRuntimeFor | ||
|
|
||
| #### Scenario: State synchronization before fallback | ||
| - **WHEN** fallbackToInterpreter is called | ||
| - **THEN** the current stack state SHALL be flushed to EVMInstance | ||
| - **AND** memory state SHALL be synchronized with EVMInstance | ||
| - **AND** the target PC SHALL be validated as a valid instruction boundary | ||
|
|
||
| #### Scenario: Runtime function invocation | ||
| - **WHEN** state synchronization completes | ||
| - **THEN** EVMMirBuilder SHALL call RuntimeFunctions.HandleFallback | ||
| - **AND** the call SHALL pass the EVMInstance pointer and target PC | ||
| - **AND** the call SHALL use the existing callRuntimeFor template mechanism | ||
|
|
||
| ### Requirement: Runtime fallback function | ||
| The runtime system SHALL provide evmHandleFallback function to manage JIT-to-interpreter transition. | ||
|
|
||
| #### Scenario: Fallback function signature | ||
| - **WHEN** the runtime fallback function is defined | ||
| - **THEN** it SHALL have signature void evmHandleFallback(zen::runtime::EVMInstance *, uint64_t) | ||
| - **AND** it SHALL be registered in the RuntimeFunctions structure | ||
| - **AND** it SHALL be accessible via the existing function table mechanism | ||
|
|
||
| #### Scenario: Interpreter instance creation | ||
| - **WHEN** evmHandleFallback is called | ||
| - **THEN** it SHALL create a new interpreter instance | ||
| - **AND** the interpreter SHALL be initialized with the provided EVMInstance | ||
| - **AND** execution SHALL resume from the specified PC | ||
|
|
||
| #### Scenario: State validation during transition | ||
| - **WHEN** the fallback function processes the transition | ||
| - **THEN** it SHALL validate the target PC is within bytecode bounds | ||
| - **AND** it SHALL verify stack state consistency | ||
| - **AND** it SHALL ensure memory state integrity | ||
|
|
||
| ### Requirement: Interpreter state restoration | ||
| The EVM interpreter SHALL support execution from arbitrary EVM state provided by JIT fallback. | ||
|
|
||
| #### Scenario: State-based execution entry point | ||
| - **WHEN** interpreter receives fallback execution request | ||
| - **THEN** it SHALL provide executeFromState(EVMInstance*, uint64_t) method | ||
| - **AND** the method SHALL restore execution context from EVMInstance | ||
| - **AND** execution SHALL begin at the specified PC | ||
|
|
||
| #### Scenario: Stack state restoration | ||
| - **WHEN** executeFromState is called | ||
| - **THEN** the interpreter SHALL restore stack contents from EVMInstance | ||
| - **AND** it SHALL set the stack pointer to the correct position | ||
| - **AND** it SHALL validate stack size constraints | ||
|
|
||
| #### Scenario: Memory state consistency | ||
| - **WHEN** interpreter resumes execution | ||
| - **THEN** it SHALL use the existing memory from EVMInstance | ||
| - **AND** memory operations SHALL be consistent with JIT memory semantics | ||
| - **AND** memory size and growth behavior SHALL remain unchanged | ||
|
|
||
| ### Requirement: Execution state preservation | ||
| The fallback mechanism SHALL preserve complete EVM execution state across the JIT-interpreter boundary. | ||
|
|
||
| #### Scenario: Program counter preservation | ||
| - **WHEN** fallback occurs at instruction boundary | ||
| - **THEN** the exact PC value SHALL be preserved | ||
| - **AND** interpreter SHALL resume at the correct bytecode position | ||
| - **AND** no instructions SHALL be skipped or repeated | ||
|
|
||
| #### Scenario: Stack state preservation | ||
| - **WHEN** JIT execution has modified the stack | ||
| - **THEN** all stack values SHALL be preserved in correct order | ||
| - **AND** stack size SHALL be maintained accurately | ||
| - **AND** stack overflow/underflow conditions SHALL be preserved | ||
|
|
||
| #### Scenario: Gas accounting continuity | ||
| - **WHEN** execution transitions from JIT to interpreter | ||
| - **THEN** remaining gas SHALL be preserved exactly | ||
| - **AND** gas costs SHALL continue to be tracked consistently | ||
| - **AND** gas exhaustion conditions SHALL be handled identically |
Uh oh!
There was an error while loading. Please reload this page.