Skip to content

Commit

Permalink
Introduce basic operations with doubles
Browse files Browse the repository at this point in the history
  • Loading branch information
hextriclosan committed Oct 16, 2024
1 parent 2021a90 commit 93a4736
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 23 deletions.
22 changes: 22 additions & 0 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,15 @@ fn should_do_subtraction_with_floats() {
assert_eq!(-998.9, get_float(last_frame_value))
}

#[test]
fn should_do_subtraction_with_doubles() {
let mut vm = VM::new("std");
let last_frame_value = vm
.run("samples.arithmetics.sub.doubles.SubDoubles")
.unwrap();
assert_eq!(-8.76543211E200, get_double(last_frame_value))
}

#[test]
fn should_do_trivial_cast() {
let mut vm = VM::new("std");
Expand Down Expand Up @@ -389,3 +398,16 @@ fn get_float(locals: Option<Vec<i32>>) -> f32 {

f32::from_bits(value as u32)
}

fn get_double(locals_opt: Option<Vec<i32>>) -> f64 {
let locals = locals_opt.unwrap();

let two = &locals[locals.len().saturating_sub(2)..];
let low = two[0] as u32;
let high = two[1] as u32;

let high_i64 = (high as u64) << 32;
let low_i64 = low as u64;

f64::from_bits(high_i64 | low_i64)
}
9 changes: 9 additions & 0 deletions tests/test_data/SubDoubles.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package samples.arithmetics.sub.doubles;

public class SubDoubles {
public static void main(String[] args) {
double first = 1.23456789e200;
double second = 1e201;
double result = first - second;
}
}
Binary file not shown.
81 changes: 70 additions & 11 deletions vm/src/execution_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use crate::execution_engine::ldc_resolution_manager::LdcResolutionManager;
use crate::execution_engine::opcode::*;
use crate::execution_engine::system_native_table::invoke_native_method;
use crate::heap::heap::{with_heap_read_lock, with_heap_write_lock};
use crate::helper::i32toi64;
use crate::method_area::instance_checker::InstanceChecker;
use crate::method_area::method_area::with_method_area;
use crate::stack::stack_frame::{i32toi64, StackFrame};
use crate::stack::stack_frame::StackFrame;
use jdescriptor::get_length;

pub(crate) struct Engine {
Expand Down Expand Up @@ -127,19 +128,13 @@ impl Engine {
println!("LDC_W -> cpoolindex={cpoolindex}, value={value}");
}
LDC2_W => {
//todo: merge me with LDC
let cpoolindex = Self::extract_two_bytes(stack_frame) as u16;

let java_class = with_method_area(|method_area| {
method_area.get(current_class_name.as_str())
})?;
let cpool_helper = java_class.cpool_helper();
let value = self
.ldc_resolution_manager
.resolve_ldc2_w(&current_class_name, cpoolindex)?;

// todo add support of other types
let value = cpool_helper.get_long(cpoolindex).ok_or_else(|| {
Error::new_constant_pool(&format!(
"Error getting value as Long by index {cpoolindex}"
))
})?;
stack_frame.push_i64(value);

stack_frame.incr_pc();
Expand Down Expand Up @@ -245,6 +240,24 @@ impl Engine {
stack_frame.incr_pc();
println!("FLOAD_1 -> value={value}");
}
DLOAD_1 => {
let (low, high, value) = stack_frame.get_two_bytes_from_local(1);

stack_frame.push(low);
stack_frame.push(high);

stack_frame.incr_pc();
println!("DLOAD_1 -> value={value}");
}
DLOAD_3 => {
let (low, high, value) = stack_frame.get_two_bytes_from_local(3);

stack_frame.push(low);
stack_frame.push(high);

stack_frame.incr_pc();
println!("DLOAD_3 -> value={value}");
}
ALOAD_0 => {
let reference = stack_frame.get_local(0);
stack_frame.push(reference);
Expand Down Expand Up @@ -362,6 +375,19 @@ impl Engine {
let value = i32toi64(high, low);
println!("LSTORE -> value={value}");
}
DSTORE => {
stack_frame.incr_pc();
let pos = stack_frame.get_bytecode_byte() as usize;
let high = stack_frame.pop();
let low = stack_frame.pop();

stack_frame.set_local(pos, low);
stack_frame.set_local(pos + 1, high);

stack_frame.incr_pc();
let value = i32toi64(high, low);
println!("DSTORE -> value={value}");
}
ASTORE => {
stack_frame.incr_pc();
let index = stack_frame.get_bytecode_byte() as usize;
Expand Down Expand Up @@ -448,6 +474,28 @@ impl Engine {
stack_frame.incr_pc();
println!("FSTORE_3 -> value={value}");
}
DSTORE_1 => {
let high = stack_frame.pop();
let low = stack_frame.pop();

stack_frame.set_local(1, low);
stack_frame.set_local(2, high);

stack_frame.incr_pc();
let value = ((high as i64) << 32) | (low as i64);
println!("DSTORE_1 -> value={value}");
}
DSTORE_3 => {
let high = stack_frame.pop();
let low = stack_frame.pop();

stack_frame.set_local(3, low);
stack_frame.set_local(4, high);

stack_frame.incr_pc();
let value = ((high as i64) << 32) | (low as i64);
println!("DSTORE_3 -> value={value}");
}
ASTORE_0 => {
let objectref = stack_frame.pop();
stack_frame.set_local(0, objectref);
Expand Down Expand Up @@ -623,6 +671,17 @@ impl Engine {
stack_frame.incr_pc();
println!("FSUB -> {a} - {b} = {result}");
}
DSUB => {
let b = f64::from_bits(stack_frame.pop_i64() as u64);
let a = f64::from_bits(stack_frame.pop_i64() as u64);

let result = a - b;

stack_frame.push_i64(result.to_bits() as i64);

stack_frame.incr_pc();
println!("DSUB -> {a} - {b} = {result}");
}
IMUL => {
let b = stack_frame.pop();
let a = stack_frame.pop();
Expand Down
50 changes: 47 additions & 3 deletions vm/src/execution_engine/ldc_resolution_manager.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::error::Error;
use crate::execution_engine::string_pool_helper::StringPoolHelper;
use crate::helper::{i32toi64, i64_to_vec};
use crate::method_area::method_area::with_method_area;
use std::collections::HashMap;
use std::sync::RwLock;

type CPoolIndex = u16;
type Value = i32;
type Value = Vec<i32>;

pub struct LdcResolutionManager {
cache: RwLock<HashMap<String, HashMap<CPoolIndex, Value>>>,
Expand All @@ -30,7 +31,7 @@ impl LdcResolutionManager {
.get(current_class_name)
.map(|map| map.get(&cpoolindex))
{
return Ok(*value);
return Ok(value[0]);
}

let java_class = with_method_area(|method_area| method_area.get(current_class_name))?;
Expand Down Expand Up @@ -58,12 +59,55 @@ impl LdcResolutionManager {
.expect("error getting cache write lock")
.entry(current_class_name.to_string())
.or_insert_with(HashMap::new)
.insert(cpoolindex, result);
.insert(cpoolindex, vec![result]);

Ok(result)
}

pub fn resolve_ldc2_w(
&self,
current_class_name: &str,
cpoolindex: u16,
) -> crate::error::Result<i64> {
if let Some(Some(value)) = self
.cache
.read()
.expect("error getting cache lock")
.get(current_class_name)
.map(|map| map.get(&cpoolindex))
{
return Ok(i32toi64(value[0], value[1]));
}

let java_class = with_method_area(|method_area| method_area.get(current_class_name))?;
let cpool_helper = java_class.cpool_helper();

let result = if let Some(value) = cpool_helper.get_long(cpoolindex) {
value
} else if let Some(value) = cpool_helper.get_double(cpoolindex) {
Self::double_to_int(value)
} else {
return Err(Error::new_constant_pool(&format!(
"Error resolving ldc: {}",
cpoolindex
)));
};

self.cache
.write()
.expect("error getting cache write lock")
.entry(current_class_name.to_string())
.or_insert_with(HashMap::new)
.insert(cpoolindex, i64_to_vec(result));

Ok(result)
}

fn float_to_int(value: f32) -> i32 {
value.to_bits() as i32
}

fn double_to_int(value: f64) -> i64 {
value.to_bits() as i64
}
}
13 changes: 13 additions & 0 deletions vm/src/helper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pub fn i32toi64(high: i32, low: i32) -> i64 {
let high_converted = (high as i64) << 32;
let low_converted = low as u32/*to prevent sign extension*/ as i64;

high_converted | low_converted
}

pub fn i64_to_vec(value: i64) -> Vec<i32> {
let low = value as i32;
let high = (value >> 32) as i32;

vec![high, low]
}
1 change: 1 addition & 0 deletions vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ pub mod vm;

mod execution_engine;
mod heap;
mod helper;
mod method_area;
mod system_native;
23 changes: 21 additions & 2 deletions vm/src/method_area/cpool_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ impl CPoolHelper {
}
}

pub fn get_double(&self, index: u16) -> Option<f64> {
match self.get(CPoolType::Double, index)? {
ConstantPool::Double { value } => Some(*value),
_ => None,
}
}

pub fn get_class(&self, index: u16) -> Option<String> {
let name_index = match self.get(CPoolType::Class, index)? {
ConstantPool::Class { name_index } => Some(name_index),
Expand Down Expand Up @@ -194,8 +201,8 @@ impl CPoolHelper {
mod tests {
use super::*;
use jclass::constant_pool::ConstantPool::{
Class, Empty, Fieldref, Float, Integer, InterfaceMethodref, Long, Methodref, NameAndType,
String, Utf8,
Class, Double, Empty, Fieldref, Float, Integer, InterfaceMethodref, Long, Methodref,
NameAndType, String, Utf8,
};

#[test]
Expand Down Expand Up @@ -555,6 +562,18 @@ mod tests {
assert_eq!(Some(3.14), actual)
}

#[test]
fn should_return_double() {
let resolver = CPoolHelper::new(&vec![
Empty,
Class { name_index: 2 },
Double { value: 4.2217E-105 },
]);

let actual = resolver.get_double(2);
assert_eq!(Some(4.2217E-105), actual)
}

#[test]
fn should_return_class_as_string() {
let resolver = CPoolHelper::new(&vec![
Expand Down
9 changes: 2 additions & 7 deletions vm/src/stack/stack_frame.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::helper::i32toi64;

#[derive(Clone)]
pub(crate) struct StackFrame {
pc: usize,
Expand Down Expand Up @@ -101,10 +103,3 @@ impl<'a> StackFrame {
&self.current_class_name
}
}

pub fn i32toi64(high: i32, low: i32) -> i64 {
let high_converted = (high as i64) << 32;
let low_converted = low as u32/*to prevent sign extension*/ as i64;

high_converted | low_converted
}

0 comments on commit 93a4736

Please sign in to comment.