# 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, method: &MethodData, args: Vec) { 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`