use crate::vm::error::{Error, Result};
use crate::vm::execution_engine::string_pool_helper::StringPoolHelper;
use crate::vm::heap::heap::{with_heap_read_lock, with_heap_write_lock};
use crate::vm::method_area::method_area::with_method_area;
use crate::vm::method_area::primitives_helper::PRIMITIVE_TYPE_BY_CODE;
use crate::vm::stack::stack_value::StackValue;
use jdescriptor::TypeDescriptor;
pub fn i32toi64(high: i32, low: i32) -> i64 {
let high_converted = (high as i64) << 32;
let low_converted = low as u32 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]
}
pub fn vec_to_i64(value: &[i32]) -> i64 {
match value.len() {
1 => value[0] as i64,
2 => i32toi64(value[0], value[1]),
_ => panic!("Invalid value length: {}", value.len()),
}
}
pub fn clazz_ref(class_name: &str) -> Result<i32> {
with_method_area(|area| {
let clazz_ref = area.load_reflection_class(class_name)?;
Ok::<i32, Error>(clazz_ref)
})
}
pub fn get_length(type_descriptor: &TypeDescriptor) -> Result<i32> {
match type_descriptor {
TypeDescriptor::Byte
| TypeDescriptor::Char
| TypeDescriptor::Integer
| TypeDescriptor::Short
| TypeDescriptor::Boolean
| TypeDescriptor::Float
| TypeDescriptor::Array(_, _)
| TypeDescriptor::Object(_) => Ok(1),
TypeDescriptor::Long | TypeDescriptor::Double => Ok(2),
TypeDescriptor::Void => Err(Error::new_execution("Void type doesn't have a length")),
}
}
pub fn default_value(type_descriptor: &TypeDescriptor) -> Result<Vec<i32>> {
match type_descriptor {
TypeDescriptor::Byte
| TypeDescriptor::Char
| TypeDescriptor::Integer
| TypeDescriptor::Short
| TypeDescriptor::Boolean => Ok(vec![0]),
TypeDescriptor::Float => Ok(0.0f32.to_vec()),
TypeDescriptor::Long => Ok(vec![0, 0]),
TypeDescriptor::Double => Ok(0.0f64.to_vec()),
TypeDescriptor::Array(_, _) => Ok(vec![0]),
TypeDescriptor::Object(_) => Ok(vec![0]),
TypeDescriptor::Void => Err(Error::new_execution("Void type doesn't have a value")),
}
}
pub fn argument_length(args: &[TypeDescriptor]) -> Result<i32> {
args.iter().map(get_length).sum()
}
pub fn strip_nest_host(class_name: &str) -> Option<&str> {
class_name.find('$').map(|index| &class_name[..index])
}
pub fn create_array_of_strings(props: &[String]) -> Result<i32> {
let class_of_array = "java/lang/String";
let class_of_array = format!("[L{class_of_array};");
let length = props.len() as i32;
let array_ref = with_heap_write_lock(|heap| heap.create_array(&class_of_array, length));
for (index, prop) in props.iter().enumerate() {
let string_ref = StringPoolHelper::get_string(prop)?;
with_heap_write_lock(|heap| {
heap.set_array_value(array_ref, index as i32, vec![string_ref])
})?
}
Ok(array_ref)
}
#[cfg(unix)]
pub fn get_fd(fd_ref: i32) -> Result<i32> {
with_heap_read_lock(|heap| {
let raw = heap.get_object_field_value(fd_ref, "java/io/FileDescriptor", "fd")?;
Ok::<i32, Error>(raw[0])
})
}
#[cfg(windows)]
pub fn get_handle(fd_ref: i32) -> Result<i64> {
with_heap_read_lock(|heap| {
let raw = heap.get_object_field_value(fd_ref, "java/io/FileDescriptor", "handle")?;
Ok::<i64, Error>(vec_to_i64(&raw))
})
}
pub fn decorate(type_name: String) -> String {
if PRIMITIVE_TYPE_BY_CODE.contains_key(type_name.as_str()) || (type_name.starts_with('[') && PRIMITIVE_TYPE_BY_CODE.contains_key(&type_name[1..])) || ((type_name.starts_with('L') || type_name.starts_with('[')) && type_name.ends_with(';'))
{
type_name
} else {
format!("L{};", type_name)
}
}
pub fn undecorate(type_name: &str) -> &str {
if type_name.starts_with('L') && type_name.ends_with(';') {
&type_name[1..type_name.len() - 1]
} else {
type_name
}
}