diff --git a/src/bytecode.rs b/src/bytecode.rs index 690865c..c6190c5 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -22,19 +22,28 @@ impl Bytecode { 0x0E => (Instruction::PushConstDouble0(), 1), 0x0F => (Instruction::PushConstDouble1(), 1), + 0x10 => (Instruction::LoadByteImmediate(self.bytes[offset+1]), 2), 0x11 => (Instruction::LoadShortImmediate((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0x12 => (Instruction::LoadConstant(self.bytes[offset+1]), 2), 0x14 => (Instruction::LoadConstant64((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), - 0x26 => (Instruction::LoadDouble0(), 1), - 0x27 => (Instruction::LoadDouble1(), 1), - 0x28 => (Instruction::LoadDouble2(), 1), - 0x29 => (Instruction::LoadDouble3(), 1), - 0x2A => (Instruction::LoadReference0(), 1), - 0x2B => (Instruction::LoadReference1(), 1), - 0x2C => (Instruction::LoadReference2(), 1), - 0x2D => (Instruction::LoadReference3(), 1), + 0x1A => (Instruction::LoadLocalInt0(), 1), + 0x1B => (Instruction::LoadLocalInt1(), 1), + 0x1C => (Instruction::LoadLocalInt2(), 1), + 0x1D => (Instruction::LoadLocalInt3(), 1), + 0x26 => (Instruction::LoadLocalDouble0(), 1), + 0x27 => (Instruction::LoadLocalDouble1(), 1), + 0x28 => (Instruction::LoadLocalDouble2(), 1), + 0x29 => (Instruction::LoadLocalDouble3(), 1), + 0x2A => (Instruction::LoadLocalReference0(), 1), + 0x2B => (Instruction::LoadLocalReference1(), 1), + 0x2C => (Instruction::LoadLocalReference2(), 1), + 0x2D => (Instruction::LoadLocalReference3(), 1), + 0x3B => (Instruction::StoreLocalInt0(), 1), + 0x3C => (Instruction::StoreLocalInt1(), 1), + 0x3D => (Instruction::StoreLocalInt2(), 1), + 0x3E => (Instruction::StoreLocalInt3(), 1), 0x4B => (Instruction::StoreReference0(), 1), 0x4C => (Instruction::StoreReference1(), 1), 0x4D => (Instruction::StoreReference2(), 1), @@ -43,6 +52,7 @@ impl Bytecode { 0x57 => (Instruction::Pop(), 1), 0x59 => (Instruction::Duplicate(), 1), + 0x68 => (Instruction::MultiplyInt(), 1), 0x6D => (Instruction::DivideLong(), 1), 0x7A => (Instruction::ShiftIntRight(), 1), @@ -105,19 +115,28 @@ pub enum Instruction { PushConstDouble0() = 0x0E, // Push 0.0 PushConstDouble1() = 0x0F, // Push 1.0 + LoadByteImmediate(u8) = 0x10, // push immediate short LoadShortImmediate(u16) = 0x11, // push immediate short LoadConstant(u8) = 0x12, // Push from constant pool LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool + LoadLocalInt0() = 0x1A, // Load int from local variable + LoadLocalInt1() = 0x1B, // Load int from local variable + LoadLocalInt2() = 0x1C, // Load int from local variable + LoadLocalInt3() = 0x1D, // Load int from local variable - LoadDouble0() = 0x26, // Load local double variable reference onto stack - LoadDouble1() = 0x27, // Load local double variable reference onto stack - LoadDouble2() = 0x28, // Load local double variable reference onto stack - LoadDouble3() = 0x29, // Load local double variable reference onto stack - LoadReference0() = 0x2A, // Load local reference variable reference onto stack - LoadReference1() = 0x2B, // Load local reference variable reference onto stack - LoadReference2() = 0x2C, // Load local reference variable reference onto stack - LoadReference3() = 0x2D, // Load local reference variable reference onto stack + LoadLocalDouble0() = 0x26, // Load local double variable reference onto stack + LoadLocalDouble1() = 0x27, // Load local double variable reference onto stack + LoadLocalDouble2() = 0x28, // Load local double variable reference onto stack + LoadLocalDouble3() = 0x29, // Load local double variable reference onto stack + LoadLocalReference0() = 0x2A, // Load local reference variable reference onto stack + LoadLocalReference1() = 0x2B, // Load local reference variable reference onto stack + LoadLocalReference2() = 0x2C, // Load local reference variable reference onto stack + LoadLocalReference3() = 0x2D, // Load local reference variable reference onto stack + StoreLocalInt0() = 0x3B, // store int into local variable + StoreLocalInt1() = 0x3C, // store int into local variable + StoreLocalInt2() = 0x3D, // store int into local variable + StoreLocalInt3() = 0x3E, // store int into local variable StoreReference0() = 0x4B, // store reference into local variable StoreReference1() = 0x4C, // store reference into local variable StoreReference2() = 0x4D, // store reference into local variable @@ -126,6 +145,7 @@ pub enum Instruction { Pop() = 0x57, // Pop top stack value Duplicate() = 0x59, // duplicate top stack value + MultiplyInt() = 0x68, // int multiplication DivideLong() = 0x6D, // long division ShiftIntRight() = 0x7a, // shift int diff --git a/src/heap_area.rs b/src/heap_area.rs index 918ee55..70d7092 100644 --- a/src/heap_area.rs +++ b/src/heap_area.rs @@ -3,35 +3,65 @@ use std::collections::HashMap; use crate::stackframe::Value; use crate::classfile::{ AbstractTypeDescription, MethodInfo }; +#[derive(Debug)] pub struct HeapArea { + pub memory_capacity: usize, + pub memory_used: usize, pub object_area: ObjectArea, pub static_area: StaticArea, } -type ObjectReference=u32; +impl HeapArea { + pub fn new(memory_capacity: usize) -> Self { + HeapArea { + memory_capacity, + memory_used: 0, + object_area: ObjectArea::default(), + static_area: StaticArea::default(), + } + } +} +pub type ObjectReference=u32; + +const DEFAULT_COMPARTMENT_CAPACITY: usize = u16::MAX as usize; + +#[derive(Default, Debug)] pub struct ObjectArea { compartments: Vec, } +#[derive(Debug)] pub struct ObjectCompartment { - objects: Box<[HeapObject]>, + objects: Box<[ObjectCompartmentEntry]>, + first_free: usize, + reserved_count: usize, } +#[derive(Debug)] +pub enum ObjectCompartmentEntry { + Valid(HeapObject), + Empty(usize), // next empty value +} + +#[derive(Debug)] pub struct HeapObject { fields: Box<[ObjectField]>, } +#[derive(Default, Debug)] pub struct StaticArea { static_objects: HashMap, } +#[derive(Debug)] pub struct StaticObject { pub class_index: usize, pub fields: Box<[ObjectField]>, pub methods: Box<[MethodInfo]>, } +#[derive(Debug)] pub struct ObjectField { pub type_description: AbstractTypeDescription, pub value: Value, diff --git a/src/jvm.rs b/src/jvm.rs index 0b46519..8125e8a 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -1,5 +1,6 @@ use core::fmt::{Display, Formatter}; +use std::collections::VecDeque; use std::error::Error as ErrorTrait; use crate::accessmasks::{ ClassAccessFlagMask, ClassAccessFlag, MethodAccessFlagMask, MethodAccessFlag}; @@ -9,12 +10,15 @@ use crate::classfile::{ JavaClassFile, MethodInfo, MethodDescriptor, AbstractTyp use crate::classstore; use crate::classstore::ClassStore; use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo}; -use crate::stackframe::{ StackFrame, Value }; +use crate::heap_area::HeapArea; +use crate::stackframe; +use crate::stackframe::{ StackFrame, Value, OperandStack }; #[derive(Debug)] pub enum Error { ClassStoreError(classstore::Error), ClassFileError(classfile::Error), + StackFrameError(stackframe::Error, String), BadNameError(String), RunTimeError(String), OpcodeError(String), @@ -45,8 +49,9 @@ impl Display for Error { #[derive(Debug)] pub struct JVM { - class_store: ClassStore, - stack_frames: Vec, + pub class_store: ClassStore, + pub stack_frames: Vec, + pub heap_area: HeapArea, } impl JVM { @@ -54,6 +59,7 @@ impl JVM { return JVM { class_store: ClassStore::new(), stack_frames: Vec::new(), + heap_area: HeapArea::new(usize::MAX), } } @@ -130,12 +136,30 @@ impl JVM { while self.stack_frames.len() != 0 { let jvm_op = self.bytecode_loop()?; match jvm_op { - JVMCallbackOperation::PopFrame() => self.stack_frames.truncate(self.stack_frames.len() - 1), + JVMCallbackOperation::PopFrame() => { + self.stack_frames.truncate(self.stack_frames.len() - 1) + }, + + JVMCallbackOperation::ReturnFrame(value) => { + // Pop returning frame + self.stack_frames.truncate(self.stack_frames.len() - 1); + + let frame = { + let frame_index = self.stack_frames.len() - 1; + &mut self.stack_frames[frame_index] + }; + let class = self.class_store.class_file_from_idx(frame.class_index).unwrap(); + let method = & class.methods[frame.method_index as usize]; + wrap_stackframe_error(class, method, self.stack_frames.last_mut().unwrap().operand_stack.push(value))?; + } + JVMCallbackOperation::PushFrame(frame) => self.stack_frames.push(frame), + JVMCallbackOperation::LoadClass(name) => { self.class_store.load_class(&name)?; () }, + JVMCallbackOperation::InitClass(name) => { self.init_class(*self.class_store.class_idx_from_name(&name).unwrap()); } @@ -237,19 +261,70 @@ impl JVM { ))); } - let arguments = Vec::new(); - // TODO: Pass arguments + let mut arguments = VecDeque::new(); + fill_arguments(class, method, &mut arguments, &callee_method_info.descriptor.argument_types, &mut frame.operand_stack)?; let new_frame = StackFrame::new( callee_class_file, callee_class_index, callee_method_index as u16, - &arguments.into_boxed_slice(), + &arguments.make_contiguous(), ); return Ok(JVMCallbackOperation::PushFrame(new_frame)); }, + Instruction::LoadByteImmediate(byte) => { + // sign extend into int + let i8_int = i8::from_be_bytes([byte]); + + let frame_result = frame.operand_stack.push(Value::Int(i8_int as i32)); + match frame_result { + Ok(_) => (), + Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))), + } + }, + + Instruction::LoadLocalInt0() => { + load_local_int(class, method, frame, 0)?; + } + Instruction::LoadLocalInt1() => { + load_local_int(class, method, frame, 1)?; + } + Instruction::LoadLocalInt2() => { + load_local_int(class, method, frame, 2)?; + } + Instruction::LoadLocalInt3() => { + load_local_int(class, method, frame, 3)?; + } + + Instruction::MultiplyInt() => { + let factor_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let factor_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + wrap_stackframe_error(class, method, frame.operand_stack.push(Value::Int(factor_1 * factor_2)))?; + } + + Instruction::PushConstInt5() => { + let frame_result = frame.operand_stack.push(Value::Int(5)); + match frame_result { + Ok(_) => (), + Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))), + } + } + + Instruction::ReturnInt() => { + let expected_type = AbstractTypeDescription { + array_level: 0, + kind: AbstractTypeKind::Int(), + }; + if method.descriptor.return_type != expected_type { + return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type))) + } + + let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + return Ok(JVMCallbackOperation::ReturnFrame(Value::Int(int))); + } Instruction::ReturnVoid() => { let expected_type = AbstractTypeDescription { array_level: 0, @@ -263,6 +338,27 @@ impl JVM { return Ok(JVMCallbackOperation::PopFrame()); }, + Instruction::StoreLocalInt0() => { + let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + wrap_stackframe_error(class, method, frame.store_local(0, Value::Int(int)))?; + }, + Instruction::StoreLocalInt1() => { + let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(1))?; + + wrap_stackframe_error(class, method, frame.store_local(0, Value::Int(int)))?; + }, + Instruction::StoreLocalInt2() => { + let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(2))?; + + wrap_stackframe_error(class, method, frame.store_local(0, Value::Int(int)))?; + }, + Instruction::StoreLocalInt3() => { + let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(3))?; + + wrap_stackframe_error(class, method, frame.store_local(0, Value::Int(int)))?; + }, + _ => { return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction))) }, @@ -270,6 +366,7 @@ impl JVM { } } + // TODO: Review this, maybe crash when there is no return? Ok(JVMCallbackOperation::PopFrame()) } @@ -277,7 +374,168 @@ impl JVM { enum JVMCallbackOperation { PopFrame(), + ReturnFrame(Value), PushFrame(StackFrame), LoadClass(String), InitClass(String), } + +fn load_local_int(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> { + let frame_result = frame.load_local_int(index as u16); + let local_int = match frame_result { + Ok(i) => { + i + }, + Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))), + }; + + let frame_result = frame.operand_stack.push(Value::Int(local_int)); + match frame_result { + Ok(_) => Ok(()), + Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))), + } +} + +fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut VecDeque, argument_types: &Box<[AbstractTypeDescription]>, stack: &mut OperandStack) -> Result<(), Error> { + for argument_type in argument_types { + if argument_type.array_level != 0 { + // TODO: Type checking + arguments.push_front( + Value::Reference(wrap_stackframe_error(class, method, stack.pop_reference(0))?), + ) + } else { + match argument_type.kind { + AbstractTypeKind::Void() => return Err(Error::RunTimeError("Functions cannot take arguments of type void".to_string())), + // TODO: Add better description + AbstractTypeKind::Byte() => { + arguments.push_front( + Value::Byte( + wrap_stackframe_error( + class, + method, + stack.pop_byte(0) + )? + ) + ) + }, + AbstractTypeKind::Char() => { + arguments.push_front( + Value::Char( + wrap_stackframe_error( + class, + method, + stack.pop_char(0) + )? + ) + ) + }, + AbstractTypeKind::Double() => { + arguments.push_front( + Value::Double1( + wrap_stackframe_error( + class, + method, + stack.pop_double1(0) + )? + ) + ); + arguments.push_front( + Value::Double0( + wrap_stackframe_error( + class, + method, + stack.pop_double0(0) + )? + ) + ); + }, + AbstractTypeKind::Float() => { + arguments.push_front( + Value::Float( + wrap_stackframe_error( + class, + method, + stack.pop_float(0) + )? + ) + ) + }, + AbstractTypeKind::Int() => { + arguments.push_front( + Value::Int( + wrap_stackframe_error( + class, + method, + stack.pop_int(0) + )? + ) + ) + }, + AbstractTypeKind::Long() => { + arguments.push_front( + Value::Long1( + wrap_stackframe_error( + class, + method, + stack.pop_long1(0) + )? + ) + ); + arguments.push_front( + Value::Long0( + wrap_stackframe_error( + class, + method, + stack.pop_long0(0) + )? + ) + ); + }, + AbstractTypeKind::Classname(ref name) => { + // TODO: Type checking + arguments.push_front( + Value::Reference( + wrap_stackframe_error( + class, + method, + stack.pop_reference(0) + )? + ) + ) + }, + AbstractTypeKind::Short() => { + arguments.push_front( + Value::Short( + wrap_stackframe_error( + class, + method, + stack.pop_short(0) + )? + ) + ) + }, + AbstractTypeKind::Boolean() => { + arguments.push_front( + Value::Boolean( + wrap_stackframe_error( + class, + method, + stack.pop_boolean(0) + )? + ) + ) + }, + + } + } + } + + Ok(()) +} + +fn wrap_stackframe_error(class: &JavaClassFile, method: &MethodInfo, frame_result: Result) -> Result { + match frame_result { + Ok(t) => Ok(t), + Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))), + } +} diff --git a/src/main.rs b/src/main.rs index f19fe18..fd80f00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,10 @@ fn main() { &[]//&[Value::Int(1), Value::Int(2)], ).expect("failed to call main() on supplied class"); - jvm.run().unwrap(); + match jvm.run() { + Ok(()) => (), + Err(e) => println!("{:#?}", e), + }; - println!("{:#?}", jvm); + println!("{:#?}", jvm.stack_frames); } diff --git a/src/stackframe.rs b/src/stackframe.rs index 0521986..5539fbc 100644 --- a/src/stackframe.rs +++ b/src/stackframe.rs @@ -1,5 +1,5 @@ - use crate::classfile::{ JavaClassFile, AttributeData }; +use crate::heap_area::ObjectReference; #[derive(Copy, Clone, Debug)] pub enum Value { @@ -7,9 +7,9 @@ pub enum Value { Byte(u8), Char(u16), Short(u16), - Int(u32), - Float(u32), - Reference(u32), + Int(i32), + Float(f32), + Reference(ObjectReference), ReturnAddress(u32), Double0(u32), Double1(u32), @@ -24,6 +24,12 @@ pub struct OperandStack { depth: u16, } +#[derive(Debug)] +pub enum Error { + PushError(String), + LocalError(String), +} + impl OperandStack { fn new(size: u16) -> Self { return OperandStack { @@ -31,6 +37,165 @@ impl OperandStack { depth: 0, } } + + pub fn push(&mut self, value: Value) -> Result<(), Error> { + if self.depth as usize == self.stack.len() { + return Err(Error::PushError(format!("Trying to push onto full operand stack, capacity: {}, value: {:?}", self.depth, value))) + } + + self.stack[self.depth as usize] = value; + self.depth += 1; + + Ok(()) + } + + pub fn pop_boolean(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::Boolean(b) => Ok(b), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Boolean but found '{:?}'", index, value))) + } + } + + pub fn pop_byte(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + match value { + Value::Byte(b) => Ok(b), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Byte but found '{:?}'", index, value))) + } + } + + pub fn pop_char(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::Char(c) => Ok(c), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Char but found '{:?}'", index, value))) + } + } + + pub fn pop_short(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::Short(s) => Ok(s), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Short but found '{:?}'", index, value))) + } + } + + pub fn pop_int(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::Int(i) => Ok(i), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Int but found '{:?}'", index, value))) + } + } + + pub fn pop_float(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::Float(f) => Ok(f), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Float but found '{:?}'", index, value))) + } + } + + pub fn pop_reference(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::Reference(o) => Ok(o), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Reference but found '{:?}'", index, value))) + } + } + + pub fn pop_returnaddress(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::ReturnAddress(a) => Ok(a), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected ReturnAddress but found '{:?}'", index, value))) + } + } + + pub fn pop_double0(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::Double0(a) => Ok(a), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Double0 but found '{:?}'", index, value))) + } + } + + pub fn pop_double1(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::Double1(a) => Ok(a), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Double1 but found '{:?}'", index, value))) + } + } + + pub fn pop_long0(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::Long0(a) => Ok(a), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Long0 but found '{:?}'", index, value))) + } + } + + pub fn pop_long1(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + self.depth -= 1; + match value { + Value::Long1(a) => Ok(a), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Long1 but found '{:?}'", index, value))) + } + } + + pub fn pop_double(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let higher_bytes = self.stack[absolute_index]; + let lower_bytes = self.stack[absolute_index + 1]; + self.depth -= 2; + match (higher_bytes, lower_bytes) { + (Value::Double0(hi), Value::Double1(lo)) => { + let v: u64 = ((hi as u64) << 32) | lo as u64; + Ok( + f64::from_bits(v) + ) + }, + _ => Err(Error::LocalError(format!("Mismatched types at index {} of the function operand stack, expected (Double0, Double1) but found '{:?}'", index, (higher_bytes, lower_bytes)))) + } + } + + pub fn pop_long(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let higher_bytes = self.stack[absolute_index]; + let lower_bytes = self.stack[absolute_index + 1]; + self.depth -= 2; + match (higher_bytes, lower_bytes) { + (Value::Long0(hi), Value::Long1(lo)) => { + Ok(((hi as u64) << 32) | lo as u64) + }, + _ => Err(Error::LocalError(format!("Mismatched types at index {} of the function operand stack, expected (Long0, Long1) but found '{:?}'", index, (higher_bytes, lower_bytes)))) + } + } } #[derive(Debug)] @@ -65,4 +230,25 @@ impl StackFrame { instruction_pointer: 0, } } + + pub fn load_local_int(&self, index: u16) -> Result { + let local = self.locals[index as usize]; + match local { + Value::Int(i) => Ok(i), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function locals, expected Int but found '{:?}'", index, local))) + } + } + + pub fn store_local(&mut self, index: u16, value: Value) -> Result<(), Error> { + let field = self.locals.get_mut(index as usize); + match field { + Some(f) => { + *f = value; + Ok(()) + }, + None => { + Err(Error::LocalError(format!("Tried to get local at index {} when max_locals is {}", index, self.locals.len()))) + } + } + } }