From 4229b5141c79059d99f9fd251c4489a84401b0a8 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Sun, 2 Feb 2025 20:46:51 -0500 Subject: [PATCH] wip --- Cargo.toml | 19 +- classfile/src/attribute/resolved.rs | 13 +- classfile/src/constant_pool/types.rs | 30 ++- generators/Cargo.toml | 17 -- generators/vm_symbols/Cargo.toml | 2 +- runtime/build.rs | 11 +- runtime/src/globals/fields.rs | 59 +++++ runtime/src/interpreter.rs | 2 +- runtime/src/native/java/lang/Class.rs | 6 +- runtime/src/native/java/lang/Object.rs | 10 +- .../java/lang/invoke/MethodHandleNatives.rs | 224 +++++++++--------- .../native/jdk/internal/reflect/Reflection.rs | 10 +- runtime/src/objects/class/mod.rs | 17 +- runtime/src/objects/constant_pool/cp_types.rs | 2 +- runtime/src/thread/exceptions.rs | 17 +- runtime/src/thread/frame/stack.rs | 2 +- runtime/src/thread/mod.rs | 2 +- symbols/build.rs | 6 +- symbols/src/lib.rs | 2 + tools/Cargo.toml | 14 -- 20 files changed, 283 insertions(+), 182 deletions(-) delete mode 100644 generators/Cargo.toml delete mode 100644 tools/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index 547f9af..f18873f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,8 @@ [workspace] resolver = "2" members = [ + "generators/*", + "tools/*", "classfile", "instructions", "runtime", @@ -13,7 +15,6 @@ members = [ "jni", "jni/sys", ] -exclude = ["tools", "generators"] [workspace.dependencies] classfile = { path = "classfile" } @@ -34,6 +35,16 @@ tracing = "0.1.41" paste = "1.0.15" zip = { version = "2.2.1", default-features = false } -# Nested workspace members -tools = { path = "tools" } -generators = { path = "generators" } +# Generators +combine = "4.6.7" +bitflags = "2.6.0" +indexmap = "2.7.0" +proc-macro2 = "1" +quote = "1" +syn = { version = "2", default-features = false } +walkdir = "2.5.0" + +# Tools +anyhow = "1.0.93" +clap = "4.0.29" +tracing-subscriber = "0.3.18" diff --git a/classfile/src/attribute/resolved.rs b/classfile/src/attribute/resolved.rs index 64eb4f1..d7f38df 100644 --- a/classfile/src/attribute/resolved.rs +++ b/classfile/src/attribute/resolved.rs @@ -6,6 +6,8 @@ use crate::attribute::BootstrapMethod; use crate::constant_pool::types::{self, LoadableConstantPoolValue, MethodHandleEntry}; use crate::constant_pool::ConstantPool; +use std::fmt::{Debug, Formatter}; + use common::int_types::{s4, s8, u2}; pub struct ResolvedAnnotation { @@ -140,13 +142,22 @@ pub enum ResolvedElementValueType { }, } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct ResolvedBootstrapMethod { pub method_handle_index: u2, pub method_handle_info: MethodHandleEntry<'static>, pub arguments: Vec>, } +impl Debug for ResolvedBootstrapMethod { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ResolvedBoostrapMethod") + .field("method_handle_info", &self.method_handle_info) + .field("arguments", &self.arguments) + .finish() + } +} + impl ResolvedBootstrapMethod { pub(crate) fn resolve_from(raw: &BootstrapMethod, constant_pool: &ConstantPool) -> Self { let method_handle_info = diff --git a/classfile/src/constant_pool/types.rs b/classfile/src/constant_pool/types.rs index 056552c..f14a16f 100644 --- a/classfile/src/constant_pool/types.rs +++ b/classfile/src/constant_pool/types.rs @@ -1,6 +1,7 @@ use super::{ConstantPool, ConstantPoolValueInfo}; use std::borrow::Cow; +use std::fmt::{Debug, Display, Formatter}; use common::int_types::{s4, s8, u1, u2, u4}; @@ -76,12 +77,12 @@ pub enum ReferenceKind { PutStatic = 4, /// REF_invokeVirtual InvokeVirtual = 5, - /// REF_newInvokeSpecial - NewInvokeSpecial = 6, /// REF_invokeStatic - InvokeStatic = 7, + InvokeStatic = 6, /// REF_invokeSpecial - InvokeSpecial = 8, + InvokeSpecial = 7, + /// REF_newInvokeSpecial + NewInvokeSpecial = 8, /// REF_invokeInterface InvokeInterface = 9, } @@ -142,12 +143,20 @@ impl<'a> ReferenceEntry<'a> { } } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct ClassNameEntry<'a> { pub name_index: u2, pub name: >::Entry, } +impl Debug for ClassNameEntry<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("ClassNameEntry") + .field(&String::from_utf8_lossy(&self.name)) + .finish() + } +} + impl<'a> ClassNameEntry<'a> { pub fn into_owned(self) -> ClassNameEntry<'static> { ClassNameEntry { @@ -195,7 +204,7 @@ impl<'a> MethodRefEntry<'a> { } } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct NameAndTypeEntry<'a> { pub name_index: u2, pub name: >::Entry, @@ -203,6 +212,15 @@ pub struct NameAndTypeEntry<'a> { pub descriptor: >::Entry, } +impl Debug for NameAndTypeEntry<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("NameAndTypeEntry") + .field(&String::from_utf8_lossy(&self.name)) + .field(&String::from_utf8_lossy(&self.descriptor)) + .finish() + } +} + impl<'a> NameAndTypeEntry<'a> { pub fn into_owned(self) -> NameAndTypeEntry<'static> { NameAndTypeEntry { diff --git a/generators/Cargo.toml b/generators/Cargo.toml deleted file mode 100644 index b2a0f8e..0000000 --- a/generators/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[workspace] -resolver = "2" -members = [ - "native_methods", - "vm_symbols", -] - -[workspace.dependencies] -common = { path = "../common" } - -combine = "4.6.7" -bitflags = "2.6.0" -indexmap = "2.7.0" -proc-macro2 = "1" -quote = "1" -syn = { version = "2", default-features = false } -walkdir = "2.5.0" \ No newline at end of file diff --git a/generators/vm_symbols/Cargo.toml b/generators/vm_symbols/Cargo.toml index 3c2f614..9f85a51 100644 --- a/generators/vm_symbols/Cargo.toml +++ b/generators/vm_symbols/Cargo.toml @@ -7,6 +7,6 @@ edition = "2021" proc-macro = true [dependencies] -syn = { workspace = true, features = ["full"] } +syn = { workspace = true, features = ["full", "parsing"] } proc-macro2.workspace = true quote.workspace = true \ No newline at end of file diff --git a/runtime/build.rs b/runtime/build.rs index 2280cf1..0744774 100644 --- a/runtime/build.rs +++ b/runtime/build.rs @@ -1,10 +1,11 @@ fn main() { - println!("cargo:rerun-if-changed=../generators/native_methods"); - println!("cargo:rerun-if-changed=src/native/mod.rs"); - println!("cargo:rerun-if-changed=src/native/java/*.rs"); - println!("cargo:rerun-if-changed=src/native/jdk/*.rs"); + println!("cargo::rerun-if-changed=../generators/native_methods"); + println!("cargo::rerun-if-changed=src/native/mod.rs"); + println!("cargo::rerun-if-changed=src/native/java/*.rs"); + println!("cargo::rerun-if-changed=src/native/jdk/*.rs"); if let Err(e) = native_methods::generate() { - panic!("Failed to generate native methods: {}", e); + println!("cargo::error=Failed to generate native methods: {e}"); + std::process::exit(1); } } diff --git a/runtime/src/globals/fields.rs b/runtime/src/globals/fields.rs index 34499d0..1417f2a 100644 --- a/runtime/src/globals/fields.rs +++ b/runtime/src/globals/fields.rs @@ -597,7 +597,66 @@ pub mod jdk_internal_misc_UnsafeConstants { } pub mod java_lang_invoke_MemberName { + use crate::objects::class_instance::ClassInstance; + use crate::objects::instance::Instance; + use crate::objects::reference::{MirrorInstanceRef, Reference}; use classfile::FieldType; + use instructions::Operand; + use jni::sys::jint; + + /// `java.lang.invoke.MemberName#clazz` field + pub fn clazz(instance: &ClassInstance) -> MirrorInstanceRef { + instance + .get_field_value0(clazz_field_offset()) + .expect_reference() + .extract_mirror() + } + + pub fn set_clazz(instance: &mut ClassInstance, value: Reference) { + instance.put_field_value0(clazz_field_offset(), Operand::Reference(value)) + } + + /// `java.lang.invoke.MemberName#name` field + pub fn name(instance: &ClassInstance) -> Reference { + instance + .get_field_value0(name_field_offset()) + .expect_reference() + } + + pub fn set_name(instance: &mut ClassInstance, value: Reference) { + instance.put_field_value0(name_field_offset(), Operand::Reference(value)) + } + + /// `java.lang.invoke.MemberName#type` field + pub fn type_(instance: &ClassInstance) -> Reference { + instance + .get_field_value0(type_field_offset()) + .expect_reference() + } + + pub fn set_type(instance: &mut ClassInstance, value: Reference) { + instance.put_field_value0(type_field_offset(), Operand::Reference(value)); + } + + /// `java.lang.invoke.MemberName#flags` field + pub fn flags(instance: &ClassInstance) -> jint { + instance.get_field_value0(flags_field_offset()).expect_int() + } + + pub fn set_flags(instance: &mut ClassInstance, value: jint) { + instance.put_field_value0(flags_field_offset(), Operand::Int(value)); + } + + /// `java.lang.invoke.MemberName#method` field + pub fn method(instance: &ClassInstance) -> Reference { + instance + .get_field_value0(flags_field_offset()) + .expect_reference() + } + + pub fn set_method(instance: &mut ClassInstance, value: Reference) { + instance.put_field_value0(method_field_offset(), Operand::Reference(value)); + } field_module! { @CLASS java_lang_invoke_MemberName; diff --git a/runtime/src/interpreter.rs b/runtime/src/interpreter.rs index 376277a..2c107f6 100644 --- a/runtime/src/interpreter.rs +++ b/runtime/src/interpreter.rs @@ -909,7 +909,7 @@ impl Interpreter { return; } - + match opcode { OpCode::instanceof => stack.push_int(0), OpCode::checkcast => panic!("ClassCastException"), // TODO diff --git a/runtime/src/native/java/lang/Class.rs b/runtime/src/native/java/lang/Class.rs index b051f66..694e376 100644 --- a/runtime/src/native/java/lang/Class.rs +++ b/runtime/src/native/java/lang/Class.rs @@ -5,7 +5,9 @@ use crate::objects::class::Class; use crate::objects::instance::Instance; use crate::objects::reference::{ArrayInstanceRef, MirrorInstanceRef, Reference}; use crate::string_interner::StringInterner; -use crate::thread::exceptions::{handle_exception, throw, throw_with_ret, Throws}; +use crate::thread::exceptions::{ + handle_exception, throw, throw_and_return_null, throw_with_ret, Throws, +}; use crate::thread::JavaThread; use std::sync::Arc; @@ -222,7 +224,7 @@ pub fn getDeclaringClass0( handle_exception!(Reference::null(), thread, target_class.loader().load(outer)); if outer.is_array() { - throw_with_ret!(Reference::null(), thread, IncompatibleClassChangeError); + throw_and_return_null!(thread, IncompatibleClassChangeError); } declaring_class = Reference::mirror(outer.mirror()); diff --git a/runtime/src/native/java/lang/Object.rs b/runtime/src/native/java/lang/Object.rs index 780c52d..b79a998 100644 --- a/runtime/src/native/java/lang/Object.rs +++ b/runtime/src/native/java/lang/Object.rs @@ -2,6 +2,7 @@ use crate::objects::instance::CloneableInstance; use crate::objects::reference::Reference; use crate::thread::JavaThread; +use crate::thread::exceptions::throw_and_return_null; use ::jni::env::JniEnv; use ::jni::sys::{jint, jlong}; use common::traits::PtrType; @@ -31,20 +32,17 @@ pub fn clone(_: JniEnv, this: Reference /* java.lang.Object */) -> Reference /* if this.is_array() { let array = this.extract_array(); let instance = array.get(); - let cloned = unsafe { instance.clone() }; + let cloned = unsafe { CloneableInstance::clone(instance) }; return Reference::array(cloned); } let instance_ref = this.extract_class(); let instance = instance_ref.get(); if !instance.class().is_cloneable() { - // TODO - panic!("CloneNotSupportedException"); + throw_and_return_null!(JavaThread::current(), CloneNotSupportedException); } - tracing::debug!(target: "method", "Cloning instance of {}", instance.class().name); - - let cloned = unsafe { instance.clone() }; + let cloned = unsafe { CloneableInstance::clone(instance) }; Reference::class(cloned) } diff --git a/runtime/src/native/java/lang/invoke/MethodHandleNatives.rs b/runtime/src/native/java/lang/invoke/MethodHandleNatives.rs index 451b612..2288758 100644 --- a/runtime/src/native/java/lang/invoke/MethodHandleNatives.rs +++ b/runtime/src/native/java/lang/invoke/MethodHandleNatives.rs @@ -1,3 +1,4 @@ +use crate::globals::{classes, fields}; use crate::native::java::lang::invoke::MethodHandleNatives; use crate::objects::class::Class; use crate::objects::class_instance::ClassInstance; @@ -5,7 +6,7 @@ use crate::objects::instance::Instance; use crate::objects::method::Method; use crate::objects::reference::{ClassInstanceRef, Reference}; use crate::string_interner::StringInterner; -use crate::thread::exceptions::{throw, throw_with_ret, Throws}; +use crate::thread::exceptions::{throw, throw_and_return_null, Throws}; use crate::thread::JavaThread; use std::fmt::Write; @@ -26,30 +27,29 @@ pub fn new_member_name( descriptor: Symbol, callee_class: &'static Class, ) -> Throws { - let member_name_instance = - ClassInstance::new(crate::globals::classes::java_lang_invoke_MemberName()); + let member_name_instance = ClassInstance::new(classes::java_lang_invoke_MemberName()); let member_name = member_name_instance.get_mut(); - member_name.put_field_value0( - crate::globals::fields::java_lang_invoke_MemberName::clazz_field_offset(), - Operand::Reference(Reference::mirror(callee_class.mirror())), + fields::java_lang_invoke_MemberName::set_clazz( + member_name, + Reference::mirror(callee_class.mirror()), ); - member_name.put_field_value0( - crate::globals::fields::java_lang_invoke_MemberName::name_field_offset(), - Operand::Reference(Reference::class(StringInterner::intern_symbol(name))), + fields::java_lang_invoke_MemberName::set_name( + member_name, + Reference::class(StringInterner::intern_symbol(name)), ); // TODO: Not correct for field members - member_name.put_field_value0( - crate::globals::fields::java_lang_invoke_MemberName::type_field_offset(), - Operand::Reference(Reference::class(StringInterner::intern_symbol(descriptor))), + fields::java_lang_invoke_MemberName::set_type( + member_name, + Reference::class(StringInterner::intern_symbol(descriptor)), ); Throws::Ok(member_name_instance) } pub fn method_type_signature(method_type: Reference) -> Throws { - if !method_type.is_instance_of(crate::globals::classes::java_lang_invoke_MethodType()) { + if !method_type.is_instance_of(classes::java_lang_invoke_MethodType()) { throw!(@DEFER InternalError, "not a MethodType"); } @@ -57,9 +57,7 @@ pub fn method_type_signature(method_type: Reference) -> Throws { signature.push('('); let parameters = method_type - .get_field_value0( - crate::globals::fields::java_lang_invoke_MethodType::ptypes_field_offset(), - ) + .get_field_value0(fields::java_lang_invoke_MethodType::ptypes_field_offset()) .expect_reference() .extract_array(); @@ -83,7 +81,7 @@ pub fn method_type_signature(method_type: Reference) -> Throws { signature.push(')'); let return_type = method_type - .get_field_value0(crate::globals::fields::java_lang_invoke_MethodType::rtype_field_offset()) + .get_field_value0(fields::java_lang_invoke_MethodType::rtype_field_offset()) .expect_reference(); if return_type.is_null() { @@ -110,39 +108,39 @@ pub fn method_type_signature(method_type: Reference) -> Throws { pub fn resolve_member_name( member_name: &mut ClassInstance, ref_kind: ReferenceKind, - calling_class: &'static Class, + calling_class: Option<&'static Class>, lookup_mode: jint, ) -> Throws<()> { + if calling_class.is_none() { + assert!( + (lookup_mode & LM_TRUSTED) == LM_TRUSTED, + "untrusted member resolution requires a calling class" + ); + } + let mut is_valid = true; let mut flags = 0; - let defining_class_field = member_name - .get_field_value0(crate::globals::fields::java_lang_invoke_MemberName::clazz_field_offset()) - .expect_reference() - .extract_mirror(); + let defining_class_field = fields::java_lang_invoke_MemberName::clazz(member_name); if defining_class_field.get().is_primitive() { throw!(@DEFER InternalError, "primitive class"); } let defining_class = defining_class_field.get().target_class(); - let name_field = member_name - .get_field_value0(crate::globals::fields::java_lang_invoke_MemberName::name_field_offset()) - .expect_reference(); + let name_field = fields::java_lang_invoke_MemberName::name(member_name); let name_str = StringInterner::rust_string_from_java_string(name_field.extract_class()); let name = Symbol::intern(name_str); - let type_field = member_name - .get_field_value0(crate::globals::fields::java_lang_invoke_MemberName::type_field_offset()) - .expect_reference(); + let type_field = fields::java_lang_invoke_MemberName::type_(member_name); let descriptor: Symbol; - if type_field.is_instance_of(crate::globals::classes::java_lang_String()) { + if type_field.is_instance_of(classes::java_lang_String()) { let descriptor_str = StringInterner::rust_string_from_java_string(type_field.extract_class()); descriptor = Symbol::intern(descriptor_str); - } else if type_field.is_instance_of(crate::globals::classes::java_lang_Class()) { + } else if type_field.is_instance_of(classes::java_lang_Class()) { descriptor = type_field.extract_target_class().as_signature(); - } else if type_field.is_instance_of(crate::globals::classes::java_lang_invoke_MethodType()) { + } else if type_field.is_instance_of(classes::java_lang_invoke_MethodType()) { descriptor = method_type_signature(type_field)?; } else { throw!(@DEFER InternalError, "unrecognized field"); @@ -154,10 +152,7 @@ pub fn resolve_member_name( | ReferenceKind::PutField | ReferenceKind::PutStatic => { // Already default initialized to `null`, just being explicit - member_name.put_field_value0( - crate::globals::fields::java_lang_invoke_MemberName::method_field_offset(), - Operand::Reference(Reference::null()), - ); + fields::java_lang_invoke_MemberName::set_method(member_name, Reference::null()); let field = defining_class.resolve_field(name, descriptor)?; @@ -181,40 +176,44 @@ pub fn resolve_member_name( flags |= MethodHandleNatives::MN_IS_METHOD; flags |= (ref_kind as jint) << MethodHandleNatives::MN_REFERENCE_KIND_SHIFT; - match ref_kind { - ReferenceKind::InvokeSpecial => { - is_valid = method.class() == calling_class - || calling_class - .parent_iter() - .any(|super_class| super_class == calling_class) - || calling_class - .interfaces - .iter() - .any(|interface| *interface == defining_class) - || method.class() == crate::globals::classes::java_lang_Object(); - }, - ReferenceKind::NewInvokeSpecial => { - flags |= MethodHandleNatives::MN_IS_CONSTRUCTOR; - - is_valid = method.name == sym!(object_initializer_name); - if method.is_protected() { - is_valid &= method.class().shares_package_with(calling_class); - } else { - is_valid &= method.class() == calling_class; - } - }, - ReferenceKind::InvokeStatic => { - is_valid = method.is_static(); - }, - ReferenceKind::InvokeVirtual => { - if method.is_protected() && !method.class().shares_package_with(calling_class) { - is_valid = method - .class() - .parent_iter() - .any(|super_class| super_class == calling_class); - } - }, - _ => unreachable!(), + if let Some(calling_class) = calling_class { + match ref_kind { + ReferenceKind::InvokeSpecial => { + is_valid = method.class() == calling_class + || calling_class + .parent_iter() + .any(|super_class| super_class == calling_class) + || calling_class + .interfaces + .iter() + .any(|interface| *interface == defining_class) + || method.class() == classes::java_lang_Object(); + }, + ReferenceKind::NewInvokeSpecial => { + flags |= MethodHandleNatives::MN_IS_CONSTRUCTOR; + + is_valid = method.name == sym!(object_initializer_name); + if method.is_protected() { + is_valid &= method.class().shares_package_with(calling_class); + } else { + is_valid &= method.class() == calling_class; + } + }, + ReferenceKind::InvokeStatic => { + is_valid = method.is_static(); + }, + ReferenceKind::InvokeVirtual => { + if method.is_protected() + && !method.class().shares_package_with(calling_class) + { + is_valid = method + .class() + .parent_iter() + .any(|super_class| super_class == calling_class); + } + }, + _ => unreachable!(), + } } if !is_valid { @@ -227,19 +226,30 @@ pub fn resolve_member_name( // Create the java.lang.invoke.ResolvedMethodName instance let resolved_method_name = - ClassInstance::new(crate::globals::classes::java_lang_invoke_ResolvedMethodName()); + ClassInstance::new(classes::java_lang_invoke_ResolvedMethodName()); resolved_method_name.get_mut().put_field_value0( - crate::globals::fields::java_lang_invoke_ResolvedMethodName::vmholder_field_offset( - ), + fields::java_lang_invoke_ResolvedMethodName::vmholder_field_offset(), Operand::Reference(Reference::mirror(method.class().mirror())), ); + + fields::java_lang_invoke_MemberName::set_method( + member_name, + Reference::class(resolved_method_name), + ); + + fields::java_lang_invoke_MemberName::set_clazz( + member_name, + Reference::mirror(method.class().mirror()), + ); }, ReferenceKind::InvokeInterface => { todo!("MH of kind interface method"); }, } + fields::java_lang_invoke_MemberName::set_flags(member_name, flags); + Throws::Ok(()) } @@ -272,21 +282,16 @@ pub fn resolve( speculative_resolve: jboolean, ) -> Reference /* java.lang.invoke.MemberName */ { if self_.is_null() { - throw_with_ret!( - Reference::null(), - JavaThread::current(), - NullPointerException - ); + throw_and_return_null!(JavaThread::current(), NullPointerException); } - let flags = self_ - .get_field_value0(crate::globals::fields::java_lang_invoke_MemberName::flags_field_offset()) - .expect_int(); + let class_instance = self_.extract_class(); + + let flags = fields::java_lang_invoke_MemberName::flags(class_instance.get()); let reference_kind = match ReferenceKind::from_u8((flags >> MN_REFERENCE_KIND_SHIFT) as u8) { Some(reference_kind) => reference_kind, None => { - throw_with_ret!( - Reference::null(), + throw_and_return_null!( JavaThread::current(), InternalError, "obsolete MemberName format" @@ -294,36 +299,41 @@ pub fn resolve( }, }; - match resolve_member_name( - self_.extract_class().get_mut(), + // `LM_TRUSTED` implies a `null` `calling_class` + let calling_class; + if (lookup_mode & LM_TRUSTED) == LM_TRUSTED { + calling_class = None; + } else { + calling_class = Some(caller.extract_target_class()); + } + + if let Throws::Exception(e) = resolve_member_name( + class_instance.get_mut(), reference_kind, - caller.extract_target_class(), + calling_class, lookup_mode, ) { - Throws::Ok(_) => self_.clone(), /* TODO: is this right? `self_` gets modified, should we make a new object and edit that instead? */ - Throws::Exception(exception) => { - if speculative_resolve { - // Speculative resolution is allowed to fail - return Reference::null(); - } + if speculative_resolve { + // Speculative resolution is allowed to fail + return Reference::null(); + } - if reference_kind.is_field() { - throw_with_ret!( - Reference::null(), - JavaThread::current(), - NoSuchFieldError, - "field resolution failed" - ); - } else { - throw_with_ret!( - Reference::null(), - JavaThread::current(), - NoSuchMethodError, - "method resolution failed" - ); - } - }, + if reference_kind.is_field() { + throw_and_return_null!( + JavaThread::current(), + NoSuchFieldError, + "field resolution failed" + ); + } else { + throw_and_return_null!( + JavaThread::current(), + NoSuchMethodError, + "method resolution failed" + ); + } } + + self_ } // -- Field layout queries parallel to jdk.internal.misc.Unsafe -- diff --git a/runtime/src/native/jdk/internal/reflect/Reflection.rs b/runtime/src/native/jdk/internal/reflect/Reflection.rs index 88f988d..b5939dd 100644 --- a/runtime/src/native/jdk/internal/reflect/Reflection.rs +++ b/runtime/src/native/jdk/internal/reflect/Reflection.rs @@ -1,5 +1,6 @@ use crate::objects::class::Class; use crate::objects::reference::Reference; +use crate::thread::exceptions::throw_and_return_null; use crate::thread::JavaThread; use ::jni::env::JniEnv; @@ -17,7 +18,7 @@ pub fn getCallerClass(env: JniEnv, _class: &'static Class) -> Reference { // [1] [ @CallerSensitive API.method ] // [.] [ (skipped intermediate frames) ] // [n] [ caller ] - for (n, frame) in current_thread.frame_stack().iter().rev().enumerate() { + for (n, frame) in current_thread.frame_stack().iter().enumerate() { let method = frame.method(); // TODO: @@ -32,9 +33,10 @@ pub fn getCallerClass(env: JniEnv, _class: &'static Class) -> Reference { } if !method.is_caller_sensitive() { - // TODO - panic!( - "InternalError, `getCallerClass` is not called from a @CallerSensitive method" + throw_and_return_null!( + current_thread, + InternalError, + "`getCallerClass` is not called from a @CallerSensitive method" ); } diff --git a/runtime/src/objects/class/mod.rs b/runtime/src/objects/class/mod.rs index 0804ea2..9cbb779 100644 --- a/runtime/src/objects/class/mod.rs +++ b/runtime/src/objects/class/mod.rs @@ -621,7 +621,7 @@ impl Class { // // If T is a class type, then S must be the same class as T, or S must be a subclass of T; if !T_class.is_interface() && !T_class.is_array() { - if S_class.name == T_class.name { + if S_class == T_class { return true; } @@ -636,13 +636,12 @@ impl Class { // // If T is a class type, then T must be Object. if !T_class.is_interface() && !T_class.is_array() { - return T_class.name == sym!(java_lang_Object); + return T_class == crate::globals::classes::java_lang_Object(); } // If T is an interface type, then T must be one of the interfaces implemented by arrays (JLS ยง4.10.3). if T_class.is_interface() { - let class_name = T_class.name; - return class_name == sym!(java_lang_Cloneable) - || class_name == sym!(java_io_Serializable); + return T_class == crate::globals::classes::java_lang_Cloneable() + || T_class == crate::globals::classes::java_io_Serializable(); } // If T is an array type TC[], that is, an array of components of type TC, then one of the following must be true: if T_class.is_array() { @@ -980,15 +979,19 @@ impl Class { } pub fn implements(&self, class: &Class) -> bool { + if self.is_interface() && self == class { + return true; + } + for interface in &self.interfaces { - if class.name == interface.name || class.implements(&interface) { + if class == *interface || class.implements(&interface) { return true; } } for parent in self.parent_iter() { for interface in &parent.interfaces { - if class.name == interface.name || class.implements(&interface) { + if class == *interface || class.implements(&interface) { return true; } } diff --git a/runtime/src/objects/constant_pool/cp_types.rs b/runtime/src/objects/constant_pool/cp_types.rs index a6d0f80..af612bb 100644 --- a/runtime/src/objects/constant_pool/cp_types.rs +++ b/runtime/src/objects/constant_pool/cp_types.rs @@ -485,7 +485,7 @@ impl EntryType for MethodHandle { MethodHandleNatives::resolve_member_name( member_name.get_mut(), value.reference_kind, - invoking_class, + Some(invoking_class), 0, )?; diff --git a/runtime/src/thread/exceptions.rs b/runtime/src/thread/exceptions.rs index fb36748..9b868a6 100644 --- a/runtime/src/thread/exceptions.rs +++ b/runtime/src/thread/exceptions.rs @@ -98,6 +98,9 @@ pub enum ExceptionKind { /// java.lang.ArrayIndexOutOfBoundsException ArrayIndexOutOfBoundsException, + /// java.lang.CloneNotSupportedException + CloneNotSupportedException, + /// java.lang.NullPointerException NullPointerException, /// java.lang.IllegalArgumentException @@ -136,6 +139,8 @@ impl ExceptionKind { sym!(java_lang_ArrayIndexOutOfBoundsException) }, + ExceptionKind::CloneNotSupportedException => sym!(java_lang_CloneNotSupportedException), + ExceptionKind::NullPointerException => sym!(java_lang_NullPointerException), ExceptionKind::IllegalArgumentException => sym!(java_lang_IllegalArgumentException), ExceptionKind::IllegalStateException => sym!(java_lang_IllegalStateException), @@ -251,6 +256,16 @@ macro_rules! throw_with_ret { }; } +macro_rules! throw_and_return_null { + ($thread:expr, $($tt:tt)*) => { + crate::thread::exceptions::throw_with_ret!( + $crate::objects::reference::Reference::null(), + $thread, + $($tt)* + ); + }; +} + macro_rules! handle_exception { ($thread:expr, $throwsy_expr:expr) => {{ crate::thread::exceptions::handle_exception!((), $thread, $throwsy_expr) @@ -266,7 +281,7 @@ macro_rules! handle_exception { }}; } -pub(crate) use {handle_exception, throw, throw_with_ret}; +pub(crate) use {handle_exception, throw, throw_and_return_null, throw_with_ret}; /// See [`JavaThread::throw_exception`] #[must_use = "must know whether the exception was thrown"] diff --git a/runtime/src/thread/frame/stack.rs b/runtime/src/thread/frame/stack.rs index b4b2f07..ff14433 100644 --- a/runtime/src/thread/frame/stack.rs +++ b/runtime/src/thread/frame/stack.rs @@ -96,7 +96,7 @@ impl FrameStack { } pub fn iter(&self) -> impl DoubleEndedIterator> { - self.__inner().iter().filter_map(|frame| match frame { + self.__inner().iter().rev().filter_map(|frame| match frame { StackFrame::Real(frame) => Some(VisibleStackFrame::Regular(frame)), StackFrame::Native(frame) => Some(VisibleStackFrame::Native(frame)), StackFrame::Fake => None, diff --git a/runtime/src/thread/mod.rs b/runtime/src/thread/mod.rs index 609e6f5..61b8d2a 100644 --- a/runtime/src/thread/mod.rs +++ b/runtime/src/thread/mod.rs @@ -350,7 +350,7 @@ impl JavaThread { pub fn invoke_method_with_local_stack(&self, method: &'static Method, locals: LocalStack) { if method.is_native() { self.invoke_native(method, locals); - tracing::debug!(target: "JavaThread", "Native method finished"); + tracing::debug!(target: "JavaThread", "Native method `{method:?}` finished"); return; } diff --git a/symbols/build.rs b/symbols/build.rs index 678241e..203cb35 100644 --- a/symbols/build.rs +++ b/symbols/build.rs @@ -1,5 +1,5 @@ fn main() { - println!("cargo:rerun-if-changed=../generators/vm_symbols"); - println!("cargo:rerun-if-changed=../generators/native_methods"); - println!("cargo:rerun-if-changed=../generated/native/*"); + println!("cargo::rerun-if-changed=../generators/vm_symbols"); + println!("cargo::rerun-if-changed=../generators/native_methods"); + println!("cargo::rerun-if-changed=../generated/native/*"); } diff --git a/symbols/src/lib.rs b/symbols/src/lib.rs index 94c793a..df539fc 100644 --- a/symbols/src/lib.rs +++ b/symbols/src/lib.rs @@ -221,6 +221,8 @@ vm_symbols::define_symbols! { java_lang_NegativeArraySizeException: "java/lang/NegativeArraySizeException", java_lang_ArrayIndexOutOfBoundsException: "java/lang/ArrayIndexOutOfBoundsException", + java_lang_CloneNotSupportedException: "java/lang/CloneNotSupportedException", + java_lang_NullPointerException: "java/lang/NullPointerException", java_lang_IllegalAccessError: "java/lang/IllegalAccessError", java_lang_IllegalArgumentException: "java/lang/IllegalArgumentException", diff --git a/tools/Cargo.toml b/tools/Cargo.toml deleted file mode 100644 index a5efa9d..0000000 --- a/tools/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[workspace] -resolver = "2" -members = [ - "sj", - "jimage", - "jmod", -] - -[workspace.dependencies] -anyhow = "1.0.93" -clap = "4.0.29" -libloading = "0.8.5" -tracing = "0.1.40" -tracing-subscriber = "0.3.18" \ No newline at end of file