From 3c989c4c6c158edad2c7d14623f66c7cab75b77c Mon Sep 17 00:00:00 2001 From: Igor Rudenko Date: Fri, 1 Nov 2024 20:07:54 +0200 Subject: [PATCH] Introduction of object fields offsets --- tests/should_do_trivial_unsafe_things.rs | 2 +- tests/test_data/UnsafeUsage.java | 18 ++++++++++- .../jdkinternal/unsafe/trivial/Examinee.class | Bin 0 -> 343 bytes .../unsafe/trivial/UnsafeUsage.class | Bin 643 -> 1053 bytes .../unsafe/trivial/UnsafeUsage2.class | Bin 0 -> 727 bytes .../execution_engine/system_native_table.rs | 5 +++ vm/src/method_area/java_class.rs | 30 ++++++++++++++++-- vm/src/method_area/method_area.rs | 4 +-- vm/src/system_native/mod.rs | 1 + vm/src/system_native/unsafe_.rs | 25 +++++++++++++++ 10 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 tests/test_data/samples/jdkinternal/unsafe/trivial/Examinee.class create mode 100644 tests/test_data/samples/jdkinternal/unsafe/trivial/UnsafeUsage2.class create mode 100644 vm/src/system_native/unsafe_.rs diff --git a/tests/should_do_trivial_unsafe_things.rs b/tests/should_do_trivial_unsafe_things.rs index c556c124..bfebfde2 100644 --- a/tests/should_do_trivial_unsafe_things.rs +++ b/tests/should_do_trivial_unsafe_things.rs @@ -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)) } diff --git a/tests/test_data/UnsafeUsage.java b/tests/test_data/UnsafeUsage.java index 7a1f04fb..4c987c77 100644 --- a/tests/test_data/UnsafeUsage.java +++ b/tests/test_data/UnsafeUsage.java @@ -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; } diff --git a/tests/test_data/samples/jdkinternal/unsafe/trivial/Examinee.class b/tests/test_data/samples/jdkinternal/unsafe/trivial/Examinee.class new file mode 100644 index 0000000000000000000000000000000000000000..5b76e465b5a3d57f237c03289f7b5ca302f54a9b GIT binary patch literal 343 zcmYLE%TB{E5F96=p(apM3cVG$K`IdeM-Z0^BqRg}D0ioED~H5Ic~txshX{!SAHYW; z*5Saxv%6!>%td#Ev>n8>jhvQpp-$`tI3P2J zE_4ZLQ|cTW)>cZO%IML_RClPmpnuB@!w;}f@CJS;1`RetF=`;*Tfu;^507v}xDQS- M0*55rCC$Qv{|r-Lh&NX-x%Mu3h8W|0pw6kQT)(tQw&E2&-mJ9K^w zt`_(ylD5>&gssY|Wpn9Swveu6YtpxDU9MZUA@kNRJf0KTzR^eGC!Q3wgcd{k@aV6I zp%xff$?3=9m;3~C#>%orzsW;C2^#+2nH%fJK_WdM?l46F=nKvEvalLgX@ zK$=x+I|JiJAcK)X0Z4+R85r0ZI2jZflz?oI(ijG2phgA;mC3J|6m88|K&qL*s>Q(K oTnsD>JPd*iyg)fgc5Ph5YBQY-BB&97-3gx5NE~-T5F9+S^JezV(_8=e`QE<*`+t+oobtAfJJ?~UO$s}Xa`neiluB}D z*J&^9YQ-W=o0ouv(5CyEL2FG0l3}&268UyE?#byp(TfSu#zG|w>rVF{7ds5r%MX2d znyE>Wns68z%Y7FenmU=xrhR#&a?09ezxVTb?2xM^dhRksdNw+ha@UJYRu`FUgaL-T zR5hv3C~tV@U>>*TFg?CD$BM_d=incy#c+>e9U4XYduV}$DtHm^;{g%mL|vlPDL?&+ zM#znCdRXRB5Nccnq0VIx8axg{lMjNh!ViOUTx);E=9@?L%HAhzzxaF63Ov%ij~brP R>Rlq%NXSF_TsoKF{Q_PcnCSoj literal 0 HcmV?d00001 diff --git a/vm/src/execution_engine/system_native_table.rs b/vm/src/execution_engine/system_native_table.rs index 7d874791..6c6727bd 100644 --- a/vm/src/execution_engine/system_native_table.rs +++ b/vm/src/execution_engine/system_native_table.rs @@ -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; @@ -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>, ); + 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>, + ); table.insert( "jdk/internal/misc/Unsafe:arrayIndexScale0:(Ljava/lang/Class;)I", int_stub as fn(&[i32]) -> crate::error::Result>, diff --git a/vm/src/method_area/java_class.rs b/vm/src/method_area/java_class.rs index 6750f1b5..07870afe 100644 --- a/vm/src/method_area/java_class.rs +++ b/vm/src/method_area/java_class.rs @@ -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; @@ -36,11 +37,11 @@ pub(crate) struct Fields { #[derive(Debug)] pub(crate) struct FieldDescriptors { - pub(crate) descriptor_by_name: HashMap, + pub(crate) descriptor_by_name: IndexMap, } impl FieldDescriptors { - pub fn new(descriptor_by_name: HashMap) -> Self { + pub fn new(descriptor_by_name: IndexMap) -> Self { Self { descriptor_by_name } } } @@ -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 { + 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 { diff --git a/vm/src/method_area/method_area.rs b/vm/src/method_area/method_area.rs index 94a091fc..d1853073 100644 --- a/vm/src/method_area/method_area.rs +++ b/vm/src/method_area/method_area.rs @@ -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(); @@ -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, diff --git a/vm/src/system_native/mod.rs b/vm/src/system_native/mod.rs index e3d0a6ae..653096df 100644 --- a/vm/src/system_native/mod.rs +++ b/vm/src/system_native/mod.rs @@ -1,3 +1,4 @@ pub(crate) mod class; pub(crate) mod string; pub(crate) mod system; +pub(crate) mod unsafe_; diff --git a/vm/src/system_native/unsafe_.rs b/vm/src/system_native/unsafe_.rs new file mode 100644 index 00000000..8e38efb1 --- /dev/null +++ b/vm/src/system_native/unsafe_.rs @@ -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> { + 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 { + 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) +}