diff --git a/crates/core/src/class_file/class_file.rs b/crates/core/src/class_file/class_file.rs index d8ae096..fc67c13 100644 --- a/crates/core/src/class_file/class_file.rs +++ b/crates/core/src/class_file/class_file.rs @@ -1,7 +1,8 @@ use crate::attributes::{Attribute, AttributeInfo, CodeAttribute}; use crate::class_file::constant_pool::{ConstantPoolError, ConstantPoolExt, ConstantPoolOwned}; use crate::instructions::Ops; -use crate::{BaseType, FieldType, MethodDescriptor, Value}; +use crate::value::Value; +use crate::{BaseType, FieldType, MethodDescriptor}; use deku::ctx::Endian::Big; use deku::{DekuContainerRead, DekuError}; use deku_derive::{DekuRead, DekuWrite}; @@ -660,10 +661,10 @@ pub enum Constant { impl From for Value { fn from(value: Constant) -> Self { match value { - Constant::Int(x) => Value::Int(x), - Constant::Long(x) => Value::Long(x), - Constant::Float(x) => Value::Float(x), - Constant::Double(x) => Value::Double(x), + Constant::Int(x) => x.into(), + Constant::Long(x) => x.into(), + Constant::Float(x) => x.into(), + Constant::Double(x) => x.into(), Constant::String(x) => { todo!("Constant string") } diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index ed16e8a..1ed672c 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -19,8 +19,9 @@ use crate::attributes::{Attribute, CodeAttribute}; use crate::class_file::constant_pool::ConstantPoolExt; use crate::class_file::constant_pool::{ConstantPoolError, ConstantPoolGet}; use crate::class_file::{Bytecode, ClassFile, ConstantPoolEntry, MethodData}; -use crate::object::Object; +use crate::objects::array::{ArrayReference, Reference}; use crate::thread::VmThread; +use ::jni::sys::{jbyte, jchar, jdouble, jfloat, jint, jlong, jshort}; use deku::{DekuContainerRead, DekuError}; use deku_derive::{DekuRead, DekuWrite}; use env_logger::Builder; @@ -31,6 +32,7 @@ use std::fs::File; use std::io::Read; use std::ops::Deref; use std::sync::{Arc, Mutex}; +use value::{Primitive, Value}; use vm::Vm; mod attributes; @@ -42,19 +44,18 @@ mod instructions; mod jni; mod macros; mod native_libraries; -mod object; -mod object_manager; +mod objects; mod rng; mod thread; +mod value; mod vm; - -const NULL: Value = Value::Reference(None); +// const NULL: Value = Value::Reference(None); // include!(concat!(env!("OUT_DIR"), "/bindings.rs")); /// pseudo main pub fn run() { Builder::from_default_env() - .filter_level(LevelFilter::Trace) + .filter_level(LevelFilter::Info) .filter_module("deku", LevelFilter::Warn) .filter_module("jvm_rs_core::class_file::class_file", LevelFilter::Info) .filter_module("jvm_rs_core::attributes", LevelFilter::Info) @@ -110,51 +111,39 @@ pub fn run() { // vm.method(ops.clone(), code, var_table); } -/// A reference-counted, thread-safe pointer to an Object. -type ObjectRef = Arc>; - -/// Represents a JVM runtime value. -/// -/// This enum covers all primitive types and object references that can exist -/// on the operand stack or in local variables during bytecode execution. -#[derive(Debug, Clone)] -enum Value { - /// Boolean value (true/false) - Boolean(bool), - /// Unicode character - Char(u16), - /// 32-bit floating point - Float(f32), - /// 64-bit floating point - Double(f64), - /// Signed 8-bit integer - Byte(i8), - /// Signed 16-bit integer - Short(i16), - /// Signed 32-bit integer - Int(i32), - /// Signed 64-bit integer - Long(i64), - /// Reference to an object (or null) - Reference(Option), -} - -impl Display for Value { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Value::Boolean(b) => write!(f, "bool({})", b), - Value::Char(c) => write!(f, "char({})", char::from_u32(*c as u32).unwrap_or('?')), - Value::Float(fl) => write!(f, "float({})", fl), - Value::Double(d) => write!(f, "double({})", d), - Value::Byte(b) => write!(f, "byte({})", b), - Value::Short(s) => write!(f, "short({})", s), - Value::Int(i) => write!(f, "int({})", i), - Value::Long(l) => write!(f, "long({})", l), - Value::Reference(Some(obj)) => write!(f, "Ref({})", obj.lock().unwrap().id), - Value::Reference(None) => write!(f, "null"), - } - } -} +// impl Value { +// fn Int(i: i32) -> Value { +// Value::Primitive(Primitive::Int(i)) +// } +// +// fn Float(f: f32) -> Value { +// Value::Primitive(Primitive::Float(f)) +// } +// +// fn Double(d: f64) -> Value { +// Value::Primitive(Primitive::Double(d)) +// } +// +// fn Long(l: i64) -> Value { +// Value::Primitive(Primitive::Long(l)) +// } +// +// fn Char(c: u16) -> Value { +// Value::Primitive(Primitive::Char(c)) +// } +// +// fn Boolean(b: bool) -> Value { +// Value::Primitive(Primitive::Boolean(b)) +// } +// +// fn Byte(b: i8) -> Value { +// Value::Primitive(Primitive::Byte(b)) +// } +// +// fn Short(s: i16) -> Value { +// Value::Primitive(Primitive::Short(s)) +// } +// } /// Represents a JVM stack frame for method execution. /// @@ -224,13 +213,13 @@ impl Frame { let binding = self.bytecode.code.clone(); let mut ops = binding.iter(); for op in ops { - println!("Executing Op: {:?}", op); + trace!("Executing Op: {:?}", op); let result = self.execute_instruction(op); match result { - Ok(ExecutionResult::Return(c)) => return Ok(None), + Ok(ExecutionResult::Return(())) => return Ok(None), Ok(ExecutionResult::ReturnValue(val)) => return Ok(Some(val)), Ok(_) => { - println!( + trace!( "State:\n\tStack: [{}]\n\tLocals: [{}]\n", self.stack .iter() @@ -456,60 +445,60 @@ impl Frame { match op { // Constants Ops::aconst_null => { - self.stack.push(NULL); + self.stack.push(Value::NULL); Ok(ExecutionResult::Continue) } Ops::iconst_m1 => { - self.stack.push(Value::Int(-1)); + self.stack.push(Value::Primitive(Primitive::Int(-1))); Ok(ExecutionResult::Continue) } Ops::iconst_0 => { - self.stack.push(Value::Int(0)); + self.stack.push(Value::Primitive(Primitive::Int(0))); Ok(ExecutionResult::Continue) } Ops::iconst_1 => { - self.stack.push(Value::Int(1)); + self.stack.push(Value::Primitive(Primitive::Int(1))); Ok(ExecutionResult::Continue) } Ops::iconst_2 => { - self.stack.push(Value::Int(2)); + self.stack.push(Value::Primitive(Primitive::Int(2))); Ok(ExecutionResult::Continue) } Ops::iconst_3 => { - self.stack.push(Value::Int(3)); + self.stack.push(Value::Primitive(Primitive::Int(3))); Ok(ExecutionResult::Continue) } Ops::iconst_4 => { - self.stack.push(Value::Int(4)); + self.stack.push(4.into()); Ok(ExecutionResult::Continue) } Ops::iconst_5 => { - self.stack.push(Value::Int(5)); + self.stack.push(5.into()); Ok(ExecutionResult::Continue) } Ops::bipush(byte) => { - self.stack.push(Value::Int(*byte as i32)); + self.stack.push((*byte as i32).into()); Ok(ExecutionResult::Continue) } Ops::ldc(index) => { let thing = self.pool.get_constant(index.to_owned() as u16)?; - println!("\tLoading constant: {}", thing); + trace!("\tLoading constant: {}", thing); let resolved: Option = match thing { ConstantPoolEntry::Utf8(x) => { - println!("{:?}", String::from_utf8(x.bytes.clone())); + warn!("{:?}", String::from_utf8(x.bytes.clone())); warn!("Utf8 loading not yet implemented"); None } - ConstantPoolEntry::Integer(x) => Some(Value::Int(x.clone())), - ConstantPoolEntry::Float(x) => Some(Value::Float(x.clone())), + ConstantPoolEntry::Integer(x) => Some(Value::from(*x)), + ConstantPoolEntry::Float(x) => Some(Value::from(*x)), ConstantPoolEntry::Class(x) => None, ConstantPoolEntry::String(x) => { warn!("String loading not yet implemented"); @@ -543,10 +532,10 @@ impl Frame { } Ops::ldc2_w(index) => { let val = self.pool.get_constant(*index)?; - println!("\tLoading constant: {}", val); + trace!("\tLoading constant: {}", val); let resolved = match val { - ConstantPoolEntry::Double(x) => Some(Value::Double(x.clone())), - ConstantPoolEntry::Long(x) => Some(Value::Long(x.clone())), + ConstantPoolEntry::Double(x) => Some(Value::from(*x)), + ConstantPoolEntry::Long(x) => Some(Value::from(*x)), _ => None, }; if let Some(x) = resolved { @@ -636,6 +625,22 @@ impl Frame { } // store + Ops::istore(index) => { + store!(self, i, *index as usize) + } + Ops::istore_0 => { + store!(self, i, 0) + } + Ops::istore_1 => { + store!(self, i, 1) + } + Ops::istore_2 => { + store!(self, i, 2) + } + Ops::istore_3 => { + store!(self, i, 3) + } + Ops::fstore(index) => { store!(self, f, *index as usize) } @@ -651,6 +656,7 @@ impl Frame { Ops::fstore_3 => { store!(self, f, 3) } + Ops::dstore(index) => { store!(self, d, *index as usize) } @@ -663,10 +669,10 @@ impl Frame { Ops::dstore_2 => { store!(self, d, 2) } - Ops::dstore_3 => { store!(self, d, 3) } + Ops::lstore(index) => { store!(self, l, *index as usize) } @@ -679,11 +685,47 @@ impl Frame { Ops::lstore_2 => { store!(self, l, 2) } - Ops::lstore_3 => { store!(self, l, 3) } + Ops::astore(index) => { + store!(self, a, *index as usize) + } + Ops::astore_0 => { + store!(self, a, 0) + } + Ops::astore_1 => { + store!(self, a, 1) + } + Ops::astore_2 => { + store!(self, a, 2) + } + Ops::astore_3 => { + store!(self, a, 3) + } + Ops::iastore => { + let Value::Primitive(Primitive::Int(value)) = + self.stack.pop().expect("value on stack") + else { + panic!("Value on stack was not int") + }; + let Value::Primitive(Primitive::Int(index)) = + self.stack.pop().expect("value on stack") + else { + panic!("index on stack was not int") + }; + let Value::Reference(Some(Reference::ArrayReference(ArrayReference::Primitive( + arr, + )))) = self.stack.pop().expect("value on stack") + else { + panic!("Reference not on stack") + }; + let (id, array) = *arr.lock().unwrap(); + + Ok(ExecutionResult::Continue) + } + //Stack Ops::dup => { if let Some(value) = self.stack.last() { @@ -698,10 +740,12 @@ impl Frame { Ops::dadd => { let value1 = self.stack.pop().expect("Stack must have value"); let value2 = self.stack.pop().expect("Stack must have value"); - if let (Value::Double(double1), Value::Double(double2)) = - (value1.clone(), value2.clone()) + if let ( + Value::Primitive(Primitive::Double(double1)), + Value::Primitive(Primitive::Double(double2)), + ) = (value1.clone(), value2.clone()) { - self.stack.push(Value::Double(double1 + double2)); + self.stack.push(Value::from(double1 + double2)); Ok(ExecutionResult::Continue) } else { Err(VmError::StackError(format!( @@ -710,11 +754,53 @@ impl Frame { } } - //Conversions + // Conversions + Ops::i2l => { + if let Value::Primitive(Primitive::Int(int)) = + self.stack.pop().expect("Stack must have value") + { + let long: i64 = int.into(); + self.stack.push(Value::from(long)); + Ok(ExecutionResult::Continue) + } else { + Err(VmError::StackError("Popped value was not int".to_string())) + } + } + Ops::i2f => { + todo!("int to float cast") + } + Ops::i2d => { + if let Value::Primitive(Primitive::Int(int)) = + self.stack.pop().expect("Stack must have value") + { + let double: f64 = int.into(); + self.stack.push(Value::from(double)); + Ok(ExecutionResult::Continue) + } else { + Err(VmError::StackError("Popped value was not int".to_string())) + } + } + Ops::l2i => { + todo!("long to int cast") + } + Ops::l2f => { + todo!("long to float cast") + } + Ops::l2d => { + todo!("long to double cast") + } + Ops::f2i => { + todo!("float to int cast") + } + Ops::f2l => { + todo!("float to long cast") + } Ops::f2d => { - if let Value::Float(float) = self.stack.pop().expect("Stack must have value") { + if let Value::Primitive(Primitive::Float(float)) = + self.stack.pop().expect("Stack must have value") + { let double: f64 = float.into(); - self.stack.push(Value::Double(double)); + self.stack.push(Value::from(double)); Ok(ExecutionResult::Continue) } else { Err(VmError::StackError( @@ -722,6 +808,33 @@ impl Frame { )) } } + Ops::d2i => { + todo!("double to int cast") + } + Ops::d2l => { + if let Value::Primitive(Primitive::Double(double)) = + self.stack.pop().expect("Stack must have value") + { + let long: i64 = double as i64; + self.stack.push(Value::from(long)); + Ok(ExecutionResult::Continue) + } else { + Err(VmError::StackError("Popped value was not int".to_string())) + } + } + Ops::d2f => { + todo!("double to float cast") + } + Ops::i2b => { + todo!("int to byte cast") + } + Ops::i2c => { + todo!("int to char cast") + } + Ops::i2s => { + todo!("int to short cast") + } + // Control Ops::return_void => Ok(ExecutionResult::Return(())), @@ -767,22 +880,31 @@ impl Frame { } Ops::getfield(index) => { - todo!("op getfield: index - {}", index) + let field_ref = self.pool.resolve_field(*index)?; + trace!("Getting field {field_ref:?}"); + if let Value::Reference(object_ref) = + self.stack.pop().expect("object reference on stack") + { + if let Some(Reference::ObjectReference(object)) = object_ref { + let val = object.lock().unwrap().get_field(&field_ref.name); + self.stack.push(val); + Ok(ExecutionResult::Continue) + } else { + Err(VmError::StackError("Null pointer exception".to_string())) + } + } else { + Err(VmError::StackError( + "putfield tried to operate on a non object stack value".to_string(), + )) + } } Ops::putfield(index) => { let field_ref = self.pool.resolve_field(*index)?; trace!("Setting field {field_ref:?}"); - let init_class = self - .thread - .get_class(&field_ref.class) - .expect("pre initialised class"); - // let static_field = init_class - // .find_field(&field_ref.name, field_ref.desc) - // .expect("TO hecken work"); let value = self.stack.pop().expect("value on stack"); if let Value::Reference(reference) = self.stack.pop().expect("object on stack") { - if let Some(object) = reference { + if let Some(Reference::ObjectReference(object)) = reference { object.lock().unwrap().set_field(&field_ref.name, value); Ok(ExecutionResult::Continue) } else { @@ -843,6 +965,14 @@ impl Frame { Ok(ExecutionResult::Continue) } + Ops::invokeinterface(_, _, _) => { + todo!("invokeInterface") + } + + Ops::invokedynamic(_, _) => { + todo!("invokeDynamic") + } + // can init class Ops::new(index) => { let class = self.pool.resolve_class_name(*index)?; @@ -851,11 +981,44 @@ impl Frame { .thread .get_or_resolve_class(&class, self.thread.clone()) .expect("TO hecken work"); - let object = self.thread.gc.write().unwrap().new(init_class); - self.stack.push(Value::Reference(Some(object))); + let object = self.thread.gc.write().unwrap().new_object(init_class); + self.stack + .push(Value::Reference(Some(Reference::from(object)))); Ok(ExecutionResult::Continue) - // todo!("'New' instruction") } + + Ops::newarray(array_type) => { + let value = self.stack.pop().expect("value to have stack"); + let Value::Primitive(Primitive::Int(count)) = value else { + panic!("stack item was not int") + }; + let array = self.thread.gc.write().unwrap().new_primitive_array(); + self.stack + .push(Value::Reference(Some(Reference::from(array)))); + Ok(ExecutionResult::Continue) + } + Ops::anewarray(_) => { + todo!("anewarray") + } + Ops::arraylength => { + todo!("arraylength") + } + Ops::athrow => { + todo!("athrow") + } + Ops::checkcast(_) => { + todo!("checkcast") + } + Ops::instanceof(_) => { + todo!("instanceof") + } + Ops::monitorenter => { + todo!("monitorenter") + } + Ops::monitorexit => { + todo!("monitorexit") + } + _ => { todo!("Unimplemented op: {:?}", op) } diff --git a/crates/core/src/macros.rs b/crates/core/src/macros.rs index 9d9d150..e3a7382 100644 --- a/crates/core/src/macros.rs +++ b/crates/core/src/macros.rs @@ -1,5 +1,5 @@ use crate::class_file::constant_pool::ConstantPoolError; -use crate::Value; +use crate::value::Value; #[macro_export] macro_rules! store { @@ -7,7 +7,7 @@ macro_rules! store { { let index: usize = $index; let value = $self.stack.pop().expect("Must contain value on stack"); - println!("\tStoring: {value:?} into local[{index}]"); + trace!("\tStoring: {value:?} into local[{index}]"); $self.vars[index] = value; $self.vars[index + 1] = Value::Reference(None); Ok(ExecutionResult::Continue) @@ -20,7 +20,7 @@ macro_rules! store { { let index: usize = $index; let value = $self.stack.pop().expect("Must contain value on stack"); - println!("\tStoring: {value:?} into local[{index}]"); + trace!("\tStoring: {value:?} into local[{index}]"); $self.vars[index] = value; Ok(ExecutionResult::Continue) } @@ -28,6 +28,9 @@ macro_rules! store { ($self:expr, f, $index:expr) => { store!($self, i, $index) }; + ($self:expr, a, $index:expr) => { + store!($self, i, $index) + }; } #[macro_export] @@ -36,7 +39,7 @@ macro_rules! load { { let index: usize = $index; let value = $self.vars.get(index).expect("Local var to exist"); - println!("\tLoading: local[{index}] - {value} onto stack"); + trace!("\tLoading: local[{index}] - {value} onto stack"); $self.stack.push(value.clone()); Ok(ExecutionResult::Continue) } diff --git a/crates/core/src/objects/array.rs b/crates/core/src/objects/array.rs new file mode 100644 index 0000000..9a105a0 --- /dev/null +++ b/crates/core/src/objects/array.rs @@ -0,0 +1,63 @@ +use crate::objects::object::{Object, ObjectReference}; +use crate::value::{Primitive, Value}; +use std::fmt::{Display, Formatter}; +use std::sync::{Arc, Mutex}; + +#[derive(Debug, Clone)] +pub enum Reference { + ObjectReference(ObjectReference), + ArrayReference(ArrayReference), +} + +impl Display for Reference { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let id = match self { + Reference::ObjectReference(x) => x.lock().unwrap().id, + Reference::ArrayReference(ArrayReference::Primitive(x)) => x.lock().unwrap().0, + Reference::ArrayReference(ArrayReference::Object(x)) => x.lock().unwrap().0, + }; + write!(f, "{}", id) + } +} + +impl From for Reference { + fn from(value: ObjectReference) -> Self { + Self::ObjectReference(value) + } +} + +impl From for Reference { + fn from(value: PrimitiveArrayReference) -> Self { + Self::ArrayReference(ArrayReference::Primitive(value)) + } +} + +impl From for Reference { + fn from(value: ObjectArrayReference) -> Self { + Self::ArrayReference(ArrayReference::Object(value)) + } +} + +#[derive(Debug, Clone)] +pub enum ArrayReference { + Primitive(PrimitiveArrayReference), + Object(ObjectArrayReference), +} + +pub type PrimitiveArrayReference = Arc>; +type PrimitiveArray = (u32, Vec); + +pub type ObjectArrayReference = Arc>; +type ObjectArray = (u32, Vec); + +#[derive(Debug)] +pub struct Array { + id: u32, + backing: Vec, +} + +impl Array { + fn set(&self, index: i32, value: Value) { + let thing : [100, u32] + } +} diff --git a/crates/core/src/objects/mod.rs b/crates/core/src/objects/mod.rs new file mode 100644 index 0000000..da0b02b --- /dev/null +++ b/crates/core/src/objects/mod.rs @@ -0,0 +1,3 @@ +pub mod array; +pub mod object; +pub mod object_manager; diff --git a/crates/core/src/object.rs b/crates/core/src/objects/object.rs similarity index 73% rename from crates/core/src/object.rs rename to crates/core/src/objects/object.rs index 1ae86b5..90f205c 100644 --- a/crates/core/src/object.rs +++ b/crates/core/src/objects/object.rs @@ -1,12 +1,12 @@ use crate::class::RuntimeClass; -use crate::class_file::ClassFile; -use crate::Value; +use crate::value::Value; use dashmap::DashMap; use log::trace; -use std::cell::RefCell; use std::fmt::Display; use std::sync::{Arc, Mutex}; +pub type ObjectReference = Arc>; + #[derive(Debug, Clone)] pub struct Object { pub id: u32, @@ -20,6 +20,14 @@ impl Object { trace!("Setting '{}' to '{}'", field_name, value); self.fields.insert(field_name.to_string(), value); } + + pub fn get_field(&self, field_name: &str) -> Value { + trace!("Fields for object:\n\t{:?}", self.fields); + self.fields + .get(&field_name.to_string()) + .map(|e| e.clone()) + .unwrap_or(Value::NULL) + } } impl Display for Object { diff --git a/crates/core/src/thread.rs b/crates/core/src/thread.rs index 6fb8e67..f8acfa0 100644 --- a/crates/core/src/thread.rs +++ b/crates/core/src/thread.rs @@ -2,9 +2,10 @@ use crate::class::RuntimeClass; use crate::class_file::{ClassFile, MethodData, MethodRef}; use crate::class_loader::{ClassLoader, LoaderRef}; use crate::jni::create_jni_function_table; -use crate::object_manager::ObjectManager; +use crate::objects::object_manager::ObjectManager; +use crate::value::{Primitive, Value}; use crate::vm::Vm; -use crate::{BaseType, FieldType, Frame, MethodDescriptor, Value, VmError}; +use crate::{BaseType, FieldType, Frame, MethodDescriptor, VmError}; use deku::DekuError::Incomplete; use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jobject, jshort}; use jni::JNIEnv; @@ -255,35 +256,35 @@ impl VmThread { } Some(FieldType::Base(BaseType::Long)) => { let v = cif.call::(cp, built_args.as_ref()); - Ok(Some(Value::Long(v))) + Ok(Some(Value::Primitive(Primitive::Long(v)))) } Some(FieldType::Base(BaseType::Int)) => { let v = cif.call::(cp, built_args.as_ref()); - Ok(Some(Value::Int(v))) + Ok(Some(v.into())) } Some(FieldType::Base(BaseType::Float)) => { let v = cif.call::(cp, built_args.as_ref()); - Ok(Some(Value::Float(v))) + Ok(Some(v.into())) } Some(FieldType::Base(BaseType::Double)) => { let v = cif.call::(cp, built_args.as_ref()); - Ok(Some(Value::Double(v))) + Ok(Some(v.into())) } Some(FieldType::Base(BaseType::Boolean)) => { let v = cif.call::(cp, built_args.as_ref()); - Ok(Some(Value::Int(v as i32))) + Ok(Some(v.into())) } Some(FieldType::Base(BaseType::Byte)) => { let v = cif.call::(cp, built_args.as_ref()); - Ok(Some(Value::Byte(v))) + Ok(Some(v.into())) } Some(FieldType::Base(BaseType::Char)) => { let v = cif.call::(cp, built_args.as_ref()); - Ok(Some(Value::Char(v))) + Ok(Some(v.into())) } Some(FieldType::Base(BaseType::Short)) => { let v = cif.call::(cp, built_args.as_ref()); - Ok(Some(Value::Short(v))) + Ok(Some(v.into())) } Some(FieldType::ClassType(_)) | Some(FieldType::ArrayType(_)) => { let v = cif.call::(cp, built_args.as_ref()); @@ -304,14 +305,14 @@ fn build_args<'a>(params: Vec, storage: &'a mut Vec>) -> Vec for value in params { match value { - Value::Int(x) => storage.push(Box::new(x) as Box), - Value::Boolean(x) => storage.push(Box::new(x) as Box), - Value::Char(x) => storage.push(Box::new(x) as Box), - Value::Float(x) => storage.push(Box::new(x) as Box), - Value::Double(x) => storage.push(Box::new(x) as Box), - Value::Byte(x) => storage.push(Box::new(x) as Box), - Value::Short(x) => storage.push(Box::new(x) as Box), - Value::Long(x) => storage.push(Box::new(x) as Box), + Value::Primitive(Primitive::Int(x)) => storage.push(Box::new(x) as Box), + Value::Primitive(Primitive::Boolean(x)) => storage.push(Box::new(x) as Box), + Value::Primitive(Primitive::Char(x)) => storage.push(Box::new(x) as Box), + Value::Primitive(Primitive::Float(x)) => storage.push(Box::new(x) as Box), + Value::Primitive(Primitive::Double(x)) => storage.push(Box::new(x) as Box), + Value::Primitive(Primitive::Byte(x)) => storage.push(Box::new(x) as Box), + Value::Primitive(Primitive::Short(x)) => storage.push(Box::new(x) as Box), + Value::Primitive(Primitive::Long(x)) => storage.push(Box::new(x) as Box), Value::Reference(x) => storage.push(Box::new(x) as Box), } } diff --git a/crates/core/src/value.rs b/crates/core/src/value.rs new file mode 100644 index 0000000..3cbd08a --- /dev/null +++ b/crates/core/src/value.rs @@ -0,0 +1,89 @@ +use crate::objects::array::Reference; +use crate::objects::object::ObjectReference; +use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort}; +use std::fmt::{Display, Formatter}; + +/// A reference-counted, thread-safe pointer to an Object. + +/// Represents a JVM runtime value. +/// +/// This enum covers all primitive types and object references that can exist +/// on the operand stack or in local variables during bytecode execution. +#[derive(Debug, Clone)] +pub enum Value { + Primitive(Primitive), + /// Reference to an object (or null) + Reference(Option), +} + +macro_rules! impl_value_from { + ($type:ty, $variant:ident) => { + impl From<$type> for Value { + fn from(value: $type) -> Self { + Self::Primitive(Primitive::$variant(value)) + } + } + }; +} +impl_value_from!(jint, Int); +impl_value_from!(jlong, Long); +impl_value_from!(jfloat, Float); +impl_value_from!(jdouble, Double); +impl_value_from!(jbyte, Byte); +impl_value_from!(jshort, Short); +impl_value_from!(jchar, Char); + +impl From for Value { + fn from(value: jboolean) -> Self { + Self::Primitive(Primitive::Boolean(value != 0)) + } +} + +#[derive(Debug, Clone)] +pub enum Primitive { + /// Boolean value (true/false) + Boolean(bool), + /// Unicode character + Char(u16), + /// 32-bit floating point + Float(f32), + /// 64-bit floating point + Double(f64), + /// Signed 8-bit integer + Byte(i8), + /// Signed 16-bit integer + Short(i16), + /// Signed 32-bit integer + Int(i32), + /// Signed 64-bit integer + Long(i64), +} + +impl Display for Primitive { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Primitive::Boolean(b) => write!(f, "bool({})", b), + Primitive::Char(c) => write!(f, "char({})", char::from_u32(*c as u32).unwrap_or('?')), + Primitive::Float(fl) => write!(f, "float({})", fl), + Primitive::Double(d) => write!(f, "double({})", d), + Primitive::Byte(b) => write!(f, "byte({})", b), + Primitive::Short(s) => write!(f, "short({})", s), + Primitive::Int(i) => write!(f, "int({})", i), + Primitive::Long(l) => write!(f, "long({})", l), + } + } +} + +impl Value { + pub const NULL: Value = Value::Reference(None); +} + +impl Display for Value { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Value::Primitive(prim) => write!(f, "{}", prim), + Value::Reference(Some(obj)) => write!(f, "Ref({})", obj), + Value::Reference(None) => write!(f, "null"), + } + } +} diff --git a/crates/core/src/vm.rs b/crates/core/src/vm.rs index e235dc2..edab94c 100644 --- a/crates/core/src/vm.rs +++ b/crates/core/src/vm.rs @@ -1,7 +1,7 @@ use crate::class_file::ClassFile; use crate::class_loader::ClassLoader; -use crate::object::Object; -use crate::object_manager::ObjectManager; +use crate::objects::object::Object; +use crate::objects::object_manager::ObjectManager; use crate::thread::VmThread; use crate::Frame; use libloading::os::windows::Symbol;