Skip to content

Commit

Permalink
Introduction of object fields offsets
Browse files Browse the repository at this point in the history
  • Loading branch information
hextriclosan committed Nov 1, 2024
1 parent 695b190 commit 4b25cd6
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 6 deletions.
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)
}

0 comments on commit 4b25cd6

Please sign in to comment.