|
| 1 | +# EVM JIT Fallback Design |
| 2 | + |
| 3 | +## Architecture Overview |
| 4 | + |
| 5 | +The fallback mechanism involves three main components: |
| 6 | + |
| 7 | +1. **EVMMirBuilder Fallback Interface**: Generates MIR instructions to capture state and call runtime |
| 8 | +2. **Runtime Fallback Function**: Transfers execution state and creates interpreter instance |
| 9 | +3. **Interpreter State Restoration**: Resumes execution from provided EVM state |
| 10 | + |
| 11 | +## State Transfer Design |
| 12 | + |
| 13 | +### EVM State Components |
| 14 | +The following state must be preserved during fallback: |
| 15 | + |
| 16 | +- **Program Counter (PC)**: Current bytecode position |
| 17 | +- **Stack State**: Complete evaluation stack contents and size |
| 18 | +- **Memory State**: Memory contents and size |
| 19 | +- **Storage State**: Already handled by EVMInstance (no transfer needed) |
| 20 | +- **Gas State**: Remaining gas and gas costs |
| 21 | +- **Call Context**: Caller, value, calldata (already in EVMInstance) |
| 22 | + |
| 23 | +### State Capture Mechanism |
| 24 | + |
| 25 | +```cpp |
| 26 | +// In EVMMirBuilder |
| 27 | +void fallbackToInterpreter(uint64_t targetPC) { |
| 28 | + // 1. Save current PC |
| 29 | + // 2. Sync gas |
| 30 | + // 3. Flush stack state to EVMInstance |
| 31 | + // 4. Sync memory state |
| 32 | + // 5. Call runtime fallback function |
| 33 | + callRuntimeFor(RuntimeFunctions.HandleFallback, targetPC); |
| 34 | +} |
| 35 | +``` |
| 36 | +
|
| 37 | +### Runtime Interface Design |
| 38 | +
|
| 39 | +```cpp |
| 40 | +// New runtime function signature |
| 41 | +using FallbackFn = void (*)(zen::runtime::EVMInstance *, uint64_t); |
| 42 | +
|
| 43 | +// Implementation |
| 44 | +void evmHandleFallback(zen::runtime::EVMInstance *Instance, uint64_t PC); |
| 45 | +``` |
| 46 | + |
| 47 | +## Interpreter Integration |
| 48 | + |
| 49 | +### State Restoration |
| 50 | +The interpreter must be enhanced to accept initial state: |
| 51 | + |
| 52 | +```cpp |
| 53 | +class EVMInterpreter { |
| 54 | + // New method for state-based execution |
| 55 | + evmc_result executeFromState(EVMInstance* instance, uint64_t startPC); |
| 56 | + |
| 57 | + // Restore stack from EVMInstance |
| 58 | + void restoreStackState(EVMInstance* instance); |
| 59 | + |
| 60 | + // Memory is already accessible via EVMInstance |
| 61 | +}; |
| 62 | +``` |
| 63 | +
|
| 64 | +### Execution Flow |
| 65 | +
|
| 66 | +1. **JIT Execution**: Normal compiled execution until fallback trigger |
| 67 | +2. **State Capture**: EVMMirBuilder saves all volatile state to EVMInstance |
| 68 | +3. **Runtime Transition**: Call evmHandleFallback with target PC |
| 69 | +4. **Interpreter Creation**: Runtime creates new interpreter instance |
| 70 | +5. **State Restoration**: Interpreter loads state from EVMInstance |
| 71 | +6. **Continued Execution**: Interpreter resumes from specified PC |
| 72 | +
|
| 73 | +## Implementation Phases |
| 74 | +
|
| 75 | +### Phase 1: Basic Infrastructure |
| 76 | +- Add fallbackToInterpreter method to EVMMirBuilder |
| 77 | +- Implement evmHandleFallback runtime function |
| 78 | +- Add executeFromState method to interpreter |
| 79 | +
|
| 80 | +### Phase 2: State Management |
| 81 | +- Implement stack state synchronization |
| 82 | +- Add memory state consistency checks |
| 83 | +- Handle gas accounting across transition |
| 84 | +
|
| 85 | +### Phase 3: Integration & Testing |
| 86 | +- Add fallback triggers for unsupported opcodes when block begins |
| 87 | +- Use an undefined opcode to trigger fallback when testing macro defined |
| 88 | +- Write unit tests for fallback mechanism |
| 89 | +
|
| 90 | +## Error Handling |
| 91 | +
|
| 92 | +### Fallback Triggers |
| 93 | +
|
| 94 | +The fallback mechanism will be triggered when the next JIT execution block has more than one of the following exceptions: |
| 95 | +
|
| 96 | +#### 1. Undefined Opcodes |
| 97 | +- **Invalid instructions**: When encountering opcodes that are not defined in the current EVM revision |
| 98 | +- **Unimplemented opcodes**: Instructions that exist in the specification but are not yet implemented in the JIT compiler |
| 99 | +
|
| 100 | +#### 2. Stack Overflow/Underflow |
| 101 | +- **Stack overflow**: When stack operations would exceed the maximum stack size (1024 elements) |
| 102 | +- **Stack underflow**: When attempting to pop from an empty stack or access stack elements that don't exist |
| 103 | +
|
| 104 | +#### 3. Out of Gas |
| 105 | +- **Insufficient gas**: When remaining gas is not sufficient to complete the current operation |
| 106 | +- **Gas limit exceeded**: When the total gas consumption would exceed the transaction gas limit |
| 107 | +
|
| 108 | +#### 4. Testing Triggers (Test Only) |
| 109 | +- **FALLBACK opcode**: A specific undefined opcode designated as FALLBACK to trigger fallback mechanism during testing |
| 110 | +- **Debug mode**: When testing macros are defined to force fallback for validation purposes |
| 111 | +
|
| 112 | +### Error Conditions |
| 113 | +- Invalid PC values (must point to valid instruction boundary) |
| 114 | +- Stack overflow/underflow during state transfer |
| 115 | +- Memory inconsistencies between JIT and interpreter views |
| 116 | +- Gas exhaustion during fallback process |
| 117 | +
|
| 118 | +## Performance Considerations |
| 119 | +
|
| 120 | +### Optimization Strategies |
| 121 | +- Minimize state synchronization overhead |
| 122 | +- Use efficient stack flushing mechanisms |
| 123 | +- Avoid unnecessary memory copies |
| 124 | +- Batch state updates when possible |
| 125 | +
|
| 126 | +### Performance Monitoring |
| 127 | +- Track fallback frequency and triggers |
| 128 | +- Measure state transfer overhead |
| 129 | +- Monitor interpreter performance post-fallback |
| 130 | +- Identify optimization opportunities |
| 131 | +
|
| 132 | +## Security & Determinism |
| 133 | +
|
| 134 | +### Deterministic Execution |
| 135 | +- Ensure identical results across JIT/interpreter boundary |
| 136 | +- Maintain consistent gas accounting |
| 137 | +- Preserve exact stack and memory semantics |
| 138 | +- Handle edge cases identically |
| 139 | +
|
| 140 | +### Security Considerations |
| 141 | +- Validate all transferred state for consistency |
| 142 | +- Prevent state corruption during transition |
| 143 | +- Ensure proper error propagation |
| 144 | +- Maintain execution context isolation |
0 commit comments