From 4e29d8971ac51d1cc2ddfd2ce32b702f54a93f16 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 26 Sep 2025 18:26:49 +0200 Subject: [PATCH 01/27] Initial JVMCI support for Valhalla. --- .../aarch64/jvmciCodeInstaller_aarch64.cpp | 3 + .../cpu/x86/jvmciCodeInstaller_x86.cpp | 28 ++- src/hotspot/share/code/nmethod.cpp | 2 +- src/hotspot/share/code/nmethod.hpp | 2 +- .../share/jvmci/jvmciCodeInstaller.cpp | 44 +++- .../share/jvmci/jvmciCodeInstaller.hpp | 3 + src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 125 +++++++++- src/hotspot/share/jvmci/jvmciEnv.cpp | 8 +- src/hotspot/share/jvmci/jvmciEnv.hpp | 1 + src/hotspot/share/jvmci/jvmciJavaClasses.hpp | 5 +- src/hotspot/share/jvmci/jvmciRuntime.cpp | 37 +++ src/hotspot/share/jvmci/jvmciRuntime.hpp | 7 + src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 31 +++ src/hotspot/share/oops/fieldInfo.hpp | 1 + src/hotspot/share/oops/instanceKlass.hpp | 2 + src/hotspot/share/oops/methodData.hpp | 6 +- .../classes/java/lang/reflect/Field.java | 25 ++ .../com/sun/tools/javac/jvm/ClassReader.java | 8 +- .../classes/jdk/vm/ci/code/CodeUtil.java | 16 ++ .../jdk/vm/ci/code/RegisterConfig.java | 27 ++- .../classes/jdk/vm/ci/code/VirtualObject.java | 18 ++ .../jdk/vm/ci/hotspot/ACmpDataAccessor.java | 19 ++ .../jdk/vm/ci/hotspot/CompilerToVM.java | 98 +++++++- .../DirectHotSpotObjectConstantImpl.java | 5 + .../ci/hotspot/HotSpotCompiledCodeStream.java | 9 + .../HotSpotConstantReflectionProvider.java | 3 + .../vm/ci/hotspot/HotSpotJVMCIReflection.java | 4 + .../ci/hotspot/HotSpotMetaAccessProvider.java | 22 ++ .../jdk/vm/ci/hotspot/HotSpotMethodData.java | 183 ++++++++++++++- .../vm/ci/hotspot/HotSpotObjectConstant.java | 4 + .../ci/hotspot/HotSpotObjectConstantImpl.java | 14 +- .../ci/hotspot/HotSpotProfilingInfoImpl.java | 12 + .../hotspot/HotSpotResolvedJavaFieldImpl.java | 79 ++++++- .../HotSpotResolvedJavaMethodImpl.java | 214 ++++++++++++++++-- .../ci/hotspot/HotSpotResolvedJavaType.java | 11 + .../ci/hotspot/HotSpotResolvedObjectType.java | 31 +++ .../HotSpotResolvedObjectTypeImpl.java | 199 +++++++++++++--- .../hotspot/HotSpotResolvedPrimitiveType.java | 5 + .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 16 ++ .../IndirectHotSpotObjectConstantImpl.java | 21 +- .../hotspot/SharedLibraryJVMCIReflection.java | 27 +++ .../jdk/vm/ci/hotspot/SingleTypeEntry.java | 36 +++ .../amd64/AMD64HotSpotRegisterConfig.java | 61 +++++ .../jdk/vm/ci/meta/DefaultProfilingInfo.java | 5 + .../classes/jdk/vm/ci/meta/JavaKind.java | 2 +- .../jdk/vm/ci/meta/MetaAccessProvider.java | 8 + .../classes/jdk/vm/ci/meta/ProfilingInfo.java | 21 ++ .../jdk/vm/ci/meta/ResolvedJavaField.java | 58 +++++ .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 152 ++++++++++++- .../jdk/vm/ci/meta/ResolvedJavaType.java | 31 +++ 50 files changed, 1651 insertions(+), 98 deletions(-) create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/ACmpDataAccessor.java create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SingleTypeEntry.java diff --git a/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp b/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp index 071dd2c4179..6905458e278 100644 --- a/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp @@ -133,6 +133,7 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& metho case INVOKEINTERFACE: { assert(!method->is_static(), "cannot call static method with invokeinterface"); call = nativeCall_at(_instructions->start() + pc_offset); + // TODO: attach method for valhalla calling convention see jvmciCodeInstaller_x86.cpp _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc)); call->trampoline_jump(cbuf, SharedRuntime::get_resolve_virtual_call_stub(), JVMCI_CHECK); break; @@ -140,6 +141,7 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& metho case INVOKESTATIC: { assert(method->is_static(), "cannot call non-static method with invokestatic"); call = nativeCall_at(_instructions->start() + pc_offset); + // TODO: attach method for valhalla calling convention see jvmciCodeInstaller_x86.cpp _instructions->relocate(call->instruction_address(), relocInfo::static_call_type); call->trampoline_jump(cbuf, SharedRuntime::get_resolve_static_call_stub(), JVMCI_CHECK); break; @@ -147,6 +149,7 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& metho case INVOKESPECIAL: { assert(!method->is_static(), "cannot call static method with invokespecial"); call = nativeCall_at(_instructions->start() + pc_offset); + // TODO: attach method for valhalla calling convention see jvmciCodeInstaller_x86.cpp _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type); call->trampoline_jump(cbuf, SharedRuntime::get_resolve_opt_virtual_call_stub(), JVMCI_CHECK); break; diff --git a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp index 9e6a4789dc2..6af9229b71a 100644 --- a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp +++ b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp @@ -164,9 +164,15 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, j call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_virtual_call_stub()); + if (method->has_scalarized_args() && !method->mismatch()) { _instructions->relocate(call->instruction_address(), - virtual_call_Relocation::spec(_invoke_mark_pc), + virtual_call_Relocation::spec(_invoke_mark_pc, _oop_recorder->find_index(method())), Assembler::call32_operand); + } else { + _instructions->relocate(call->instruction_address(), + virtual_call_Relocation::spec(_invoke_mark_pc), + Assembler::call32_operand); + } break; } case INVOKESTATIC: { @@ -174,16 +180,32 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, j call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_static_call_stub()); - _instructions->relocate(call->instruction_address(), + // calls to the ValueObjectMethods class do not exist in bytecode, need to attach them + if (method->has_scalarized_args() || method() == Universe::is_substitutable_method() || method() == Universe::value_object_hash_code_method()) { + _instructions->relocate(call->instruction_address(), + relocInfo::static_call_type, Assembler::call32_operand,_oop_recorder->find_index(method())); + }else{ + _instructions->relocate(call->instruction_address(), relocInfo::static_call_type, Assembler::call32_operand); + } + break; } case INVOKESPECIAL: { assert(!method->is_static(), "cannot call static method with invokespecial"); call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); - _instructions->relocate(call->instruction_address(), + + // attach the target method only for scalarized args to avoid a null check on the receiver if receiver was optimized from non-scalarized to scalarized + // attach only for scalarized args otherwise assert(attached_method->has_scalarized_args(), "invalid use of attached method"); will trigger + // see resolved_method_index in machnode.hpp + if (method->has_scalarized_args() && !method->mismatch()) { + _instructions->relocate(call->instruction_address(), + relocInfo::opt_virtual_call_type, Assembler::call32_operand, _oop_recorder->find_index(method())); + } else { + _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type, Assembler::call32_operand); + } break; } default: diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 0ff4faf69e4..69ac21bbb2b 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -723,7 +723,7 @@ void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map // If inline types are passed as fields, use the extended signature // which contains the types of all (oop) fields of the inline type. - if (is_compiled_by_c2() && callee->has_scalarized_args()) { + if ((is_compiled_by_c2() || is_compiled_by_jvmci()) && callee->has_scalarized_args()) { const GrowableArray* sig = callee->adapter()->get_sig_cc(); assert(sig != nullptr, "sig should never be null"); TempNewSymbol tmp_sig = SigEntry::create_symbol(sig); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 981ab7fbaa6..f66e6860b20 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -763,7 +763,7 @@ class nmethod : public CodeBlob { bool needs_stack_repair() const { if (is_compiled_by_c1()) { return method()->c1_needs_stack_repair(); - } else if (is_compiled_by_c2()) { + } else if (is_compiled_by_c2() || is_compiled_by_jvmci()) { return method()->c2_needs_stack_repair(); } else { return false; diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 2ac960c78fb..b6de39705cc 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -41,6 +41,9 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/align.hpp" +#include "ci/ciSignature.hpp" +#include "oops/inlineKlass.hpp" +#include "runtime/globals.hpp" // frequently used constants // Allocate them with new so they are never destroyed (otherwise, a @@ -785,6 +788,14 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, JVMCI_THROW_MSG_(IllegalArgumentException, "nmethod entry barrier is missing", JVMCI::ok); } + if(_offsets.value(CodeOffsets::Verified_Inline_Entry) == -1) { + _offsets.set_value(CodeOffsets::Verified_Inline_Entry, _offsets.value(CodeOffsets::Verified_Entry)); + } + + if(_offsets.value(CodeOffsets::Verified_Inline_Entry_RO) == -1) { + _offsets.set_value(CodeOffsets::Verified_Inline_Entry_RO, _offsets.value(CodeOffsets::Verified_Entry)); + } + JVMCIObject mirror = installed_code; nmethod* nm = nullptr; // nm is an out parameter of register_method result = runtime()->register_method(jvmci_env(), @@ -1111,9 +1122,19 @@ void CodeInstaller::read_virtual_objects(HotSpotCompiledCodeStream* stream, JVMC if (is_auto_box) { _has_auto_box = true; } + // see code in output.cpp (PhaseOutput::FillLocArray) + bool check_is_not_null = stream->read_bool("nonNull"); + ScopeValue *is_init = nullptr; + if (check_is_not_null) { + ScopeValue* cur_second = nullptr; + BasicType type = (BasicType) stream->read_u1("basicType"); + ScopeValue* value; + u1 tag = stream->read_u1("tag"); + is_init = get_scope_value(stream, tag, type, cur_second, JVMCI_CHECK); + } oop javaMirror = klass->java_mirror(); ScopeValue *klass_sv = new ConstantOopWriteValue(JNIHandles::make_local(javaMirror)); - ObjectValue* sv = is_auto_box ? new AutoBoxObjectValue(id, klass_sv) : new ObjectValue(id, klass_sv); + ObjectValue* sv = is_auto_box ? new AutoBoxObjectValue(id, klass_sv) : new ObjectValue(id, klass_sv, true, is_init); objects->at_put(id, sv); } // All the values which could be referenced by the VirtualObjects @@ -1141,6 +1162,18 @@ int CodeInstaller::map_jvmci_bci(int bci) { return bci; } +bool has_scalarized_return(methodHandle& methodHandle){ + if (!InlineTypeReturnedAsFields) { + return false; + } + Method* method = methodHandle(); + InlineKlass* klass = method->returns_inline_type(Thread::current()); + if (klass != nullptr) { + return !method->is_native() && klass->can_be_returned_as_fields(); + } + return false; +} + void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool is_mh_invoke, bool return_oop, JVMCI_TRAPS) { if (full_info) { read_virtual_objects(stream, JVMCI_CHECK); @@ -1182,7 +1215,7 @@ void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stre } // has_ea_local_in_scope and arg_escape should be added to JVMCI - const bool return_scalarized = false; + const bool return_scalarized = has_scalarized_return(method); const bool has_ea_local_in_scope = false; const bool arg_escape = false; _debug_recorder->describe_scope(pc_offset, method, nullptr, bci, reexecute, rethrow_exception, is_mh_invoke, return_oop, @@ -1328,9 +1361,16 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, HotSpotCompile case UNVERIFIED_ENTRY: _offsets.set_value(CodeOffsets::Entry, pc_offset); break; + case INLINE_ENTRY: + _offsets.set_value(CodeOffsets::Inline_Entry, pc_offset); + break; case VERIFIED_ENTRY: _offsets.set_value(CodeOffsets::Verified_Entry, pc_offset); + break; + case VERIFIED_INLINE_ENTRY: _offsets.set_value(CodeOffsets::Verified_Inline_Entry, pc_offset); + break; + case VERIFIED_INLINE_ENTRY_RO: _offsets.set_value(CodeOffsets::Verified_Inline_Entry_RO, pc_offset); break; case OSR_ENTRY: diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp index a8279e99dc2..0637d2c9e0f 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp @@ -147,7 +147,10 @@ class CodeInstaller : public StackObj { enum MarkId { INVALID_MARK, VERIFIED_ENTRY, + VERIFIED_INLINE_ENTRY, + VERIFIED_INLINE_ENTRY_RO, UNVERIFIED_ENTRY, + INLINE_ENTRY, OSR_ENTRY, EXCEPTION_HANDLER_ENTRY, DEOPT_HANDLER_ENTRY, diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index a43a269a4f8..a9d53dcf058 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -48,10 +48,12 @@ #include "oops/constantPool.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.hpp" +#include "oops/methodData.hpp" #include "oops/method.inline.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/trainingData.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "oops/layoutKind.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" #include "prims/nativeLookup.hpp" @@ -370,6 +372,40 @@ C2V_VMENTRY_NULL(jbyteArray, getBytecode, (JNIEnv* env, jobject, ARGUMENT_PAIR(m return JVMCIENV->get_jbyteArray(result); C2V_END +C2V_VMENTRY_0(jbooleanArray, getScalarizedParametersInfo, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), jbooleanArray infoArray, jint len)) + Method* method = UNPACK_PAIR(Method, method); + JVMCIPrimitiveArray result = JVMCIENV->wrap(infoArray); + for(int i=0; iput_bool_at(result, i, method->is_scalarized_arg(i)); + } + return JVMCIENV->get_jbooleanArray(result); +C2V_END + +C2V_VMENTRY_0(jboolean, hasScalarizedParameters, (JNIEnv* env, jobject, ARGUMENT_PAIR(method))) + Method* method = UNPACK_PAIR(Method, method); + return method->has_scalarized_args(); +C2V_END + +C2V_VMENTRY_0(jboolean, hasScalarizedReturn, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), ARGUMENT_PAIR(klass))) + Method* method = UNPACK_PAIR(Method, method); + Klass* klass = UNPACK_PAIR(Klass, klass); + if(!klass->is_inline_klass()) return false; + InlineKlass* inlineKlass = InlineKlass::cast(klass); + return !method->is_native() && inlineKlass->can_be_returned_as_fields(); +C2V_END + +C2V_VMENTRY_0(jboolean, hasCallingConventionMismatch, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), ARGUMENT_PAIR(klass))) + Method* method = UNPACK_PAIR(Method, method); + return method->mismatch(); +C2V_END + +C2V_VMENTRY_0(jboolean, canBePassedAsFields, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) + Klass* klass = UNPACK_PAIR(Klass, klass); + assert(klass->is_inline_klass(), "Klass should be an inline type"); + InlineKlass* inlineKlass = InlineKlass::cast(klass); + return inlineKlass->can_be_passed_as_fields(); +C2V_END + C2V_VMENTRY_0(jint, getExceptionTableLength, (JNIEnv* env, jobject, ARGUMENT_PAIR(method))) Method* method = UNPACK_PAIR(Method, method); return method->exception_table_length(); @@ -429,6 +465,20 @@ C2V_VMENTRY_NULL(jobject, getResolvedJavaMethod, (JNIEnv* env, jobject, jobject return JVMCIENV->get_jobject(result); } +C2V_VMENTRY_NULL(jobject, getIsSubstitutableMethod, (JNIEnv* env)) + // class will be initialized in SharedRuntime::find_callee_info_helper if necessary + methodHandle method(THREAD, Universe::is_substitutable_method()); + JVMCIObject result = JVMCIENV->get_jvmci_method(method, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); +} + +C2V_VMENTRY_NULL(jobject, getValueObjectHashCodeMethod, (JNIEnv* env)) + // TODO: do we need to initialize here? + methodHandle method(THREAD, Universe::value_object_hash_code_method()); + JVMCIObject result = JVMCIENV->get_jvmci_method(method, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); +} + C2V_VMENTRY_NULL(jobject, getConstantPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass_or_method), jboolean is_klass)) ConstantPool* cp = nullptr; if (UNPACK_PAIR(address, klass_or_method) == nullptr) { @@ -507,7 +557,10 @@ C2V_VMENTRY_NULL(jobject, getResolvedJavaType0, (JNIEnv* env, jobject, jobject b } } else if (JVMCIENV->isa_HotSpotMethodData(base_object)) { jlong base_address = (intptr_t) JVMCIENV->asMethodData(base_object); - Klass* k = *((Klass**) (intptr_t) (base_address + offset)); + intptr_t temp = (intptr_t) *((Klass**) (intptr_t) (base_address + offset)); + + // profiled type: cell without bit 0 and 1 + klass = (Klass*) (temp & TypeEntries::type_klass_mask); if (k == nullptr || k->class_loader_data() == nullptr || !TrainingData::is_klass_loaded(k)) { return nullptr; } @@ -681,6 +734,39 @@ C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jchar type_char, return JVMCIENV->get_jobject(result); C2V_END +C2V_VMENTRY_NULL(jobject, getFlatArrayType, (JNIEnv* env, jobject, jchar type_char, ARGUMENT_PAIR(klass))) + JVMCIKlassHandle array_klass(THREAD); + Klass* klass = UNPACK_PAIR(Klass, klass); + + if(klass->is_inline_klass()){ + InlineKlass* inline_klass = InlineKlass::cast(klass); + ArrayKlass* flat_array_klass; + if(inline_klass->flat_array()){ + flat_array_klass = (ArrayKlass*)inline_klass->flat_array_klass(LayoutKind::NON_ATOMIC_FLAT, CHECK_NULL); + }else{ + flat_array_klass = (ArrayKlass*)inline_klass->null_free_reference_array(CHECK_NULL); + } + // Request a flat array, but we might not actually get it...either way "null-free" are the aaload/aastore semantics + //ArrayKlass* flat_array_klass = (ArrayKlass*)inline_klass->flat_array_klass(LayoutKind::NON_ATOMIC_FLAT, CHECK_NULL); + array_klass = flat_array_klass; + assert(array_klass->is_null_free_array_klass(), "Expect a null-free array class here"); + //assert(array_klass->is_flatArray_klass, "Expect a flat array class here"); + }else{ + array_klass = klass->array_klass(CHECK_NULL); + } + JVMCIObject result = JVMCIENV->get_jvmci_type(array_klass, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); +C2V_END + +C2V_VMENTRY_NULL(jobject, getDefaultInlineTypeInstance, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) + JVMCIKlassHandle array_klass(THREAD); + Klass* klass = UNPACK_PAIR(Klass, klass); + + assert(klass->is_inline_klass(), "Should only be called for inline types"); + oop default_value = InlineKlass::cast(klass)->default_value(); + return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(default_value)); +C2V_END + C2V_VMENTRY_NULL(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror)) requireInHotSpot("lookupClass", JVMCI_CHECK_NULL); if (mirror == nullptr) { @@ -2285,7 +2371,7 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredFieldsInfo, (JNIEnv* env, jobject, ARG return array.as_jobject(); C2V_END -static jobject read_field_value(Handle obj, long displacement, jchar type_char, bool is_static, Thread* THREAD, JVMCIEnv* JVMCIENV) { +static jobject read_field_value(Handle obj, long displacement, jchar type_char, bool is_static, jboolean is_flat, Thread* THREAD, JVMCIEnv* JVMCIENV) { BasicType basic_type = JVMCIENV->typeCharToBasicType(type_char, JVMCI_CHECK_NULL); int basic_type_elemsize = type2aelembytes(basic_type); @@ -2321,12 +2407,18 @@ static jobject read_field_value(Handle obj, long displacement, jchar type_char, } else if (obj->is_instance()) { InstanceKlass* klass = InstanceKlass::cast(is_static ? java_lang_Class::as_Klass(obj()) : obj->klass()); fieldDescriptor fd; - if (!klass->find_field_from_offset(displacement, is_static, &fd)) { - JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Can't find field at displacement %d in object of type %s", (int) displacement, klass->external_name())); - } - if (fd.field_type() != T_OBJECT && fd.field_type() != T_ARRAY) { - JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Field at displacement %d in object of type %s is %s but expected %s", (int) displacement, - klass->external_name(), type2name(fd.field_type()), type2name(basic_type))); + if(is_flat) { + // TODO: correct sanity check for flat fields, for flat fields the container klass is not klass the field was originally defined in. + // that's why !klass->find_field_from_offset(displacement, is_static, &fd) will fail, so skip it for now. + // use TestLWorld#run1, MyValue1.o embedded in TestLWorld at offset 144 fails + } else{ + if (!klass->find_field_from_offset(displacement, is_static, &fd)) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Can't find field at displacement %d in object of type %s", (int) displacement, klass->external_name())); + } + if (fd.field_type() != T_OBJECT && fd.field_type() != T_ARRAY) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Field at displacement %d in object of type %s is %s but expected %s", (int) displacement, + klass->external_name(), type2name(fd.field_type()), type2name(basic_type))); + } } } else if (obj->is_typeArray()) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, "Can't read objects from primitive array"); @@ -2398,10 +2490,10 @@ static jobject read_field_value(Handle obj, long displacement, jchar type_char, C2V_VMENTRY_NULL(jobject, readStaticFieldValue, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), long displacement, jchar type_char)) Klass* klass = UNPACK_PAIR(Klass, klass); Handle obj(THREAD, klass->java_mirror()); - return read_field_value(obj, displacement, type_char, true, THREAD, JVMCIENV); + return read_field_value(obj, displacement, type_char, true, false, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, ARGUMENT_PAIR(expected_type), long displacement, jchar type_char)) +C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, ARGUMENT_PAIR(expected_type), long displacement, jchar type_char, jboolean is_flat)) if (object == nullptr) { JVMCI_THROW_NULL(NullPointerException); } @@ -2418,7 +2510,7 @@ C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, } } bool is_static = expected_klass == nullptr && java_lang_Class::is_instance(obj()) && displacement >= InstanceMirrorKlass::offset_of_static_fields(); - return read_field_value(obj, displacement, type_char, is_static, THREAD, JVMCIENV); + return read_field_value(obj, displacement, type_char, is_static, is_flat, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_0(jboolean, isInstance, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jobject object)) @@ -3329,6 +3421,11 @@ C2V_END JNINativeMethod CompilerToVM::methods[] = { {CC "getBytecode", CC "(" HS_METHOD2 ")[B", FN_PTR(getBytecode)}, + {CC "getScalarizedParametersInfo", CC "(" HS_METHOD2 "[ZI)[Z", FN_PTR(getScalarizedParametersInfo)}, + {CC "hasScalarizedParameters", CC "(" HS_METHOD2 ")Z", FN_PTR(hasScalarizedParameters)}, + {CC "hasScalarizedReturn", CC "(" HS_METHOD2 HS_KLASS2 ")Z", FN_PTR(hasScalarizedReturn)}, + {CC "hasCallingConventionMismatch", CC "(" HS_METHOD2 ")Z", FN_PTR(hasCallingConventionMismatch)}, + {CC "canBePassedAsFields", CC "(" HS_KLASS2 ")Z", FN_PTR(canBePassedAsFields)}, {CC "getExceptionTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getExceptionTableStart)}, {CC "getExceptionTableLength", CC "(" HS_METHOD2 ")I", FN_PTR(getExceptionTableLength)}, {CC "findUniqueConcreteMethod", CC "(" HS_KLASS2 HS_METHOD2 ")" HS_METHOD, FN_PTR(findUniqueConcreteMethod)}, @@ -3343,6 +3440,8 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "lookupJClass", CC "(J)" HS_RESOLVED_TYPE, FN_PTR(lookupJClass)}, {CC "getJObjectValue", CC "(" OBJECTCONSTANT ")J", FN_PTR(getJObjectValue)}, {CC "getArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getArrayType)}, + {CC "getFlatArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getFlatArrayType)}, + {CC "getDefaultInlineTypeInstance", CC "(" HS_KLASS2 ")" JAVACONSTANT, FN_PTR(getDefaultInlineTypeInstance)}, {CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)}, {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupNameInPool)}, {CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, @@ -3371,6 +3470,8 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "getMaxCallTargetOffset", CC "(J)J", FN_PTR(getMaxCallTargetOffset)}, {CC "asResolvedJavaMethod", CC "(" EXECUTABLE ")" HS_METHOD, FN_PTR(asResolvedJavaMethod)}, {CC "getResolvedJavaMethod", CC "(" OBJECTCONSTANT "J)" HS_METHOD, FN_PTR(getResolvedJavaMethod)}, + {CC "getIsSubstitutableMethod", CC "()" HS_METHOD, FN_PTR(getIsSubstitutableMethod)}, + {CC "getValueObjectHashCodeMethod", CC "()" HS_METHOD, FN_PTR(getValueObjectHashCodeMethod)}, {CC "getConstantPool", CC "(" OBJECT "JZ)" HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, {CC "getResolvedJavaType0", CC "(Ljava/lang/Object;JZ)" HS_KLASS, FN_PTR(getResolvedJavaType0)}, {CC "readConfiguration", CC "()[" OBJECT, FN_PTR(readConfiguration)}, @@ -3416,7 +3517,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "getAllMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getAllMethods)}, {CC "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)}, {CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)}, - {CC "readFieldValue", CC "(" OBJECTCONSTANT HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readFieldValue)}, + {CC "readFieldValue", CC "(" OBJECTCONSTANT HS_KLASS2 "JCZ)" JAVACONSTANT, FN_PTR(readFieldValue)}, {CC "isInstance", CC "(" HS_KLASS2 OBJECTCONSTANT ")Z", FN_PTR(isInstance)}, {CC "isAssignableFrom", CC "(" HS_KLASS2 HS_KLASS2 ")Z", FN_PTR(isAssignableFrom)}, {CC "isTrustedForIntrinsics", CC "(" HS_KLASS2 ")Z", FN_PTR(isTrustedForIntrinsics)}, diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 23473940178..87e0b2e6c3e 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -1592,6 +1592,7 @@ JVMCIObject JVMCIEnv::new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS) { HotSpotJVMCI::FieldInfo::set_classfileFlags(JVMCIENV, obj_h(), (jint)fieldinfo->access_flags().as_field_flags()); HotSpotJVMCI::FieldInfo::set_internalFlags(JVMCIENV, obj_h(), (jint)fieldinfo->field_flags().as_uint()); HotSpotJVMCI::FieldInfo::set_initializerIndex(JVMCIENV, obj_h(), (jint)fieldinfo->initializer_index()); + HotSpotJVMCI::FieldInfo::set_nullMarkerOffset(JVMCIENV, obj_h(), (jint)fieldinfo->null_marker_offset()); return wrap(obj_h()); } else { JNIAccessMark jni(this, THREAD); @@ -1602,7 +1603,8 @@ JVMCIObject JVMCIEnv::new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS) { (jint)fieldinfo->offset(), (jint)fieldinfo->access_flags().as_field_flags(), (jint)fieldinfo->field_flags().as_uint(), - (jint)fieldinfo->initializer_index()); + (jint)fieldinfo->initializer_index(), + (jint)fieldinfo->null_marker_offset()); return wrap(result); } @@ -1625,7 +1627,7 @@ JVMCIObject JVMCIEnv::get_object_constant(oop objOop, bool compressed, bool dont JNIAccessMark jni(this, THREAD); jobject result = jni()->NewObject(JNIJVMCI::IndirectHotSpotObjectConstantImpl::clazz(), JNIJVMCI::IndirectHotSpotObjectConstantImpl::constructor(), - handle, compressed, dont_register); + handle, compressed, dont_register, obj->is_inline_type()); return wrap(result); } } @@ -1738,7 +1740,7 @@ void JVMCIEnv::initialize_installed_code(JVMCIObject installed_code, CodeBlob* c if (cb->is_nmethod()) { nmethod* nm = cb->as_nmethod_or_null(); if (nm->is_in_use()) { - set_InstalledCode_entryPoint(installed_code, (jlong) nm->verified_entry_point()); + set_InstalledCode_entryPoint(installed_code, (jlong) nm->verified_inline_entry_point()); } } else { set_InstalledCode_entryPoint(installed_code, (jlong) cb->code_begin()); diff --git a/src/hotspot/share/jvmci/jvmciEnv.hpp b/src/hotspot/share/jvmci/jvmciEnv.hpp index fbe5be88c3f..52a452df602 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.hpp +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp @@ -328,6 +328,7 @@ class JVMCIEnv : public ResourceObj { jarray get_jarray(JVMCIArray array) { assert(array.as_jobject() == nullptr || is_hotspot() == array.is_hotspot(), "mismatch"); return array.as_jobject(); } jobjectArray get_jobjectArray(JVMCIObjectArray objectArray) { assert(objectArray.as_jobject() == nullptr || is_hotspot() == objectArray.is_hotspot(), "mismatch"); return objectArray.as_jobject(); } jbyteArray get_jbyteArray(JVMCIPrimitiveArray primitiveArray) { assert(primitiveArray.as_jobject() == nullptr || is_hotspot() == primitiveArray.is_hotspot(), "mismatch"); return primitiveArray.as_jbyteArray(); } + jbooleanArray get_jbooleanArray(JVMCIPrimitiveArray primitiveArray) { assert(primitiveArray.as_jobject() == nullptr || is_hotspot() == primitiveArray.is_hotspot(), "mismatch"); return primitiveArray.as_jbooleanArray(); } JVMCIObject wrap(jobject obj); JVMCIObjectArray wrap(jobjectArray obj) { return (JVMCIObjectArray) wrap((jobject) obj); } diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp index 8bd34f52def..0b4092242e2 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp @@ -79,7 +79,8 @@ int_field(FieldInfo, classfileFlags) \ int_field(FieldInfo, internalFlags) \ int_field(FieldInfo, initializerIndex) \ - jvmci_constructor(FieldInfo, "(IIIIII)V") \ + int_field(FieldInfo, nullMarkerOffset) \ + jvmci_constructor(FieldInfo, "(IIIIIII)V") \ end_class \ start_class(HotSpotResolvedJavaMethodImpl, jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl) \ long_field(HotSpotResolvedJavaMethodImpl, methodHandle) \ @@ -179,7 +180,7 @@ end_class \ start_class(IndirectHotSpotObjectConstantImpl, jdk_vm_ci_hotspot_IndirectHotSpotObjectConstantImpl) \ long_field(IndirectHotSpotObjectConstantImpl, objectHandle) \ - jvmci_constructor(IndirectHotSpotObjectConstantImpl, "(JZZ)V") \ + jvmci_constructor(IndirectHotSpotObjectConstantImpl, "(JZZZ)V") \ end_class \ start_class(JavaKind, jdk_vm_ci_meta_JavaKind) \ char_field(JavaKind, typeChar) \ diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index c0335e7c67e..f869662e9c3 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -44,6 +44,8 @@ #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "oops/flatArrayKlass.hpp" +#include "oops/flatArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" #include "runtime/arguments.hpp" @@ -53,6 +55,7 @@ #include "runtime/frame.inline.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/handles.inline.hpp" #include "runtime/mutex.hpp" #include "runtime/reflection.hpp" #include "runtime/sharedRuntime.hpp" @@ -413,6 +416,19 @@ JRT_LEAF(jboolean, JVMCIRuntime::object_notify(JavaThread* current, oopDesc* obj JRT_END +JRT_ENTRY(void, JVMCIRuntime::load_unknown_inline(JavaThread* current, flatArrayOopDesc* array, jint index)) + assert(array->klass()->is_flatArray_klass(), "should not be called"); + + assert(array->length() > 0 && index < array->length(), "already checked"); + oop obj = array->read_value_from_flat_array(index, THREAD); + current->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::store_unknown_inline(JavaThread* current, flatArrayOopDesc* array, jint index, oopDesc* value)) + assert(array->klass()->is_flatArray_klass(), "should not be called"); + array->write_value_to_flat_array(value, index, THREAD); +JRT_END + // Object.notifyAll() fast path, caller does slow path JRT_LEAF(jboolean, JVMCIRuntime::object_notifyAll(JavaThread* current, oopDesc* obj)) assert(current == JavaThread::current(), "pre-condition"); @@ -453,6 +469,16 @@ JRT_BLOCK_ENTRY(int, JVMCIRuntime::throw_class_cast_exception(JavaThread* curren return caller_is_deopted(); JRT_END +JRT_BLOCK_ENTRY(int, JVMCIRuntime::throw_identity_exception(JavaThread* current, const char* exception, Klass* klass)) + JRT_BLOCK; + ResourceMark rm(current); + char* message = SharedRuntime::generate_identity_exception_message(current, klass); + TempNewSymbol symbol = SymbolTable::new_symbol(exception); + SharedRuntime::throw_and_post_jvmti_exception(current, symbol, message); + JRT_BLOCK_END; + return caller_is_deopted(); +JRT_END + class ArgumentPusher : public SignatureIterator { protected: JavaCallArguments* _jca; @@ -855,6 +881,17 @@ jlong JVMCIRuntime::make_oop_handle(const Handle& obj) { assert(oopDesc::is_oop(obj()), "not an oop"); oop* ptr = OopHandle(object_handles(), obj()).ptr_raw(); + if (obj()->is_inline_type()) { + int index = _oop_handles.find(ptr); + if (index != -1) { + // Satisfy OopHandles::release precondition that all + // handles being released are null. + NativeAccess<>::oop_store(ptr, (oop) nullptr); + object_handles()->release(ptr); + ptr = _oop_handles.at(index); + return reinterpret_cast(ptr); + } + } MutexLocker ml(_lock); _oop_handles.append(ptr); return reinterpret_cast(ptr); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index f4c322e831c..2c6c991e5a2 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -30,6 +30,9 @@ #include "jvmci/jvmci.hpp" #include "jvmci/jvmciExceptions.hpp" #include "jvmci/jvmciObject.hpp" +#include "runtime/handles.inline.hpp" +#include "oops/flatArrayKlass.hpp" +#include "oops/flatArrayOop.inline.hpp" #include "utilities/linkedlist.hpp" #if INCLUDE_G1GC #include "gc/g1/g1CardTable.hpp" @@ -556,6 +559,9 @@ class JVMCIRuntime: public CHeapObj { static void monitorexit (JavaThread* current, oopDesc* obj, BasicLock* lock); static jboolean object_notify(JavaThread* current, oopDesc* obj); static jboolean object_notifyAll(JavaThread* current, oopDesc* obj); + static void load_unknown_inline(JavaThread* thread, flatArrayOopDesc* array, jint index); + static void store_unknown_inline(JavaThread* thread, flatArrayOopDesc* array, jint index, oopDesc* value); + static void vm_error(JavaThread* current, jlong where, jlong format, jlong value); static oopDesc* load_and_clear_exception(JavaThread* thread); static void log_printf(JavaThread* thread, const char* format, jlong v1, jlong v2, jlong v3); @@ -577,6 +583,7 @@ class JVMCIRuntime: public CHeapObj { // helper methods to throw exception with complex messages static int throw_klass_external_name_exception(JavaThread* current, const char* exception, Klass* klass); static int throw_class_cast_exception(JavaThread* current, const char* exception, Klass* caster_klass, Klass* target_klass); + static int throw_identity_exception(JavaThread* current, const char* exception, Klass* klass); // A helper to allow invocation of an arbitrary Java method. For simplicity the method is // restricted to a static method that takes at most one argument. For calling convention diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 716f8eda8c6..0fa8232c45d 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -278,12 +278,18 @@ nonstatic_field(Klass, _secondary_supers, Array*) \ nonstatic_field(Klass, _super, Klass*) \ nonstatic_field(Klass, _super_check_offset, juint) \ + nonstatic_field(InstanceKlass, _adr_inlineklass_fixed_block, InlineKlassFixedBlock const *) \ + nonstatic_field(InlineKlassFixedBlock, _payload_offset, int) \ + nonstatic_field(InlineKlassFixedBlock, _null_marker_offset, int) \ + nonstatic_field(FieldInfo, _null_marker_offset, u4) \ volatile_nonstatic_field(Klass, _subklass, Klass*) \ nonstatic_field(Klass, _layout_helper, jint) \ + nonstatic_field(Klass, _prototype_header, markWord) \ nonstatic_field(Klass, _name, Symbol*) \ volatile_nonstatic_field(Klass, _next_sibling, Klass*) \ nonstatic_field(Klass, _java_mirror, OopHandle) \ nonstatic_field(Klass, _access_flags, AccessFlags) \ + nonstatic_field(Klass, _kind, Klass::KlassKind const) \ nonstatic_field(Klass, _class_loader_data, ClassLoaderData*) \ nonstatic_field(Klass, _secondary_supers_bitmap, uintx) \ nonstatic_field(Klass, _hash_slot, uint8_t) \ @@ -306,6 +312,7 @@ nonstatic_field(Method, _flags._status, u4) \ volatile_nonstatic_field(Method, _code, nmethod*) \ volatile_nonstatic_field(Method, _from_compiled_entry, address) \ + volatile_nonstatic_field(Method, _from_compiled_inline_ro_entry, address) \ \ nonstatic_field(MethodCounters, _invoke_mask, int) \ nonstatic_field(MethodCounters, _backedge_mask, int) \ @@ -515,12 +522,16 @@ \ declare_constant(FieldInfo::FieldFlags::_ff_injected) \ declare_constant(FieldInfo::FieldFlags::_ff_stable) \ + declare_constant(FieldInfo::FieldFlags::_ff_flat) \ + declare_constant(FieldInfo::FieldFlags::_ff_null_free_inline_type) \ + declare_constant(FieldInfo::FieldFlags::_ff_null_marker) \ declare_preprocessor_constant("JVM_ACC_VARARGS", JVM_ACC_VARARGS) \ declare_preprocessor_constant("JVM_ACC_BRIDGE", JVM_ACC_BRIDGE) \ declare_preprocessor_constant("JVM_ACC_ANNOTATION", JVM_ACC_ANNOTATION) \ declare_preprocessor_constant("JVM_ACC_ENUM", JVM_ACC_ENUM) \ declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ declare_preprocessor_constant("JVM_ACC_INTERFACE", JVM_ACC_INTERFACE) \ + declare_preprocessor_constant("JVM_ACC_IDENTITY", JVM_ACC_IDENTITY) \ \ declare_constant(JVM_CONSTANT_Utf8) \ declare_constant(JVM_CONSTANT_Unicode) \ @@ -559,6 +570,8 @@ declare_constant(BitData::exception_seen_flag) \ declare_constant(BitData::null_seen_flag) \ declare_constant(BranchData::not_taken_off_set) \ + declare_constant(ACmpData::left_inline_type_flag) \ + declare_constant(ACmpData::right_inline_type_flag) \ \ declare_constant_with_value("CardTable::dirty_card", CardTable::dirty_card_val()) \ declare_constant_with_value("LockStack::_end_offset", LockStack::end_offset()) \ @@ -589,7 +602,10 @@ declare_constant(nmethod::InvalidationReason::ZOMBIE) \ \ declare_constant(CodeInstaller::VERIFIED_ENTRY) \ + declare_constant(CodeInstaller::VERIFIED_INLINE_ENTRY) \ + declare_constant(CodeInstaller::VERIFIED_INLINE_ENTRY_RO) \ declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ + declare_constant(CodeInstaller::INLINE_ENTRY) \ declare_constant(CodeInstaller::OSR_ENTRY) \ declare_constant(CodeInstaller::EXCEPTION_HANDLER_ENTRY) \ declare_constant(CodeInstaller::DEOPT_HANDLER_ENTRY) \ @@ -816,6 +832,7 @@ declare_constant(Klass::_lh_instance_slow_path_bit) \ declare_constant(Klass::_lh_log2_element_size_shift) \ declare_constant(Klass::_lh_log2_element_size_mask) \ + declare_constant(Klass::FlatArrayKlassKind) \ declare_constant(Klass::_lh_element_type_shift) \ declare_constant(Klass::_lh_element_type_mask) \ declare_constant(Klass::_lh_header_size_shift) \ @@ -823,6 +840,9 @@ declare_constant(Klass::_lh_array_tag_shift) \ declare_constant(Klass::_lh_array_tag_type_value) \ declare_constant(Klass::_lh_array_tag_ref_value) \ + declare_constant(Klass::_lh_array_tag_obj_value) \ + declare_constant(Klass::_lh_null_free_shift) \ + declare_constant(Klass::_lh_null_free_mask) \ \ declare_constant(markWord::no_hash) \ \ @@ -874,6 +894,13 @@ \ declare_constant(markWord::no_hash_in_place) \ declare_constant(markWord::no_lock_in_place) \ + declare_constant(markWord::inline_type_pattern) \ + declare_constant(markWord::inline_type_mask_in_place) \ + declare_constant(markWord::inline_type_bit_in_place) \ + declare_constant(markWord::null_free_flat_array_pattern) \ + declare_constant(markWord::flat_array_mask_in_place) \ + declare_constant(markWord::null_free_array_pattern) \ + declare_constant(markWord::null_free_array_mask_in_place) \ // Helper macro to support ZGC pattern where the function itself isn't exported #define DECLARE_FUNCTION_FROM_ADDR(declare_function_with_value, name) \ @@ -887,6 +914,7 @@ declare_function(SharedRuntime::enable_stack_reserved_zone) \ declare_function(SharedRuntime::frem) \ declare_function(SharedRuntime::drem) \ + declare_function(SharedRuntime::store_inline_type_fields_to_buf) \ JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_start)) \ JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_end)) \ JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_mount)) \ @@ -926,11 +954,14 @@ declare_function(JVMCIRuntime::exception_handler_for_pc) \ declare_function(JVMCIRuntime::monitorenter) \ declare_function(JVMCIRuntime::monitorexit) \ + declare_function(JVMCIRuntime::load_unknown_inline) \ + declare_function(JVMCIRuntime::store_unknown_inline) \ declare_function(JVMCIRuntime::object_notify) \ declare_function(JVMCIRuntime::object_notifyAll) \ declare_function(JVMCIRuntime::throw_and_post_jvmti_exception) \ declare_function(JVMCIRuntime::throw_klass_external_name_exception) \ declare_function(JVMCIRuntime::throw_class_cast_exception) \ + declare_function(JVMCIRuntime::throw_identity_exception) \ declare_function(JVMCIRuntime::log_primitive) \ declare_function(JVMCIRuntime::log_object) \ declare_function(JVMCIRuntime::log_printf) \ diff --git a/src/hotspot/share/oops/fieldInfo.hpp b/src/hotspot/share/oops/fieldInfo.hpp index 4fac76255cb..26c5e430304 100644 --- a/src/hotspot/share/oops/fieldInfo.hpp +++ b/src/hotspot/share/oops/fieldInfo.hpp @@ -60,6 +60,7 @@ class FieldInfo { friend class FieldStreamBase; friend class FieldInfoReader; friend class VMStructs; + friend class JVMCIVMStructs; public: diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 74f1536a858..fefdc670cf8 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -141,6 +141,8 @@ struct JvmtiCachedClassFileData; class SigEntry; class InlineKlassFixedBlock { + friend class JVMCIVMStructs; + Array** _extended_sig; Array** _return_regs; address* _pack_handler; diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index e387d5ed074..6dd54335322 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -2071,12 +2071,14 @@ class ArrayLoadData : public ProfileData { }; class ACmpData : public BranchData { -private: + friend class VMStructs; + friend class JVMCIVMStructs; +protected: enum { left_inline_type_flag = DataLayout::first_flag, right_inline_type_flag }; - +private: SingleTypeEntry _left; SingleTypeEntry _right; diff --git a/src/java.base/share/classes/java/lang/reflect/Field.java b/src/java.base/share/classes/java/lang/reflect/Field.java index 4cb72f41a9e..ba888a24974 100644 --- a/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/src/java.base/share/classes/java/lang/reflect/Field.java @@ -77,6 +77,7 @@ class Field extends AccessibleObject implements Member { // Generics and annotations support private final transient String signature; private final byte[] annotations; + private final boolean trustedFinal; /** * Fields are mutable due to {@link AccessibleObject#setAccessible(boolean)}. @@ -136,6 +137,30 @@ private FieldRepository getGenericInfo() { this.slot = slot; this.signature = signature; this.annotations = annotations; + this.trustedFinal = isTrustedFinal(); + } + + /** + * Package-private constructor + */ + @SuppressWarnings("deprecation") + Field(Class declaringClass, + String name, + Class type, + int modifiers, + boolean trustedFinal, + int slot, + String signature, + byte[] annotations) { + this.clazz = declaringClass; + this.name = name; + this.type = type; + this.modifiers = modifiers; + this.trustedFinal = trustedFinal; + this.slot = slot; + this.signature = signature; + this.annotations = annotations; + this.flags = this.trustedFinal ? TRUST_FINAL : 0; } /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index e8d73e9c2e9..7fbdb2df885 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -596,11 +596,9 @@ Type classSigToType() { sbp - startSbp)); try { - if (outer == Type.noType) { - ClassType et = (ClassType) t.erasure(types); - return new ClassType(et.getEnclosingType(), List.nil(), et.tsym, et.getMetadata()); - } - return new ClassType(outer, List.nil(), t, List.nil()); + return (outer == Type.noType) ? + t.erasure(types) : + new ClassType(outer, List.nil(), t); } finally { sbp = startSbp; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java index 59af250a695..51509b37862 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Map; import jdk.vm.ci.meta.JavaType; @@ -437,4 +438,19 @@ public static CallingConvention getCallingConvention(CodeCacheProvider codeCache RegisterConfig registerConfig = codeCache.getRegisterConfig(); return registerConfig.getCallingConvention(type, retType, argTypes, valueKindFactory); } + + /** + * Create a calling convention from a {@link ResolvedJavaMethod} with scalarized inline type parameters . + * + * @param scalarizeReceiver true if the receiver should be scalarized, false otherwise + */ + public static CallingConvention getValhallaCallingConvention(CodeCacheProvider codeCache, CallingConvention.Type type, ResolvedJavaMethod method, ValueKindFactory valueKindFactory, boolean scalarizeReceiver) { + if (!method.hasScalarizedParameters()) return getCallingConvention(codeCache, type, method, valueKindFactory); + Signature sig = method.getSignature(); + List argTypes = method.getScalarizedParameters(scalarizeReceiver); + JavaType retType = sig.getReturnType(null); + RegisterConfig registerConfig = codeCache.getRegisterConfig(); + return registerConfig.getCallingConvention(type, retType, argTypes.toArray(new JavaType[argTypes.size()]), valueKindFactory); + } + } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java index 0cc1980b28f..dc30a48755c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java @@ -24,10 +24,9 @@ import java.util.List; import jdk.vm.ci.code.CallingConvention.Type; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.PlatformKind; -import jdk.vm.ci.meta.ValueKind; +import jdk.vm.ci.meta.*; + +import java.util.List; /** * A register configuration binds roles and {@linkplain RegisterAttributes attributes} to physical @@ -40,6 +39,15 @@ public interface RegisterConfig { */ Register getReturnRegister(JavaKind kind); + /** + * Gets the registers to be used for returning multiple values e.g. used for a scalarized inline object. Same procedure as with {@link #getReturnRegister(JavaKind)}. + * @param kinds the kinds used to decide if a value will be returned in a general or float register. + * @param includeFirstGeneralRegister determines if the first general register, which will contain the oop or tagged hub, should be skipped + */ + default Register[] getReturnRegisters(JavaKind[] kinds, boolean includeFirstGeneralRegister) { + throw new UnsupportedOperationException("config for multiple register usage on return not implemented yet"); + } + /** * Gets the maximum allowed size of the frame. */ @@ -63,6 +71,17 @@ default int getMaximumFrameSize() { */ CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory valueKindFactory); + /** + * Gets the ordered set of registers that are used to return a nullable scalarized inline object according to the return convention. + * The first register contains an oop or tagged hub, while the rest contains the field values. + * + * @param returnTypes types of the values being returned + * @param valueKindFactory the factory to create custom {@link ValueKind ValueKinds} + * @param includeFirstGeneralRegister determines if the first general register, which will contain the oop or tagged hub, should be skipped + */ + default List getReturnConvention(List returnTypes, ValueKindFactory valueKindFactory, boolean includeFirstGeneralRegister) { + throw new UnsupportedOperationException("config for multiple register usage on return not implemented yet"); + } /** * Gets the ordered set of registers that are can be used to pass parameters according to a * given calling convention. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/VirtualObject.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/VirtualObject.java index 1033fa559f8..2a5c2f6a173 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/VirtualObject.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/VirtualObject.java @@ -44,6 +44,7 @@ public final class VirtualObject implements JavaValue { private JavaKind[] slotKinds; private final int id; private boolean isAutoBox; + private JavaValue[] nonNull; /** * Creates a new {@link VirtualObject} for the given type, with the given fields. If @@ -240,6 +241,14 @@ public JavaValue[] getValues() { return values; } + /** + * Virtual objects can also be null. Returns an array containing one value indicating if the virtual object is non-null. + */ + @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "`values` is intentional mutable") + public JavaValue[] getNonNull() { + return nonNull; + } + /** * Returns the kind of the value at {@code index}. */ @@ -279,6 +288,15 @@ public void setValues(JavaValue[] values, JavaKind[] slotKinds) { this.slotKinds = slotKinds; } + /** + * Overwrites the current value with a new one. + * + * @param nonNull an array containing one value indicating if the virtual object is non-null. + */ + public void setNonNull(JavaValue[] nonNull) { + this.nonNull = nonNull; + } + @Override public int hashCode() { return 42 + type.hashCode(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/ACmpDataAccessor.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/ACmpDataAccessor.java new file mode 100644 index 00000000000..bd6caddc8b7 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/ACmpDataAccessor.java @@ -0,0 +1,19 @@ +package jdk.vm.ci.hotspot; + +/** + * The acmp comparison compares two objects for equality. Due to Valhalla, profiling data is now attached to this comparison. + * This class represents the profiled type information of both operands. + * Corresponds to {@code ciACmpData} + */ +public interface ACmpDataAccessor { + /** + * @return the profiled type information of the left operand + */ + SingleTypeEntry getLeft(); + + /** + * @return the profiled type information of the right operand + */ + SingleTypeEntry getRight(); + +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index b25f7a09256..f7f0a1ee2dc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -132,6 +132,74 @@ byte[] getBytecode(HotSpotResolvedJavaMethodImpl method) { private native byte[] getBytecode(HotSpotResolvedJavaMethodImpl method, long methodPointer); + /** + * Delivers information about scalarized parameters in the signature of the {@code method} + * + * @return a boolean array with the value true at index i if the parameter is scalarized, false otherwise + */ + boolean[] getScalarizedParametersInfo(HotSpotResolvedJavaMethodImpl method) { + int len = method.getSignature().getParameterCount(!method.isStatic()); + return getScalarizedParametersInfo(method, method.getMethodPointer(), new boolean[len], len); + } + + private native boolean[] getScalarizedParametersInfo(HotSpotResolvedJavaMethodImpl method, long methodPointer, boolean[] infoArray, int len); + + /** + * Determines if any parameter in the {@code method} is scalarized. + * + * @return true if any parameter is scalarized + */ + boolean hasScalarizedParameters(HotSpotResolvedJavaMethodImpl method) { + return hasScalarizedParameters(method, method.getMethodPointer()); + } + + private native boolean hasScalarizedParameters(HotSpotResolvedJavaMethodImpl method, long methodPointer); + + /** + * Determines if the scalarized calling convention of the {@code method} does not match that of a subclass. + * + * @return true if there is a mismatch + */ + boolean hasCallingConventionMismatch(HotSpotResolvedJavaMethodImpl method) { + return hasCallingConventionMismatch(method, method.getMethodPointer()); + } + + private native boolean hasCallingConventionMismatch(HotSpotResolvedJavaMethodImpl method, long methodPointer); + + /** + * Determines if the return value of the {@code method} is scalarized. + * + * @return true if the return value is scalarized + */ + boolean hasScalarizedReturn(HotSpotResolvedJavaMethodImpl method, HotSpotResolvedObjectTypeImpl inlineType) { + return hasScalarizedReturn(method, method.getMethodPointer(), inlineType, inlineType.getMetaspacePointer()); + } + + private native boolean hasScalarizedReturn(HotSpotResolvedJavaMethodImpl method, long methodPointer, HotSpotResolvedObjectTypeImpl returnType, long inlineTypePointer); + + /** + * Computes the scalarized signature of the {@code method}. + * + * @return the scalarized signature + */ + HotSpotSignature getScalarizedSignature(HotSpotResolvedJavaMethodImpl method) { + return getScalarizedSignature(method, method.getMethodPointer()); + } + + private native HotSpotSignature getScalarizedSignature(HotSpotResolvedJavaMethodImpl method, long methodPointer); + + /** + * Determines if a inline type can be passed scalarized as an argument. + * + * @return true if the inline type can be scalarized + */ + boolean canBePassedAsFields(HotSpotResolvedObjectTypeImpl type) { + return canBePassedAsFields(type, type.getKlassPointer()); + } + + private native boolean canBePassedAsFields(HotSpotResolvedObjectTypeImpl type, long klassPointer); + + /** * Gets the number of entries in {@code method}'s exception handler table or 0 if it has no * exception handler table. @@ -968,6 +1036,10 @@ int getVtableIndexForInterfaceMethod(HotSpotResolvedObjectTypeImpl type, HotSpot */ native HotSpotResolvedJavaMethodImpl getResolvedJavaMethod(HotSpotObjectConstantImpl base, long displacement); + native HotSpotResolvedJavaMethodImpl getIsSubstitutableMethod(); + + native HotSpotResolvedJavaMethodImpl getValueObjectHashCodeMethod(); + /** * Gets the {@code ConstantPool*} associated with {@code object} and returns a * {@link HotSpotConstantPool} wrapping it. @@ -1006,6 +1078,10 @@ HotSpotConstantPool getConstantPool(MetaspaceObject object) { */ private native HotSpotResolvedObjectTypeImpl getResolvedJavaType0(Object base, long displacement, boolean compressed); + HotSpotResolvedObjectTypeImpl getResolvedJavaType(Object base, long displacement) { + return getResolvedJavaType0(base, displacement, false); + } + HotSpotResolvedObjectTypeImpl getResolvedJavaType(HotSpotConstantPool base, long displacement) { return getResolvedJavaType0(base, displacement, false); } @@ -1111,6 +1187,20 @@ HotSpotResolvedObjectTypeImpl getArrayType(char primitiveTypeChar, HotSpotResolv native HotSpotResolvedObjectTypeImpl getArrayType(char typeChar, HotSpotResolvedObjectTypeImpl klass, long klassPointer); + HotSpotResolvedObjectTypeImpl getFlatArrayType(HotSpotResolvedObjectTypeImpl nonPrimitiveKlass) { + long nonPrimitiveKlassPointer = nonPrimitiveKlass.getKlassPointer(); + return getFlatArrayType((char) 0, nonPrimitiveKlass, nonPrimitiveKlassPointer); + } + + native HotSpotResolvedObjectTypeImpl getFlatArrayType(char typeChar, HotSpotResolvedObjectTypeImpl klass, long klassPointer); + + JavaConstant getDefaultInlineTypeInstance(HotSpotResolvedObjectTypeImpl nonPrimitiveKlass) { + long nonPrimitiveKlassPointer = nonPrimitiveKlass.getKlassPointer(); + return getDefaultInlineTypeInstance(nonPrimitiveKlass, nonPrimitiveKlassPointer); + } + + native JavaConstant getDefaultInlineTypeInstance(HotSpotResolvedObjectTypeImpl klass, long klassPointer); + /** * Forces initialization of {@code klass}. */ @@ -1210,11 +1300,15 @@ JavaConstant readStaticFieldValue(HotSpotResolvedObjectTypeImpl declaringKlass, * @throws IllegalArgumentException if any of the sanity checks fail */ JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedObjectTypeImpl expectedType, long offset, char typeChar) { + return readFieldValue(object, expectedType, offset, typeChar, false); + } + + JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedObjectTypeImpl expectedType, long offset, char typeChar, boolean isFlat) { long expectedTypePointer = expectedType != null ? expectedType.getKlassPointer() : 0L; - return readFieldValue(object, expectedType, expectedTypePointer, offset, typeChar); + return readFieldValue(object, expectedType, expectedTypePointer, offset, typeChar, isFlat); } - native JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedObjectTypeImpl expectedType, long expectedTypePointer, long offset, char typeChar); + native JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedObjectTypeImpl expectedType, long expectedTypePointer, long offset, char typeChar, boolean isFlat); /** * @see ResolvedJavaType#isInstance(JavaConstant) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java index c241af0348a..2f5e0114426 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java @@ -69,4 +69,9 @@ public JavaConstant uncompress() { public int getIdentityHashCode() { return System.identityHashCode(object); } + + @Override + public boolean objectIsInlineType() { + return !getType().isIdentity(); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java index 2cd5e839ee8..5fa47b6f4e1 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java @@ -996,6 +996,15 @@ private void writeVirtualObjects(VirtualObject[] virtualObjects) { VirtualObject vo = virtualObjects[i]; writeObjectType("type", vo.getType()); writeBoolean("isAutoBox", vo.isAutoBox()); + + // if virtual object can be null e.g. the scalarized return value of an invoke, also insert null indication + writeBoolean("nonNull", vo.getNonNull() != null); + if (vo.getNonNull() != null) { + writeBasicType(JavaKind.Int); + JavaValue jv = vo.getNonNull()[0]; + writeJavaValue(jv, JavaKind.Int); + } + } for (int i = 0; i < length; i++) { VirtualObject vo = virtualObjects[i]; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java index 9e1cd287527..4d2ba4ce03a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java @@ -66,6 +66,9 @@ public Boolean constantEquals(Constant x, Constant y) { if (x == y) { return true; } else if (x instanceof HotSpotObjectConstantImpl) { + if (runtime.getConfig().valhallaEnabled) { + return y instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) x).valhallaEquals(y); + } return y instanceof HotSpotObjectConstantImpl && x.equals(y); } else { return Objects.equals(x, y); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java index 3211e0ab409..60fbbbb554f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java @@ -52,6 +52,10 @@ abstract class HotSpotJVMCIReflection { abstract boolean equals(HotSpotObjectConstantImpl hotSpotResolvedJavaType, HotSpotObjectConstantImpl that); + Boolean valhallaEquals(HotSpotObjectConstantImpl hotSpotResolvedJavaType, HotSpotObjectConstantImpl that) { + return equals(hotSpotResolvedJavaType, that); + } + abstract ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod); abstract Annotation[][] getParameterAnnotations(HotSpotResolvedJavaMethodImpl javaMethod); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java index 0bc6fce0ce2..3366de3aa18 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java @@ -81,6 +81,28 @@ public ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod) { return runtime.getCompilerToVM().asResolvedJavaMethod(Objects.requireNonNull(reflectionMethod)); } + private ResolvedJavaMethod isSubstitutableMethod; + + @Override + public ResolvedJavaMethod getIsSubstitutableMethod() { + if (isSubstitutableMethod != null) { + return isSubstitutableMethod; + } + isSubstitutableMethod = runtime.getCompilerToVM().getIsSubstitutableMethod(); + return isSubstitutableMethod; + } + + private ResolvedJavaMethod valueObjectHashCodeMethod; + + @Override + public ResolvedJavaMethod getValueObjectHashCodeMethod() { + if (valueObjectHashCodeMethod != null) { + return valueObjectHashCodeMethod; + } + valueObjectHashCodeMethod = runtime.getCompilerToVM().getValueObjectHashCodeMethod(); + return valueObjectHashCodeMethod; + } + @Override public ResolvedJavaField lookupJavaField(Field reflectionField) { Class fieldHolder = reflectionField.getDeclaringClass(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodData.java index 938b7d872c1..70bd0524328 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodData.java @@ -76,6 +76,14 @@ static final class VMState { final int branchDataSize = cellIndexToOffset(3); final int notTakenCountOffset = cellIndexToOffset(config.branchDataNotTakenOffset); + // inherits from branch and two cells for types + final int acmpDataSize = branchDataSize + cellsToBytes(1)*2; + + final int leftOperandOffset = cellIndexToOffset(3); + final int rightOperandOffset = cellIndexToOffset(4); + final int leftInlineTypeFlag = 1 << config.leftInlineTypeFlag; + final int rightInlineTypeFlag = 1 << config.rightInlineTypeFlag; + final int arrayDataLengthOffset = cellIndexToOffset(config.arrayDataArrayLenOffset); final int arrayDataStartOffset = cellIndexToOffset(config.arrayDataArrayStartOffset); @@ -106,7 +114,7 @@ static final class VMState { new UnknownProfileData(this, config.dataLayoutSpeculativeTrapDataTag), new UnknownProfileData(this, config.dataLayoutArrayStoreDataTag), new UnknownProfileData(this, config.dataLayoutArrayLoadDataTag), - new UnknownProfileData(this, config.dataLayoutACmpDataTag), + new ACmpData(this, config.dataLayoutACmpDataTag), }; // @formatter:on @@ -290,6 +298,11 @@ private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) { return VMState.truncateLongToInt(value); } + private long readPointer(int position, int offsetInBytes) { + long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); + return UNSAFE.getAddress(methodDataPointer + fullOffsetInBytes); + } + /** * Since the values are stored in cells (platform words) this method uses * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. @@ -680,6 +693,10 @@ static class BranchData extends JumpData { super(state, tag, state.branchDataSize); } + protected BranchData(VMState state, int tag, int staticSize) { + super(state, tag, staticSize); + } + @Override public double getBranchTakenProbability(HotSpotMethodData data, int position) { long takenCount = data.readUnsignedInt(position, state.takenCountOffset); @@ -704,6 +721,170 @@ public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) } } + static class ACmpData extends BranchData { + + abstract static class SingleTypeEntryImpl implements SingleTypeEntry { + private final long value; + private final VMState state; + private HotSpotResolvedObjectType validType; + private boolean maybeNull; + private boolean neverNull; + private boolean alwaysNull; + private boolean inlineType; + + final static long nullSeen =1; + final static long typeMask = ~nullSeen; + final static long typeUnknown = 2; + + SingleTypeEntryImpl(ACmpData aCmpData, HotSpotMethodData data, int position) { + this.state = aCmpData.state; + this.value = data.readPointer(position, getOperandOffset()); + + int offset = state.computeFullOffset(position, getOperandOffset()); + this.validType = computeValidType(this.value, data, offset); + + if(!wasNullSeen(this.value)){ + this.neverNull = true; + }else if(isTypeNone(this.value)){ + this.alwaysNull = true; + }else{ + this.maybeNull = true; + } + + int flags = aCmpData.getFlags(data, position); + this.inlineType =(flags & getInlineFlag()) !=0; + } + + abstract int getOperandOffset(); + abstract int getInlineFlag(); + + protected VMState getState(){ + return state; + } + + private static boolean isTypeNone(long value){ + return (value & typeMask) == 0; + } + + private static boolean isTypeUnknown(long value){ + return (value & typeUnknown) != 0; + } + + private static boolean wasNullSeen(long value){ + return (value & nullSeen) != 0; + } + + private HotSpotResolvedObjectType computeValidType(long value, HotSpotMethodData data, int offset){ + if(!isTypeNone(value) && ! isTypeUnknown(value)){ + return compilerToVM().getResolvedJavaType(data, offset); + }else{ + return null; + } + + } + + @Override + public HotSpotResolvedObjectType getValidType(){ + return validType; + } + + @Override + public boolean maybeNull(){ + return maybeNull; + } + + @Override + public boolean neverNull(){ + return neverNull; + } + + @Override + public boolean alwaysNull(){ + return alwaysNull; + } + + @Override + public boolean inlineType(){ + return inlineType; + } + + + } + + static class LeftSingleTypeEntryImpl extends SingleTypeEntryImpl { + + LeftSingleTypeEntryImpl(ACmpData aCmpData,HotSpotMethodData data, int position) { + super(aCmpData, data, position); + } + + @Override + int getOperandOffset(){ + return getState().leftOperandOffset; + } + + @Override + int getInlineFlag(){ + return getState().leftInlineTypeFlag; + } + } + + static class RightSingleTypeEntryImpl extends SingleTypeEntryImpl { + + RightSingleTypeEntryImpl(ACmpData aCmpData, HotSpotMethodData data, int position) { + super(aCmpData, data, position); + } + + @Override + int getOperandOffset(){ + return getState().rightOperandOffset; + } + + @Override + int getInlineFlag(){ + return getState().rightInlineTypeFlag; + } + } + + static class ACmpDataAccessorImpl implements ACmpDataAccessor{ + + private final SingleTypeEntry left; + private final SingleTypeEntry right; + + ACmpDataAccessorImpl(ACmpData aCmpData, HotSpotMethodData data, int position){ + left = aCmpData.getLeft(aCmpData, data, position); + right = aCmpData.getRight(aCmpData, data, position); + } + + @Override + public SingleTypeEntry getLeft() { + return left; + } + + @Override + public SingleTypeEntry getRight() { + return right; + } + } + + + ACmpData(VMState state, int tag) { + super(state, tag, state.acmpDataSize); + } + + private SingleTypeEntry getLeft(ACmpData aCmpData, HotSpotMethodData data, int position) { + return new LeftSingleTypeEntryImpl(aCmpData, data, position); + } + + private SingleTypeEntry getRight(ACmpData aCmpData, HotSpotMethodData data, int position) { + return new RightSingleTypeEntryImpl(aCmpData, data, position); + } + + public ACmpDataAccessor getACmpAccessor(HotSpotMethodData data, int position){ + return new ACmpDataAccessorImpl(this, data, position); + } + + } + static class ArrayData extends HotSpotMethodDataAccessor { ArrayData(VMState state, int tag, int staticSize) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstant.java index bed38f91988..647d2d5cf02 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstant.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstant.java @@ -114,4 +114,8 @@ default Assumptions.AssumptionResult getCallSiteTarget() { @Override String toValueString(); + + default boolean objectIsInlineType(){ + return false; + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java index 1dcc969b3e6..c2476ddbf3c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java @@ -168,6 +168,16 @@ public boolean equals(Object o) { return false; } + public Boolean valhallaEquals(Object o) { + if (o == this) { + return true; + } else if (o instanceof HotSpotObjectConstantImpl) { + HotSpotObjectConstantImpl other = (HotSpotObjectConstantImpl) o; + return runtime().reflection.valhallaEquals(this, other); + } + return false; + } + @Override public int hashCode() { return getIdentityHashCode(); @@ -196,9 +206,9 @@ public JavaConstant readFieldValue(HotSpotResolvedJavaField field) { if (field.isStatic()) { return null; } - HotSpotResolvedObjectTypeImpl declaringClass = (HotSpotResolvedObjectTypeImpl) field.getDeclaringClass(); + HotSpotResolvedObjectTypeImpl declaringClass = (HotSpotResolvedObjectTypeImpl) field.getContainerClass(); char typeChar = field.getType().getJavaKind().getTypeChar(); - return runtime().compilerToVm.readFieldValue(this, declaringClass, field.getOffset(), typeChar); + return runtime().compilerToVm.readFieldValue(this, declaringClass, field.getOffset(), typeChar, declaringClass != field.getDeclaringClass()); } public ResolvedJavaType asJavaType() { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfoImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfoImpl.java index 3dcdedef282..0cc6bd55a64 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfoImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfoImpl.java @@ -127,6 +127,18 @@ public TriState getExceptionSeen(int bci) { return dataAccessor.getExceptionSeen(methodData, position); } + @Override + public Object getACmpData(int bci) { + if (!isMature) { + return null; + } + findBCI(bci); + if(dataAccessor instanceof HotSpotMethodData.ACmpData aCmpData){ + return aCmpData.getACmpAccessor(methodData, position); + } + return null; + } + @Override public TriState getNullSeen(int bci) { findBCI(bci); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index b75edb9df08..d386e439f29 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -36,11 +36,7 @@ import java.util.List; import jdk.internal.vm.VMSupport; -import jdk.vm.ci.meta.AnnotationData; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.*; /** * Represents a field in a HotSpot type. @@ -48,13 +44,16 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { private final HotSpotResolvedObjectTypeImpl holder; + + private HotSpotResolvedObjectTypeImpl containerClass; + private JavaType type; /** * Offset (in bytes) of field from start of its storage container (i.e. {@code instanceOop} or * {@code Klass*}). */ - private final int offset; + private int offset; /** * Value of {@code fieldDescriptor::index()}. @@ -89,7 +88,7 @@ public boolean equals(Object obj) { HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; if (that.offset != this.offset || that.isStatic() != this.isStatic()) { return false; - } else if (this.holder.equals(that.holder)) { + } else if (this.holder.equals(that.holder) && this.getContainerClass().equals(that.getContainerClass())) { return true; } } @@ -111,6 +110,52 @@ public boolean isInternal() { return (internalFlags & (1 << config().jvmFieldFlagInternalShift)) != 0; } + @Override + public boolean isNullFreeInlineType() { + return (internalFlags & (1 << config().jvmFieldFlagNullFreeInlineTypeShift)) != 0; + } + + @Override + public boolean isFlat() { + return (internalFlags & (1 << config().jvmFieldFlagFlatShift)) != 0; + } + + @Override + public boolean isInitialized() { + assert isStatic() : "should only be called on static fields"; + if (getDeclaringClass().isInitialized()) { + return !runtime().getCompilerToVM().readStaticFieldValue(getDeclaringClass(), getOffset(), JavaKind.Object.getTypeChar()).isNull(); + } + return false; + } + + @Override + public int getNullMarkerOffset() { + return holder.getFieldInfo(index).getNullMarkerOffset(); + } + + @Override + public HotSpotResolvedJavaField getNullMarkerField() { + HotSpotResolvedJavaType byteType = HotSpotResolvedPrimitiveType.forKind(JavaKind.Byte); + return new HotSpotResolvedJavaFieldImpl(holder, byteType, getNullMarkerOffset(), 0, 0, -1) { + @Override + public String getName() { + return "nullMarkerOffset"; + } + + @Override + public int getNullMarkerOffset() { + return -1; + } + + @Override + public JavaConstant getConstantValue() { + return null; + } + }; + //return new HotSpotResolvedJavaFieldImpl(holder, byteType, getNullMarkerOffset(), 0, 0, -1); + } + /** * Determines if a given object contains this field. * @@ -131,6 +176,21 @@ public HotSpotResolvedObjectTypeImpl getDeclaringClass() { return holder; } + @Override + public HotSpotResolvedObjectTypeImpl getContainerClass() { + if (containerClass == null) { + return holder; + } + return containerClass; + } + + @Override + public ResolvedJavaField setContainerClass(ResolvedJavaType containerClass) { + HotSpotResolvedJavaFieldImpl field = new HotSpotResolvedJavaFieldImpl(holder, type, offset, classfileFlags, internalFlags, index); + field.containerClass = (HotSpotResolvedObjectTypeImpl) containerClass; + return field; + } + @Override public String getName() { return holder.getFieldInfo(index).getName(holder); @@ -162,6 +222,11 @@ public int getOffset() { return offset; } + @Override + public ResolvedJavaField changeOffset(int newOffset) { + return new HotSpotResolvedJavaFieldImpl(holder, type, newOffset, classfileFlags, internalFlags, index); + } + /** * Gets the value of this field's index (i.e. {@code fieldDescriptor::index()} in the encoded * fields of the declaring class. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 224e8b1a070..8290ccd3593 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -38,29 +38,15 @@ import java.lang.reflect.Executable; import java.lang.reflect.Modifier; import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; import java.util.List; -import java.util.Objects; import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; -import jdk.vm.ci.meta.AnnotationData; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.ConstantPool; -import jdk.vm.ci.meta.DefaultProfilingInfo; -import jdk.vm.ci.meta.ExceptionHandler; -import jdk.vm.ci.meta.JavaMethod; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.LineNumberTable; -import jdk.vm.ci.meta.Local; -import jdk.vm.ci.meta.LocalVariableTable; -import jdk.vm.ci.meta.ProfilingInfo; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.SpeculationLog; -import jdk.vm.ci.meta.TriState; +import jdk.vm.ci.meta.*; /** * Implementation of {@link JavaMethod} for resolved HotSpot methods. @@ -810,4 +796,200 @@ public BitSet getOopMapAt(int bci) { compilerToVM().getOopMapAt(this, bci, oopMap); return BitSet.valueOf(oopMap); } + + private boolean[] scalarizedParametersInfo; + + @Override + public boolean isScalarizedParameter(int index, boolean indexIncludesReceiverIfExists) { + // see ciMethod::is_scalarized_arg + if (scalarizedParametersInfo == null) { + scalarizedParametersInfo = compilerToVM().getScalarizedParametersInfo(this); + } + // if method is non-static index 0 refers to receiver, therefore adapt the index + return scalarizedParametersInfo[index + ((isStatic() || indexIncludesReceiverIfExists) ? 0 : 1)]; + } + + + @Override + public boolean isParameterNullFree(int index, boolean indexIncludesReceiverIfExists) { + // maybe for the future + if (!indexIncludesReceiverIfExists) return false; + if (!isStatic() && index == 0) return true; + return false; + } + + private TriState hasScalarizedParameters = TriState.UNKNOWN; + + @Override + public boolean hasScalarizedParameters() { + // see ciMethod::has_scalarized_args + if (hasScalarizedParameters.isKnown()) return hasScalarizedParameters.toBoolean(); + boolean result = compilerToVM().hasScalarizedParameters(this); + hasScalarizedParameters = TriState.get(result); + return result; + } + + private TriState hasScalarizedReturn = TriState.UNKNOWN; + + @Override + public boolean hasScalarizedReturn() { + if (hasScalarizedReturn.isKnown()) return hasScalarizedReturn.toBoolean(); + boolean result; + if (!returnsInlineType()) { + result = false; + } else { + result = compilerToVM().hasScalarizedReturn(this, getReturnedInlineType()); + } + hasScalarizedReturn = TriState.get(result); + return result; + } + + private TriState hasScalarizedReceiver = TriState.UNKNOWN; + + @Override + public boolean hasScalarizedReceiver() { + if (hasScalarizedReceiver.isKnown()) return hasScalarizedReceiver.toBoolean(); + boolean result = !isStatic() && isScalarizedParameter(0, true); + hasScalarizedReceiver = TriState.get(result); + return result; + } + + private TriState hasCallingConventionMismatch = TriState.UNKNOWN; + + @Override + public boolean hasCallingConventionMismatch() { + if (hasCallingConventionMismatch.isKnown()) return hasCallingConventionMismatch.toBoolean(); + boolean result = compilerToVM().hasCallingConventionMismatch(this); + hasCallingConventionMismatch = TriState.get(result); + return result; + } + + @Override + public List getScalarizedReturn() { + assert hasScalarizedReturn() : "Scalarized return presumed"; + JavaType type = signature.getReturnType(getDeclaringClass()); + assert type instanceof HotSpotResolvedObjectType : "HotSpotResolvedObjectType expected"; + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + ResolvedJavaField[] fields = resolvedType.getInstanceFields(true); + + // one extra field for oop or hub + int length = fields.length + 1; + List types = new ArrayList<>(length); + types.add(resolvedType); + for (int i = 1; i < length; i++) { + types.add(fields[i - 1].getType()); + } + return List.copyOf(types); + } + + private boolean returnsInlineType() { + JavaType returnType = signature.getReturnType(getDeclaringClass()); + + // check if the method returns an object + // the type is not expected to be resolved + if (returnType instanceof HotSpotResolvedObjectType type) { + // check if the returned value is an inline type + return !type.isInterface() && !type.isAbstract() && !type.isIdentity(); + } + return false; + } + + private HotSpotResolvedObjectTypeImpl getReturnedInlineType() { + return (HotSpotResolvedObjectTypeImpl) signature.getReturnType(getDeclaringClass()); + } + + + @Override + public List getScalarizedParameterNullFree(int index, boolean indexIncludesReceiverIfExists) { + return getScalarizedParameter(index, indexIncludesReceiverIfExists, true); + } + + @Override + public List getScalarizedParameter(int index, boolean indexIncludesReceiverIfExists) { + return getScalarizedParameter(index, indexIncludesReceiverIfExists, isParameterNullFree(index, indexIncludesReceiverIfExists)); + } + + private List getScalarizedParameter(int index, boolean indexIncludesReceiverIfExists, boolean nullFree) { + assert isScalarizedParameter(index, indexIncludesReceiverIfExists) : "Scalarized parameter presumed"; + boolean includeReceiver = indexIncludesReceiverIfExists && !isStatic(); + int previousIndex = index; + if (includeReceiver) { + if (index == 0) { + assert nullFree : "receiver should be null-free"; + return getFields(getDeclaringClass(), true, null); + } else { + index--; + } + } + JavaType type = signature.getParameterType(index, getDeclaringClass()); + assert type instanceof HotSpotResolvedObjectType : "HotSpotResolvedObjectType expected"; + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + return getFields((HotSpotResolvedObjectTypeImpl) resolvedType, nullFree, nullFree ? null : getScalarizedParameterNonNullType(previousIndex, indexIncludesReceiverIfExists)); + + } + + @Override + public List getScalarizedParameterFields(int index, boolean indexIncludesReceiverIfExists) { + assert isScalarizedParameter(index, indexIncludesReceiverIfExists) : "Scalarized parameter presumed"; + boolean includeReceiver = indexIncludesReceiverIfExists && !isStatic(); + if (includeReceiver) { + if (index == 0) { + return List.of(getDeclaringClass().getInstanceFields(true)); + } else { + index--; + } + } + JavaType type = signature.getParameterType(index, getDeclaringClass()); + assert type instanceof HotSpotResolvedObjectType : "HotSpotResolvedObjectType expected"; + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + return List.of(resolvedType.getInstanceFields(true)); + } + + @Override + public JavaType getScalarizedParameterNonNullType(int index, boolean indexIncludesReceiverIfExists) { + assert isScalarizedParameter(index, indexIncludesReceiverIfExists) /*&& !isParameterNullFree(index, indexIncludesReceiverIfExists)*/ : "Scalarized nullable parameter presumed"; + return HotSpotResolvedPrimitiveType.forKind(NON_NULL_KIND); + } + + private static final JavaKind NON_NULL_KIND = JavaKind.Byte; + + + @Override + public List getScalarizedParameters(boolean scalarizeReceiver) { + // see TypeTuple::make_domain in opto/type.cpp + assert hasScalarizedParameters() : "Any scalarized parameters presumed"; + List types = new ArrayList<>(); + if (hasScalarizedReceiver() && scalarizeReceiver) { + types.addAll(getFields(getDeclaringClass(), true, null)); + } else if (!isStatic()) { + types.add(getDeclaringClass()); + } + for (int i = 0; i < signature.getParameterCount(false); i++) { + JavaType type = signature.getParameterType(i, getDeclaringClass()); + + if (isScalarizedParameter(i, false)) { + assert type instanceof HotSpotResolvedObjectType : "HotSpotResolvedObjectType expected"; + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + boolean nullFree = isParameterNullFree(i, false); + types.addAll(getFields((HotSpotResolvedObjectTypeImpl) resolvedType, nullFree, nullFree ? null : getScalarizedParameterNonNullType(i, false))); + } else { + types.add(type); + } + } + + return List.copyOf(types); + } + + + private List getFields(HotSpotResolvedObjectTypeImpl holder, boolean nullFree, JavaType nonNullType) { + ResolvedJavaField[] fields = holder.getInstanceFields(true); + List types = new ArrayList<>(fields.length + (!nullFree ? 1 : 0)); + if (!nullFree) { + types.add(nonNullType); + } + for (int i = 0; i < fields.length; i++) { + types.add(fields[i].getType()); + } + return List.copyOf(types); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index ab634568a84..e49f82d7a8f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -31,6 +31,7 @@ public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { HotSpotResolvedObjectType arrayOfType; + HotSpotResolvedObjectType flatArrayOfType; protected HotSpotResolvedJavaType(String name) { super(name); @@ -54,6 +55,8 @@ public int hashCode() { */ protected abstract HotSpotResolvedObjectType getArrayType(); + abstract HotSpotResolvedObjectTypeImpl getFlatArrayType(); + @Override public HotSpotResolvedObjectType getArrayClass() { if (arrayOfType == null) { @@ -62,6 +65,14 @@ public HotSpotResolvedObjectType getArrayClass() { return arrayOfType; } + @Override + public final HotSpotResolvedObjectType getFlatArrayClass() { + if (flatArrayOfType == null) { + flatArrayOfType = getFlatArrayType(); + } + return flatArrayOfType; + } + /** * Checks whether this type is currently being initialized. If a type is being initialized it * implies that it was {@link #isLinked() linked} and that the static initializer is currently diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index 1fc5f1bfd6a..1febe30bc9f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -39,6 +39,21 @@ public interface HotSpotResolvedObjectType extends ResolvedJavaType { @Override HotSpotResolvedObjectType getArrayClass(); + @Override + default HotSpotResolvedObjectType getFlatArrayClass(){ + return null; + } + + @Override + default HotSpotResolvedObjectType convertToFlatArray(){ + return null; + } + + @Override + default JavaConstant getDefaultInlineTypeInstance(){ + return null; + } + @Override ResolvedJavaType getComponentType(); @@ -75,6 +90,18 @@ default JavaKind getJavaKind() { */ int instanceSize(); + /** + * Gets the component size in an array + */ + default int getLog2ComponentSize(){ + return -1; + } + + @Override + default boolean isFlatArray(){ + return false; + } + int getVtableLength(); @Override @@ -105,6 +132,10 @@ default JavaConstant getJavaMirror() { int superCheckOffset(); + default int payloadOffset() { + return -1; + } + long prototypeMarkWord(); int layoutHelper(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 46e53411dee..36cb769e2fa 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -22,6 +22,17 @@ */ package jdk.vm.ci.hotspot; +import jdk.internal.vm.VMSupport; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.*; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.ByteOrder; +import java.util.*; + import static java.util.Objects.requireNonNull; import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; import static jdk.vm.ci.hotspot.HotSpotConstantPool.isSignaturePolymorphicHolder; @@ -30,34 +41,6 @@ import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.nio.ByteOrder; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; - -import jdk.internal.vm.VMSupport; -import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.AnnotationData; -import jdk.vm.ci.meta.Assumptions.AssumptionResult; -import jdk.vm.ci.meta.Assumptions.ConcreteMethod; -import jdk.vm.ci.meta.Assumptions.ConcreteSubtype; -import jdk.vm.ci.meta.Assumptions.LeafType; -import jdk.vm.ci.meta.Assumptions.NoFinalizableSubclass; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.UnresolvedJavaField; -import jdk.vm.ci.meta.UnresolvedJavaType; - /** * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. This class is not * an {@link MetaspaceHandleObject} because it doesn't have to be scanned for GC. It's liveness is @@ -103,7 +86,7 @@ static HotSpotResolvedObjectTypeImpl getJavaLangObject() { /** * Gets the JVMCI mirror from a HotSpot type. - * + *

* Called from the VM. * * @param klassPointer a native pointer to the Klass* @@ -464,6 +447,14 @@ public boolean isInterface() { return (getAccessFlags() & config().jvmAccInterface) != 0; } + @Override + public boolean isIdentity() { + if (config().valhallaEnabled) { + return isArray() || (getAccessFlags() & config().jvmAccIdentity) != 0; + } + return !isInterface(); + } + @Override public boolean isAssignableFrom(ResolvedJavaType other) { assert other != null; @@ -544,6 +535,26 @@ public int instanceSize() { return needsSlowPath ? -size : size; } + @Override + public int getLog2ComponentSize() { + assert isArray(); + HotSpotVMConfig config = config(); + final int layoutHelper = layoutHelper(); + // assert(lh < (jint)_lh_neutral_value, "must be array"); + // int l2esz = (lh >> _lh_log2_element_size_shift) & _lh_log2_element_size_mask; + assert layoutHelper < config.klassLayoutHelperNeutralValue : "must be array"; + int l2esz = (layoutHelper >> config.klassLayoutHelperLog2ElementSizeShift) & config.klassLayoutHelperLog2ElementSizeMask; + return l2esz; + } + + @Override + public boolean isFlatArray() { + HotSpotVMConfig config = config(); + assert isArray(); + assert getKlassPointer() != 0 : getName(); + return UNSAFE.getInt(getKlassPointer() + config.klassKind) == config.klassFlatArray; + } + @Override public int layoutHelper() { HotSpotVMConfig config = config(); @@ -681,6 +692,25 @@ protected HotSpotResolvedObjectTypeImpl getArrayType() { return runtime().compilerToVm.getArrayType((char) 0, this); } + @Override + public HotSpotResolvedObjectTypeImpl getFlatArrayType() { + return runtime().compilerToVm.getFlatArrayType(this); + } + + @Override + public HotSpotResolvedObjectTypeImpl convertToFlatArray() { + assert isArray() : "only an array class can be converted to flat array class"; + ResolvedJavaType componentType = this.getComponentType(); + assert componentType != null : "component type must not be null"; + if (!(componentType instanceof HotSpotResolvedObjectTypeImpl)) return this; + return runtime().compilerToVm.getFlatArrayType((HotSpotResolvedObjectTypeImpl) componentType); + } + + @Override + public JavaConstant getDefaultInlineTypeInstance() { + return runtime().compilerToVm.getDefaultInlineTypeInstance(this); + } + /** * This class represents the field information for one field contained in the fields array of an * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. @@ -693,6 +723,7 @@ static class FieldInfo { private final int classfileFlags; private final int internalFlags; private final int initializerIndex; + private final int nullMarkerOffset; /** * Creates a field info with the provided indices. @@ -704,13 +735,14 @@ static class FieldInfo { * @param internalFlags field's internal flags (from the VM) * @param initializerIndex field's initial value index in the constant pool */ - FieldInfo(int nameIndex, int signatureIndex, int offset, int classfileFlags, int internalFlags, int initializerIndex) { + FieldInfo(int nameIndex, int signatureIndex, int offset, int classfileFlags, int internalFlags, int initializerIndex, int nullMarkerOffset) { this.nameIndex = nameIndex; this.signatureIndex = signatureIndex; this.offset = offset; this.classfileFlags = classfileFlags; this.internalFlags = internalFlags; this.initializerIndex = initializerIndex; + this.nullMarkerOffset = nullMarkerOffset; } private int getClassfileFlags() { @@ -737,6 +769,10 @@ public int getOffset() { return offset; } + public int getNullMarkerOffset() { + return nullMarkerOffset; + } + /** * Returns the name of this field as a {@link String}. If the field is an internal field the * name index is pointing into the vmSymbols table. @@ -776,6 +812,29 @@ private boolean isInternal() { return (getInternalFlags() & (1 << config().jvmFieldFlagInternalShift)) != 0; } + private boolean isFlat() { + return (getInternalFlags() & (1 << config().jvmFieldFlagFlatShift)) != 0; + } + + private boolean isNullFreeInlineType() { + return (getInternalFlags() & (1 << config().jvmFieldFlagNullFreeInlineTypeShift)) != 0; + } + + private boolean hasNullMarker() { + return (getInternalFlags() & (1 << config().jvmFieldFlagNullMarkerShift)) != 0; + } + + private boolean hasInternalNullMarker() { + return true; + //return (getInternalFlags() & (1 << config().jvmFieldFlagInternalNullMarkerShift)) != 0; + } + +// private int internalNullMarkerOffset() { +// HotSpotVMConfig config = config(); +// long fixedBlockPointer = UNSAFE.getAddress(getKlassPointer() + config.inlineKlassFixedBlockAdr); +// return UNSAFE.getInt(fixedBlockPointer + config.internalNullMarkerOffset); +// } + public boolean isStatic() { return Modifier.isStatic(getClassfileFlags()); } @@ -783,6 +842,10 @@ public boolean isStatic() { @Override public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { + return getInstanceFields(includeSuperclasses, config().valhallaEnabled); + } + + public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses, boolean valhallaEnabled) { if (instanceFields == null) { if (isArray() || isInterface()) { instanceFields = NO_FIELDS; @@ -791,7 +854,12 @@ public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { if (getSuperclass() != null) { prepend = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); } - instanceFields = getFields(false, prepend); + if (valhallaEnabled) { + instanceFields = getFlattenedFields(prepend); + } else { + instanceFields = getFields(false, prepend); + } + } } if (!includeSuperclasses && getSuperclass() != null) { @@ -827,6 +895,68 @@ public ResolvedJavaField[] getStaticFields() { } } + /** + * Gets the (flattened) instance fields of this class. + * + * @param prepend an array to be prepended to the returned result + */ + private HotSpotResolvedJavaField[] getFlattenedFields(HotSpotResolvedJavaField[] prepend) { + + + HotSpotVMConfig config = config(); + int resultCount = 0; + int index = 0; + + + for (index = 0; index < getFieldInfo().length; index++) { + if (!getFieldInfo(index).isStatic()) { + resultCount++; + } + } + + if (resultCount == 0) { + return prepend; + } + + List resultList = new ArrayList<>(Arrays.asList(prepend)); + + int prependLength = prepend.length; + resultCount = 0; + resultCount += prependLength; + + for (index = 0; index < getFieldInfo().length; index++) { + if (getFieldInfo(index).isStatic()) continue; + + FieldInfo fieldInfo = getFieldInfo(index); + int fieldOffset = fieldInfo.getOffset(); + if (fieldInfo.isFlat()) { + HotSpotResolvedJavaField resolvedJavaField = createField(getFieldInfo(index).getType(this), fieldInfo.getOffset(), fieldInfo.getClassfileFlags(), fieldInfo.getInternalFlags(), index); + JavaType field = resolvedJavaField.getType(); + + if (field instanceof HotSpotResolvedObjectType resolvedFieldType) { + ResolvedJavaField[] innerFields = resolvedFieldType.getInstanceFields(true); + resultCount += innerFields.length; + + // compute all flattened fields recursively + for (int i = 0; i < innerFields.length; ++i) { + // holder has no header so remove the header offset + int offset = fieldOffset + (innerFields[i].getOffset() - resolvedFieldType.payloadOffset()); + HotSpotResolvedJavaField innerField = (HotSpotResolvedJavaField) innerFields[i]; + resultList.add((HotSpotResolvedJavaField) innerField.changeOffset(offset).setContainerClass((HotSpotResolvedObjectType) resolvedJavaField.getDeclaringClass())); + } + } + + } else { + HotSpotResolvedJavaField resolvedJavaField = createField(fieldInfo.getType(this), fieldInfo.getOffset(), fieldInfo.getClassfileFlags(), fieldInfo.getInternalFlags(), index); + resultCount++; + resultList.add(resolvedJavaField); + } + } + assert resultList.size() == resultCount : "wrong flat field count"; + resultList.sort(fieldSortingMethod); + return resultList.toArray(new HotSpotResolvedJavaField[resultList.size()]); + } + /** * Gets the instance or static fields of this class. * @@ -988,6 +1118,13 @@ public int superCheckOffset() { return UNSAFE.getInt(getKlassPointer() + config.superCheckOffsetOffset); } + @Override + public int payloadOffset() { + HotSpotVMConfig config = config(); + long fixedBlockPointer = UNSAFE.getAddress(getKlassPointer() + config.inlineKlassFixedBlockAdr); + return UNSAFE.getInt(fixedBlockPointer + config.payloadOffset); + } + @Override public long prototypeMarkWord() { HotSpotVMConfig config = config(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index 9da92713be4..f9148cc8033 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -97,6 +97,11 @@ protected HotSpotResolvedObjectType getArrayType() { return runtime().compilerToVm.getArrayType(getJavaKind().getTypeChar(), null); } + @Override + HotSpotResolvedObjectTypeImpl getFlatArrayType() { + return getArrayType(); + } + @Override public ResolvedJavaType getElementalType() { return this; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index d463ace9181..00718419d28 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -72,12 +72,16 @@ static String getHostArchitectureName() { final int objectAlignment = getFlag("ObjectAlignmentInBytes", Integer.class); final int klassOffsetInBytes = getFieldValue("CompilerToVM::Data::oopDesc_klass_offset_in_bytes", Integer.class, "int"); + public final boolean valhallaEnabled = getFlag("EnableValhalla", Boolean.class); final int subklassOffset = getFieldOffset("Klass::_subklass", Integer.class, "Klass*"); final int superOffset = getFieldOffset("Klass::_super", Integer.class, "Klass*"); final int nextSiblingOffset = getFieldOffset("Klass::_next_sibling", Integer.class, "Klass*"); final int superCheckOffsetOffset = getFieldOffset("Klass::_super_check_offset", Integer.class, "juint"); final int secondarySuperCacheOffset = getFieldOffset("Klass::_secondary_super_cache", Integer.class, "Klass*"); + final int payloadOffset = getFieldOffset("InlineKlassFixedBlock::_payload_offset", Integer.class, "int"); + final int nullMarkerOffset = getFieldOffset("FieldInfo::_null_marker_offset", Integer.class, "u4"); + final int inlineKlassFixedBlockAdr = getFieldOffset("InstanceKlass::_adr_inlineklass_fixed_block", Integer.class, "InlineKlassFixedBlock const *"); final int classLoaderDataOffset = getFieldOffset("Klass::_class_loader_data", Integer.class, "ClassLoaderData*"); @@ -91,6 +95,10 @@ static String getHostArchitectureName() { final int klassLayoutHelperNeutralValue = getConstant("Klass::_lh_neutral_value", Integer.class); final int klassLayoutHelperInstanceSlowPathBit = getConstant("Klass::_lh_instance_slow_path_bit", Integer.class); + final int klassLayoutHelperLog2ElementSizeShift = getConstant("Klass::_lh_log2_element_size_shift", Integer.class); + final int klassLayoutHelperLog2ElementSizeMask = getConstant("Klass::_lh_log2_element_size_mask", Integer.class); + final int klassKind = getFieldOffset("Klass::_kind", Integer.class, "Klass::KlassKind const"); + final int klassFlatArray = getConstant("Klass::FlatArrayKlassKind", Integer.class); final int vtableEntrySize = getFieldValue("CompilerToVM::Data::sizeof_vtableEntry", Integer.class, "int"); final int vtableEntryMethodOffset = getFieldOffset("vtableEntry::_method", Integer.class, "Method*"); @@ -119,6 +127,11 @@ static String getHostArchitectureName() { final int jvmAccHasFinalizer = getConstant("KlassFlags::_misc_has_finalizer", Integer.class); final int jvmFieldFlagInternalShift = getConstant("FieldInfo::FieldFlags::_ff_injected", Integer.class); final int jvmFieldFlagStableShift = getConstant("FieldInfo::FieldFlags::_ff_stable", Integer.class); + final int jvmFieldFlagFlatShift = getConstant("FieldInfo::FieldFlags::_ff_flat", Integer.class); + final int jvmFieldFlagNullFreeInlineTypeShift = getConstant("FieldInfo::FieldFlags::_ff_null_free_inline_type", Integer.class); + final int jvmFieldFlagNullMarkerShift = getConstant("FieldInfo::FieldFlags::_ff_null_marker", Integer.class); + //final int jvmFieldFlagInternalNullMarkerShift = getConstant("FieldInfo::FieldFlags::_ff_internal_null_marker", Integer.class); + final int jvmAccIsCloneableFast = getConstant("KlassFlags::_misc_is_cloneable_fast", Integer.class); // These modifiers are not public in Modifier so we get them via vmStructs. @@ -128,6 +141,7 @@ static String getHostArchitectureName() { final int jvmAccVarargs = getConstant("JVM_ACC_VARARGS", Integer.class); final int jvmAccEnum = getConstant("JVM_ACC_ENUM", Integer.class); final int jvmAccInterface = getConstant("JVM_ACC_INTERFACE", Integer.class); + final int jvmAccIdentity = getConstant("JVM_ACC_IDENTITY", Integer.class); final int jvmMiscFlagsHasDefaultMethods = getConstant("InstanceKlassFlags::_misc_has_nonstatic_concrete_methods", Integer.class); final int jvmMiscFlagsDeclaresDefaultMethods = getConstant("InstanceKlassFlags::_misc_declares_nonstatic_concrete_methods", Integer.class); @@ -391,4 +405,6 @@ String getCodeInstallResultDescription(int codeInstallResult) { final int arrayDataArrayLenOffset = getConstant("ArrayData::array_len_off_set", Integer.class); final int arrayDataArrayStartOffset = getConstant("ArrayData::array_start_off_set", Integer.class); final int multiBranchDataPerCaseCellCount = getConstant("MultiBranchData::per_case_cell_count", Integer.class); + final int leftInlineTypeFlag = getConstant("ACmpData::left_inline_type_flag", Integer.class); + final int rightInlineTypeFlag = getConstant("ACmpData::right_inline_type_flag", Integer.class); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java index 2b8f717840e..dafcdd2cf71 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java @@ -51,6 +51,8 @@ final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl final IndirectHotSpotObjectConstantImpl base; + private final boolean objectIsInlineType; + private static class Audit { final Object scope; final long handle; @@ -71,11 +73,12 @@ private static class Audit { private Object rawAudit; @VMEntryPoint - private IndirectHotSpotObjectConstantImpl(long objectHandle, boolean compressed, boolean skipRegister) { + private IndirectHotSpotObjectConstantImpl(long objectHandle, boolean compressed, boolean skipRegister, boolean objectIsInlineType) { super(compressed); assert objectHandle != 0 && UnsafeAccess.UNSAFE.getLong(objectHandle) != 0; this.objectHandle = objectHandle; this.base = null; + this.objectIsInlineType = objectIsInlineType; if (!skipRegister) { HotSpotObjectConstantScope scope = HotSpotObjectConstantScope.CURRENT.get(); if (scope != null && !scope.isGlobal()) { @@ -102,6 +105,7 @@ private IndirectHotSpotObjectConstantImpl(IndirectHotSpotObjectConstantImpl base // There should only be one level of indirection to the base object. assert base.base == null || base.base.base == null; this.base = base.base != null ? base.base : base; + this.objectIsInlineType = base.objectIsInlineType; } long getHandle() { @@ -182,7 +186,15 @@ public int getIdentityHashCode() { checkHandle(); int hash = hashCode; if (hash == 0) { - hash = runtime().compilerToVm.getIdentityHashCode(this); + if (objectIsInlineType) { + // The method ValueObjectMethods:valueObjectHashCode is private, we would need to go into the VM. + // This is not allowed though, because Java calls are disabled when libjvmci enters + // the VM via a C2V (i.e. CompilerToVM) native method. + // guarantee(thread->can_call_java(), "cannot make java calls from the native compiler"); triggers + hash = Long.hashCode(objectHandle); + } else { + hash = runtime().compilerToVm.getIdentityHashCode(this); + } if (hash == 0) { hash = 31; } @@ -190,4 +202,9 @@ public int getIdentityHashCode() { } return hash; } + + @Override + public boolean objectIsInlineType() { + return objectIsInlineType; + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java index d7e8fd37ab2..cbc94969390 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java @@ -93,6 +93,33 @@ boolean equals(HotSpotObjectConstantImpl x, HotSpotObjectConstantImpl y) { return runtime().compilerToVm.equals(x, indirectX.getHandle(), y, indirectY.getHandle()); } + @Override + Boolean valhallaEquals(HotSpotObjectConstantImpl x, HotSpotObjectConstantImpl y) { + if (x == y) { + return true; + } + if (x.compressed != y.compressed) { + return false; + } + if (x instanceof DirectHotSpotObjectConstantImpl && y instanceof DirectHotSpotObjectConstantImpl) { + DirectHotSpotObjectConstantImpl xd = (DirectHotSpotObjectConstantImpl) x; + DirectHotSpotObjectConstantImpl yd = (DirectHotSpotObjectConstantImpl) y; + return (xd.object == yd.object); + } + if (x instanceof DirectHotSpotObjectConstantImpl || y instanceof DirectHotSpotObjectConstantImpl) { + // Mixing of constant types is always inequal + return false; + } + IndirectHotSpotObjectConstantImpl indirectX = (IndirectHotSpotObjectConstantImpl) x; + IndirectHotSpotObjectConstantImpl indirectY = (IndirectHotSpotObjectConstantImpl) y; + boolean result = runtime().compilerToVm.equals(x, indirectX.getHandle(), y, indirectY.getHandle()); + if (!result && indirectX.objectIsInlineType() && indirectY.objectIsInlineType()) { + // reference comparison of oops falsified, doesn't mean that the two inline objects are not equal + return null; + } + return result; + } + @Override ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod) { // ResolvedJavaMethod.getParameters allows a return value of null diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SingleTypeEntry.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SingleTypeEntry.java new file mode 100644 index 00000000000..ac1d6d35813 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SingleTypeEntry.java @@ -0,0 +1,36 @@ +package jdk.vm.ci.hotspot; + +/** + * The acmp comparison compares two objects for equality. Due to Valhalla, profiling data is now attached to this comparison. + * This class represents the profiled type information of one operand. + * Corresponds to {@code ciSingleTypeEntry} + */ +public interface SingleTypeEntry{ + + + /** + * @return returns the profiled type, null if multiple types have been seen + */ + HotSpotResolvedObjectType getValidType(); + + /** + * @return whether the operand was seen to be null, false otherwise + */ + boolean maybeNull(); + + /** + * @return whether the operand was never null, false otherwise + */ + boolean neverNull(); + + /** + * @return whether the operand was always null, false otherwise + */ + boolean alwaysNull(); + + /** + * @return whether the operand was seen to be an inline type, false otherwise + */ + boolean inlineType(); + +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java index 3849ac779c4..a5e76346e09 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java @@ -103,6 +103,7 @@ public List getAttributesMap() { } private final List javaGeneralParameterRegisters; + private final List javaGeneralReturnRegisters; private final List nativeGeneralParameterRegisters; private final List javaXMMParameterRegisters; private final List nativeXMMParameterRegisters; @@ -149,11 +150,14 @@ public AMD64HotSpotRegisterConfig(TargetDescription target, List alloc if (windowsOS) { javaGeneralParameterRegisters = List.of(rdx, r8, r9, rdi, rsi, rcx); + // see assembler_x86.hpp and SharedRuntime::java_return_convention in sharedRuntime_x86_64.cpp + javaGeneralReturnRegisters = List.of(rax, rcx, rsi, rdi, r9, r8, rdx); nativeGeneralParameterRegisters = List.of(rcx, rdx, r8, r9); nativeXMMParameterRegisters = List.of(xmm0, xmm1, xmm2, xmm3); this.needsNativeStackHomeSpace = true; } else { javaGeneralParameterRegisters = List.of(rsi, rdx, rcx, r8, r9, rdi); + javaGeneralReturnRegisters = List.of(rax, rdi, r9, r8, rcx, rdx, rsi); nativeGeneralParameterRegisters = List.of(rdi, rsi, rdx, rcx, r8, r9); nativeXMMParameterRegisters = List.of(xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7); this.needsNativeStackHomeSpace = false; @@ -198,6 +202,15 @@ public CallingConvention getCallingConvention(Type type, JavaType returnType, Ja return callingConvention(javaGeneralParameterRegisters, javaXMMParameterRegisters, false, returnType, parameterTypes, hotspotType, valueKindFactory); } + @Override + public List getReturnConvention(List returnTypes, ValueKindFactory valueKindFactory, boolean includeFirstGeneralRegister) { + JavaKind[] kinds = new JavaKind[returnTypes.size()]; + for (int i = 0; i < returnTypes.size(); i++) { + kinds[i] = returnTypes.get(i).getJavaKind().getStackKind(); + } + return getReturnLocations(getReturnRegisters(kinds, includeFirstGeneralRegister), returnTypes, valueKindFactory); + } + @Override public List getCallingConventionRegisters(Type type, JavaKind kind) { HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; @@ -307,6 +320,54 @@ public Register getReturnRegister(JavaKind kind) { } } + @Override + public Register[] getReturnRegisters(JavaKind[] kinds, boolean includeFirstGeneralRegister) { + Register[] registers = new Register[kinds.length]; + List generalReturnRegisters = javaGeneralReturnRegisters; + List xmmReturnRegisters = javaXMMParameterRegisters; + + int currentGeneral = includeFirstGeneralRegister ? 0 : 1; + int currentXMM = 0; + + Register register; + for (int i = 0; i < kinds.length; i++) { + final JavaKind kind = kinds[i]; + + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Object: + assert currentGeneral < generalReturnRegisters.size() : "return values can only be stored in registers"; + registers[i] = generalReturnRegisters.get(currentGeneral++); + + break; + case Float: + case Double: + assert currentXMM < xmmReturnRegisters.size() : "return values can only be stored in registers"; + registers[i] = xmmReturnRegisters.get(currentXMM++); + break; + default: + throw JVMCIError.shouldNotReachHere(); + } + + assert registers[i] != null : "return values can only be stored in registers"; + } + return registers; + } + + public List getReturnLocations(Register[] registers, List returnTypes, ValueKindFactory valueKindFactory) { + List locations = new ArrayList<>(returnTypes.size()); + for (int i = 0; i < registers.length; i++) { + final JavaKind kind = returnTypes.get(i).getJavaKind().getStackKind(); + locations.add(registers[i].asValue(valueKindFactory.getValueKind(kind))); + } + return List.copyOf(locations); + } + @Override public Register getFrameRegister() { return rsp; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DefaultProfilingInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DefaultProfilingInfo.java index 4fa945a8969..a2fa48e6c2f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DefaultProfilingInfo.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DefaultProfilingInfo.java @@ -70,6 +70,11 @@ public TriState getExceptionSeen(int bci) { return exceptionSeen; } + @Override + public Object getACmpData(int bci) { + return null; + } + @Override public TriState getNullSeen(int bci) { return TriState.UNKNOWN; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java index baa7e295d32..1f371f729ef 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java @@ -60,7 +60,7 @@ public enum JavaKind { Object('A', 12, "Object", 1, false, null, null), /** The void kind. */ - Void('V', 14, "void", 0, false, java.lang.Void.TYPE, java.lang.Void.class), + Void('V', 15, "void", 0, false, java.lang.Void.TYPE, java.lang.Void.class), /** The non-type. */ Illegal('-', 99, "illegal", 0, false, null, null); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java index 2686ab1737f..3af6d88caae 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java @@ -62,6 +62,14 @@ default ResolvedJavaType[] lookupJavaTypes(Class[] classes) { */ ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod); + default ResolvedJavaMethod getIsSubstitutableMethod() { + return null; + } + + default ResolvedJavaMethod getValueObjectHashCodeMethod() { + return null; + } + /** * Provides the {@link ResolvedJavaField} for a {@link Field} obtained via reflection. */ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ProfilingInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ProfilingInfo.java index 7eaa8e96670..35f50628d52 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ProfilingInfo.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ProfilingInfo.java @@ -22,6 +22,9 @@ */ package jdk.vm.ci.meta; +import jdk.vm.ci.hotspot.ACmpDataAccessor; +import jdk.vm.ci.hotspot.SingleTypeEntry; + /** * Provides access to the profiling information of one specific method. Every accessor method * returns the information that is available at the time of invocation. If a method is invoked @@ -75,6 +78,15 @@ public interface ProfilingInfo { */ TriState getExceptionSeen(int bci); + /** + * Returns the AcmpProfile for the given BCI. + * + * @return Returns a AcmpData object, or null if not available. + */ + default Object getACmpData(int bci) { + return null; + } + /** * Returns information if null was ever seen for the given BCI. This information is collected * for the aastore, checkcast and instanceof bytecodes. @@ -171,6 +183,15 @@ default String toString(ResolvedJavaMethod method, String sep) { buf.append(String.format("nullSeen@%d: %s%s", i, getNullSeen(i).name(), sep)); } + ACmpDataAccessor aCmpData = (ACmpDataAccessor) getACmpData(i); + if (getACmpData(i) != null) { + SingleTypeEntry left = aCmpData.getLeft(); + String formatString = "ACmpType@%d: %s alwaysNull:%b inlineType:%b%s"; + buf.append(String.format(formatString, i, left.getValidType(), left.alwaysNull(), left.inlineType(), sep)); + SingleTypeEntry right = aCmpData.getRight(); + buf.append(String.format(formatString, i, right.getValidType(), right.alwaysNull(), right.inlineType(), sep)); + } + JavaTypeProfile typeProfile = getTypeProfile(i); MetaUtil.appendProfile(buf, typeProfile, i, "types", sep); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index cb891ab2e1b..d2f1f89f63e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -46,6 +46,20 @@ public interface ResolvedJavaField extends JavaField, ModifiersProvider, Annotat */ int getOffset(); + /** + * returns a new instance with a changed offset of the field relative to the base of its storage container + */ + default ResolvedJavaField changeOffset(int newOffset) { + throw new UnsupportedOperationException(); + } + + /** + * returns a resolved java field which represents the null marker field of a flattened inline type + */ + default ResolvedJavaField getNullMarkerField() { + throw new UnsupportedOperationException(); + } + default boolean isFinal() { return ModifiersProvider.super.isFinalFlagSet(); } @@ -56,6 +70,38 @@ default boolean isFinal() { */ boolean isInternal(); + /** + * Determines if this field is flat. Such a field, for example, is not derived + * from a class file. + */ + default boolean isFlat() { + throw new UnsupportedOperationException(); + } + + /** + * Determines if a null-restricted static field is already initialized. Such a field, for example, is not derived + * from a class file. + */ + default boolean isInitialized() { + throw new UnsupportedOperationException(); + } + + /** + * Determines if this field is a null free inline type. Such a field, for example, is not derived + * from a class file. + */ + default boolean isNullFreeInlineType() { + throw new UnsupportedOperationException(); + } + + /** + * Returns the null marker offset for nullable flattened fields. Such a field, for example, is not derived + * from a class file. + */ + default int getNullMarkerOffset() { + throw new UnsupportedOperationException(); + } + /** * Determines if this field is a synthetic field as defined by the Java Language Specification. */ @@ -68,6 +114,18 @@ default boolean isFinal() { @Override ResolvedJavaType getDeclaringClass(); + /** + * Returns the {@link ResolvedJavaType} object that represents the class in which an inline object (to which the field belongs) is embedded. + * This differs to {@link #getDeclaringClass} if the inline object is flattened. + */ + default ResolvedJavaType getContainerClass() { + throw new UnsupportedOperationException(); + } + + default ResolvedJavaField setContainerClass(ResolvedJavaType containerClass) { + throw new UnsupportedOperationException(); + } + /** * Gets the value of the {@code ConstantValue} attribute ({@jvms 4.7.2}) associated with this * field. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index 958133a6554..3947f24b8ce 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -22,13 +22,14 @@ */ package jdk.vm.ci.meta; + import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; -import java.util.BitSet; +import java.util.List; /** * Represents a resolved Java method. Methods, like fields and types, are resolved through @@ -486,4 +487,153 @@ default boolean isScoped() { * responsibility to ensure the same speculation log is used throughout a compilation. */ SpeculationLog getSpeculationLog(); + + /** + * Gets the information if a parameter at a certain position in the method signature is scalarized. + * Inline type arguments may not be passed by reference, but in scalarized form. + * We get an argument per field of the inline type. + * + * @param index the index of a formal parameter in the signature + * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise + * @return true if the parameter is scalarized, false otherwise + */ + default boolean isScalarizedParameter(int index, boolean indexIncludesReceiverIfExists) { + return false; + } + + /** + * Counts the number of scalarized parameters of a method. + * + * @return the number of scalarized parameters in this method + */ + default int getScalarizedParametersCount() { + int count = 0; + for (int i = 0; i < getSignature().getParameterCount(!isStatic()); i++) { + if (isScalarizedParameter(i, true)) { + count++; + } + } + return count; + } + + /** + * Gets the information if a parameter at a certain position in the method signature is non free. + * + * @param index the index of a formal parameter in the signature + * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise + * @return true if the parameter is null free, false otherwise + */ + default boolean isParameterNullFree(int index, boolean indexIncludesReceiverIfExists) { + return false; + } + + /** + * Finds out if this method has scalarized parameters. + * + * @return true if the method has scalarized parameters, false otherwise + */ + default boolean hasScalarizedParameters() { + return false; + } + + /** + * Finds out if this method has a scalarized return. + * + * @return true if this method returns it's return value in a scalarized form, false otherwise + */ + default boolean hasScalarizedReturn() { + return false; + } + + /** + * Finds out if this method has a scalarized receiver. + * + * @return true if this method's receiver is passed scalarized, false otherwise + */ + default boolean hasScalarizedReceiver() { + return false; + } + + /** + * Finds out if the scalarized calling convention of a method does not match that of a subclass. + * See CompiledEntrySignature::compute_calling_conventions which detects these mismatches. + * + * @return true if there is a mismatch + */ + default boolean hasCallingConventionMismatch() { + return false; + } + + /** + * Gets the type information of the method's scalarized return. + * + * @return the scalarized return type which consists of the return type as well as the instance fields of the return type + */ + default List getScalarizedReturn() { + throw new UnsupportedOperationException("scalarized return not yet implemented"); + } + + /** + * Gets the scalarized method signature. + * + * @param scalarizeReceiver true if the receiver should be scalarized as well, false otherwise + * @return the types representing the scalarized method signature + */ + default List getScalarizedParameters(boolean scalarizeReceiver) { + throw new UnsupportedOperationException("scalarized parameters not yet implemented"); + } + + /** + * Similar to as {@link #getScalarizedParameterNullFree(int, boolean)} but also includes the is not null type if the parameter is not null free. + * + * @param index the index of a formal parameter in the signature + * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise + * @return the instance fields as types including the is not null type + */ + default List getScalarizedParameter(int index, boolean indexIncludesReceiverIfExists) { + throw new UnsupportedOperationException("scalarized parameter not yet implemented"); + } + + /** + * Gets the instance fields of a scalarized parameter as types. + * + * @param index the index of a formal parameter in the signature + * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise + * @return the instance fields as types + */ + default List getScalarizedParameterNullFree(int index, boolean indexIncludesReceiverIfExists) { + throw new UnsupportedOperationException("scalarized parameter not yet implemented"); + } + + /** + * Gets the instance fields of a scalarized parameter. + * + * @param index the index of a formal parameter in the signature + * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise + * @return the instance fields of a scalarized parameter + */ + default List getScalarizedParameterFields(int index, boolean indexIncludesReceiverIfExists) { + throw new UnsupportedOperationException("getParameterFields is not supported"); + } + + /** + * Gets the type used for a scalarized parameter to represent its is not null information. + * + * @param index the index of a formal parameter in the signature + * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise + * @return the type representing the is not null information + */ + default JavaType getScalarizedParameterNonNullType(int index, boolean indexIncludesReceiverIfExists) { + throw new UnsupportedOperationException("getScalarizedParameterNonNull is not supported"); + } + + /** + * Gets the ordered type information of each field according to {@link ResolvedJavaType#getInstanceFields(boolean)} of the method's scalarized receiver. + * + * @return the scalarized receiver which consists of its instance fields. + */ + default List getScalarizedReceiver() { + assert hasScalarizedReceiver() : "Scalarized receiver presumed"; + return getScalarizedParameter(0, true); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index cdb24c5f1ad..cdcc9b954a8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -247,6 +247,25 @@ default ResolvedJavaType getElementalType() { @Override ResolvedJavaType getArrayClass(); + /** + * Gets the array class type used when creating an array with {@link jdk.internal.value.ValueClass#newNullRestrictedArray(Class, int)} + */ + default ResolvedJavaType getFlatArrayClass() { + throw new UnsupportedOperationException(); + } + + default ResolvedJavaType convertToFlatArray() { + throw new UnsupportedOperationException(); + } + + default boolean isFlatArray() { + return false; + } + + default JavaConstant getDefaultInlineTypeInstance() { + throw new UnsupportedOperationException(); + } + /** * Resolves the method implementation for virtual dispatches on objects of this dynamic type. * This resolution process only searches "up" the class hierarchy of this type. A broader search @@ -425,4 +444,16 @@ default ResolvedJavaField resolveField(UnresolvedJavaField unresolvedJavaField, default boolean isConcrete() { return isArray() || !isAbstract(); } + + /** + * Checks whether this type has an identity. See {@link Class#isIdentity()}. + * + * @return {@code true} if this type has an identity + */ + default boolean isIdentity(){ + if (isPrimitive()) { + return false; + } + return !isInterface(); + } } From 5704b5645bebfba2051cc3792c3f53cf0d004d98 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 26 Sep 2025 21:17:37 +0200 Subject: [PATCH 02/27] Rebase corrections. --- .../share/jvmci/jvmciCodeInstaller.cpp | 2 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 70 +++++++++---------- src/hotspot/share/jvmci/jvmciRuntime.cpp | 10 +-- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 - .../ci/hotspot/HotSpotResolvedJavaType.java | 2 +- .../HotSpotResolvedObjectTypeImpl.java | 1 - .../hotspot/HotSpotResolvedPrimitiveType.java | 2 +- 7 files changed, 41 insertions(+), 47 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index b6de39705cc..966d4fcf18b 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -1167,7 +1167,7 @@ bool has_scalarized_return(methodHandle& methodHandle){ return false; } Method* method = methodHandle(); - InlineKlass* klass = method->returns_inline_type(Thread::current()); + InlineKlass* klass = method->returns_inline_type(); if (klass != nullptr) { return !method->is_native() && klass->can_be_returned_as_fields(); } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index a9d53dcf058..70dbb50eaf3 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -560,7 +560,7 @@ C2V_VMENTRY_NULL(jobject, getResolvedJavaType0, (JNIEnv* env, jobject, jobject b intptr_t temp = (intptr_t) *((Klass**) (intptr_t) (base_address + offset)); // profiled type: cell without bit 0 and 1 - klass = (Klass*) (temp & TypeEntries::type_klass_mask); + Klass* k = (Klass*) (temp & TypeEntries::type_klass_mask); if (k == nullptr || k->class_loader_data() == nullptr || !TrainingData::is_klass_loaded(k)) { return nullptr; } @@ -734,38 +734,38 @@ C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jchar type_char, return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY_NULL(jobject, getFlatArrayType, (JNIEnv* env, jobject, jchar type_char, ARGUMENT_PAIR(klass))) - JVMCIKlassHandle array_klass(THREAD); - Klass* klass = UNPACK_PAIR(Klass, klass); - - if(klass->is_inline_klass()){ - InlineKlass* inline_klass = InlineKlass::cast(klass); - ArrayKlass* flat_array_klass; - if(inline_klass->flat_array()){ - flat_array_klass = (ArrayKlass*)inline_klass->flat_array_klass(LayoutKind::NON_ATOMIC_FLAT, CHECK_NULL); - }else{ - flat_array_klass = (ArrayKlass*)inline_klass->null_free_reference_array(CHECK_NULL); - } - // Request a flat array, but we might not actually get it...either way "null-free" are the aaload/aastore semantics - //ArrayKlass* flat_array_klass = (ArrayKlass*)inline_klass->flat_array_klass(LayoutKind::NON_ATOMIC_FLAT, CHECK_NULL); - array_klass = flat_array_klass; - assert(array_klass->is_null_free_array_klass(), "Expect a null-free array class here"); - //assert(array_klass->is_flatArray_klass, "Expect a flat array class here"); - }else{ - array_klass = klass->array_klass(CHECK_NULL); - } - JVMCIObject result = JVMCIENV->get_jvmci_type(array_klass, JVMCI_CHECK_NULL); - return JVMCIENV->get_jobject(result); -C2V_END - -C2V_VMENTRY_NULL(jobject, getDefaultInlineTypeInstance, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) - JVMCIKlassHandle array_klass(THREAD); - Klass* klass = UNPACK_PAIR(Klass, klass); - - assert(klass->is_inline_klass(), "Should only be called for inline types"); - oop default_value = InlineKlass::cast(klass)->default_value(); - return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(default_value)); -C2V_END +// C2V_VMENTRY_NULL(jobject, getFlatArrayType, (JNIEnv* env, jobject, jchar type_char, ARGUMENT_PAIR(klass))) +// JVMCIKlassHandle array_klass(THREAD); +// Klass* klass = UNPACK_PAIR(Klass, klass); + +// if(klass->is_inline_klass()){ +// InlineKlass* inline_klass = InlineKlass::cast(klass); +// ArrayKlass* flat_array_klass; +// if(inline_klass->flat_array()){ +// flat_array_klass = (ArrayKlass*)inline_klass->flat_array_klass(LayoutKind::NON_ATOMIC_FLAT, CHECK_NULL); +// }else{ +// flat_array_klass = (ArrayKlass*)inline_klass->null_free_reference_array(CHECK_NULL); +// } +// // Request a flat array, but we might not actually get it...either way "null-free" are the aaload/aastore semantics +// //ArrayKlass* flat_array_klass = (ArrayKlass*)inline_klass->flat_array_klass(LayoutKind::NON_ATOMIC_FLAT, CHECK_NULL); +// array_klass = flat_array_klass; +// assert(array_klass->is_null_free_array_klass(), "Expect a null-free array class here"); +// //assert(array_klass->is_flatArray_klass, "Expect a flat array class here"); +// }else{ +// array_klass = klass->array_klass(CHECK_NULL); +// } +// JVMCIObject result = JVMCIENV->get_jvmci_type(array_klass, JVMCI_CHECK_NULL); +// return JVMCIENV->get_jobject(result); +// C2V_END + +// C2V_VMENTRY_NULL(jobject, getDefaultInlineTypeInstance, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) +// JVMCIKlassHandle array_klass(THREAD); +// Klass* klass = UNPACK_PAIR(Klass, klass); + +// assert(klass->is_inline_klass(), "Should only be called for inline types"); +// oop default_value = InlineKlass::cast(klass)->default_value(); +// return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(default_value)); +// C2V_END C2V_VMENTRY_NULL(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror)) requireInHotSpot("lookupClass", JVMCI_CHECK_NULL); @@ -3440,8 +3440,8 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "lookupJClass", CC "(J)" HS_RESOLVED_TYPE, FN_PTR(lookupJClass)}, {CC "getJObjectValue", CC "(" OBJECTCONSTANT ")J", FN_PTR(getJObjectValue)}, {CC "getArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getArrayType)}, - {CC "getFlatArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getFlatArrayType)}, - {CC "getDefaultInlineTypeInstance", CC "(" HS_KLASS2 ")" JAVACONSTANT, FN_PTR(getDefaultInlineTypeInstance)}, + // {CC "getFlatArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getFlatArrayType)}, + // {CC "getDefaultInlineTypeInstance", CC "(" HS_KLASS2 ")" JAVACONSTANT, FN_PTR(getDefaultInlineTypeInstance)}, {CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)}, {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupNameInPool)}, {CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index f869662e9c3..fff515c37f0 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -417,16 +417,12 @@ JRT_LEAF(jboolean, JVMCIRuntime::object_notify(JavaThread* current, oopDesc* obj JRT_END JRT_ENTRY(void, JVMCIRuntime::load_unknown_inline(JavaThread* current, flatArrayOopDesc* array, jint index)) - assert(array->klass()->is_flatArray_klass(), "should not be called"); - - assert(array->length() > 0 && index < array->length(), "already checked"); - oop obj = array->read_value_from_flat_array(index, THREAD); - current->set_vm_result(obj); + oop buffer = array->obj_at(index, THREAD); + current->set_vm_result_oop(buffer); JRT_END JRT_ENTRY(void, JVMCIRuntime::store_unknown_inline(JavaThread* current, flatArrayOopDesc* array, jint index, oopDesc* value)) - assert(array->klass()->is_flatArray_klass(), "should not be called"); - array->write_value_to_flat_array(value, index, THREAD); + array->obj_at_put(index, value, THREAD); JRT_END // Object.notifyAll() fast path, caller does slow path diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 0fa8232c45d..b332adabf8a 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -840,7 +840,6 @@ declare_constant(Klass::_lh_array_tag_shift) \ declare_constant(Klass::_lh_array_tag_type_value) \ declare_constant(Klass::_lh_array_tag_ref_value) \ - declare_constant(Klass::_lh_array_tag_obj_value) \ declare_constant(Klass::_lh_null_free_shift) \ declare_constant(Klass::_lh_null_free_mask) \ \ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index e49f82d7a8f..1d06ec1170a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -55,7 +55,7 @@ public int hashCode() { */ protected abstract HotSpotResolvedObjectType getArrayType(); - abstract HotSpotResolvedObjectTypeImpl getFlatArrayType(); + abstract HotSpotResolvedObjectType getFlatArrayType(); @Override public HotSpotResolvedObjectType getArrayClass() { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 36cb769e2fa..31b3ff6a7c2 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -953,7 +953,6 @@ private HotSpotResolvedJavaField[] getFlattenedFields(HotSpotResolvedJavaField[] } } assert resultList.size() == resultCount : "wrong flat field count"; - resultList.sort(fieldSortingMethod); return resultList.toArray(new HotSpotResolvedJavaField[resultList.size()]); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index f9148cc8033..561a9dba718 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -98,7 +98,7 @@ protected HotSpotResolvedObjectType getArrayType() { } @Override - HotSpotResolvedObjectTypeImpl getFlatArrayType() { + HotSpotResolvedObjectType getFlatArrayType() { return getArrayType(); } From d1331cce93ea10c39926386ed82f43ac6890b8c9 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 26 Sep 2025 23:12:16 +0200 Subject: [PATCH 03/27] Distinguish between declared and non-declared fields. --- .../ci/hotspot/HotSpotObjectConstantImpl.java | 2 +- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 77 ++++---- .../HotSpotResolvedObjectTypeImpl.java | 166 ++++++++++-------- .../hotspot/HotSpotResolvedPrimitiveType.java | 5 + .../jdk/vm/ci/meta/ResolvedJavaField.java | 20 +-- .../jdk/vm/ci/meta/ResolvedJavaType.java | 2 + 6 files changed, 135 insertions(+), 137 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java index c2476ddbf3c..cc139a40e0a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java @@ -206,7 +206,7 @@ public JavaConstant readFieldValue(HotSpotResolvedJavaField field) { if (field.isStatic()) { return null; } - HotSpotResolvedObjectTypeImpl declaringClass = (HotSpotResolvedObjectTypeImpl) field.getContainerClass(); + HotSpotResolvedObjectTypeImpl declaringClass = (HotSpotResolvedObjectTypeImpl) field.getOriginalHolder(); char typeChar = field.getType().getJavaKind().getTypeChar(); return runtime().compilerToVm.readFieldValue(this, declaringClass, field.getOffset(), typeChar, declaringClass != field.getDeclaringClass()); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index d386e439f29..62f97bf4d9a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -32,7 +32,6 @@ import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; import java.lang.annotation.Annotation; -import java.util.Collections; import java.util.List; import jdk.internal.vm.VMSupport; @@ -45,7 +44,7 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { private final HotSpotResolvedObjectTypeImpl holder; - private HotSpotResolvedObjectTypeImpl containerClass; + private HotSpotResolvedObjectTypeImpl originalHolder; private JavaType type; @@ -79,6 +78,28 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { this.index = index; } + // Special copy constructor used to flatten inline type fields by + // copying the fields of the inline type to a new holder klass. + HotSpotResolvedJavaFieldImpl(HotSpotResolvedJavaFieldImpl declaredField, HotSpotResolvedJavaFieldImpl subField) { + this.holder = declaredField.holder; + this.originalHolder = subField.getOriginalHolder(); + this.type = subField.type; + this.offset = declaredField.offset + (subField.offset - ((HotSpotResolvedObjectType) declaredField.getType()).payloadOffset()); + this.classfileFlags = declaredField.classfileFlags; + this.internalFlags = declaredField.internalFlags; + this.index = declaredField.index; + } + + // Constructor for a null marker + HotSpotResolvedJavaFieldImpl(HotSpotResolvedJavaFieldImpl declaredField) { + this.holder = declaredField.holder; + this.type = HotSpotResolvedPrimitiveType.forKind(JavaKind.Boolean); + this.offset = declaredField.getNullMarkerOffset(); + this.classfileFlags = declaredField.classfileFlags; + this.internalFlags = declaredField.internalFlags; + this.index = declaredField.index; + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -88,7 +109,7 @@ public boolean equals(Object obj) { HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; if (that.offset != this.offset || that.isStatic() != this.isStatic()) { return false; - } else if (this.holder.equals(that.holder) && this.getContainerClass().equals(that.getContainerClass())) { + } else if (this.holder.equals(that.holder) && this.getOriginalHolder().equals(that.getOriginalHolder())) { return true; } } @@ -134,28 +155,6 @@ public int getNullMarkerOffset() { return holder.getFieldInfo(index).getNullMarkerOffset(); } - @Override - public HotSpotResolvedJavaField getNullMarkerField() { - HotSpotResolvedJavaType byteType = HotSpotResolvedPrimitiveType.forKind(JavaKind.Byte); - return new HotSpotResolvedJavaFieldImpl(holder, byteType, getNullMarkerOffset(), 0, 0, -1) { - @Override - public String getName() { - return "nullMarkerOffset"; - } - - @Override - public int getNullMarkerOffset() { - return -1; - } - - @Override - public JavaConstant getConstantValue() { - return null; - } - }; - //return new HotSpotResolvedJavaFieldImpl(holder, byteType, getNullMarkerOffset(), 0, 0, -1); - } - /** * Determines if a given object contains this field. * @@ -177,23 +176,16 @@ public HotSpotResolvedObjectTypeImpl getDeclaringClass() { } @Override - public HotSpotResolvedObjectTypeImpl getContainerClass() { - if (containerClass == null) { + public HotSpotResolvedObjectTypeImpl getOriginalHolder() { + if (originalHolder == null) { return holder; } - return containerClass; - } - - @Override - public ResolvedJavaField setContainerClass(ResolvedJavaType containerClass) { - HotSpotResolvedJavaFieldImpl field = new HotSpotResolvedJavaFieldImpl(holder, type, offset, classfileFlags, internalFlags, index); - field.containerClass = (HotSpotResolvedObjectTypeImpl) containerClass; - return field; + return originalHolder; } @Override public String getName() { - return holder.getFieldInfo(index).getName(holder); + return getOriginalHolder().getFieldInfo(index).getName(getOriginalHolder()); } @Override @@ -204,7 +196,7 @@ public JavaType getType() { if (currentType instanceof UnresolvedJavaType) { // Don't allow unresolved types to hang around forever UnresolvedJavaType unresolvedType = (UnresolvedJavaType) currentType; - JavaType resolved = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedType.getName(), holder, false); + JavaType resolved = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedType.getName(), getOriginalHolder(), false); if (resolved instanceof ResolvedJavaType) { type = resolved; } @@ -222,11 +214,6 @@ public int getOffset() { return offset; } - @Override - public ResolvedJavaField changeOffset(int newOffset) { - return new HotSpotResolvedJavaFieldImpl(holder, type, newOffset, classfileFlags, internalFlags, index); - } - /** * Gets the value of this field's index (i.e. {@code fieldDescriptor::index()} in the encoded * fields of the declaring class. @@ -258,7 +245,7 @@ public boolean isStable() { private boolean hasAnnotations() { if (!isInternal()) { HotSpotVMConfig config = config(); - final long metaspaceAnnotations = UNSAFE.getAddress(holder.getKlassPointer() + config.instanceKlassAnnotationsOffset); + final long metaspaceAnnotations = UNSAFE.getAddress(getOriginalHolder().getKlassPointer() + config.instanceKlassAnnotationsOffset); if (metaspaceAnnotations != 0) { long fieldsAnnotations = UNSAFE.getAddress(metaspaceAnnotations + config.annotationsFieldAnnotationsOffset); if (fieldsAnnotations != 0) { @@ -296,7 +283,7 @@ public T getAnnotation(Class annotationClass) { @Override public JavaConstant getConstantValue() { - return holder.getFieldInfo(index).getConstantValue(holder); + return getOriginalHolder().getFieldInfo(index).getConstantValue(getOriginalHolder()); } @Override @@ -320,7 +307,7 @@ public List getAnnotationData(ResolvedJavaType type1, ResolvedJa } private List getAnnotationData0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationData(holder, index, filter); + byte[] encoded = compilerToVM().getEncodedFieldAnnotationData(getOriginalHolder(), index, filter); return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 31b3ff6a7c2..8ea926c738c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -59,6 +59,8 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem private HotSpotResolvedJavaMethodImpl[] methodCacheArray; private HashMap methodCacheHashMap; private volatile HotSpotResolvedJavaField[] instanceFields; + private volatile HotSpotResolvedJavaField[] declaredInstanceFields; + private volatile HotSpotResolvedJavaField[] staticFields; private volatile HotSpotResolvedObjectTypeImpl[] interfaces; private HotSpotConstantPool constantPool; private final JavaConstant mirror; @@ -612,6 +614,14 @@ HotSpotResolvedJavaField createField(JavaType type, int offset, int classfileFla return new HotSpotResolvedJavaFieldImpl(this, type, offset, classfileFlags, internalFlags, index); } + HotSpotResolvedJavaField createField(HotSpotResolvedJavaField declaringField, HotSpotResolvedJavaField subfield) { + return new HotSpotResolvedJavaFieldImpl((HotSpotResolvedJavaFieldImpl) declaringField, (HotSpotResolvedJavaFieldImpl) subfield); + } + + HotSpotResolvedJavaField createField(HotSpotResolvedJavaField declaringField) { + return new HotSpotResolvedJavaFieldImpl((HotSpotResolvedJavaFieldImpl) declaringField); + } + @Override public AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method) { HotSpotResolvedJavaMethod hmethod = (HotSpotResolvedJavaMethod) method; @@ -728,11 +738,11 @@ static class FieldInfo { /** * Creates a field info with the provided indices. * - * @param nameIndex index of field's name in the constant pool - * @param signatureIndex index of field's signature in the constant pool - * @param offset field's offset - * @param classfileFlags field's access flags (from the class file) - * @param internalFlags field's internal flags (from the VM) + * @param nameIndex index of field's name in the constant pool + * @param signatureIndex index of field's signature in the constant pool + * @param offset field's offset + * @param classfileFlags field's access flags (from the class file) + * @param internalFlags field's internal flags (from the VM) * @param initializerIndex field's initial value index in the constant pool */ FieldInfo(int nameIndex, int signatureIndex, int offset, int classfileFlags, int internalFlags, int initializerIndex, int nullMarkerOffset) { @@ -776,6 +786,7 @@ public int getNullMarkerOffset() { /** * Returns the name of this field as a {@link String}. If the field is an internal field the * name index is pointing into the vmSymbols table. + * * @param klass field's holder class */ public String getName(HotSpotResolvedObjectTypeImpl klass) { @@ -785,6 +796,7 @@ public String getName(HotSpotResolvedObjectTypeImpl klass) { /** * Returns the signature of this field as {@link String}. If the field is an internal field * the signature index is pointing into the vmSymbols table. + * * @param klass field's holder class */ public String getSignature(HotSpotResolvedObjectTypeImpl klass) { @@ -842,38 +854,38 @@ public boolean isStatic() { @Override public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { - return getInstanceFields(includeSuperclasses, config().valhallaEnabled); - } - - public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses, boolean valhallaEnabled) { if (instanceFields == null) { - if (isArray() || isInterface()) { - instanceFields = NO_FIELDS; - } else { - HotSpotResolvedJavaField[] prepend = NO_FIELDS; - if (getSuperclass() != null) { - prepend = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); - } - if (valhallaEnabled) { - instanceFields = getFlattenedFields(prepend); - } else { - instanceFields = getFields(false, prepend); - } + computeInstanceFields(); + } + return getFields(instanceFields, includeSuperclasses, false); + } - } + public ResolvedJavaField[] getDeclaredInstanceFields(boolean includeSuperclasses) { + if (declaredInstanceFields == null) { + computeInstanceFields(); } + return getFields(declaredInstanceFields, includeSuperclasses, true); + } + + public ResolvedJavaField[] getFields(HotSpotResolvedJavaField[] fields, boolean includeSuperclasses, boolean declared) { if (!includeSuperclasses && getSuperclass() != null) { - int superClassFieldCount = getSuperclass().getInstanceFields(true).length; - if (superClassFieldCount == instanceFields.length) { + int superClassFieldCount; + HotSpotResolvedObjectTypeImpl superclass = getSuperclass(); + if (declared) { + superClassFieldCount = superclass.getDeclaredInstanceFields(true).length; + } else { + superClassFieldCount = superclass.getDeclaredInstanceFields(true).length; + } + if (superClassFieldCount == fields.length) { // This class does not have any instance fields of its own. return NO_FIELDS; } else if (superClassFieldCount != 0) { // Fields of the current class can be interleaved with fields of its super-classes // but the array of fields to be returned must be sorted by increasing offset // This code populates the array, then applies the sorting function - HotSpotResolvedJavaField[] result = new HotSpotResolvedJavaField[instanceFields.length - superClassFieldCount]; + HotSpotResolvedJavaField[] result = new HotSpotResolvedJavaField[fields.length - superClassFieldCount]; int i = 0; - for (HotSpotResolvedJavaField f : instanceFields) { + for (HotSpotResolvedJavaField f : fields) { if (f.getDeclaringClass() == this) { result[i++] = f; } @@ -883,27 +895,36 @@ public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses, boolea // The super classes of this class do not have any instance fields. } } - return instanceFields; + return fields; } @Override public ResolvedJavaField[] getStaticFields() { - if (isArray()) { - return new HotSpotResolvedJavaField[0]; - } else { - return getFields(true, NO_FIELDS); + if (staticFields == null) { + computeStaticFields(); } + return staticFields; } - /** - * Gets the (flattened) instance fields of this class. - * - * @param prepend an array to be prepended to the returned result - */ - private HotSpotResolvedJavaField[] getFlattenedFields(HotSpotResolvedJavaField[] prepend) { + private void computeInstanceFields() { + HotSpotResolvedJavaField[] declaredPrepend; + HotSpotResolvedJavaField[] prepend; - HotSpotVMConfig config = config(); + if (isArray() || isInterface()) { + instanceFields = NO_FIELDS; + declaredInstanceFields = NO_FIELDS; + return; + } else { + declaredPrepend = NO_FIELDS; + prepend = NO_FIELDS; + if (getSuperclass() != null) { + declaredPrepend = (HotSpotResolvedJavaField[]) getSuperclass().getDeclaredInstanceFields(true); + prepend = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); + } + } + + int declaredResultCount = 0; int resultCount = 0; int index = 0; @@ -915,12 +936,17 @@ private HotSpotResolvedJavaField[] getFlattenedFields(HotSpotResolvedJavaField[] } if (resultCount == 0) { - return prepend; + declaredInstanceFields = declaredPrepend; + instanceFields = prepend; + return; } - List resultList = new ArrayList<>(Arrays.asList(prepend)); + List declaredFields = new ArrayList<>(Arrays.asList(declaredPrepend)); + List fields = new ArrayList<>(Arrays.asList(prepend)); + int declaredPrependLength = declaredPrepend.length; int prependLength = prepend.length; + declaredResultCount += declaredPrependLength; resultCount = 0; resultCount += prependLength; @@ -928,76 +954,72 @@ private HotSpotResolvedJavaField[] getFlattenedFields(HotSpotResolvedJavaField[] if (getFieldInfo(index).isStatic()) continue; FieldInfo fieldInfo = getFieldInfo(index); - int fieldOffset = fieldInfo.getOffset(); + HotSpotResolvedJavaField resolvedJavaField = createField(getFieldInfo(index).getType(this), fieldInfo.getOffset(), fieldInfo.getClassfileFlags(), fieldInfo.getInternalFlags(), index); + declaredFields.add(resolvedJavaField); + declaredResultCount++; + if (fieldInfo.isFlat()) { - HotSpotResolvedJavaField resolvedJavaField = createField(getFieldInfo(index).getType(this), fieldInfo.getOffset(), fieldInfo.getClassfileFlags(), fieldInfo.getInternalFlags(), index); - JavaType field = resolvedJavaField.getType(); + JavaType fieldType = resolvedJavaField.getType(); - if (field instanceof HotSpotResolvedObjectType resolvedFieldType) { + if (fieldType instanceof HotSpotResolvedObjectType resolvedFieldType) { ResolvedJavaField[] innerFields = resolvedFieldType.getInstanceFields(true); resultCount += innerFields.length; // compute all flattened fields recursively for (int i = 0; i < innerFields.length; ++i) { - // holder has no header so remove the header offset - int offset = fieldOffset + (innerFields[i].getOffset() - resolvedFieldType.payloadOffset()); - HotSpotResolvedJavaField innerField = (HotSpotResolvedJavaField) innerFields[i]; - resultList.add((HotSpotResolvedJavaField) innerField.changeOffset(offset).setContainerClass((HotSpotResolvedObjectType) resolvedJavaField.getDeclaringClass())); + declaredFields.add(createField(resolvedJavaField, (HotSpotResolvedJavaField) innerFields[i])); + } + if (fieldInfo.hasNullMarker()) { + declaredFields.add(createField(resolvedJavaField)); + resultCount++; } } - } else { - HotSpotResolvedJavaField resolvedJavaField = createField(fieldInfo.getType(this), fieldInfo.getOffset(), fieldInfo.getClassfileFlags(), fieldInfo.getInternalFlags(), index); resultCount++; - resultList.add(resolvedJavaField); + declaredFields.add(resolvedJavaField); } } - assert resultList.size() == resultCount : "wrong flat field count"; - return resultList.toArray(new HotSpotResolvedJavaField[resultList.size()]); + assert fields.size() == resultCount && declaredFields.size() == declaredResultCount : "wrong field count"; + declaredInstanceFields = declaredFields.toArray(new HotSpotResolvedJavaField[0]); + instanceFields = fields.toArray(new HotSpotResolvedJavaField[0]); } - /** - * Gets the instance or static fields of this class. - * - * @param retrieveStaticFields specifies whether to return instance or static fields - * @param prepend an array to be prepended to the returned result - */ - private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSpotResolvedJavaField[] prepend) { - HotSpotVMConfig config = config(); + private void computeStaticFields() { + if (isArray()) { + staticFields = NO_FIELDS; + return; + } + int resultCount = 0; int index = 0; for (index = 0; index < getFieldInfo().length; index++) { - if (getFieldInfo(index).isStatic() == retrieveStaticFields) { + if (getFieldInfo(index).isStatic()) { resultCount++; } } if (resultCount == 0) { - return prepend; + staticFields = NO_FIELDS; + return; } - int prependLength = prepend.length; - resultCount += prependLength; - + resultCount = 0; HotSpotResolvedJavaField[] result = new HotSpotResolvedJavaField[resultCount]; - if (prependLength != 0) { - System.arraycopy(prepend, 0, result, 0, prependLength); - } // Fields of the current class can be interleaved with fields of its super-classes // but the array of fields to be returned must be sorted by increasing offset // This code populates the array, then applies the sorting function - int resultIndex = prependLength; + int resultIndex = 0; for (int i = 0; i < getFieldInfo().length; ++i) { FieldInfo field = getFieldInfo(i); - if (field.isStatic() == retrieveStaticFields) { + if (field.isStatic()) { int offset = field.getOffset(); HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(this), offset, field.getClassfileFlags(), field.getInternalFlags(), i); result[resultIndex++] = resolvedJavaField; } } - return result; + staticFields = result; } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index 561a9dba718..21f1b43a100 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -228,6 +228,11 @@ public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { return new ResolvedJavaField[0]; } + @Override + public ResolvedJavaField[] getDeclaredInstanceFields(boolean includeSuperclasses) { + return new ResolvedJavaField[0]; + } + @Override public ResolvedJavaField[] getStaticFields() { return new ResolvedJavaField[0]; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index d2f1f89f63e..75cc9a11093 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -46,20 +46,6 @@ public interface ResolvedJavaField extends JavaField, ModifiersProvider, Annotat */ int getOffset(); - /** - * returns a new instance with a changed offset of the field relative to the base of its storage container - */ - default ResolvedJavaField changeOffset(int newOffset) { - throw new UnsupportedOperationException(); - } - - /** - * returns a resolved java field which represents the null marker field of a flattened inline type - */ - default ResolvedJavaField getNullMarkerField() { - throw new UnsupportedOperationException(); - } - default boolean isFinal() { return ModifiersProvider.super.isFinalFlagSet(); } @@ -118,11 +104,7 @@ default int getNullMarkerOffset() { * Returns the {@link ResolvedJavaType} object that represents the class in which an inline object (to which the field belongs) is embedded. * This differs to {@link #getDeclaringClass} if the inline object is flattened. */ - default ResolvedJavaType getContainerClass() { - throw new UnsupportedOperationException(); - } - - default ResolvedJavaField setContainerClass(ResolvedJavaType containerClass) { + default ResolvedJavaType getOriginalHolder() { throw new UnsupportedOperationException(); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index cdcc9b954a8..70f90a4a5b8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -324,6 +324,8 @@ default ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, Reso */ ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses); + ResolvedJavaField[] getDeclaredInstanceFields(boolean includeSuperclasses); + /** * Returns the static fields of this class, including {@linkplain ResolvedJavaField#isInternal() * internal} fields. A zero-length array is returned for array and primitive types. The order of From cbe5ed0568ad66a1bb623c70b89643f7826f2b0c Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Sat, 27 Sep 2025 00:07:20 +0200 Subject: [PATCH 04/27] Combine computeInstanceFields and computerStaticFields. --- .../HotSpotResolvedObjectTypeImpl.java | 89 ++++++++----------- 1 file changed, 36 insertions(+), 53 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 8ea926c738c..8637fbf5db0 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -855,14 +855,14 @@ public boolean isStatic() { @Override public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { if (instanceFields == null) { - computeInstanceFields(); + computeFields(); } return getFields(instanceFields, includeSuperclasses, false); } public ResolvedJavaField[] getDeclaredInstanceFields(boolean includeSuperclasses) { if (declaredInstanceFields == null) { - computeInstanceFields(); + computeFields(); } return getFields(declaredInstanceFields, includeSuperclasses, true); } @@ -901,17 +901,20 @@ public ResolvedJavaField[] getFields(HotSpotResolvedJavaField[] fields, boolean @Override public ResolvedJavaField[] getStaticFields() { if (staticFields == null) { - computeStaticFields(); + computeFields(); } return staticFields; } - private void computeInstanceFields() { + private void computeFields() { HotSpotResolvedJavaField[] declaredPrepend; HotSpotResolvedJavaField[] prepend; if (isArray() || isInterface()) { + if (isArray()) { + staticFields = NO_FIELDS; + } instanceFields = NO_FIELDS; declaredInstanceFields = NO_FIELDS; return; @@ -926,23 +929,35 @@ private void computeInstanceFields() { int declaredResultCount = 0; int resultCount = 0; + int staticResultCount = 0; int index = 0; for (index = 0; index < getFieldInfo().length; index++) { if (!getFieldInfo(index).isStatic()) { resultCount++; + } else { + staticResultCount++; } } if (resultCount == 0) { declaredInstanceFields = declaredPrepend; instanceFields = prepend; + } + + if (staticResultCount == 0) { + staticFields = NO_FIELDS; + } + + if (resultCount == 0 || staticResultCount == 0) { return; } - List declaredFields = new ArrayList<>(Arrays.asList(declaredPrepend)); - List fields = new ArrayList<>(Arrays.asList(prepend)); + // as the type should once become an unmodifiable list, use a list already + List tempDeclaredFields = new ArrayList<>(Arrays.asList(declaredPrepend)); + List tempFields = new ArrayList<>(Arrays.asList(prepend)); + List tempStaticFields = new ArrayList<>(); int declaredPrependLength = declaredPrepend.length; int prependLength = prepend.length; @@ -951,11 +966,16 @@ private void computeInstanceFields() { resultCount += prependLength; for (index = 0; index < getFieldInfo().length; index++) { - if (getFieldInfo(index).isStatic()) continue; - FieldInfo fieldInfo = getFieldInfo(index); + if (fieldInfo.isStatic()) { + int offset = fieldInfo.getOffset(); + HotSpotResolvedJavaField resolvedJavaField = createField(fieldInfo.getType(this), offset, fieldInfo.getClassfileFlags(), fieldInfo.getInternalFlags(), index); + tempStaticFields.add(resolvedJavaField); + continue; + } + HotSpotResolvedJavaField resolvedJavaField = createField(getFieldInfo(index).getType(this), fieldInfo.getOffset(), fieldInfo.getClassfileFlags(), fieldInfo.getInternalFlags(), index); - declaredFields.add(resolvedJavaField); + tempDeclaredFields.add(resolvedJavaField); declaredResultCount++; if (fieldInfo.isFlat()) { @@ -967,59 +987,22 @@ private void computeInstanceFields() { // compute all flattened fields recursively for (int i = 0; i < innerFields.length; ++i) { - declaredFields.add(createField(resolvedJavaField, (HotSpotResolvedJavaField) innerFields[i])); + tempDeclaredFields.add(createField(resolvedJavaField, (HotSpotResolvedJavaField) innerFields[i])); } if (fieldInfo.hasNullMarker()) { - declaredFields.add(createField(resolvedJavaField)); + tempDeclaredFields.add(createField(resolvedJavaField)); resultCount++; } } } else { resultCount++; - declaredFields.add(resolvedJavaField); - } - } - assert fields.size() == resultCount && declaredFields.size() == declaredResultCount : "wrong field count"; - declaredInstanceFields = declaredFields.toArray(new HotSpotResolvedJavaField[0]); - instanceFields = fields.toArray(new HotSpotResolvedJavaField[0]); - } - - private void computeStaticFields() { - if (isArray()) { - staticFields = NO_FIELDS; - return; - } - - int resultCount = 0; - int index = 0; - - for (index = 0; index < getFieldInfo().length; index++) { - if (getFieldInfo(index).isStatic()) { - resultCount++; - } - } - - if (resultCount == 0) { - staticFields = NO_FIELDS; - return; - } - - resultCount = 0; - HotSpotResolvedJavaField[] result = new HotSpotResolvedJavaField[resultCount]; - - // Fields of the current class can be interleaved with fields of its super-classes - // but the array of fields to be returned must be sorted by increasing offset - // This code populates the array, then applies the sorting function - int resultIndex = 0; - for (int i = 0; i < getFieldInfo().length; ++i) { - FieldInfo field = getFieldInfo(i); - if (field.isStatic()) { - int offset = field.getOffset(); - HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(this), offset, field.getClassfileFlags(), field.getInternalFlags(), i); - result[resultIndex++] = resolvedJavaField; + tempDeclaredFields.add(resolvedJavaField); } } - staticFields = result; + assert tempFields.size() == resultCount && tempDeclaredFields.size() == declaredResultCount : "wrong field count"; + declaredInstanceFields = tempDeclaredFields.toArray(new HotSpotResolvedJavaField[0]); + instanceFields = tempFields.toArray(new HotSpotResolvedJavaField[0]); + staticFields = tempStaticFields.toArray(new HotSpotResolvedJavaField[0]); } @Override From 305ff928f1de0c2711c1fd84d214c92766952463 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Sat, 27 Sep 2025 01:00:12 +0200 Subject: [PATCH 05/27] Provide an interface for the new array layouts. --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 55 ++++++------------- .../jdk/vm/ci/hotspot/CompilerToVM.java | 20 +------ .../ci/hotspot/HotSpotResolvedJavaType.java | 14 +---- .../ci/hotspot/HotSpotResolvedObjectType.java | 20 ------- .../HotSpotResolvedObjectTypeImpl.java | 30 +--------- .../hotspot/HotSpotResolvedPrimitiveType.java | 9 +-- .../jdk/vm/ci/meta/ResolvedJavaType.java | 19 ------- 7 files changed, 26 insertions(+), 141 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 70dbb50eaf3..035075baef7 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -715,7 +715,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jchar type_char, ARGUMENT_PAIR(klass))) +C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jchar type_char, ARGUMENT_PAIR(klass), jboolean atomic, jboolean null_restricted, jboolean vm_type)) JVMCIKlassHandle array_klass(THREAD); Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { @@ -728,45 +728,26 @@ C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jchar type_char, JVMCI_THROW_MSG_NULL(InternalError, err_msg("No array klass for primitive type %s", type2name(type))); } } else { - array_klass = klass->array_klass(CHECK_NULL); + if (klass->is_inline_klass() && vm_type) { + InlineKlass* vk = InlineKlass::cast(klass); + ArrayKlass::ArrayProperties props = ArrayKlass::ArrayProperties::DEFAULT; + if (null_restricted) { + props = (ArrayKlass::ArrayProperties)(props | ArrayKlass::ArrayProperties::NULL_RESTRICTED); + } + if (!atomic) { + props = (ArrayKlass::ArrayProperties)(props | ArrayKlass::ArrayProperties::NON_ATOMIC); + } + ArrayKlass* ak = vk->array_klass(THREAD); + array_klass = ObjArrayKlass::cast(ak)->klass_with_properties(props, THREAD); + } else { + ArrayKlass* ak = klass->array_klass(THREAD); + array_klass = ObjArrayKlass::cast(ak)->klass_with_properties(ArrayKlass::ArrayProperties::DEFAULT, THREAD); + } } JVMCIObject result = JVMCIENV->get_jvmci_type(array_klass, JVMCI_CHECK_NULL); return JVMCIENV->get_jobject(result); C2V_END -// C2V_VMENTRY_NULL(jobject, getFlatArrayType, (JNIEnv* env, jobject, jchar type_char, ARGUMENT_PAIR(klass))) -// JVMCIKlassHandle array_klass(THREAD); -// Klass* klass = UNPACK_PAIR(Klass, klass); - -// if(klass->is_inline_klass()){ -// InlineKlass* inline_klass = InlineKlass::cast(klass); -// ArrayKlass* flat_array_klass; -// if(inline_klass->flat_array()){ -// flat_array_klass = (ArrayKlass*)inline_klass->flat_array_klass(LayoutKind::NON_ATOMIC_FLAT, CHECK_NULL); -// }else{ -// flat_array_klass = (ArrayKlass*)inline_klass->null_free_reference_array(CHECK_NULL); -// } -// // Request a flat array, but we might not actually get it...either way "null-free" are the aaload/aastore semantics -// //ArrayKlass* flat_array_klass = (ArrayKlass*)inline_klass->flat_array_klass(LayoutKind::NON_ATOMIC_FLAT, CHECK_NULL); -// array_klass = flat_array_klass; -// assert(array_klass->is_null_free_array_klass(), "Expect a null-free array class here"); -// //assert(array_klass->is_flatArray_klass, "Expect a flat array class here"); -// }else{ -// array_klass = klass->array_klass(CHECK_NULL); -// } -// JVMCIObject result = JVMCIENV->get_jvmci_type(array_klass, JVMCI_CHECK_NULL); -// return JVMCIENV->get_jobject(result); -// C2V_END - -// C2V_VMENTRY_NULL(jobject, getDefaultInlineTypeInstance, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) -// JVMCIKlassHandle array_klass(THREAD); -// Klass* klass = UNPACK_PAIR(Klass, klass); - -// assert(klass->is_inline_klass(), "Should only be called for inline types"); -// oop default_value = InlineKlass::cast(klass)->default_value(); -// return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(default_value)); -// C2V_END - C2V_VMENTRY_NULL(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror)) requireInHotSpot("lookupClass", JVMCI_CHECK_NULL); if (mirror == nullptr) { @@ -3439,9 +3420,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "lookupType", CC "(" STRING HS_KLASS2 "IZ)" HS_RESOLVED_TYPE, FN_PTR(lookupType)}, {CC "lookupJClass", CC "(J)" HS_RESOLVED_TYPE, FN_PTR(lookupJClass)}, {CC "getJObjectValue", CC "(" OBJECTCONSTANT ")J", FN_PTR(getJObjectValue)}, - {CC "getArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getArrayType)}, - // {CC "getFlatArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getFlatArrayType)}, - // {CC "getDefaultInlineTypeInstance", CC "(" HS_KLASS2 ")" JAVACONSTANT, FN_PTR(getDefaultInlineTypeInstance)}, + {CC "getArrayType", CC "(C" HS_KLASS2 "ZZZ)" HS_KLASS, FN_PTR(getArrayType)}, {CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)}, {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupNameInPool)}, {CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index f7f0a1ee2dc..b0f61496c0e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -1180,26 +1180,12 @@ HotSpotResolvedJavaType getComponentType(HotSpotResolvedObjectTypeImpl klass) { * @param primitiveTypeChar a {@link JavaKind#getTypeChar()} value for a primitive type * @param nonPrimitiveKlass a non-primitive type */ - HotSpotResolvedObjectTypeImpl getArrayType(char primitiveTypeChar, HotSpotResolvedObjectTypeImpl nonPrimitiveKlass) { + HotSpotResolvedObjectTypeImpl getArrayType(char primitiveTypeChar, HotSpotResolvedObjectTypeImpl nonPrimitiveKlass, boolean atomic, boolean nullRestricted, boolean vmType) { long nonPrimitiveKlassPointer = nonPrimitiveKlass != null ? nonPrimitiveKlass.getKlassPointer() : 0L; - return getArrayType(primitiveTypeChar, nonPrimitiveKlass, nonPrimitiveKlassPointer); + return getArrayType(primitiveTypeChar, nonPrimitiveKlass, nonPrimitiveKlassPointer, atomic, nullRestricted, vmType); } - native HotSpotResolvedObjectTypeImpl getArrayType(char typeChar, HotSpotResolvedObjectTypeImpl klass, long klassPointer); - - HotSpotResolvedObjectTypeImpl getFlatArrayType(HotSpotResolvedObjectTypeImpl nonPrimitiveKlass) { - long nonPrimitiveKlassPointer = nonPrimitiveKlass.getKlassPointer(); - return getFlatArrayType((char) 0, nonPrimitiveKlass, nonPrimitiveKlassPointer); - } - - native HotSpotResolvedObjectTypeImpl getFlatArrayType(char typeChar, HotSpotResolvedObjectTypeImpl klass, long klassPointer); - - JavaConstant getDefaultInlineTypeInstance(HotSpotResolvedObjectTypeImpl nonPrimitiveKlass) { - long nonPrimitiveKlassPointer = nonPrimitiveKlass.getKlassPointer(); - return getDefaultInlineTypeInstance(nonPrimitiveKlass, nonPrimitiveKlassPointer); - } - - native JavaConstant getDefaultInlineTypeInstance(HotSpotResolvedObjectTypeImpl klass, long klassPointer); + native HotSpotResolvedObjectTypeImpl getArrayType(char typeChar, HotSpotResolvedObjectTypeImpl klass, long klassPointer, boolean atomic, boolean nullRestricted, boolean vmType); /** * Forces initialization of {@code klass}. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index 1d06ec1170a..b49a99493df 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -53,26 +53,16 @@ public int hashCode() { /** * Gets the array type of this type without caching the result. */ - protected abstract HotSpotResolvedObjectType getArrayType(); - - abstract HotSpotResolvedObjectType getFlatArrayType(); + protected abstract HotSpotResolvedObjectType getArrayType(boolean atomic, boolean nullRestricted, boolean vmType); @Override public HotSpotResolvedObjectType getArrayClass() { if (arrayOfType == null) { - arrayOfType = getArrayType(); + arrayOfType = getArrayType(false, false, false); } return arrayOfType; } - @Override - public final HotSpotResolvedObjectType getFlatArrayClass() { - if (flatArrayOfType == null) { - flatArrayOfType = getFlatArrayType(); - } - return flatArrayOfType; - } - /** * Checks whether this type is currently being initialized. If a type is being initialized it * implies that it was {@link #isLinked() linked} and that the static initializer is currently diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index 1febe30bc9f..72c3c4c8bfc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -39,21 +39,6 @@ public interface HotSpotResolvedObjectType extends ResolvedJavaType { @Override HotSpotResolvedObjectType getArrayClass(); - @Override - default HotSpotResolvedObjectType getFlatArrayClass(){ - return null; - } - - @Override - default HotSpotResolvedObjectType convertToFlatArray(){ - return null; - } - - @Override - default JavaConstant getDefaultInlineTypeInstance(){ - return null; - } - @Override ResolvedJavaType getComponentType(); @@ -97,11 +82,6 @@ default int getLog2ComponentSize(){ return -1; } - @Override - default boolean isFlatArray(){ - return false; - } - int getVtableLength(); @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 8637fbf5db0..e34f34170ad 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -549,14 +549,6 @@ public int getLog2ComponentSize() { return l2esz; } - @Override - public boolean isFlatArray() { - HotSpotVMConfig config = config(); - assert isArray(); - assert getKlassPointer() != 0 : getName(); - return UNSAFE.getInt(getKlassPointer() + config.klassKind) == config.klassFlatArray; - } - @Override public int layoutHelper() { HotSpotVMConfig config = config(); @@ -698,28 +690,10 @@ public JavaConstant getJavaMirror() { } @Override - protected HotSpotResolvedObjectTypeImpl getArrayType() { - return runtime().compilerToVm.getArrayType((char) 0, this); - } - - @Override - public HotSpotResolvedObjectTypeImpl getFlatArrayType() { - return runtime().compilerToVm.getFlatArrayType(this); + protected HotSpotResolvedObjectTypeImpl getArrayType(boolean atomic, boolean nullRestricted, boolean vmType) { + return runtime().compilerToVm.getArrayType((char) 0, this, atomic, nullRestricted, vmType); } - @Override - public HotSpotResolvedObjectTypeImpl convertToFlatArray() { - assert isArray() : "only an array class can be converted to flat array class"; - ResolvedJavaType componentType = this.getComponentType(); - assert componentType != null : "component type must not be null"; - if (!(componentType instanceof HotSpotResolvedObjectTypeImpl)) return this; - return runtime().compilerToVm.getFlatArrayType((HotSpotResolvedObjectTypeImpl) componentType); - } - - @Override - public JavaConstant getDefaultInlineTypeInstance() { - return runtime().compilerToVm.getDefaultInlineTypeInstance(this); - } /** * This class represents the field information for one field contained in the fields array of an diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index 21f1b43a100..5b5732f8404 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -90,16 +90,11 @@ public int getModifiers() { } @Override - protected HotSpotResolvedObjectType getArrayType() { + protected HotSpotResolvedObjectType getArrayType(boolean atomic, boolean nullRestricted, boolean vmType) { if (kind == JavaKind.Void) { return null; } - return runtime().compilerToVm.getArrayType(getJavaKind().getTypeChar(), null); - } - - @Override - HotSpotResolvedObjectType getFlatArrayType() { - return getArrayType(); + return runtime().compilerToVm.getArrayType(getJavaKind().getTypeChar(), null, false, false, false); } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index 70f90a4a5b8..bf6caee3097 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -247,25 +247,6 @@ default ResolvedJavaType getElementalType() { @Override ResolvedJavaType getArrayClass(); - /** - * Gets the array class type used when creating an array with {@link jdk.internal.value.ValueClass#newNullRestrictedArray(Class, int)} - */ - default ResolvedJavaType getFlatArrayClass() { - throw new UnsupportedOperationException(); - } - - default ResolvedJavaType convertToFlatArray() { - throw new UnsupportedOperationException(); - } - - default boolean isFlatArray() { - return false; - } - - default JavaConstant getDefaultInlineTypeInstance() { - throw new UnsupportedOperationException(); - } - /** * Resolves the method implementation for virtual dispatches on objects of this dynamic type. * This resolution process only searches "up" the class hierarchy of this type. A broader search From 2c52b4d4cf7ce99b4830c9755cba02583072a36c Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Sat, 27 Sep 2025 01:42:18 +0200 Subject: [PATCH 06/27] Provide JVMCI types for different array layouts. --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 10 ++++------ .../ci/hotspot/HotSpotResolvedJavaType.java | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 035075baef7..3ac3abcc3bf 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -728,8 +728,9 @@ C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jchar type_char, JVMCI_THROW_MSG_NULL(InternalError, err_msg("No array klass for primitive type %s", type2name(type))); } } else { - if (klass->is_inline_klass() && vm_type) { - InlineKlass* vk = InlineKlass::cast(klass); + ArrayKlass* ak = klass->array_klass(THREAD); + array_klass = ak; + if (vm_type) { ArrayKlass::ArrayProperties props = ArrayKlass::ArrayProperties::DEFAULT; if (null_restricted) { props = (ArrayKlass::ArrayProperties)(props | ArrayKlass::ArrayProperties::NULL_RESTRICTED); @@ -737,11 +738,8 @@ C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jchar type_char, if (!atomic) { props = (ArrayKlass::ArrayProperties)(props | ArrayKlass::ArrayProperties::NON_ATOMIC); } - ArrayKlass* ak = vk->array_klass(THREAD); + ArrayKlass* ak = klass->array_klass(THREAD); array_klass = ObjArrayKlass::cast(ak)->klass_with_properties(props, THREAD); - } else { - ArrayKlass* ak = klass->array_klass(THREAD); - array_klass = ObjArrayKlass::cast(ak)->klass_with_properties(ArrayKlass::ArrayProperties::DEFAULT, THREAD); } } JVMCIObject result = JVMCIENV->get_jvmci_type(array_klass, JVMCI_CHECK_NULL); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index b49a99493df..ae63a4ae511 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -31,7 +31,8 @@ public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { HotSpotResolvedObjectType arrayOfType; - HotSpotResolvedObjectType flatArrayOfType; + HotSpotResolvedObjectType nullRestrictedAtomicArrayOfType; + HotSpotResolvedObjectType nullRestrictedNonAtomicArrayOfType; protected HotSpotResolvedJavaType(String name) { super(name); @@ -58,11 +59,25 @@ public int hashCode() { @Override public HotSpotResolvedObjectType getArrayClass() { if (arrayOfType == null) { - arrayOfType = getArrayType(false, false, false); + arrayOfType = getArrayType(true, false, true); } return arrayOfType; } + public HotSpotResolvedObjectType nullRestrictedAtomicArrayClass() { + if (nullRestrictedAtomicArrayOfType == null) { + nullRestrictedAtomicArrayOfType = getArrayType(true, true, true); + } + return nullRestrictedAtomicArrayOfType; + } + + public HotSpotResolvedObjectType getNullRestrictedNonAtomicArrayClass() { + if (nullRestrictedNonAtomicArrayOfType == null) { + nullRestrictedNonAtomicArrayOfType = getArrayType(false, true, true); + } + return nullRestrictedNonAtomicArrayOfType; + } + /** * Checks whether this type is currently being initialized. If a type is being initialized it * implies that it was {@link #isLinked() linked} and that the static initializer is currently From f83e06cfb767637debbbba67ed56189c33214dd5 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Sat, 27 Sep 2025 02:27:42 +0200 Subject: [PATCH 07/27] Provide array properties over JVMCI. --- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 4 +++ src/hotspot/share/oops/arrayKlass.hpp | 1 + .../ci/hotspot/HotSpotResolvedJavaType.java | 6 +++++ .../ci/hotspot/HotSpotResolvedObjectType.java | 2 +- .../HotSpotResolvedObjectTypeImpl.java | 25 +++++++++++++++++++ .../hotspot/HotSpotResolvedPrimitiveType.java | 16 ++++++++++++ .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 4 +++ 7 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index b332adabf8a..e1b31bb9c05 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -290,6 +290,7 @@ nonstatic_field(Klass, _java_mirror, OopHandle) \ nonstatic_field(Klass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _kind, Klass::KlassKind const) \ + nonstatic_field(ArrayKlass, ArrayKlass::_properties, ArrayKlass::ArrayProperties const) \ nonstatic_field(Klass, _class_loader_data, ClassLoaderData*) \ nonstatic_field(Klass, _secondary_supers_bitmap, uintx) \ nonstatic_field(Klass, _hash_slot, uint8_t) \ @@ -833,6 +834,9 @@ declare_constant(Klass::_lh_log2_element_size_shift) \ declare_constant(Klass::_lh_log2_element_size_mask) \ declare_constant(Klass::FlatArrayKlassKind) \ + declare_constant(ArrayKlass::INVALID) \ + declare_constant(ArrayKlass::NON_ATOMIC) \ + declare_constant(ArrayKlass::NULL_RESTRICTED) \ declare_constant(Klass::_lh_element_type_shift) \ declare_constant(Klass::_lh_element_type_mask) \ declare_constant(Klass::_lh_header_size_shift) \ diff --git a/src/hotspot/share/oops/arrayKlass.hpp b/src/hotspot/share/oops/arrayKlass.hpp index 7ed037d5d64..f0bd686dbfe 100644 --- a/src/hotspot/share/oops/arrayKlass.hpp +++ b/src/hotspot/share/oops/arrayKlass.hpp @@ -35,6 +35,7 @@ class ObjArrayKlass; class ArrayKlass: public Klass { friend class VMStructs; + friend class JVMCIVMStructs; public: enum ArrayProperties : uint32_t { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index ae63a4ae511..79e6a670d00 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -78,6 +78,12 @@ public HotSpotResolvedObjectType getNullRestrictedNonAtomicArrayClass() { return nullRestrictedNonAtomicArrayOfType; } + public abstract boolean isElementFlat(); + + public abstract boolean isElementAtomic(); + + public abstract boolean isElementNullRestricted(); + /** * Checks whether this type is currently being initialized. If a type is being initialized it * implies that it was {@link #isLinked() linked} and that the static initializer is currently diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index 72c3c4c8bfc..788859ca1b4 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -78,7 +78,7 @@ default JavaKind getJavaKind() { /** * Gets the component size in an array */ - default int getLog2ComponentSize(){ + default int getLog2ComponentSize() { return -1; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index e34f34170ad..cfd63365cc3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -549,6 +549,31 @@ public int getLog2ComponentSize() { return l2esz; } + @Override + public boolean isElementFlat() { + HotSpotVMConfig config = config(); + assert isArray(); + assert getKlassPointer() != 0 : getName(); + return UNSAFE.getInt(getKlassPointer() + config.klassKind) == config.klassFlatArray; + } + + public boolean isElementAtomic() { + HotSpotVMConfig config = config(); + assert getKlassPointer() != 0 : getName(); + assert isArray(); + int properties = UNSAFE.getInt(getKlassPointer() + config.arrayProperties); + return (properties & config.invalidArrayProperty & config.nonAtomicArrayProperty) == 0; + } + + @Override + public boolean isElementNullRestricted() { + HotSpotVMConfig config = config(); + assert getKlassPointer() != 0 : getName(); + assert isArray(); + int properties = UNSAFE.getInt(getKlassPointer() + config.arrayProperties); + return (properties & config.nullRestrictedArrayProperty) != 0; + } + @Override public int layoutHelper() { HotSpotVMConfig config = config(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index 5b5732f8404..64feceb5f27 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -97,6 +97,22 @@ protected HotSpotResolvedObjectType getArrayType(boolean atomic, boolean nullRes return runtime().compilerToVm.getArrayType(getJavaKind().getTypeChar(), null, false, false, false); } + public boolean isElementFlat() { + assert isArray(); + return false; + } + + public boolean isElementAtomic() { + assert isArray(); + return true; + } + + @Override + public boolean isElementNullRestricted() { + assert isArray(); + return true; + } + @Override public ResolvedJavaType getElementalType() { return this; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 00718419d28..37564d06c77 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -99,6 +99,10 @@ static String getHostArchitectureName() { final int klassLayoutHelperLog2ElementSizeMask = getConstant("Klass::_lh_log2_element_size_mask", Integer.class); final int klassKind = getFieldOffset("Klass::_kind", Integer.class, "Klass::KlassKind const"); final int klassFlatArray = getConstant("Klass::FlatArrayKlassKind", Integer.class); + final int arrayProperties = getFieldOffset("ArrayKlass::_properties", Integer.class, "ArrayKlass::ArrayProperties const"); + final int invalidArrayProperty = getConstant("ArrayKlass::INVALID", Integer.class); + final int nonAtomicArrayProperty = getConstant("ArrayKlass::NON_ATOMIC", Integer.class); + final int nullRestrictedArrayProperty = getConstant("ArrayKlass::NULL_RESTRICTED", Integer.class); final int vtableEntrySize = getFieldValue("CompilerToVM::Data::sizeof_vtableEntry", Integer.class, "int"); final int vtableEntryMethodOffset = getFieldOffset("vtableEntry::_method", Integer.class, "Method*"); From 0b7c932138417431a182508c61e0453fb21f538d Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Mon, 29 Sep 2025 11:00:39 +0200 Subject: [PATCH 08/27] Correct null marker. --- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 30 +++++++++---------- .../ci/hotspot/HotSpotResolvedObjectType.java | 4 +++ .../HotSpotResolvedObjectTypeImpl.java | 7 +++++ .../jdk/vm/ci/meta/ResolvedJavaField.java | 8 ++--- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 62f97bf4d9a..46bfb7be47c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -85,19 +85,20 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { this.originalHolder = subField.getOriginalHolder(); this.type = subField.type; this.offset = declaredField.offset + (subField.offset - ((HotSpotResolvedObjectType) declaredField.getType()).payloadOffset()); - this.classfileFlags = declaredField.classfileFlags; - this.internalFlags = declaredField.internalFlags; - this.index = declaredField.index; + this.classfileFlags = subField.classfileFlags; + this.internalFlags = subField.internalFlags; + this.index = subField.index; } // Constructor for a null marker HotSpotResolvedJavaFieldImpl(HotSpotResolvedJavaFieldImpl declaredField) { this.holder = declaredField.holder; this.type = HotSpotResolvedPrimitiveType.forKind(JavaKind.Boolean); - this.offset = declaredField.getNullMarkerOffset(); - this.classfileFlags = declaredField.classfileFlags; - this.internalFlags = declaredField.internalFlags; - this.index = declaredField.index; + HotSpotResolvedObjectType declaredType = (HotSpotResolvedObjectType) declaredField.getType(); + this.offset = declaredField.offset + (declaredType.nullMarkerOffset() - declaredType.payloadOffset()); + this.classfileFlags = -1; + this.internalFlags = -1; + this.index = -1; } @Override @@ -132,7 +133,7 @@ public boolean isInternal() { } @Override - public boolean isNullFreeInlineType() { + public boolean isNullRestricted() { return (internalFlags & (1 << config().jvmFieldFlagNullFreeInlineTypeShift)) != 0; } @@ -142,17 +143,14 @@ public boolean isFlat() { } @Override - public boolean isInitialized() { - assert isStatic() : "should only be called on static fields"; - if (getDeclaringClass().isInitialized()) { - return !runtime().getCompilerToVM().readStaticFieldValue(getDeclaringClass(), getOffset(), JavaKind.Object.getTypeChar()).isNull(); - } - return false; + public boolean hasNullMarker() { + return (internalFlags & (1 << config().jvmFieldFlagNullMarkerShift)) != 0; } @Override - public int getNullMarkerOffset() { - return holder.getFieldInfo(index).getNullMarkerOffset(); + public int nullMarkerOffset() { + assert hasNullMarker(); + return ((HotSpotResolvedObjectType) getType()).nullMarkerOffset(); } /** diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index 788859ca1b4..71c3e91940f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -116,6 +116,10 @@ default int payloadOffset() { return -1; } + default int nullMarkerOffset() { + return -1; + } + long prototypeMarkWord(); int layoutHelper(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index cfd63365cc3..cbaa6089776 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1128,6 +1128,13 @@ public int payloadOffset() { return UNSAFE.getInt(fixedBlockPointer + config.payloadOffset); } + @Override + public int nullMarkerOffset() { + HotSpotVMConfig config = config(); + long fixedBlockPointer = UNSAFE.getAddress(getKlassPointer() + config.inlineKlassFixedBlockAdr); + return UNSAFE.getInt(fixedBlockPointer + config.nullMarkerOffset); + } + @Override public long prototypeMarkWord() { HotSpotVMConfig config = config(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index 75cc9a11093..faae46e6d2c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -65,10 +65,10 @@ default boolean isFlat() { } /** - * Determines if a null-restricted static field is already initialized. Such a field, for example, is not derived + * Determines if this field has a null-marker. Such a field, for example, is not derived * from a class file. */ - default boolean isInitialized() { + default boolean hasNullMarker() { throw new UnsupportedOperationException(); } @@ -76,7 +76,7 @@ default boolean isInitialized() { * Determines if this field is a null free inline type. Such a field, for example, is not derived * from a class file. */ - default boolean isNullFreeInlineType() { + default boolean isNullRestricted() { throw new UnsupportedOperationException(); } @@ -84,7 +84,7 @@ default boolean isNullFreeInlineType() { * Returns the null marker offset for nullable flattened fields. Such a field, for example, is not derived * from a class file. */ - default int getNullMarkerOffset() { + default int nullMarkerOffset() { throw new UnsupportedOperationException(); } From 33424ac68afa9549f3a646748cd8eb9ef0f4b305 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Mon, 29 Sep 2025 11:45:20 +0200 Subject: [PATCH 09/27] Rename nullfree to nullrestricted. Some refactoring. --- src/hotspot/share/jvmci/jvmciEnv.cpp | 4 +-- src/hotspot/share/jvmci/jvmciJavaClasses.hpp | 3 +- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 2 +- .../HotSpotResolvedJavaMethodImpl.java | 23 ++++++------ .../HotSpotResolvedObjectTypeImpl.java | 35 ++----------------- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 4 +-- .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 6 ++-- 7 files changed, 21 insertions(+), 56 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 87e0b2e6c3e..767806d38e6 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -1592,7 +1592,6 @@ JVMCIObject JVMCIEnv::new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS) { HotSpotJVMCI::FieldInfo::set_classfileFlags(JVMCIENV, obj_h(), (jint)fieldinfo->access_flags().as_field_flags()); HotSpotJVMCI::FieldInfo::set_internalFlags(JVMCIENV, obj_h(), (jint)fieldinfo->field_flags().as_uint()); HotSpotJVMCI::FieldInfo::set_initializerIndex(JVMCIENV, obj_h(), (jint)fieldinfo->initializer_index()); - HotSpotJVMCI::FieldInfo::set_nullMarkerOffset(JVMCIENV, obj_h(), (jint)fieldinfo->null_marker_offset()); return wrap(obj_h()); } else { JNIAccessMark jni(this, THREAD); @@ -1603,8 +1602,7 @@ JVMCIObject JVMCIEnv::new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS) { (jint)fieldinfo->offset(), (jint)fieldinfo->access_flags().as_field_flags(), (jint)fieldinfo->field_flags().as_uint(), - (jint)fieldinfo->initializer_index(), - (jint)fieldinfo->null_marker_offset()); + (jint)fieldinfo->initializer_index()); return wrap(result); } diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp index 0b4092242e2..978119add3a 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp @@ -79,8 +79,7 @@ int_field(FieldInfo, classfileFlags) \ int_field(FieldInfo, internalFlags) \ int_field(FieldInfo, initializerIndex) \ - int_field(FieldInfo, nullMarkerOffset) \ - jvmci_constructor(FieldInfo, "(IIIIIII)V") \ + jvmci_constructor(FieldInfo, "(IIIIII)V") \ end_class \ start_class(HotSpotResolvedJavaMethodImpl, jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl) \ long_field(HotSpotResolvedJavaMethodImpl, methodHandle) \ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 46bfb7be47c..9b418f3ea8c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -134,7 +134,7 @@ public boolean isInternal() { @Override public boolean isNullRestricted() { - return (internalFlags & (1 << config().jvmFieldFlagNullFreeInlineTypeShift)) != 0; + return (internalFlags & (1 << config().jvmFieldFlagNullRestrictedInlineTypeShift)) != 0; } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 8290ccd3593..30edc9066d1 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -40,7 +40,6 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.BitSet; -import java.util.Collections; import java.util.List; import jdk.internal.vm.VMSupport; @@ -811,7 +810,7 @@ public boolean isScalarizedParameter(int index, boolean indexIncludesReceiverIfE @Override - public boolean isParameterNullFree(int index, boolean indexIncludesReceiverIfExists) { + public boolean isParameterNullRestricted(int index, boolean indexIncludesReceiverIfExists) { // maybe for the future if (!indexIncludesReceiverIfExists) return false; if (!isStatic() && index == 0) return true; @@ -900,22 +899,22 @@ private HotSpotResolvedObjectTypeImpl getReturnedInlineType() { @Override - public List getScalarizedParameterNullFree(int index, boolean indexIncludesReceiverIfExists) { + public List getScalarizedParameterNullRestricted(int index, boolean indexIncludesReceiverIfExists) { return getScalarizedParameter(index, indexIncludesReceiverIfExists, true); } @Override public List getScalarizedParameter(int index, boolean indexIncludesReceiverIfExists) { - return getScalarizedParameter(index, indexIncludesReceiverIfExists, isParameterNullFree(index, indexIncludesReceiverIfExists)); + return getScalarizedParameter(index, indexIncludesReceiverIfExists, isParameterNullRestricted(index, indexIncludesReceiverIfExists)); } - private List getScalarizedParameter(int index, boolean indexIncludesReceiverIfExists, boolean nullFree) { + private List getScalarizedParameter(int index, boolean indexIncludesReceiverIfExists, boolean nullRestricted) { assert isScalarizedParameter(index, indexIncludesReceiverIfExists) : "Scalarized parameter presumed"; boolean includeReceiver = indexIncludesReceiverIfExists && !isStatic(); int previousIndex = index; if (includeReceiver) { if (index == 0) { - assert nullFree : "receiver should be null-free"; + assert nullRestricted : "receiver should be null-free"; return getFields(getDeclaringClass(), true, null); } else { index--; @@ -924,7 +923,7 @@ private List getScalarizedParameter(int index, boolean indexIncludesRe JavaType type = signature.getParameterType(index, getDeclaringClass()); assert type instanceof HotSpotResolvedObjectType : "HotSpotResolvedObjectType expected"; ResolvedJavaType resolvedType = (ResolvedJavaType) type; - return getFields((HotSpotResolvedObjectTypeImpl) resolvedType, nullFree, nullFree ? null : getScalarizedParameterNonNullType(previousIndex, indexIncludesReceiverIfExists)); + return getFields((HotSpotResolvedObjectTypeImpl) resolvedType, nullRestricted, nullRestricted ? null : getScalarizedParameterNonNullType(previousIndex, indexIncludesReceiverIfExists)); } @@ -970,8 +969,8 @@ public List getScalarizedParameters(boolean scalarizeReceiver) { if (isScalarizedParameter(i, false)) { assert type instanceof HotSpotResolvedObjectType : "HotSpotResolvedObjectType expected"; ResolvedJavaType resolvedType = (ResolvedJavaType) type; - boolean nullFree = isParameterNullFree(i, false); - types.addAll(getFields((HotSpotResolvedObjectTypeImpl) resolvedType, nullFree, nullFree ? null : getScalarizedParameterNonNullType(i, false))); + boolean nullRestricted = isParameterNullRestricted(i, false); + types.addAll(getFields((HotSpotResolvedObjectTypeImpl) resolvedType, nullRestricted, nullRestricted ? null : getScalarizedParameterNonNullType(i, false))); } else { types.add(type); } @@ -981,10 +980,10 @@ public List getScalarizedParameters(boolean scalarizeReceiver) { } - private List getFields(HotSpotResolvedObjectTypeImpl holder, boolean nullFree, JavaType nonNullType) { + private List getFields(HotSpotResolvedObjectTypeImpl holder, boolean nullRestricted, JavaType nonNullType) { ResolvedJavaField[] fields = holder.getInstanceFields(true); - List types = new ArrayList<>(fields.length + (!nullFree ? 1 : 0)); - if (!nullFree) { + List types = new ArrayList<>(fields.length + (!nullRestricted ? 1 : 0)); + if (!nullRestricted) { types.add(nonNullType); } for (int i = 0; i < fields.length; i++) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index cbaa6089776..a1e72e003e5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -732,7 +732,6 @@ static class FieldInfo { private final int classfileFlags; private final int internalFlags; private final int initializerIndex; - private final int nullMarkerOffset; /** * Creates a field info with the provided indices. @@ -744,14 +743,13 @@ static class FieldInfo { * @param internalFlags field's internal flags (from the VM) * @param initializerIndex field's initial value index in the constant pool */ - FieldInfo(int nameIndex, int signatureIndex, int offset, int classfileFlags, int internalFlags, int initializerIndex, int nullMarkerOffset) { + FieldInfo(int nameIndex, int signatureIndex, int offset, int classfileFlags, int internalFlags, int initializerIndex) { this.nameIndex = nameIndex; this.signatureIndex = signatureIndex; this.offset = offset; this.classfileFlags = classfileFlags; this.internalFlags = internalFlags; this.initializerIndex = initializerIndex; - this.nullMarkerOffset = nullMarkerOffset; } private int getClassfileFlags() { @@ -778,10 +776,6 @@ public int getOffset() { return offset; } - public int getNullMarkerOffset() { - return nullMarkerOffset; - } - /** * Returns the name of this field as a {@link String}. If the field is an internal field the * name index is pointing into the vmSymbols table. @@ -823,29 +817,6 @@ private boolean isInternal() { return (getInternalFlags() & (1 << config().jvmFieldFlagInternalShift)) != 0; } - private boolean isFlat() { - return (getInternalFlags() & (1 << config().jvmFieldFlagFlatShift)) != 0; - } - - private boolean isNullFreeInlineType() { - return (getInternalFlags() & (1 << config().jvmFieldFlagNullFreeInlineTypeShift)) != 0; - } - - private boolean hasNullMarker() { - return (getInternalFlags() & (1 << config().jvmFieldFlagNullMarkerShift)) != 0; - } - - private boolean hasInternalNullMarker() { - return true; - //return (getInternalFlags() & (1 << config().jvmFieldFlagInternalNullMarkerShift)) != 0; - } - -// private int internalNullMarkerOffset() { -// HotSpotVMConfig config = config(); -// long fixedBlockPointer = UNSAFE.getAddress(getKlassPointer() + config.inlineKlassFixedBlockAdr); -// return UNSAFE.getInt(fixedBlockPointer + config.internalNullMarkerOffset); -// } - public boolean isStatic() { return Modifier.isStatic(getClassfileFlags()); } @@ -977,7 +948,7 @@ private void computeFields() { tempDeclaredFields.add(resolvedJavaField); declaredResultCount++; - if (fieldInfo.isFlat()) { + if (resolvedJavaField.isFlat()) { JavaType fieldType = resolvedJavaField.getType(); if (fieldType instanceof HotSpotResolvedObjectType resolvedFieldType) { @@ -988,7 +959,7 @@ private void computeFields() { for (int i = 0; i < innerFields.length; ++i) { tempDeclaredFields.add(createField(resolvedJavaField, (HotSpotResolvedJavaField) innerFields[i])); } - if (fieldInfo.hasNullMarker()) { + if (resolvedJavaField.hasNullMarker()) { tempDeclaredFields.add(createField(resolvedJavaField)); resultCount++; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 37564d06c77..ddc1cc6da1d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -26,7 +26,6 @@ import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.services.Services; import jdk.internal.misc.Unsafe; import jdk.internal.util.Architecture; @@ -132,9 +131,8 @@ static String getHostArchitectureName() { final int jvmFieldFlagInternalShift = getConstant("FieldInfo::FieldFlags::_ff_injected", Integer.class); final int jvmFieldFlagStableShift = getConstant("FieldInfo::FieldFlags::_ff_stable", Integer.class); final int jvmFieldFlagFlatShift = getConstant("FieldInfo::FieldFlags::_ff_flat", Integer.class); - final int jvmFieldFlagNullFreeInlineTypeShift = getConstant("FieldInfo::FieldFlags::_ff_null_free_inline_type", Integer.class); + final int jvmFieldFlagNullRestrictedInlineTypeShift = getConstant("FieldInfo::FieldFlags::_ff_null_free_inline_type", Integer.class); final int jvmFieldFlagNullMarkerShift = getConstant("FieldInfo::FieldFlags::_ff_null_marker", Integer.class); - //final int jvmFieldFlagInternalNullMarkerShift = getConstant("FieldInfo::FieldFlags::_ff_internal_null_marker", Integer.class); final int jvmAccIsCloneableFast = getConstant("KlassFlags::_misc_is_cloneable_fast", Integer.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index 3947f24b8ce..1cdb29590e3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -523,7 +523,7 @@ default int getScalarizedParametersCount() { * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise * @return true if the parameter is null free, false otherwise */ - default boolean isParameterNullFree(int index, boolean indexIncludesReceiverIfExists) { + default boolean isParameterNullRestricted(int index, boolean indexIncludesReceiverIfExists) { return false; } @@ -584,7 +584,7 @@ default List getScalarizedParameters(boolean scalarizeReceiver) { } /** - * Similar to as {@link #getScalarizedParameterNullFree(int, boolean)} but also includes the is not null type if the parameter is not null free. + * Similar to as {@link #getScalarizedParameterNullRestricted(int, boolean)} but also includes the is not null type if the parameter is not null free. * * @param index the index of a formal parameter in the signature * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise @@ -601,7 +601,7 @@ default List getScalarizedParameter(int index, boolean indexIncludesRe * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise * @return the instance fields as types */ - default List getScalarizedParameterNullFree(int index, boolean indexIncludesReceiverIfExists) { + default List getScalarizedParameterNullRestricted(int index, boolean indexIncludesReceiverIfExists) { throw new UnsupportedOperationException("scalarized parameter not yet implemented"); } From 1a3395f6a0195344df43eeb84f31596a53e0fbad Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Mon, 29 Sep 2025 13:53:06 +0200 Subject: [PATCH 10/27] Make interface methods non-default. --- .../jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index 71c3e91940f..191c5efb3db 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -112,13 +112,9 @@ default JavaConstant getJavaMirror() { int superCheckOffset(); - default int payloadOffset() { - return -1; - } + int payloadOffset(); - default int nullMarkerOffset() { - return -1; - } + int nullMarkerOffset(); long prototypeMarkWord(); From 5fb6d11a99620e5f24f47e827a37b4428703ef3c Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Wed, 8 Oct 2025 05:46:50 +0200 Subject: [PATCH 11/27] Refactoring. --- .../vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java | 10 +++++++--- .../jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java | 4 +--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 9b418f3ea8c..564e4d4d6e5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -78,8 +78,10 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { this.index = index; } - // Special copy constructor used to flatten inline type fields by - // copying the fields of the inline type to a new holder klass. + /** + * Special copy constructor used to flatten inline type fields by + * copying the fields of the inline type to a new holder klass. + */ HotSpotResolvedJavaFieldImpl(HotSpotResolvedJavaFieldImpl declaredField, HotSpotResolvedJavaFieldImpl subField) { this.holder = declaredField.holder; this.originalHolder = subField.getOriginalHolder(); @@ -90,7 +92,9 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { this.index = subField.index; } - // Constructor for a null marker + /** + * Constructor for a null marker + */ HotSpotResolvedJavaFieldImpl(HotSpotResolvedJavaFieldImpl declaredField) { this.holder = declaredField.holder; this.type = HotSpotResolvedPrimitiveType.forKind(JavaKind.Boolean); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index 191c5efb3db..9d8e8a14c09 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -78,9 +78,7 @@ default JavaKind getJavaKind() { /** * Gets the component size in an array */ - default int getLog2ComponentSize() { - return -1; - } + int getLog2ComponentSize(); int getVtableLength(); From 5c786a6c46c9d4f8334167f2bcafe86ffe122cb3 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Thu, 16 Oct 2025 22:12:30 +0200 Subject: [PATCH 12/27] Remove redundant null marker methods from field classes. --- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 - .../hotspot/HotSpotResolvedJavaFieldImpl.java | 11 ---------- .../HotSpotResolvedObjectTypeImpl.java | 2 +- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 1 - .../jdk/vm/ci/meta/ResolvedJavaField.java | 21 +++---------------- 5 files changed, 4 insertions(+), 32 deletions(-) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index e1b31bb9c05..fa03ce557d0 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -525,7 +525,6 @@ declare_constant(FieldInfo::FieldFlags::_ff_stable) \ declare_constant(FieldInfo::FieldFlags::_ff_flat) \ declare_constant(FieldInfo::FieldFlags::_ff_null_free_inline_type) \ - declare_constant(FieldInfo::FieldFlags::_ff_null_marker) \ declare_preprocessor_constant("JVM_ACC_VARARGS", JVM_ACC_VARARGS) \ declare_preprocessor_constant("JVM_ACC_BRIDGE", JVM_ACC_BRIDGE) \ declare_preprocessor_constant("JVM_ACC_ANNOTATION", JVM_ACC_ANNOTATION) \ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 564e4d4d6e5..5295fad4873 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -146,17 +146,6 @@ public boolean isFlat() { return (internalFlags & (1 << config().jvmFieldFlagFlatShift)) != 0; } - @Override - public boolean hasNullMarker() { - return (internalFlags & (1 << config().jvmFieldFlagNullMarkerShift)) != 0; - } - - @Override - public int nullMarkerOffset() { - assert hasNullMarker(); - return ((HotSpotResolvedObjectType) getType()).nullMarkerOffset(); - } - /** * Determines if a given object contains this field. * diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index a1e72e003e5..45d5a4ca399 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -959,7 +959,7 @@ private void computeFields() { for (int i = 0; i < innerFields.length; ++i) { tempDeclaredFields.add(createField(resolvedJavaField, (HotSpotResolvedJavaField) innerFields[i])); } - if (resolvedJavaField.hasNullMarker()) { + if (!resolvedJavaField.isNullRestricted()) { tempDeclaredFields.add(createField(resolvedJavaField)); resultCount++; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index ddc1cc6da1d..198519315e4 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -132,7 +132,6 @@ static String getHostArchitectureName() { final int jvmFieldFlagStableShift = getConstant("FieldInfo::FieldFlags::_ff_stable", Integer.class); final int jvmFieldFlagFlatShift = getConstant("FieldInfo::FieldFlags::_ff_flat", Integer.class); final int jvmFieldFlagNullRestrictedInlineTypeShift = getConstant("FieldInfo::FieldFlags::_ff_null_free_inline_type", Integer.class); - final int jvmFieldFlagNullMarkerShift = getConstant("FieldInfo::FieldFlags::_ff_null_marker", Integer.class); final int jvmAccIsCloneableFast = getConstant("KlassFlags::_misc_is_cloneable_fast", Integer.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index faae46e6d2c..4b2100b1b2e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -65,29 +65,14 @@ default boolean isFlat() { } /** - * Determines if this field has a null-marker. Such a field, for example, is not derived - * from a class file. - */ - default boolean hasNullMarker() { - throw new UnsupportedOperationException(); - } - - /** - * Determines if this field is a null free inline type. Such a field, for example, is not derived - * from a class file. + * Determines if this field contains a null-restricted value object. + * Therefore, if this is a flat field and not null-restricted, it must contain a null marker. + * Such a field, for example, is not derived from a class file. */ default boolean isNullRestricted() { throw new UnsupportedOperationException(); } - /** - * Returns the null marker offset for nullable flattened fields. Such a field, for example, is not derived - * from a class file. - */ - default int nullMarkerOffset() { - throw new UnsupportedOperationException(); - } - /** * Determines if this field is a synthetic field as defined by the Java Language Specification. */ From 7db92dcd219552c258f1871e48006a1c587af6f5 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Thu, 16 Oct 2025 23:08:22 +0200 Subject: [PATCH 13/27] Add return convention in register config for aarch64. Refactoring in register config. --- .../jdk/vm/ci/code/RegisterConfig.java | 17 ++----- .../aarch64/AArch64HotSpotRegisterConfig.java | 44 +++++++++++++++++++ .../amd64/AMD64HotSpotRegisterConfig.java | 36 +++++---------- 3 files changed, 57 insertions(+), 40 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java index dc30a48755c..641b35639c8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java @@ -26,8 +26,6 @@ import jdk.vm.ci.code.CallingConvention.Type; import jdk.vm.ci.meta.*; -import java.util.List; - /** * A register configuration binds roles and {@linkplain RegisterAttributes attributes} to physical * registers. @@ -39,15 +37,6 @@ public interface RegisterConfig { */ Register getReturnRegister(JavaKind kind); - /** - * Gets the registers to be used for returning multiple values e.g. used for a scalarized inline object. Same procedure as with {@link #getReturnRegister(JavaKind)}. - * @param kinds the kinds used to decide if a value will be returned in a general or float register. - * @param includeFirstGeneralRegister determines if the first general register, which will contain the oop or tagged hub, should be skipped - */ - default Register[] getReturnRegisters(JavaKind[] kinds, boolean includeFirstGeneralRegister) { - throw new UnsupportedOperationException("config for multiple register usage on return not implemented yet"); - } - /** * Gets the maximum allowed size of the frame. */ @@ -72,14 +61,14 @@ default int getMaximumFrameSize() { CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory valueKindFactory); /** - * Gets the ordered set of registers that are used to return a nullable scalarized inline object according to the return convention. + * Gets the return convention describing in which registers a scalarized value is returned. * The first register contains an oop or tagged hub, while the rest contains the field values. * * @param returnTypes types of the values being returned * @param valueKindFactory the factory to create custom {@link ValueKind ValueKinds} - * @param includeFirstGeneralRegister determines if the first general register, which will contain the oop or tagged hub, should be skipped + * @param includeFirstGeneralRegister determines if the first general register, which will contain the oop or tagged hub, should be skipped. */ - default List getReturnConvention(List returnTypes, ValueKindFactory valueKindFactory, boolean includeFirstGeneralRegister) { + default List getReturnConvention(List returnTypes, ValueKindFactory valueKindFactory, boolean includeFirstGeneralRegister) { throw new UnsupportedOperationException("config for multiple register usage on return not implemented yet"); } /** diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java index 3ca3ea68edf..2269e5d77a6 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java @@ -112,6 +112,10 @@ public List getAttributesMap() { } private final List javaGeneralParameterRegisters = List.of(r1, r2, r3, r4, r5, r6, r7, r0); + + // see SharedRuntime::java_return_convention in sharedRuntime_aarch64.cpp + private final List javaGeneralReturnRegisters = List.of(r0, r7, r6, r5, r4, r3, r2, r1); + ; private final List nativeGeneralParameterRegisters = List.of(r0, r1, r2, r3, r4, r5, r6, r7); private final List simdParameterRegisters = List.of(v0, v1, v2, v3, v4, v5, v6, v7); @@ -318,6 +322,46 @@ public Register getReturnRegister(JavaKind kind) { } } + @Override + public List getReturnConvention(List returnTypes, ValueKindFactory valueKindFactory, boolean includeFirstGeneralRegister) { + AllocatableValue[] locations = new AllocatableValue[returnTypes.size()]; + List generalReturnRegisters = javaGeneralReturnRegisters; + + int currentGeneral = includeFirstGeneralRegister ? 0 : 1; + int currentSIMD = 0; + + Register register; + for (int i = 0; i < returnTypes.size(); i++) { + final JavaKind kind = returnTypes.get(i).getJavaKind().getStackKind(); + + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Object: + assert currentGeneral < generalReturnRegisters.size() : "return values can only be stored in registers"; + register = generalReturnRegisters.get(currentGeneral++); + locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); + + break; + case Float: + case Double: + assert currentSIMD < simdParameterRegisters.size() : "return values can only be stored in registers"; + register = simdParameterRegisters.get(currentSIMD++); + locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); + break; + default: + throw JVMCIError.shouldNotReachHere(); + } + + assert locations[i] != null : "return values can only be stored in registers"; + } + return List.of(locations); + } + @Override public Register getFrameRegister() { return sp; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java index a5e76346e09..bce25da6c25 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java @@ -202,15 +202,6 @@ public CallingConvention getCallingConvention(Type type, JavaType returnType, Ja return callingConvention(javaGeneralParameterRegisters, javaXMMParameterRegisters, false, returnType, parameterTypes, hotspotType, valueKindFactory); } - @Override - public List getReturnConvention(List returnTypes, ValueKindFactory valueKindFactory, boolean includeFirstGeneralRegister) { - JavaKind[] kinds = new JavaKind[returnTypes.size()]; - for (int i = 0; i < returnTypes.size(); i++) { - kinds[i] = returnTypes.get(i).getJavaKind().getStackKind(); - } - return getReturnLocations(getReturnRegisters(kinds, includeFirstGeneralRegister), returnTypes, valueKindFactory); - } - @Override public List getCallingConventionRegisters(Type type, JavaKind kind) { HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; @@ -321,8 +312,8 @@ public Register getReturnRegister(JavaKind kind) { } @Override - public Register[] getReturnRegisters(JavaKind[] kinds, boolean includeFirstGeneralRegister) { - Register[] registers = new Register[kinds.length]; + public List getReturnConvention(List returnTypes, ValueKindFactory valueKindFactory, boolean includeFirstGeneralRegister) { + AllocatableValue[] locations = new AllocatableValue[returnTypes.size()]; List generalReturnRegisters = javaGeneralReturnRegisters; List xmmReturnRegisters = javaXMMParameterRegisters; @@ -330,8 +321,8 @@ public Register[] getReturnRegisters(JavaKind[] kinds, boolean includeFirstGener int currentXMM = 0; Register register; - for (int i = 0; i < kinds.length; i++) { - final JavaKind kind = kinds[i]; + for (int i = 0; i < returnTypes.size(); i++) { + final JavaKind kind = returnTypes.get(i).getJavaKind().getStackKind(); switch (kind) { case Byte: @@ -342,30 +333,23 @@ public Register[] getReturnRegisters(JavaKind[] kinds, boolean includeFirstGener case Long: case Object: assert currentGeneral < generalReturnRegisters.size() : "return values can only be stored in registers"; - registers[i] = generalReturnRegisters.get(currentGeneral++); + register = generalReturnRegisters.get(currentGeneral++); + locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); break; case Float: case Double: assert currentXMM < xmmReturnRegisters.size() : "return values can only be stored in registers"; - registers[i] = xmmReturnRegisters.get(currentXMM++); + register = xmmReturnRegisters.get(currentXMM++); + locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); break; default: throw JVMCIError.shouldNotReachHere(); } - assert registers[i] != null : "return values can only be stored in registers"; - } - return registers; - } - - public List getReturnLocations(Register[] registers, List returnTypes, ValueKindFactory valueKindFactory) { - List locations = new ArrayList<>(returnTypes.size()); - for (int i = 0; i < registers.length; i++) { - final JavaKind kind = returnTypes.get(i).getJavaKind().getStackKind(); - locations.add(registers[i].asValue(valueKindFactory.getValueKind(kind))); + assert locations[i] != null : "return values can only be stored in registers"; } - return List.copyOf(locations); + return List.of(locations); } @Override From c4a26889e6ed05ef5258e3a658104ba9b1f05445 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Thu, 16 Oct 2025 23:48:33 +0200 Subject: [PATCH 14/27] Move methods from HotSpotResolvedObjectType to ResolvedJavaType. Add doc. --- .../vm/ci/hotspot/HotSpotResolvedObjectType.java | 4 ---- .../classes/jdk/vm/ci/meta/ResolvedJavaType.java | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index 9d8e8a14c09..53b49986b6c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -110,10 +110,6 @@ default JavaConstant getJavaMirror() { int superCheckOffset(); - int payloadOffset(); - - int nullMarkerOffset(); - long prototypeMarkWord(); int layoutHelper(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index bf6caee3097..03d5848f4be 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -439,4 +439,20 @@ default boolean isIdentity(){ } return !isInterface(); } + + /** + * Offset of the beginning of the payload in a value object allocated on the heap. + */ + default int payloadOffset() { + throw new UnsupportedOperationException(); + } + + /** + * Expresses the location of the null-marker for a flat field of this type. + * The offset begins at the start of a value object allocated on the heap. + * {@link #payloadOffset()} must be subtracted to get the offset from the beginning of the payload. + */ + default int nullMarkerOffset() { + throw new UnsupportedOperationException(); + } } From 97d99fb9b3abda6a56340811325c30a6e88a4c1c Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 00:25:43 +0200 Subject: [PATCH 15/27] Add javadoc. --- .../classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index 79e6a670d00..91a6e26bc3c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -53,6 +53,10 @@ public int hashCode() { /** * Gets the array type of this type without caching the result. + * A Java array of this type may have multiple layouts, but there only exists one Java runtime type of the array type. + * The Java runtime type is associated with a Java mirror, but does not say anything about the layout of an array. + * + * @param vmType {@code false} if the Java runtime type of the array should be returned, true otherwise. */ protected abstract HotSpotResolvedObjectType getArrayType(boolean atomic, boolean nullRestricted, boolean vmType); @@ -77,7 +81,7 @@ public HotSpotResolvedObjectType getNullRestrictedNonAtomicArrayClass() { } return nullRestrictedNonAtomicArrayOfType; } - + public abstract boolean isElementFlat(); public abstract boolean isElementAtomic(); From b8d07855ed8e81d91421ef36c0b69e37c6a9dc82 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 00:52:12 +0200 Subject: [PATCH 16/27] Also save the layout properties for virtual arrays. --- .../share/jvmci/jvmciCodeInstaller.cpp | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 966d4fcf18b..f0ba4197e26 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -1123,18 +1123,33 @@ void CodeInstaller::read_virtual_objects(HotSpotCompiledCodeStream* stream, JVMC _has_auto_box = true; } // see code in output.cpp (PhaseOutput::FillLocArray) - bool check_is_not_null = stream->read_bool("nonNull"); - ScopeValue *is_init = nullptr; - if (check_is_not_null) { + bool check_non_null = stream->read_bool("nonNull"); + ScopeValue *properties = nullptr; + if (check_non_null) { ScopeValue* cur_second = nullptr; BasicType type = (BasicType) stream->read_u1("basicType"); ScopeValue* value; u1 tag = stream->read_u1("tag"); - is_init = get_scope_value(stream, tag, type, cur_second, JVMCI_CHECK); + properties = get_scope_value(stream, tag, type, cur_second, JVMCI_CHECK); + } + if (klass->is_array_klass() && !klass->is_typeArray_klass()) { + jint props = ArrayKlass::ArrayProperties::DEFAULT; + ObjArrayKlass* ak = ObjArrayKlass::cast(klass); + if (ak->element_klass()->is_inline_klass()) { + if (klass->is_null_free_array_klass()) { + props |= ArrayKlass::ArrayProperties::NULL_RESTRICTED; + } + bool is_atomic = (ak->properties() & ArrayKlass::ArrayProperties::INVALID) == 0 && + (ak->properties() & ArrayKlass::ArrayProperties::NON_ATOMIC) == 0; + if (!is_atomic) { + props |= ArrayKlass::ArrayProperties::NON_ATOMIC; + } + } + properties = new ConstantIntValue(props); } oop javaMirror = klass->java_mirror(); ScopeValue *klass_sv = new ConstantOopWriteValue(JNIHandles::make_local(javaMirror)); - ObjectValue* sv = is_auto_box ? new AutoBoxObjectValue(id, klass_sv) : new ObjectValue(id, klass_sv, true, is_init); + ObjectValue* sv = is_auto_box ? new AutoBoxObjectValue(id, klass_sv) : new ObjectValue(id, klass_sv, true, properties); objects->at_put(id, sv); } // All the values which could be referenced by the VirtualObjects From b0e72790d1c10c694db72c3c1b77230ad1400398 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 10:58:14 +0200 Subject: [PATCH 17/27] Rename inline type to value class. --- .../classes/jdk/vm/ci/code/CodeUtil.java | 2 +- .../jdk/vm/ci/hotspot/CompilerToVM.java | 10 ++++---- .../DirectHotSpotObjectConstantImpl.java | 2 +- .../jdk/vm/ci/hotspot/HotSpotMethodData.java | 23 ++++++++++--------- .../vm/ci/hotspot/HotSpotObjectConstant.java | 2 +- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 6 ++--- .../HotSpotResolvedJavaMethodImpl.java | 10 ++++---- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 6 ++--- .../IndirectHotSpotObjectConstantImpl.java | 15 ++++++------ .../hotspot/SharedLibraryJVMCIReflection.java | 4 ++-- .../jdk/vm/ci/hotspot/SingleTypeEntry.java | 4 ++-- .../classes/jdk/vm/ci/meta/ProfilingInfo.java | 6 ++--- .../jdk/vm/ci/meta/ResolvedJavaField.java | 4 ++-- .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 4 ++-- 14 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java index 51509b37862..a27184318d3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java @@ -440,7 +440,7 @@ public static CallingConvention getCallingConvention(CodeCacheProvider codeCache } /** - * Create a calling convention from a {@link ResolvedJavaMethod} with scalarized inline type parameters . + * Create a calling convention from a {@link ResolvedJavaMethod} with value objects being passed scalarized. * * @param scalarizeReceiver true if the receiver should be scalarized, false otherwise */ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index b0f61496c0e..427cee374b9 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -171,11 +171,11 @@ boolean hasCallingConventionMismatch(HotSpotResolvedJavaMethodImpl method) { * * @return true if the return value is scalarized */ - boolean hasScalarizedReturn(HotSpotResolvedJavaMethodImpl method, HotSpotResolvedObjectTypeImpl inlineType) { - return hasScalarizedReturn(method, method.getMethodPointer(), inlineType, inlineType.getMetaspacePointer()); + boolean hasScalarizedReturn(HotSpotResolvedJavaMethodImpl method, HotSpotResolvedObjectTypeImpl valueClass) { + return hasScalarizedReturn(method, method.getMethodPointer(), valueClass, valueClass.getMetaspacePointer()); } - private native boolean hasScalarizedReturn(HotSpotResolvedJavaMethodImpl method, long methodPointer, HotSpotResolvedObjectTypeImpl returnType, long inlineTypePointer); + private native boolean hasScalarizedReturn(HotSpotResolvedJavaMethodImpl method, long methodPointer, HotSpotResolvedObjectTypeImpl returnType, long valueClassPointer); /** * Computes the scalarized signature of the {@code method}. @@ -189,9 +189,9 @@ HotSpotSignature getScalarizedSignature(HotSpotResolvedJavaMethodImpl method) { private native HotSpotSignature getScalarizedSignature(HotSpotResolvedJavaMethodImpl method, long methodPointer); /** - * Determines if a inline type can be passed scalarized as an argument. + * Determines if a value object of a certain type can be passed scalarized as an argument. * - * @return true if the inline type can be scalarized + * @return true if a value object of this type can be scalarized */ boolean canBePassedAsFields(HotSpotResolvedObjectTypeImpl type) { return canBePassedAsFields(type, type.getKlassPointer()); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java index 2f5e0114426..0e50ee2a0b3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java @@ -71,7 +71,7 @@ public int getIdentityHashCode() { } @Override - public boolean objectIsInlineType() { + public boolean isValueObject() { return !getType().isIdentity(); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodData.java index 70bd0524328..a7650c6359b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodData.java @@ -81,8 +81,8 @@ static final class VMState { final int leftOperandOffset = cellIndexToOffset(3); final int rightOperandOffset = cellIndexToOffset(4); - final int leftInlineTypeFlag = 1 << config.leftInlineTypeFlag; - final int rightInlineTypeFlag = 1 << config.rightInlineTypeFlag; + final int leftValueClassFlag = 1 << config.leftValueClassFlag; + final int rightValueClassFlag = 1 << config.rightValueClassFlag; final int arrayDataLengthOffset = cellIndexToOffset(config.arrayDataArrayLenOffset); final int arrayDataStartOffset = cellIndexToOffset(config.arrayDataArrayStartOffset); @@ -730,7 +730,7 @@ abstract static class SingleTypeEntryImpl implements SingleTypeEntry { private boolean maybeNull; private boolean neverNull; private boolean alwaysNull; - private boolean inlineType; + private boolean valueClass; final static long nullSeen =1; final static long typeMask = ~nullSeen; @@ -752,11 +752,12 @@ abstract static class SingleTypeEntryImpl implements SingleTypeEntry { } int flags = aCmpData.getFlags(data, position); - this.inlineType =(flags & getInlineFlag()) !=0; + this.valueClass = (flags & getValueClassFlag()) != 0; } abstract int getOperandOffset(); - abstract int getInlineFlag(); + + abstract int getValueClassFlag(); protected VMState getState(){ return state; @@ -804,8 +805,8 @@ public boolean alwaysNull(){ } @Override - public boolean inlineType(){ - return inlineType; + public boolean valueClass() { + return valueClass; } @@ -823,8 +824,8 @@ int getOperandOffset(){ } @Override - int getInlineFlag(){ - return getState().leftInlineTypeFlag; + int getValueClassFlag() { + return getState().leftValueClassFlag; } } @@ -840,8 +841,8 @@ int getOperandOffset(){ } @Override - int getInlineFlag(){ - return getState().rightInlineTypeFlag; + int getValueClassFlag() { + return getState().rightValueClassFlag; } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstant.java index 647d2d5cf02..8cae1d1db6b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstant.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstant.java @@ -115,7 +115,7 @@ default Assumptions.AssumptionResult getCallSiteTarget() { @Override String toValueString(); - default boolean objectIsInlineType(){ + default boolean isValueObject() { return false; } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 5295fad4873..22116d91d78 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -79,8 +79,8 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { } /** - * Special copy constructor used to flatten inline type fields by - * copying the fields of the inline type to a new holder klass. + * Special copy constructor used to flatten a value class by + * copying the fields of the value class to a new holder klass. */ HotSpotResolvedJavaFieldImpl(HotSpotResolvedJavaFieldImpl declaredField, HotSpotResolvedJavaFieldImpl subField) { this.holder = declaredField.holder; @@ -138,7 +138,7 @@ public boolean isInternal() { @Override public boolean isNullRestricted() { - return (internalFlags & (1 << config().jvmFieldFlagNullRestrictedInlineTypeShift)) != 0; + return (internalFlags & (1 << config().jvmFieldFlagNullRestrictedValueClassShift)) != 0; } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 30edc9066d1..e5eb736f2d2 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -834,10 +834,10 @@ public boolean hasScalarizedParameters() { public boolean hasScalarizedReturn() { if (hasScalarizedReturn.isKnown()) return hasScalarizedReturn.toBoolean(); boolean result; - if (!returnsInlineType()) { + if (!returnsValueObject()) { result = false; } else { - result = compilerToVM().hasScalarizedReturn(this, getReturnedInlineType()); + result = compilerToVM().hasScalarizedReturn(this, getReturnedValueClass()); } hasScalarizedReturn = TriState.get(result); return result; @@ -881,19 +881,19 @@ public List getScalarizedReturn() { return List.copyOf(types); } - private boolean returnsInlineType() { + private boolean returnsValueObject() { JavaType returnType = signature.getReturnType(getDeclaringClass()); // check if the method returns an object // the type is not expected to be resolved if (returnType instanceof HotSpotResolvedObjectType type) { - // check if the returned value is an inline type + // check if the return value is a value object return !type.isInterface() && !type.isAbstract() && !type.isIdentity(); } return false; } - private HotSpotResolvedObjectTypeImpl getReturnedInlineType() { + private HotSpotResolvedObjectTypeImpl getReturnedValueClass() { return (HotSpotResolvedObjectTypeImpl) signature.getReturnType(getDeclaringClass()); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 198519315e4..b66b14c423b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -131,7 +131,7 @@ static String getHostArchitectureName() { final int jvmFieldFlagInternalShift = getConstant("FieldInfo::FieldFlags::_ff_injected", Integer.class); final int jvmFieldFlagStableShift = getConstant("FieldInfo::FieldFlags::_ff_stable", Integer.class); final int jvmFieldFlagFlatShift = getConstant("FieldInfo::FieldFlags::_ff_flat", Integer.class); - final int jvmFieldFlagNullRestrictedInlineTypeShift = getConstant("FieldInfo::FieldFlags::_ff_null_free_inline_type", Integer.class); + final int jvmFieldFlagNullRestrictedValueClassShift = getConstant("FieldInfo::FieldFlags::_ff_null_free_inline_type", Integer.class); final int jvmAccIsCloneableFast = getConstant("KlassFlags::_misc_is_cloneable_fast", Integer.class); @@ -406,6 +406,6 @@ String getCodeInstallResultDescription(int codeInstallResult) { final int arrayDataArrayLenOffset = getConstant("ArrayData::array_len_off_set", Integer.class); final int arrayDataArrayStartOffset = getConstant("ArrayData::array_start_off_set", Integer.class); final int multiBranchDataPerCaseCellCount = getConstant("MultiBranchData::per_case_cell_count", Integer.class); - final int leftInlineTypeFlag = getConstant("ACmpData::left_inline_type_flag", Integer.class); - final int rightInlineTypeFlag = getConstant("ACmpData::right_inline_type_flag", Integer.class); + final int leftValueClassFlag = getConstant("ACmpData::left_inline_type_flag", Integer.class); + final int rightValueClassFlag = getConstant("ACmpData::right_inline_type_flag", Integer.class); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java index dafcdd2cf71..ce3b0e4611c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java @@ -23,7 +23,6 @@ package jdk.vm.ci.hotspot; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; -import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; import java.io.ByteArrayOutputStream; import java.io.PrintStream; @@ -51,7 +50,7 @@ final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl final IndirectHotSpotObjectConstantImpl base; - private final boolean objectIsInlineType; + private final boolean isValueObject; private static class Audit { final Object scope; @@ -73,12 +72,12 @@ private static class Audit { private Object rawAudit; @VMEntryPoint - private IndirectHotSpotObjectConstantImpl(long objectHandle, boolean compressed, boolean skipRegister, boolean objectIsInlineType) { + private IndirectHotSpotObjectConstantImpl(long objectHandle, boolean compressed, boolean skipRegister, boolean isValueObject) { super(compressed); assert objectHandle != 0 && UnsafeAccess.UNSAFE.getLong(objectHandle) != 0; this.objectHandle = objectHandle; this.base = null; - this.objectIsInlineType = objectIsInlineType; + this.isValueObject = isValueObject; if (!skipRegister) { HotSpotObjectConstantScope scope = HotSpotObjectConstantScope.CURRENT.get(); if (scope != null && !scope.isGlobal()) { @@ -105,7 +104,7 @@ private IndirectHotSpotObjectConstantImpl(IndirectHotSpotObjectConstantImpl base // There should only be one level of indirection to the base object. assert base.base == null || base.base.base == null; this.base = base.base != null ? base.base : base; - this.objectIsInlineType = base.objectIsInlineType; + this.isValueObject = base.isValueObject; } long getHandle() { @@ -186,7 +185,7 @@ public int getIdentityHashCode() { checkHandle(); int hash = hashCode; if (hash == 0) { - if (objectIsInlineType) { + if (isValueObject) { // The method ValueObjectMethods:valueObjectHashCode is private, we would need to go into the VM. // This is not allowed though, because Java calls are disabled when libjvmci enters // the VM via a C2V (i.e. CompilerToVM) native method. @@ -204,7 +203,7 @@ public int getIdentityHashCode() { } @Override - public boolean objectIsInlineType() { - return objectIsInlineType; + public boolean isValueObject() { + return isValueObject; } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java index cbc94969390..1a77e542f67 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java @@ -113,8 +113,8 @@ Boolean valhallaEquals(HotSpotObjectConstantImpl x, HotSpotObjectConstantImpl y) IndirectHotSpotObjectConstantImpl indirectX = (IndirectHotSpotObjectConstantImpl) x; IndirectHotSpotObjectConstantImpl indirectY = (IndirectHotSpotObjectConstantImpl) y; boolean result = runtime().compilerToVm.equals(x, indirectX.getHandle(), y, indirectY.getHandle()); - if (!result && indirectX.objectIsInlineType() && indirectY.objectIsInlineType()) { - // reference comparison of oops falsified, doesn't mean that the two inline objects are not equal + if (!result && indirectX.isValueObject() && indirectY.isValueObject()) { + // reference comparison of oops falsified, doesn't mean that the two value objects are not equal return null; } return result; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SingleTypeEntry.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SingleTypeEntry.java index ac1d6d35813..90e185ecd09 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SingleTypeEntry.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SingleTypeEntry.java @@ -29,8 +29,8 @@ public interface SingleTypeEntry{ boolean alwaysNull(); /** - * @return whether the operand was seen to be an inline type, false otherwise + * @return whether the operand was seen to be a value class, false otherwise */ - boolean inlineType(); + boolean valueClass(); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ProfilingInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ProfilingInfo.java index 35f50628d52..3b631d886f6 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ProfilingInfo.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ProfilingInfo.java @@ -186,10 +186,10 @@ default String toString(ResolvedJavaMethod method, String sep) { ACmpDataAccessor aCmpData = (ACmpDataAccessor) getACmpData(i); if (getACmpData(i) != null) { SingleTypeEntry left = aCmpData.getLeft(); - String formatString = "ACmpType@%d: %s alwaysNull:%b inlineType:%b%s"; - buf.append(String.format(formatString, i, left.getValidType(), left.alwaysNull(), left.inlineType(), sep)); + String formatString = "ACmpType@%d: %s alwaysNull:%b value class:%b%s"; + buf.append(String.format(formatString, i, left.getValidType(), left.alwaysNull(), left.valueClass(), sep)); SingleTypeEntry right = aCmpData.getRight(); - buf.append(String.format(formatString, i, right.getValidType(), right.alwaysNull(), right.inlineType(), sep)); + buf.append(String.format(formatString, i, right.getValidType(), right.alwaysNull(), right.valueClass(), sep)); } JavaTypeProfile typeProfile = getTypeProfile(i); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index 4b2100b1b2e..06f6f141ac9 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -86,8 +86,8 @@ default boolean isNullRestricted() { ResolvedJavaType getDeclaringClass(); /** - * Returns the {@link ResolvedJavaType} object that represents the class in which an inline object (to which the field belongs) is embedded. - * This differs to {@link #getDeclaringClass} if the inline object is flattened. + * Returns the {@link ResolvedJavaType} object that represents the class in which a value object (to which the field belongs) is embedded. + * This differs to {@link #getDeclaringClass} if the value object is flattened. */ default ResolvedJavaType getOriginalHolder() { throw new UnsupportedOperationException(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index 1cdb29590e3..b2671f19f76 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -490,8 +490,8 @@ default boolean isScoped() { /** * Gets the information if a parameter at a certain position in the method signature is scalarized. - * Inline type arguments may not be passed by reference, but in scalarized form. - * We get an argument per field of the inline type. + * Value class arguments may not be passed by reference, but in scalarized form. + * We get an argument per field of the value object. * * @param index the index of a formal parameter in the signature * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise From b3742c7195023c7d15356a35afc0bea4645111ae Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 13:39:45 +0200 Subject: [PATCH 18/27] Correct holder class logic. Add javadoc. --- .../ci/hotspot/HotSpotObjectConstantImpl.java | 4 +- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 41 ++++++++++--------- .../jdk/vm/ci/meta/ResolvedJavaField.java | 28 ++++++++++++- 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java index cc139a40e0a..5a7fd003369 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java @@ -206,9 +206,9 @@ public JavaConstant readFieldValue(HotSpotResolvedJavaField field) { if (field.isStatic()) { return null; } - HotSpotResolvedObjectTypeImpl declaringClass = (HotSpotResolvedObjectTypeImpl) field.getOriginalHolder(); + HotSpotResolvedObjectTypeImpl declaringClass = (HotSpotResolvedObjectTypeImpl) field.getDeclaringClass(); char typeChar = field.getType().getJavaKind().getTypeChar(); - return runtime().compilerToVm.readFieldValue(this, declaringClass, field.getOffset(), typeChar, declaringClass != field.getDeclaringClass()); + return runtime().compilerToVm.readFieldValue(this, declaringClass, field.getOffset(), typeChar, declaringClass != field.getHolderClass()); } public ResolvedJavaType asJavaType() { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 22116d91d78..d7be1efebe0 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -42,9 +42,9 @@ */ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { - private final HotSpotResolvedObjectTypeImpl holder; + private final HotSpotResolvedObjectTypeImpl declaringClass; - private HotSpotResolvedObjectTypeImpl originalHolder; + private final HotSpotResolvedObjectTypeImpl holderClass; private JavaType type; @@ -69,8 +69,9 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { */ private final int internalFlags; - HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, JavaType type, int offset, int classfileFlags, int internalFlags, int index) { - this.holder = holder; + HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl declaringClass, JavaType type, int offset, int classfileFlags, int internalFlags, int index) { + this.declaringClass = declaringClass; + this.holderClass = declaringClass; this.type = type; this.offset = offset; this.classfileFlags = classfileFlags; @@ -81,10 +82,12 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { /** * Special copy constructor used to flatten a value class by * copying the fields of the value class to a new holder klass. + * @param declaredField the declared value class field which is flattened + * @param subField a field which is declared in the type of {@code declaredField} */ HotSpotResolvedJavaFieldImpl(HotSpotResolvedJavaFieldImpl declaredField, HotSpotResolvedJavaFieldImpl subField) { - this.holder = declaredField.holder; - this.originalHolder = subField.getOriginalHolder(); + this.declaringClass = subField.declaringClass; + this.holderClass = declaredField.holderClass; this.type = subField.type; this.offset = declaredField.offset + (subField.offset - ((HotSpotResolvedObjectType) declaredField.getType()).payloadOffset()); this.classfileFlags = subField.classfileFlags; @@ -96,7 +99,8 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { * Constructor for a null marker */ HotSpotResolvedJavaFieldImpl(HotSpotResolvedJavaFieldImpl declaredField) { - this.holder = declaredField.holder; + this.declaringClass = declaredField.declaringClass; + this.holderClass = declaredField.holderClass; this.type = HotSpotResolvedPrimitiveType.forKind(JavaKind.Boolean); HotSpotResolvedObjectType declaredType = (HotSpotResolvedObjectType) declaredField.getType(); this.offset = declaredField.offset + (declaredType.nullMarkerOffset() - declaredType.payloadOffset()); @@ -114,7 +118,7 @@ public boolean equals(Object obj) { HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; if (that.offset != this.offset || that.isStatic() != this.isStatic()) { return false; - } else if (this.holder.equals(that.holder) && this.getOriginalHolder().equals(that.getOriginalHolder())) { + } else if (this.declaringClass.equals(that.declaringClass) && this.holderClass.equals(that.holderClass)) { return true; } } @@ -123,7 +127,7 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return holder.hashCode() ^ offset; + return declaringClass.hashCode() ^ offset; } @Override @@ -163,20 +167,17 @@ public boolean isInObject(JavaConstant object) { @Override public HotSpotResolvedObjectTypeImpl getDeclaringClass() { - return holder; + return declaringClass; } @Override - public HotSpotResolvedObjectTypeImpl getOriginalHolder() { - if (originalHolder == null) { - return holder; - } - return originalHolder; + public HotSpotResolvedObjectTypeImpl getHolderClass() { + return holderClass; } @Override public String getName() { - return getOriginalHolder().getFieldInfo(index).getName(getOriginalHolder()); + return declaringClass.getFieldInfo(index).getName(declaringClass); } @Override @@ -187,7 +188,7 @@ public JavaType getType() { if (currentType instanceof UnresolvedJavaType) { // Don't allow unresolved types to hang around forever UnresolvedJavaType unresolvedType = (UnresolvedJavaType) currentType; - JavaType resolved = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedType.getName(), getOriginalHolder(), false); + JavaType resolved = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedType.getName(), declaringClass, false); if (resolved instanceof ResolvedJavaType) { type = resolved; } @@ -236,7 +237,7 @@ public boolean isStable() { private boolean hasAnnotations() { if (!isInternal()) { HotSpotVMConfig config = config(); - final long metaspaceAnnotations = UNSAFE.getAddress(getOriginalHolder().getKlassPointer() + config.instanceKlassAnnotationsOffset); + final long metaspaceAnnotations = UNSAFE.getAddress(declaringClass.getKlassPointer() + config.instanceKlassAnnotationsOffset); if (metaspaceAnnotations != 0) { long fieldsAnnotations = UNSAFE.getAddress(metaspaceAnnotations + config.annotationsFieldAnnotationsOffset); if (fieldsAnnotations != 0) { @@ -274,7 +275,7 @@ public T getAnnotation(Class annotationClass) { @Override public JavaConstant getConstantValue() { - return getOriginalHolder().getFieldInfo(index).getConstantValue(getOriginalHolder()); + return declaringClass.getFieldInfo(index).getConstantValue(declaringClass); } @Override @@ -298,7 +299,7 @@ public List getAnnotationData(ResolvedJavaType type1, ResolvedJa } private List getAnnotationData0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationData(getOriginalHolder(), index, filter); + byte[] encoded = compilerToVM().getEncodedFieldAnnotationData(declaringClass, index, filter); return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index 06f6f141ac9..b0c656b6de4 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -86,10 +86,34 @@ default boolean isNullRestricted() { ResolvedJavaType getDeclaringClass(); /** - * Returns the {@link ResolvedJavaType} object that represents the class in which a value object (to which the field belongs) is embedded. + * Returns the {@link ResolvedJavaType} object that represents the class in which a field is embedded. * This differs to {@link #getDeclaringClass} if the value object is flattened. + * + *

+     * class Data {
+     *  Int32! vo_field;
+     * }
+     *
+     * value class Int32 {
+     *  int value_field;
+     * }
+     *
+     * // Int32 object heap layout
+     * - header
+     * - value_field
+     *
+     * {@code value_field.getDeclaringClass()} returns Int32
+     * {@code value_field.getHolderClass()} returns Int32
+     *
+     *  // Data object heap layout (flattened Int32)
+     * - header
+     * - value_field
+     *
+     *  {@code value_field.getDeclaringClass()} returns Int32
+     *  {@code value_field.getHolderClass()} returns Data
+     *  
*/ - default ResolvedJavaType getOriginalHolder() { + default ResolvedJavaType getHolderClass() { throw new UnsupportedOperationException(); } From f2107df50756b4f834815222efa8f9a37868a5a6 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 14:03:50 +0200 Subject: [PATCH 19/27] Provide the strict property of a field. --- .../share/classes/jdk/vm/ci/meta/ResolvedJavaField.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index b0c656b6de4..01be34ada6d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -50,6 +50,10 @@ default boolean isFinal() { return ModifiersProvider.super.isFinalFlagSet(); } + default boolean isStrict() { + return ModifiersProvider.super.isStrict(); + } + /** * Determines if this field was injected by the VM. Such a field, for example, is not derived * from a class file. From 4e96bfbdade917198935b7ff39ca37e54355d064 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 15:47:17 +0200 Subject: [PATCH 20/27] Provide some properties of heap flattening. --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 52 +++++++++++++++++- .../jdk/vm/ci/hotspot/CompilerToVM.java | 36 ++++++++++++ .../ci/hotspot/HotSpotResolvedObjectType.java | 17 ++++++ .../HotSpotResolvedObjectTypeImpl.java | 55 +++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 3ac3abcc3bf..d93a76d2a38 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -406,6 +406,50 @@ C2V_VMENTRY_0(jboolean, canBePassedAsFields, (JNIEnv* env, jobject, ARGUMENT_PAI return inlineKlass->can_be_passed_as_fields(); C2V_END +C2V_VMENTRY_0(jboolean, mustBeAtomic, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) + Klass* klass = UNPACK_PAIR(Klass, klass); + assert(klass->is_inline_klass(), "Klass should be an inline type"); + InlineKlass* inlineKlass = InlineKlass::cast(klass); + return inlineKlass->must_be_atomic(); +C2V_END + +C2V_VMENTRY_0(jboolean, hasAtomicLayout, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) + Klass* klass = UNPACK_PAIR(Klass, klass); + assert(klass->is_inline_klass(), "Klass should be an inline type"); + InlineKlass* inlineKlass = InlineKlass::cast(klass); + return inlineKlass->has_atomic_layout(); +C2V_END + +C2V_VMENTRY_0(jboolean, hasNonAtomicLayout, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) + Klass* klass = UNPACK_PAIR(Klass, klass); + assert(klass->is_inline_klass(), "Klass should be an inline type"); + InlineKlass* inlineKlass = InlineKlass::cast(klass); + return inlineKlass->has_non_atomic_layout(); +C2V_END + +C2V_VMENTRY_0(jboolean, hasNullableAtomicLayout, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) + Klass* klass = UNPACK_PAIR(Klass, klass); + assert(klass->is_inline_klass(), "Klass should be an inline type"); + InlineKlass* inlineKlass = InlineKlass::cast(klass); + return inlineKlass->has_nullable_atomic_layout(); +C2V_END + +C2V_VMENTRY_0(jint, atomicSize, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jboolean nullRestricted)) + Klass* klass = UNPACK_PAIR(Klass, klass); + assert(klass->is_inline_klass(), "Klass should be an inline type"); + InlineKlass* inlineKlass = InlineKlass::cast(klass); + assert(!nullRestricted || inlineKlass->has_atomic_layout(), "No null-free atomic layout available"); + assert( nullRestricted || inlineKlass->has_nullable_atomic_layout(), "No nullable atomic layout available"); + return nullRestricted ? inlineKlass->atomic_size_in_bytes() : inlineKlass->nullable_atomic_size_in_bytes(); +C2V_END + +C2V_VMENTRY_0(jboolean, maybeFlatInArray, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) + Klass* klass = UNPACK_PAIR(Klass, klass); + assert(klass->is_inline_klass(), "Klass should be an inline type"); + InlineKlass* inlineKlass = InlineKlass::cast(klass); + return inlineKlass->maybe_flat_in_array(); +C2V_END + C2V_VMENTRY_0(jint, getExceptionTableLength, (JNIEnv* env, jobject, ARGUMENT_PAIR(method))) Method* method = UNPACK_PAIR(Method, method); return method->exception_table_length(); @@ -3400,11 +3444,17 @@ C2V_END JNINativeMethod CompilerToVM::methods[] = { {CC "getBytecode", CC "(" HS_METHOD2 ")[B", FN_PTR(getBytecode)}, - {CC "getScalarizedParametersInfo", CC "(" HS_METHOD2 "[ZI)[Z", FN_PTR(getScalarizedParametersInfo)}, + {CC "getScalarizedParametersInfo", CC "(" HS_METHOD2 "[ZI)[Z", FN_PTR(getScalarizedParametersInfo)}, {CC "hasScalarizedParameters", CC "(" HS_METHOD2 ")Z", FN_PTR(hasScalarizedParameters)}, {CC "hasScalarizedReturn", CC "(" HS_METHOD2 HS_KLASS2 ")Z", FN_PTR(hasScalarizedReturn)}, {CC "hasCallingConventionMismatch", CC "(" HS_METHOD2 ")Z", FN_PTR(hasCallingConventionMismatch)}, {CC "canBePassedAsFields", CC "(" HS_KLASS2 ")Z", FN_PTR(canBePassedAsFields)}, + {CC "mustBeAtomic", CC "(" HS_KLASS2 ")Z", FN_PTR(mustBeAtomic)}, + {CC "hasAtomicLayout", CC "(" HS_KLASS2 ")Z", FN_PTR(hasAtomicLayout)}, + {CC "hasNonAtomicLayout", CC "(" HS_KLASS2 ")Z", FN_PTR(hasNonAtomicLayout)}, + {CC "hasNullableAtomicLayout", CC "(" HS_KLASS2 ")Z", FN_PTR(hasNullableAtomicLayout)}, + {CC "atomicSize", CC "(" HS_KLASS2 "Z)I", FN_PTR(atomicSize)}, + {CC "maybeFlatInArray", CC "(" HS_KLASS2 ")Z", FN_PTR(maybeFlatInArray)}, {CC "getExceptionTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getExceptionTableStart)}, {CC "getExceptionTableLength", CC "(" HS_METHOD2 ")I", FN_PTR(getExceptionTableLength)}, {CC "findUniqueConcreteMethod", CC "(" HS_KLASS2 HS_METHOD2 ")" HS_METHOD, FN_PTR(findUniqueConcreteMethod)}, diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index 427cee374b9..8988ab1e3db 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -1635,4 +1635,40 @@ void getOopMapAt(HotSpotResolvedJavaMethodImpl method, int bci, long[] oopMap) { * Returns whether the current thread is a CompilerThread. */ native boolean isCompilerThread(); + + public boolean mustBeAtomic(HotSpotResolvedObjectTypeImpl type) { + return mustBeAtomic(type, type.getKlassPointer()); + } + + native boolean mustBeAtomic(HotSpotResolvedObjectTypeImpl type, long klassPointer); + + public boolean hasAtomicLayout(HotSpotResolvedObjectTypeImpl type) { + return hasAtomicLayout(type, type.getKlassPointer()); + } + + native boolean hasAtomicLayout(HotSpotResolvedObjectTypeImpl type, long klassPointer); + + public boolean hasNonAtomicLayout(HotSpotResolvedObjectTypeImpl type) { + return hasNonAtomicLayout(type, type.getKlassPointer()); + } + + native boolean hasNonAtomicLayout(HotSpotResolvedObjectTypeImpl type, long klassPointer); + + public boolean hasNullableAtomicLayout(HotSpotResolvedObjectTypeImpl type) { + return hasNullableAtomicLayout(type, type.getKlassPointer()); + } + + native boolean hasNullableAtomicLayout(HotSpotResolvedObjectTypeImpl type, long klassPointer); + + public JavaKind atomicSizeToJavaKind(HotSpotResolvedObjectTypeImpl type, boolean nullRestricted) { + return JavaKind.fromWordSize(atomicSize(type, type.getKlassPointer(), nullRestricted)); + } + + native int atomicSize(HotSpotResolvedObjectTypeImpl type, long klassPointer, boolean nullRestricted); + + public boolean maybeFlatInArray(HotSpotResolvedObjectTypeImpl type) { + return maybeFlatInArray(type, type.getKlassPointer()); + } + + native boolean maybeFlatInArray(HotSpotResolvedObjectTypeImpl type, long klassPointer); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index 53b49986b6c..387b90cbe9e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -119,4 +119,21 @@ default JavaConstant getJavaMirror() { @Override ResolvedJavaMethod getClassInitializer(); + + boolean mustBeAtomic(); + + default boolean isNaturallyAtomic(boolean nullRestricted) { + int length = getInstanceFields(true).length; + return nullRestricted ? length <= 1 : length == 0; + } + + boolean hasAtomicLayout(); + + boolean hasNonAtomicLayout(); + + boolean hasNullableAtomicLayout(); + + JavaKind atomicSizeToJavaKind(boolean nullRestricted); + + boolean maybeFlatInArray(); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 45d5a4ca399..398aa501709 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1259,4 +1259,59 @@ private List getAnnotationData0(ResolvedJavaType... filter) { byte[] encoded = compilerToVM().getEncodedClassAnnotationData(this, filter); return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE); } + + private TriState mustBeAtomic = TriState.UNKNOWN; + private TriState hasAtomicLayout = TriState.UNKNOWN; + private TriState hasNonAtomicLayout = TriState.UNKNOWN; + private TriState hasNullableAtomicLayout = TriState.UNKNOWN; + private JavaKind atomicSizeToJavaKind = null; + private TriState maybeFlatInArray = TriState.UNKNOWN; + + + public boolean mustBeAtomic() { + if (mustBeAtomic.isUnknown()) { + mustBeAtomic = TriState.get(compilerToVM().mustBeAtomic(this)); + } + return mustBeAtomic.toBoolean(); + } + + @Override + public boolean hasAtomicLayout() { + if (hasAtomicLayout.isUnknown()) { + hasAtomicLayout = TriState.get(compilerToVM().hasAtomicLayout(this)); + } + return hasAtomicLayout.toBoolean(); + } + + @Override + public boolean hasNonAtomicLayout() { + if (hasNonAtomicLayout.isUnknown()) { + hasNonAtomicLayout = TriState.get(compilerToVM().hasNonAtomicLayout(this)); + } + return hasNonAtomicLayout.toBoolean(); + } + + @Override + public boolean hasNullableAtomicLayout() { + if (hasNullableAtomicLayout.isUnknown()) { + hasNullableAtomicLayout = TriState.get(compilerToVM().hasNullableAtomicLayout(this)); + } + return hasNullableAtomicLayout.toBoolean(); + } + + @Override + public JavaKind atomicSizeToJavaKind(boolean nullRestricted) { + if (atomicSizeToJavaKind == null) { + atomicSizeToJavaKind = compilerToVM().atomicSizeToJavaKind(this, nullRestricted); + } + return atomicSizeToJavaKind; + } + + @Override + public boolean maybeFlatInArray() { + if (maybeFlatInArray.isUnknown()) { + maybeFlatInArray = TriState.get(compilerToVM().maybeFlatInArray(this)); + } + return maybeFlatInArray.toBoolean(); + } } From c800c07c1f4bab5cf4cd4c0582dde85af00a2ebf Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 15:51:16 +0200 Subject: [PATCH 21/27] Rename runtime calls for the flat array load and store operation. --- src/hotspot/share/jvmci/jvmciRuntime.cpp | 4 ++-- src/hotspot/share/jvmci/jvmciRuntime.hpp | 4 ++-- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index fff515c37f0..4d40ff88996 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -416,12 +416,12 @@ JRT_LEAF(jboolean, JVMCIRuntime::object_notify(JavaThread* current, oopDesc* obj JRT_END -JRT_ENTRY(void, JVMCIRuntime::load_unknown_inline(JavaThread* current, flatArrayOopDesc* array, jint index)) +JRT_ENTRY(void, JVMCIRuntime::load_flat_array(JavaThread* current, flatArrayOopDesc* array, jint index)) oop buffer = array->obj_at(index, THREAD); current->set_vm_result_oop(buffer); JRT_END -JRT_ENTRY(void, JVMCIRuntime::store_unknown_inline(JavaThread* current, flatArrayOopDesc* array, jint index, oopDesc* value)) +JRT_ENTRY(void, JVMCIRuntime::store_flat_array(JavaThread* current, flatArrayOopDesc* array, jint index, oopDesc* value)) array->obj_at_put(index, value, THREAD); JRT_END diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index 2c6c991e5a2..b12e1d5d9af 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -559,8 +559,8 @@ class JVMCIRuntime: public CHeapObj { static void monitorexit (JavaThread* current, oopDesc* obj, BasicLock* lock); static jboolean object_notify(JavaThread* current, oopDesc* obj); static jboolean object_notifyAll(JavaThread* current, oopDesc* obj); - static void load_unknown_inline(JavaThread* thread, flatArrayOopDesc* array, jint index); - static void store_unknown_inline(JavaThread* thread, flatArrayOopDesc* array, jint index, oopDesc* value); + static void load_flat_array(JavaThread* thread, flatArrayOopDesc* array, jint index); + static void store_flat_array(JavaThread* thread, flatArrayOopDesc* array, jint index, oopDesc* value); static void vm_error(JavaThread* current, jlong where, jlong format, jlong value); static oopDesc* load_and_clear_exception(JavaThread* thread); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index fa03ce557d0..ddcc4a326c1 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -956,8 +956,8 @@ declare_function(JVMCIRuntime::exception_handler_for_pc) \ declare_function(JVMCIRuntime::monitorenter) \ declare_function(JVMCIRuntime::monitorexit) \ - declare_function(JVMCIRuntime::load_unknown_inline) \ - declare_function(JVMCIRuntime::store_unknown_inline) \ + declare_function(JVMCIRuntime::load_flat_array) \ + declare_function(JVMCIRuntime::store_flat_array) \ declare_function(JVMCIRuntime::object_notify) \ declare_function(JVMCIRuntime::object_notifyAll) \ declare_function(JVMCIRuntime::throw_and_post_jvmti_exception) \ From 65e77f69eb06174ac2ee5cd3130e6161f71a2ab1 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 16:18:54 +0200 Subject: [PATCH 22/27] Refactoring. --- .../HotSpotResolvedJavaMethodImpl.java | 61 +++++++++++-------- .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 3 +- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index e5eb736f2d2..63803571347 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -797,6 +797,8 @@ public BitSet getOopMapAt(int bci) { } private boolean[] scalarizedParametersInfo; + private TriState hasScalarizedParameters = TriState.UNKNOWN; + private TriState hasScalarizedReceiver = TriState.UNKNOWN; @Override public boolean isScalarizedParameter(int index, boolean indexIncludesReceiverIfExists) { @@ -811,56 +813,56 @@ public boolean isScalarizedParameter(int index, boolean indexIncludesReceiverIfE @Override public boolean isParameterNullRestricted(int index, boolean indexIncludesReceiverIfExists) { - // maybe for the future - if (!indexIncludesReceiverIfExists) return false; - if (!isStatic() && index == 0) return true; + // null-restriction allows also non-receiver parameters to be null-restricted in the future + if (!indexIncludesReceiverIfExists) { + return false; + } + if (!isStatic() && index == 0) { + return true; + } return false; } - private TriState hasScalarizedParameters = TriState.UNKNOWN; - @Override public boolean hasScalarizedParameters() { // see ciMethod::has_scalarized_args - if (hasScalarizedParameters.isKnown()) return hasScalarizedParameters.toBoolean(); - boolean result = compilerToVM().hasScalarizedParameters(this); - hasScalarizedParameters = TriState.get(result); - return result; + if (hasScalarizedParameters.isUnknown()) { + hasScalarizedParameters = TriState.get(compilerToVM().hasScalarizedParameters(this)); + } + return hasScalarizedParameters.toBoolean(); } - private TriState hasScalarizedReturn = TriState.UNKNOWN; - @Override public boolean hasScalarizedReturn() { - if (hasScalarizedReturn.isKnown()) return hasScalarizedReturn.toBoolean(); boolean result; if (!returnsValueObject()) { result = false; } else { result = compilerToVM().hasScalarizedReturn(this, getReturnedValueClass()); } - hasScalarizedReturn = TriState.get(result); return result; } - private TriState hasScalarizedReceiver = TriState.UNKNOWN; - @Override public boolean hasScalarizedReceiver() { - if (hasScalarizedReceiver.isKnown()) return hasScalarizedReceiver.toBoolean(); - boolean result = !isStatic() && isScalarizedParameter(0, true); - hasScalarizedReceiver = TriState.get(result); - return result; + if (hasScalarizedReceiver.isUnknown()) { + boolean result = !isStatic() && isScalarizedParameter(0, true); + hasScalarizedReceiver = TriState.get(result); + } + return hasScalarizedReceiver.toBoolean(); } private TriState hasCallingConventionMismatch = TriState.UNKNOWN; + /** + * See CompiledEntrySignature::compute_calling_conventions which detects these mismatches. + */ @Override public boolean hasCallingConventionMismatch() { - if (hasCallingConventionMismatch.isKnown()) return hasCallingConventionMismatch.toBoolean(); - boolean result = compilerToVM().hasCallingConventionMismatch(this); - hasCallingConventionMismatch = TriState.get(result); - return result; + if (hasCallingConventionMismatch.isUnknown()) { + hasCallingConventionMismatch = TriState.get(compilerToVM().hasCallingConventionMismatch(this)); + } + return hasCallingConventionMismatch.toBoolean(); } @Override @@ -871,7 +873,7 @@ public List getScalarizedReturn() { ResolvedJavaType resolvedType = (ResolvedJavaType) type; ResolvedJavaField[] fields = resolvedType.getInstanceFields(true); - // one extra field for oop or hub + // one extra field for oop or tagged hub int length = fields.length + 1; List types = new ArrayList<>(length); types.add(resolvedType); @@ -897,7 +899,6 @@ private HotSpotResolvedObjectTypeImpl getReturnedValueClass() { return (HotSpotResolvedObjectTypeImpl) signature.getReturnType(getDeclaringClass()); } - @Override public List getScalarizedParameterNullRestricted(int index, boolean indexIncludesReceiverIfExists) { return getScalarizedParameter(index, indexIncludesReceiverIfExists, true); @@ -917,6 +918,7 @@ private List getScalarizedParameter(int index, boolean indexIncludesRe assert nullRestricted : "receiver should be null-free"; return getFields(getDeclaringClass(), true, null); } else { + // signature index starts without the receiver, so substract one index--; } } @@ -946,23 +948,28 @@ public List getScalarizedParameterFields(int index, boolean i @Override public JavaType getScalarizedParameterNonNullType(int index, boolean indexIncludesReceiverIfExists) { - assert isScalarizedParameter(index, indexIncludesReceiverIfExists) /*&& !isParameterNullFree(index, indexIncludesReceiverIfExists)*/ : "Scalarized nullable parameter presumed"; + assert isScalarizedParameter(index, indexIncludesReceiverIfExists) && !isParameterNullRestricted(index, indexIncludesReceiverIfExists) : "Scalarized nullable parameter presumed"; return HotSpotResolvedPrimitiveType.forKind(NON_NULL_KIND); } private static final JavaKind NON_NULL_KIND = JavaKind.Byte; + /** + * see TypeTuple::make_domain in opto/type.cpp + */ @Override public List getScalarizedParameters(boolean scalarizeReceiver) { - // see TypeTuple::make_domain in opto/type.cpp assert hasScalarizedParameters() : "Any scalarized parameters presumed"; List types = new ArrayList<>(); if (hasScalarizedReceiver() && scalarizeReceiver) { + // we want the receiver in a scalarized form types.addAll(getFields(getDeclaringClass(), true, null)); } else if (!isStatic()) { + // add the receiver in a non-scalarized form types.add(getDeclaringClass()); } + // iterate of the parameters and add them in scalarized form if necessary for (int i = 0; i < signature.getParameterCount(false); i++) { JavaType type = signature.getParameterType(i, getDeclaringClass()); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index b2671f19f76..54677ac61c1 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -556,7 +556,6 @@ default boolean hasScalarizedReceiver() { /** * Finds out if the scalarized calling convention of a method does not match that of a subclass. - * See CompiledEntrySignature::compute_calling_conventions which detects these mismatches. * * @return true if there is a mismatch */ @@ -617,7 +616,7 @@ default List getScalarizedParameterFields(int index, boolean } /** - * Gets the type used for a scalarized parameter to represent its is not null information. + * Gets the type used for a scalarized parameter to represent its non-null information. * * @param index the index of a formal parameter in the signature * @param indexIncludesReceiverIfExists true if the receiver is included in the {@code index}, false otherwise From 96c3862752a16159d24c986c4920cef53488f038 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 16:21:07 +0200 Subject: [PATCH 23/27] Refactoring. --- .../share/classes/jdk/vm/ci/code/CodeUtil.java | 2 +- .../jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java | 2 +- .../share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java index a27184318d3..390beec6127 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java @@ -447,7 +447,7 @@ public static CallingConvention getCallingConvention(CodeCacheProvider codeCache public static CallingConvention getValhallaCallingConvention(CodeCacheProvider codeCache, CallingConvention.Type type, ResolvedJavaMethod method, ValueKindFactory valueKindFactory, boolean scalarizeReceiver) { if (!method.hasScalarizedParameters()) return getCallingConvention(codeCache, type, method, valueKindFactory); Signature sig = method.getSignature(); - List argTypes = method.getScalarizedParameters(scalarizeReceiver); + List argTypes = method.getScalarizedMethodSignature(scalarizeReceiver); JavaType retType = sig.getReturnType(null); RegisterConfig registerConfig = codeCache.getRegisterConfig(); return registerConfig.getCallingConvention(type, retType, argTypes.toArray(new JavaType[argTypes.size()]), valueKindFactory); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 63803571347..bf670291a28 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -959,7 +959,7 @@ public JavaType getScalarizedParameterNonNullType(int index, boolean indexInclud * see TypeTuple::make_domain in opto/type.cpp */ @Override - public List getScalarizedParameters(boolean scalarizeReceiver) { + public List getScalarizedMethodSignature(boolean scalarizeReceiver) { assert hasScalarizedParameters() : "Any scalarized parameters presumed"; List types = new ArrayList<>(); if (hasScalarizedReceiver() && scalarizeReceiver) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index 54677ac61c1..354a19a67c2 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -578,7 +578,7 @@ default List getScalarizedReturn() { * @param scalarizeReceiver true if the receiver should be scalarized as well, false otherwise * @return the types representing the scalarized method signature */ - default List getScalarizedParameters(boolean scalarizeReceiver) { + default List getScalarizedMethodSignature(boolean scalarizeReceiver) { throw new UnsupportedOperationException("scalarized parameters not yet implemented"); } From ac22767e8ff726d993282f6f493e3993cad565a8 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 17:52:36 +0200 Subject: [PATCH 24/27] Refactoring of method attachement. --- .../aarch64/jvmciCodeInstaller_aarch64.cpp | 3 -- .../cpu/x86/jvmciCodeInstaller_x86.cpp | 39 +++++++------------ 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp b/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp index 6905458e278..071dd2c4179 100644 --- a/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp @@ -133,7 +133,6 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& metho case INVOKEINTERFACE: { assert(!method->is_static(), "cannot call static method with invokeinterface"); call = nativeCall_at(_instructions->start() + pc_offset); - // TODO: attach method for valhalla calling convention see jvmciCodeInstaller_x86.cpp _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc)); call->trampoline_jump(cbuf, SharedRuntime::get_resolve_virtual_call_stub(), JVMCI_CHECK); break; @@ -141,7 +140,6 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& metho case INVOKESTATIC: { assert(method->is_static(), "cannot call non-static method with invokestatic"); call = nativeCall_at(_instructions->start() + pc_offset); - // TODO: attach method for valhalla calling convention see jvmciCodeInstaller_x86.cpp _instructions->relocate(call->instruction_address(), relocInfo::static_call_type); call->trampoline_jump(cbuf, SharedRuntime::get_resolve_static_call_stub(), JVMCI_CHECK); break; @@ -149,7 +147,6 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, methodHandle& metho case INVOKESPECIAL: { assert(!method->is_static(), "cannot call static method with invokespecial"); call = nativeCall_at(_instructions->start() + pc_offset); - // TODO: attach method for valhalla calling convention see jvmciCodeInstaller_x86.cpp _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type); call->trampoline_jump(cbuf, SharedRuntime::get_resolve_opt_virtual_call_stub(), JVMCI_CHECK); break; diff --git a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp index 6af9229b71a..a08f55b7196 100644 --- a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp +++ b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp @@ -154,6 +154,14 @@ void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong forei } void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, jint pc_offset, JVMCI_TRAPS) { + // attach the target method only for scalarized args to avoid a null check on the receiver if receiver was optimized from non-scalarized to scalarized + // attach only for scalarized args otherwise assert(attached_method->has_scalarized_args(), "invalid use of attached method"); will trigger + // see resolved_method_index in machnode.hpp + // TODO integrate https://github.com/graalvm/labs-openjdk/commit/c3da3483f3a04a0e77db4420fac48ac2d9155c47 instead of this logic. + int method_index = 0; + if ((method->has_scalarized_args() && !method->mismatch()) || method() == Universe::is_substitutable_method()) { + method_index = _oop_recorder->find_index(method()); + } NativeCall* call = nullptr; switch (_next_call_type) { case INLINE_INVOKE: @@ -164,15 +172,9 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, j call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_virtual_call_stub()); - if (method->has_scalarized_args() && !method->mismatch()) { _instructions->relocate(call->instruction_address(), - virtual_call_Relocation::spec(_invoke_mark_pc, _oop_recorder->find_index(method())), + virtual_call_Relocation::spec(_invoke_mark_pc, method_index), Assembler::call32_operand); - } else { - _instructions->relocate(call->instruction_address(), - virtual_call_Relocation::spec(_invoke_mark_pc), - Assembler::call32_operand); - } break; } case INVOKESTATIC: { @@ -180,14 +182,8 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, j call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_static_call_stub()); - // calls to the ValueObjectMethods class do not exist in bytecode, need to attach them - if (method->has_scalarized_args() || method() == Universe::is_substitutable_method() || method() == Universe::value_object_hash_code_method()) { - _instructions->relocate(call->instruction_address(), - relocInfo::static_call_type, Assembler::call32_operand,_oop_recorder->find_index(method())); - }else{ - _instructions->relocate(call->instruction_address(), - relocInfo::static_call_type, Assembler::call32_operand); - } + _instructions->relocate(call->instruction_address(), + relocInfo::static_call_type, Assembler::call32_operand, method_index); break; } @@ -195,17 +191,8 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, j assert(!method->is_static(), "cannot call static method with invokespecial"); call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); - - // attach the target method only for scalarized args to avoid a null check on the receiver if receiver was optimized from non-scalarized to scalarized - // attach only for scalarized args otherwise assert(attached_method->has_scalarized_args(), "invalid use of attached method"); will trigger - // see resolved_method_index in machnode.hpp - if (method->has_scalarized_args() && !method->mismatch()) { - _instructions->relocate(call->instruction_address(), - relocInfo::opt_virtual_call_type, Assembler::call32_operand, _oop_recorder->find_index(method())); - } else { - _instructions->relocate(call->instruction_address(), - relocInfo::opt_virtual_call_type, Assembler::call32_operand); - } + _instructions->relocate(call->instruction_address(), + relocInfo::opt_virtual_call_type, Assembler::call32_operand, method_index); break; } default: From 09b550dc5bbe5f5c2e4c9269ee9a9af4cd5b54c2 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 18:07:27 +0200 Subject: [PATCH 25/27] Refactoring. --- .../jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index bf670291a28..f78d0bdc3eb 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -838,7 +838,8 @@ public boolean hasScalarizedReturn() { if (!returnsValueObject()) { result = false; } else { - result = compilerToVM().hasScalarizedReturn(this, getReturnedValueClass()); + HotSpotResolvedObjectTypeImpl returnType = (HotSpotResolvedObjectTypeImpl) signature.getReturnType(getDeclaringClass()); + result = compilerToVM().hasScalarizedReturn(this, returnType); } return result; } @@ -895,10 +896,6 @@ private boolean returnsValueObject() { return false; } - private HotSpotResolvedObjectTypeImpl getReturnedValueClass() { - return (HotSpotResolvedObjectTypeImpl) signature.getReturnType(getDeclaringClass()); - } - @Override public List getScalarizedParameterNullRestricted(int index, boolean indexIncludesReceiverIfExists) { return getScalarizedParameter(index, indexIncludesReceiverIfExists, true); From d89de3b86edf368465f12366bd5d3545f48f63e3 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 18:17:27 +0200 Subject: [PATCH 26/27] Correct wrong method name. --- .../jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java | 8 ++++---- .../jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java | 6 +++--- .../jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index 91a6e26bc3c..1b26560bac8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -81,12 +81,12 @@ public HotSpotResolvedObjectType getNullRestrictedNonAtomicArrayClass() { } return nullRestrictedNonAtomicArrayOfType; } - - public abstract boolean isElementFlat(); - public abstract boolean isElementAtomic(); + public abstract boolean isComponentFlat(); - public abstract boolean isElementNullRestricted(); + public abstract boolean isComponentAtomic(); + + public abstract boolean isComponentNullRestricted(); /** * Checks whether this type is currently being initialized. If a type is being initialized it diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 398aa501709..6ae5b3729ca 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -550,14 +550,14 @@ public int getLog2ComponentSize() { } @Override - public boolean isElementFlat() { + public boolean isComponentFlat() { HotSpotVMConfig config = config(); assert isArray(); assert getKlassPointer() != 0 : getName(); return UNSAFE.getInt(getKlassPointer() + config.klassKind) == config.klassFlatArray; } - public boolean isElementAtomic() { + public boolean isComponentAtomic() { HotSpotVMConfig config = config(); assert getKlassPointer() != 0 : getName(); assert isArray(); @@ -566,7 +566,7 @@ public boolean isElementAtomic() { } @Override - public boolean isElementNullRestricted() { + public boolean isComponentNullRestricted() { HotSpotVMConfig config = config(); assert getKlassPointer() != 0 : getName(); assert isArray(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index 64feceb5f27..47329b9d7f9 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -97,18 +97,18 @@ protected HotSpotResolvedObjectType getArrayType(boolean atomic, boolean nullRes return runtime().compilerToVm.getArrayType(getJavaKind().getTypeChar(), null, false, false, false); } - public boolean isElementFlat() { + public boolean isComponentFlat() { assert isArray(); return false; } - public boolean isElementAtomic() { + public boolean isComponentAtomic() { assert isArray(); return true; } @Override - public boolean isElementNullRestricted() { + public boolean isComponentNullRestricted() { assert isArray(); return true; } From 8093a98cf75700eb13c379eadd9936d093755258 Mon Sep 17 00:00:00 2001 From: MichaelHaas99 Date: Fri, 17 Oct 2025 21:59:15 +0200 Subject: [PATCH 27/27] Refactoring. --- .../ci/hotspot/HotSpotResolvedJavaType.java | 6 ------ .../HotSpotResolvedObjectTypeImpl.java | 1 + .../jdk/vm/ci/meta/ResolvedJavaType.java | 21 +++++++++++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index 1b26560bac8..734d55a97d2 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -82,12 +82,6 @@ public HotSpotResolvedObjectType getNullRestrictedNonAtomicArrayClass() { return nullRestrictedNonAtomicArrayOfType; } - public abstract boolean isComponentFlat(); - - public abstract boolean isComponentAtomic(); - - public abstract boolean isComponentNullRestricted(); - /** * Checks whether this type is currently being initialized. If a type is being initialized it * implies that it was {@link #isLinked() linked} and that the static initializer is currently diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 6ae5b3729ca..69dca6d117a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -557,6 +557,7 @@ public boolean isComponentFlat() { return UNSAFE.getInt(getKlassPointer() + config.klassKind) == config.klassFlatArray; } + @Override public boolean isComponentAtomic() { HotSpotVMConfig config = config(); assert getKlassPointer() != 0 : getName(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index 03d5848f4be..459775ca4b3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -455,4 +455,25 @@ default int payloadOffset() { default int nullMarkerOffset() { throw new UnsupportedOperationException(); } + + /** + * Determines whether the components of this array type are stored in a flat layout. + */ + default boolean isComponentFlat() { + throw new UnsupportedOperationException(); + } + + /** + * Determines whether memory operations on components of this array type need to be accessed atomically. + */ + default boolean isComponentAtomic() { + throw new UnsupportedOperationException(); + } + + /** + * Determines whether this array type allows null to be stored as component. + */ + default boolean isComponentNullRestricted() { + throw new UnsupportedOperationException(); + } }