Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduction of object fields offsets #75

Merged
merged 1 commit into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/should_do_trivial_unsafe_things.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ fn should_do_trivial_unsafe_things() {
let last_frame_value = vm
.run("samples.jdkinternal.unsafe.trivial.UnsafeUsage")
.unwrap();
assert_eq!(4, get_int(last_frame_value))
assert_eq!(3, get_int(last_frame_value))
}
18 changes: 17 additions & 1 deletion tests/test_data/UnsafeUsage.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,24 @@ public static void main(String[] args) {

int isBigEndian = !unsafe.isBigEndian() ? 1 : 0;
var bytes = (byte[]) unsafe.allocateUninitializedArray(byte.class, 3);
int bit0 = isBigEndian + bytes.length == 4 ? 1 : 0;

int result = isBigEndian + bytes.length;
String intFieldName = new String(new char[]{'f', 'i', 'e', 'l', 'd', '3'});
long fieldOffset = unsafe.objectFieldOffset(Examinee.class, intFieldName);
int bit1 = fieldOffset == 2 ? 1 : 0;

int result = 0;
result = setBit(result, 0, bit0);
result = setBit(result, 1, bit1);
}

private static int setBit(int num, int position, int value) {
return value == 0 ? num & ~(1 << position) : num | (1 << position);
}
}

class Examinee {
private int field1 = 10;
private int field2 = 20;
private int field3 = 30;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
5 changes: 5 additions & 0 deletions vm/src/execution_engine/system_native_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::system_native::class::{
};
use crate::system_native::string::intern_wrp;
use crate::system_native::system::{arraycopy_wrp, current_time_millis_wrp};
use crate::system_native::unsafe_::object_field_offset_1_wrp;
use once_cell::sync::Lazy;
use std::collections::HashMap;

Expand Down Expand Up @@ -48,6 +49,10 @@ static SYSTEM_NATIVE_TABLE: Lazy<
"jdk/internal/misc/Unsafe:arrayBaseOffset0:(Ljava/lang/Class;)I",
int_stub as fn(&[i32]) -> crate::error::Result<Vec<i32>>,
);
table.insert(
"jdk/internal/misc/Unsafe:objectFieldOffset1:(Ljava/lang/Class;Ljava/lang/String;)J",
object_field_offset_1_wrp as fn(&[i32]) -> crate::error::Result<Vec<i32>>,
);
table.insert(
"jdk/internal/misc/Unsafe:arrayIndexScale0:(Ljava/lang/Class;)I",
int_stub as fn(&[i32]) -> crate::error::Result<Vec<i32>>,
Expand Down
30 changes: 28 additions & 2 deletions vm/src/method_area/java_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use jdescriptor::TypeDescriptor;
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use indexmap::IndexMap;

const INTERFACE: u16 = 0x00000200;

Expand Down Expand Up @@ -36,11 +37,11 @@ pub(crate) struct Fields {

#[derive(Debug)]
pub(crate) struct FieldDescriptors {
pub(crate) descriptor_by_name: HashMap<String, TypeDescriptor>,
pub(crate) descriptor_by_name: IndexMap<String, TypeDescriptor>,
}

impl FieldDescriptors {
pub fn new(descriptor_by_name: HashMap<String, TypeDescriptor>) -> Self {
pub fn new(descriptor_by_name: IndexMap<String, TypeDescriptor>) -> Self {
Self { descriptor_by_name }
}
}
Expand Down Expand Up @@ -158,6 +159,31 @@ impl JavaClass {
pub fn access_flags(&self) -> u16 {
self.access_flags
}

pub fn get_field_offset(&self, field_name: &str) -> crate::error::Result<i64> {
let key = self
.non_static_field_descriptors
.descriptor_by_name
.iter()
.find_map(|(key, _)| {
let first = key.split(':')
.next()
.map(|n| n.to_string())?;
if first == field_name {
Some(key)
} else {
None
}
})
.ok_or_else(|| crate::error::Error::new_native(&format!("Field {field_name} not found")))?;

let offset = self
.non_static_field_descriptors
.descriptor_by_name.get_index_of(key)
.ok_or_else(|| crate::error::Error::new_native(&format!("Failed to get index by key {field_name}")))?;

Ok(offset as i64)
}
}

impl Methods {
Expand Down
4 changes: 2 additions & 2 deletions vm/src/method_area/method_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ impl MethodArea {
field_infos: &[FieldInfo],
cpool_helper: &CPoolHelper,
) -> crate::error::Result<(FieldDescriptors, Fields)> {
let mut non_static_field_descriptors = HashMap::new();
let mut non_static_field_descriptors = IndexMap::new();
let mut static_field_by_name = HashMap::new();
for field_info in field_infos.iter() {
let name_index = field_info.name_index();
Expand Down Expand Up @@ -393,7 +393,7 @@ impl MethodArea {
Arc::new(JavaClass::new(
Methods::new(HashMap::new()),
Fields::new(HashMap::new()),
FieldDescriptors::new(HashMap::new()),
FieldDescriptors::new(IndexMap::new()),
CPoolHelper::new(&Vec::new()),
class_name.to_string(),
None,
Expand Down
1 change: 1 addition & 0 deletions vm/src/system_native/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod class;
pub(crate) mod string;
pub(crate) mod system;
pub(crate) mod unsafe_;
25 changes: 25 additions & 0 deletions vm/src/system_native/unsafe_.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::method_area::method_area::with_method_area;
use crate::system_native::string::get_utf8_string_by_ref;

pub(crate) fn object_field_offset_1_wrp(args: &[i32]) -> crate::error::Result<Vec<i32>> {
let _unsafe_ref = args[0];
let class_ref = args[1];
let string_ref = args[2];
let offset = object_field_offset_1(class_ref, string_ref)?;

let high = ((offset >> 32) & 0xFFFFFFFF) as i32;
let low = (offset & 0xFFFFFFFF) as i32;

Ok(vec![high, low])
}
fn object_field_offset_1(class_ref: i32, string_ref: i32) -> crate::error::Result<i64> {
let field_name = get_utf8_string_by_ref(string_ref)?;
let jc = with_method_area(|area| {
let class_name = area.get_from_reflection_table(class_ref)?;
area.get(class_name.as_str())
})?;

let offset = jc.get_field_offset(&field_name)?;

Ok(offset)
}