jvm-rs/docs/frame-interpreter.md

141 lines
4.8 KiB
Markdown

# Frame and Bytecode Interpreter
**Location**: `crates/core/src/frame/`
## Frame Structure
Each method invocation creates a `Frame` containing:
| Component | Description |
|-----------|-------------|
| Program Counter (PC) | i64 tracking current bytecode instruction |
| Operand Stack | Generic Vec-backed stack for intermediate values |
| Local Variables | Indexed slots, handles wide values (long/double occupy 2 slots) |
| Constant Pool | Arc reference to the class constant pool |
| Bytecode | Instructions for the method |
### OperandStack (`operand_stack.rs`)
- Generic Vec-backed stack with push/pop/peek operations
- `pop_n(n)` returns values in push order (not pop order) for method arguments
- Supports underflow detection
### LocalVariables (`local_vars.rs`)
- Vec-backed, indexed by slot
- Handles wide values (long, double) that occupy 2 slots with padding
- `from_args()` automatically spaces wide values correctly
- Prevents access to padding slots with runtime panic
## Execution Loop
```rust
loop {
let (offset, op) = self.next().unwrap();
self.pc = offset as i64;
let result = self.execute_instruction(op.clone());
match result {
Ok(ExecutionResult::Advance(offset)) => self.pc += offset as i64,
Ok(_) => self.pc += 1,
Err(x) => return error with stack trace,
}
}
```
## Opcode Dispatch
**Location**: `frame.rs` `execute_instruction()` (lines 199-1516)
- Single match statement over `Ops` enum variants (defined in `instructions.rs`)
- 200+ opcodes: constants, loads/stores, math, stack ops, branches, references, method invocation
- Uses helper macros (`load!`, `store!`, `binary_op!`, `shift_op!`, etc.) for common patterns
- Each opcode returns one of:
- `ExecutionResult::Continue` (auto-increment PC by 1)
- `ExecutionResult::Advance(offset)` (jump)
- `ExecutionResult::Return(())` or `ExecutionResult::ReturnValue(Value)` (exit frame)
- `VmError` on failure
## Opcode Encoding (`instructions.rs`)
- Uses `deku` derive for binary deserialization
- Each opcode has a u8 ID (0x00-0xFF)
- Some opcodes carry operands (e.g., `iload(u8)`, `goto(i16)`)
- Wide instruction prefix (0xC4) for accessing local slots > 255
## Method Invocation
**Location**: `thread.rs` (lines 308-338)
### Invocation Types
1. **`invoke()`**: Resolve method by class and descriptor, execute it
2. **`invoke_virtual()`**: Virtual dispatch - find method on actual runtime class
3. **`invoke_native()`**: Call native JNI method via FFI
### Bytecode Invocation Instructions
- **`invokevirtual`**: Virtual method dispatch - pop receiver + arguments, get actual class, call `thread.invoke_virtual()`
- **`invokespecial`**: Non-virtual (constructors, private, super) - pop receiver + arguments, call `thread.invoke()` with static resolution
- **`invokestatic`**: Static methods - pop arguments only (no receiver), call `thread.invoke()`
- **`invokeinterface`**: Interface method dispatch - similar to `invokevirtual` with interface resolution
### Frame Creation & Execution
```rust
fn execute_method(&self, class: &Arc<RuntimeClass>, method: &MethodData, args: Vec<Value>) {
let mut frame = Frame::new(
class.clone(),
method_ref,
code_attr, // Contains max_stack, max_locals, bytecode
args, // Initialize local vars with parameters
...
);
self.frame_stack.lock().push(frame.clone());
frame.execute() // Bytecode interpretation loop
self.frame_stack.lock().pop();
}
```
## Supported Instructions
### Constants
`aconst_null`, `iconst_*`, `lconst_*`, `fconst_*`, `dconst_*`, `bipush`, `sipush`, `ldc`, `ldc_w`, `ldc2_w`
### Load/Store
`iload`, `lload`, `fload`, `dload`, `aload`, `istore`, `lstore`, `fstore`, `dstore`, `astore` (including `_0-3` variants)
### Array Operations
`iaload`, `laload`, `faload`, `daload`, `aaload`, `baload`, `caload`, `saload`, `iastore`, `lastore`, `fastore`, `dastore`, `aastore`, `bastore`, `castore`, `sastore`, `arraylength`
### Stack Manipulation
`pop`, `pop2`, `dup`, `dup_x1`, `dup_x2`, `dup2`, `dup2_x1`, `dup2_x2`, `swap`
### Arithmetic
All int/long/float/double add, sub, mul, div, rem, neg operations
### Bitwise
`ishl`, `lshl`, `ishr`, `lshr`, `iushr`, `lushr`, `iand`, `land`, `ior`, `lor`, `ixor`, `lxor`
### Type Conversions
All primitive type conversions (`i2l`, `l2i`, `f2d`, etc.)
### Comparisons
`lcmp`, `fcmpl`, `fcmpg`, `dcmpl`, `dcmpg`
### Control Flow
`ifeq`, `ifne`, `iflt`, `ifge`, `ifgt`, `ifle`, `if_icmp*`, `if_acmp*`, `goto`, `ifnull`, `ifnonnull`, `tableswitch`, `lookupswitch`
### Object Operations
`new`, `newarray`, `anewarray`, `multianewarray`, `checkcast`, `instanceof`
### Field Access
`getstatic`, `putstatic`, `getfield`, `putfield`
### Method Invocation
`invokevirtual`, `invokespecial`, `invokestatic`, `invokeinterface`
### Returns
`ireturn`, `lreturn`, `freturn`, `dreturn`, `areturn`, `return`
### Synchronization
`monitorenter`, `monitorexit`