diff --git a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp index 9e6a4789dc2..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: @@ -165,7 +173,7 @@ 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()); _instructions->relocate(call->instruction_address(), - virtual_call_Relocation::spec(_invoke_mark_pc), + virtual_call_Relocation::spec(_invoke_mark_pc, method_index), Assembler::call32_operand); break; } @@ -175,7 +183,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()); _instructions->relocate(call->instruction_address(), - relocInfo::static_call_type, Assembler::call32_operand); + relocInfo::static_call_type, Assembler::call32_operand, method_index); + break; } case INVOKESPECIAL: { @@ -183,7 +192,7 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, methodHandle& method, j call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); _instructions->relocate(call->instruction_address(), - relocInfo::opt_virtual_call_type, Assembler::call32_operand); + relocInfo::opt_virtual_call_type, Assembler::call32_operand, method_index); 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..f0ba4197e26 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,34 @@ 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_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"); + 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); + 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 @@ -1141,6 +1177,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(); + 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 +1230,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 +1376,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..d93a76d2a38 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,84 @@ 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(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(); @@ -429,6 +509,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 +601,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* k = (Klass*) (temp & TypeEntries::type_klass_mask); if (k == nullptr || k->class_loader_data() == nullptr || !TrainingData::is_klass_loaded(k)) { return nullptr; } @@ -662,7 +759,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) { @@ -675,7 +772,19 @@ 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); + 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); + } + if (!atomic) { + props = (ArrayKlass::ArrayProperties)(props | ArrayKlass::ArrayProperties::NON_ATOMIC); + } + ArrayKlass* ak = klass->array_klass(THREAD); + array_klass = ObjArrayKlass::cast(ak)->klass_with_properties(props, THREAD); + } } JVMCIObject result = JVMCIENV->get_jvmci_type(array_klass, JVMCI_CHECK_NULL); return JVMCIENV->get_jobject(result); @@ -2285,7 +2394,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 +2430,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 +2513,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 +2533,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 +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 "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)}, @@ -3342,7 +3468,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 "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)}, @@ -3371,6 +3497,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 +3544,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..767806d38e6 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -1625,7 +1625,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 +1738,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..978119add3a 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp @@ -179,7 +179,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..4d40ff88996 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,15 @@ JRT_LEAF(jboolean, JVMCIRuntime::object_notify(JavaThread* current, oopDesc* obj JRT_END +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_flat_array(JavaThread* current, flatArrayOopDesc* array, jint index, oopDesc* value)) + array->obj_at_put(index, value, 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 +465,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 +877,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..b12e1d5d9af 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_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); 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..ddcc4a326c1 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -278,12 +278,19 @@ 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(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) \ @@ -306,6 +313,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 +523,15 @@ \ 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_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,10 @@ 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(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) \ @@ -823,6 +843,8 @@ 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_null_free_shift) \ + declare_constant(Klass::_lh_null_free_mask) \ \ declare_constant(markWord::no_hash) \ \ @@ -874,6 +896,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 +916,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 +956,14 @@ declare_function(JVMCIRuntime::exception_handler_for_pc) \ declare_function(JVMCIRuntime::monitorenter) \ declare_function(JVMCIRuntime::monitorexit) \ + 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) \ 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/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/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..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 @@ -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 value objects being passed scalarized. + * + * @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.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/code/RegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java index 0cc1980b28f..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 @@ -24,10 +24,7 @@ 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.*; /** * A register configuration binds roles and {@linkplain RegisterAttributes attributes} to physical @@ -63,6 +60,17 @@ default int getMaximumFrameSize() { */ CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory valueKindFactory); + /** + * 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. + */ + 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..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 @@ -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 valueClass) { + return hasScalarizedReturn(method, method.getMethodPointer(), valueClass, valueClass.getMetaspacePointer()); + } + + private native boolean hasScalarizedReturn(HotSpotResolvedJavaMethodImpl method, long methodPointer, HotSpotResolvedObjectTypeImpl returnType, long valueClassPointer); + + /** + * 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 value object of a certain type can be passed scalarized as an argument. + * + * @return true if a value object of this 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); } @@ -1104,12 +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); + native HotSpotResolvedObjectTypeImpl getArrayType(char typeChar, HotSpotResolvedObjectTypeImpl klass, long klassPointer, boolean atomic, boolean nullRestricted, boolean vmType); /** * Forces initialization of {@code klass}. @@ -1210,11 +1286,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) @@ -1555,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/DirectHotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java index c241af0348a..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 @@ -69,4 +69,9 @@ public JavaConstant uncompress() { public int getIdentityHashCode() { return System.identityHashCode(object); } + + @Override + public boolean isValueObject() { + 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..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 @@ -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 leftValueClassFlag = 1 << config.leftValueClassFlag; + final int rightValueClassFlag = 1 << config.rightValueClassFlag; + 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,171 @@ 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 valueClass; + + 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.valueClass = (flags & getValueClassFlag()) != 0; + } + + abstract int getOperandOffset(); + + abstract int getValueClassFlag(); + + 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 valueClass() { + return valueClass; + } + + + } + + static class LeftSingleTypeEntryImpl extends SingleTypeEntryImpl { + + LeftSingleTypeEntryImpl(ACmpData aCmpData,HotSpotMethodData data, int position) { + super(aCmpData, data, position); + } + + @Override + int getOperandOffset(){ + return getState().leftOperandOffset; + } + + @Override + int getValueClassFlag() { + return getState().leftValueClassFlag; + } + } + + static class RightSingleTypeEntryImpl extends SingleTypeEntryImpl { + + RightSingleTypeEntryImpl(ACmpData aCmpData, HotSpotMethodData data, int position) { + super(aCmpData, data, position); + } + + @Override + int getOperandOffset(){ + return getState().rightOperandOffset; + } + + @Override + int getValueClassFlag() { + return getState().rightValueClassFlag; + } + } + + 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..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 @@ -114,4 +114,8 @@ default Assumptions.AssumptionResult getCallSiteTarget() { @Override String toValueString(); + + default boolean isValueObject() { + 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..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 @@ -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(); @@ -198,7 +208,7 @@ public JavaConstant readFieldValue(HotSpotResolvedJavaField field) { } HotSpotResolvedObjectTypeImpl declaringClass = (HotSpotResolvedObjectTypeImpl) field.getDeclaringClass(); 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.getHolderClass()); } 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..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 @@ -32,29 +32,27 @@ 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; -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. */ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { - private final HotSpotResolvedObjectTypeImpl holder; + private final HotSpotResolvedObjectTypeImpl declaringClass; + + private final HotSpotResolvedObjectTypeImpl holderClass; + 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()}. @@ -71,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; @@ -80,6 +79,36 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { this.index = index; } + /** + * 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.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; + this.internalFlags = subField.internalFlags; + this.index = subField.index; + } + + /** + * Constructor for a null marker + */ + HotSpotResolvedJavaFieldImpl(HotSpotResolvedJavaFieldImpl declaredField) { + 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()); + this.classfileFlags = -1; + this.internalFlags = -1; + this.index = -1; + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -89,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)) { + } else if (this.declaringClass.equals(that.declaringClass) && this.holderClass.equals(that.holderClass)) { return true; } } @@ -98,7 +127,7 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return holder.hashCode() ^ offset; + return declaringClass.hashCode() ^ offset; } @Override @@ -111,6 +140,16 @@ public boolean isInternal() { return (internalFlags & (1 << config().jvmFieldFlagInternalShift)) != 0; } + @Override + public boolean isNullRestricted() { + return (internalFlags & (1 << config().jvmFieldFlagNullRestrictedValueClassShift)) != 0; + } + + @Override + public boolean isFlat() { + return (internalFlags & (1 << config().jvmFieldFlagFlatShift)) != 0; + } + /** * Determines if a given object contains this field. * @@ -128,12 +167,17 @@ public boolean isInObject(JavaConstant object) { @Override public HotSpotResolvedObjectTypeImpl getDeclaringClass() { - return holder; + return declaringClass; + } + + @Override + public HotSpotResolvedObjectTypeImpl getHolderClass() { + return holderClass; } @Override public String getName() { - return holder.getFieldInfo(index).getName(holder); + return declaringClass.getFieldInfo(index).getName(declaringClass); } @Override @@ -144,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(), holder, false); + JavaType resolved = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedType.getName(), declaringClass, false); if (resolved instanceof ResolvedJavaType) { type = resolved; } @@ -193,7 +237,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(declaringClass.getKlassPointer() + config.instanceKlassAnnotationsOffset); if (metaspaceAnnotations != 0) { long fieldsAnnotations = UNSAFE.getAddress(metaspaceAnnotations + config.annotationsFieldAnnotationsOffset); if (fieldsAnnotations != 0) { @@ -231,7 +275,7 @@ public T getAnnotation(Class annotationClass) { @Override public JavaConstant getConstantValue() { - return holder.getFieldInfo(index).getConstantValue(holder); + return declaringClass.getFieldInfo(index).getConstantValue(declaringClass); } @Override @@ -255,7 +299,7 @@ public List getAnnotationData(ResolvedJavaType type1, ResolvedJa } private List getAnnotationData0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationData(holder, 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/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 224e8b1a070..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 @@ -38,29 +38,14 @@ 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 +795,204 @@ public BitSet getOopMapAt(int bci) { compilerToVM().getOopMapAt(this, bci, oopMap); return BitSet.valueOf(oopMap); } + + private boolean[] scalarizedParametersInfo; + private TriState hasScalarizedParameters = TriState.UNKNOWN; + private TriState hasScalarizedReceiver = TriState.UNKNOWN; + + @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 isParameterNullRestricted(int index, boolean indexIncludesReceiverIfExists) { + // 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; + } + + @Override + public boolean hasScalarizedParameters() { + // see ciMethod::has_scalarized_args + if (hasScalarizedParameters.isUnknown()) { + hasScalarizedParameters = TriState.get(compilerToVM().hasScalarizedParameters(this)); + } + return hasScalarizedParameters.toBoolean(); + } + + @Override + public boolean hasScalarizedReturn() { + boolean result; + if (!returnsValueObject()) { + result = false; + } else { + HotSpotResolvedObjectTypeImpl returnType = (HotSpotResolvedObjectTypeImpl) signature.getReturnType(getDeclaringClass()); + result = compilerToVM().hasScalarizedReturn(this, returnType); + } + return result; + } + + @Override + public boolean hasScalarizedReceiver() { + 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.isUnknown()) { + hasCallingConventionMismatch = TriState.get(compilerToVM().hasCallingConventionMismatch(this)); + } + return hasCallingConventionMismatch.toBoolean(); + } + + @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 tagged 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 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 return value is a value object + return !type.isInterface() && !type.isAbstract() && !type.isIdentity(); + } + return false; + } + + @Override + public List getScalarizedParameterNullRestricted(int index, boolean indexIncludesReceiverIfExists) { + return getScalarizedParameter(index, indexIncludesReceiverIfExists, true); + } + + @Override + public List getScalarizedParameter(int index, boolean indexIncludesReceiverIfExists) { + return getScalarizedParameter(index, indexIncludesReceiverIfExists, isParameterNullRestricted(index, indexIncludesReceiverIfExists)); + } + + 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 nullRestricted : "receiver should be null-free"; + return getFields(getDeclaringClass(), true, null); + } else { + // signature index starts without the receiver, so substract one + index--; + } + } + JavaType type = signature.getParameterType(index, getDeclaringClass()); + assert type instanceof HotSpotResolvedObjectType : "HotSpotResolvedObjectType expected"; + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + return getFields((HotSpotResolvedObjectTypeImpl) resolvedType, nullRestricted, nullRestricted ? 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) && !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 getScalarizedMethodSignature(boolean scalarizeReceiver) { + 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()); + + if (isScalarizedParameter(i, false)) { + assert type instanceof HotSpotResolvedObjectType : "HotSpotResolvedObjectType expected"; + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + boolean nullRestricted = isParameterNullRestricted(i, false); + types.addAll(getFields((HotSpotResolvedObjectTypeImpl) resolvedType, nullRestricted, nullRestricted ? null : getScalarizedParameterNonNullType(i, false))); + } else { + types.add(type); + } + } + + return List.copyOf(types); + } + + + private List getFields(HotSpotResolvedObjectTypeImpl holder, boolean nullRestricted, JavaType nonNullType) { + ResolvedJavaField[] fields = holder.getInstanceFields(true); + List types = new ArrayList<>(fields.length + (!nullRestricted ? 1 : 0)); + if (!nullRestricted) { + 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..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 @@ -31,6 +31,8 @@ public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { HotSpotResolvedObjectType arrayOfType; + HotSpotResolvedObjectType nullRestrictedAtomicArrayOfType; + HotSpotResolvedObjectType nullRestrictedNonAtomicArrayOfType; protected HotSpotResolvedJavaType(String name) { super(name); @@ -51,17 +53,35 @@ 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(); + protected abstract HotSpotResolvedObjectType getArrayType(boolean atomic, boolean nullRestricted, boolean vmType); @Override public HotSpotResolvedObjectType getArrayClass() { if (arrayOfType == null) { - arrayOfType = getArrayType(); + 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 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..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 @@ -75,6 +75,11 @@ default JavaKind getJavaKind() { */ int instanceSize(); + /** + * Gets the component size in an array + */ + int getLog2ComponentSize(); + int getVtableLength(); @Override @@ -114,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 46e53411dee..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 @@ -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 @@ -76,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; @@ -103,7 +88,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 +449,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 +537,44 @@ 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 isComponentFlat() { + HotSpotVMConfig config = config(); + assert isArray(); + assert getKlassPointer() != 0 : getName(); + return UNSAFE.getInt(getKlassPointer() + config.klassKind) == config.klassFlatArray; + } + + @Override + public boolean isComponentAtomic() { + 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 isComponentNullRestricted() { + 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(); @@ -601,6 +632,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; @@ -677,10 +716,11 @@ public JavaConstant getJavaMirror() { } @Override - protected HotSpotResolvedObjectTypeImpl getArrayType() { - return runtime().compilerToVm.getArrayType((char) 0, this); + protected HotSpotResolvedObjectTypeImpl getArrayType(boolean atomic, boolean nullRestricted, boolean vmType) { + return runtime().compilerToVm.getArrayType((char) 0, this, atomic, nullRestricted, vmType); } + /** * 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. @@ -697,11 +737,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) { @@ -740,6 +780,7 @@ public int getOffset() { /** * 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) { @@ -749,6 +790,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) { @@ -784,28 +826,37 @@ public boolean isStatic() { @Override public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { if (instanceFields == null) { - if (isArray() || isInterface()) { - instanceFields = NO_FIELDS; - } else { - HotSpotResolvedJavaField[] prepend = NO_FIELDS; - if (getSuperclass() != null) { - prepend = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); - } - instanceFields = getFields(false, prepend); - } + computeFields(); } + return getFields(instanceFields, includeSuperclasses, false); + } + + public ResolvedJavaField[] getDeclaredInstanceFields(boolean includeSuperclasses) { + if (declaredInstanceFields == null) { + computeFields(); + } + 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; } @@ -815,60 +866,114 @@ public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { // 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) { + computeFields(); } + return staticFields; } - /** - * 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 computeFields() { + + HotSpotResolvedJavaField[] declaredPrepend; + HotSpotResolvedJavaField[] prepend; + + if (isArray() || isInterface()) { + if (isArray()) { + staticFields = NO_FIELDS; + } + 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 staticResultCount = 0; int index = 0; + for (index = 0; index < getFieldInfo().length; index++) { - if (getFieldInfo(index).isStatic() == retrieveStaticFields) { + if (!getFieldInfo(index).isStatic()) { resultCount++; + } else { + staticResultCount++; } } if (resultCount == 0) { - return prepend; + declaredInstanceFields = declaredPrepend; + instanceFields = prepend; + } + + if (staticResultCount == 0) { + staticFields = NO_FIELDS; + } + + if (resultCount == 0 || staticResultCount == 0) { + return; } + // 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; + declaredResultCount += declaredPrependLength; + resultCount = 0; resultCount += prependLength; - 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; - for (int i = 0; i < getFieldInfo().length; ++i) { - FieldInfo field = getFieldInfo(i); - if (field.isStatic() == retrieveStaticFields) { - int offset = field.getOffset(); - HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(this), offset, field.getClassfileFlags(), field.getInternalFlags(), i); - result[resultIndex++] = resolvedJavaField; + for (index = 0; index < getFieldInfo().length; index++) { + 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); + tempDeclaredFields.add(resolvedJavaField); + declaredResultCount++; + + if (resolvedJavaField.isFlat()) { + JavaType fieldType = resolvedJavaField.getType(); + + 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) { + tempDeclaredFields.add(createField(resolvedJavaField, (HotSpotResolvedJavaField) innerFields[i])); + } + if (!resolvedJavaField.isNullRestricted()) { + tempDeclaredFields.add(createField(resolvedJavaField)); + resultCount++; + } + } + } else { + resultCount++; + tempDeclaredFields.add(resolvedJavaField); } } - return 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 @@ -988,6 +1093,20 @@ 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 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(); @@ -1141,4 +1260,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(); + } } 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..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 @@ -90,11 +90,27 @@ 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); + return runtime().compilerToVm.getArrayType(getJavaKind().getTypeChar(), null, false, false, false); + } + + public boolean isComponentFlat() { + assert isArray(); + return false; + } + + public boolean isComponentAtomic() { + assert isArray(); + return true; + } + + @Override + public boolean isComponentNullRestricted() { + assert isArray(); + return true; } @Override @@ -223,6 +239,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/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index d463ace9181..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 @@ -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; @@ -72,12 +71,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 +94,14 @@ 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 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*"); @@ -119,6 +130,9 @@ 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 jvmFieldFlagNullRestrictedValueClassShift = getConstant("FieldInfo::FieldFlags::_ff_null_free_inline_type", 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 +142,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 +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 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 2b8f717840e..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,6 +50,8 @@ final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl final IndirectHotSpotObjectConstantImpl base; + private final boolean isValueObject; + private static class Audit { final Object scope; final long handle; @@ -71,11 +72,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 isValueObject) { super(compressed); assert objectHandle != 0 && UnsafeAccess.UNSAFE.getLong(objectHandle) != 0; this.objectHandle = objectHandle; this.base = null; + this.isValueObject = isValueObject; if (!skipRegister) { HotSpotObjectConstantScope scope = HotSpotObjectConstantScope.CURRENT.get(); if (scope != null && !scope.isGlobal()) { @@ -102,6 +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.isValueObject = base.isValueObject; } long getHandle() { @@ -182,7 +185,15 @@ public int getIdentityHashCode() { checkHandle(); int hash = hashCode; if (hash == 0) { - hash = runtime().compilerToVm.getIdentityHashCode(this); + 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. + // 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 +201,9 @@ public int getIdentityHashCode() { } return hash; } + + @Override + 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 d7e8fd37ab2..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 @@ -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.isValueObject() && indirectY.isValueObject()) { + // reference comparison of oops falsified, doesn't mean that the two value 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..90e185ecd09 --- /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 a value class, false otherwise + */ + boolean valueClass(); + +} 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 3849ac779c4..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 @@ -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; @@ -307,6 +311,47 @@ public Register getReturnRegister(JavaKind kind) { } } + @Override + public List getReturnConvention(List returnTypes, ValueKindFactory valueKindFactory, boolean includeFirstGeneralRegister) { + AllocatableValue[] locations = new AllocatableValue[returnTypes.size()]; + List generalReturnRegisters = javaGeneralReturnRegisters; + List xmmReturnRegisters = javaXMMParameterRegisters; + + int currentGeneral = includeFirstGeneralRegister ? 0 : 1; + int currentXMM = 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 currentXMM < xmmReturnRegisters.size() : "return values can only be stored in registers"; + register = xmmReturnRegisters.get(currentXMM++); + 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 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..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 @@ -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 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.valueClass(), 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..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,12 +50,33 @@ 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. */ 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 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(); + } + /** * Determines if this field is a synthetic field as defined by the Java Language Specification. */ @@ -68,6 +89,38 @@ default boolean isFinal() { @Override ResolvedJavaType getDeclaringClass(); + /** + * 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 getHolderClass() { + 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..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 @@ -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,152 @@ 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. + * 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 + * @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 isParameterNullRestricted(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. + * + * @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 getScalarizedMethodSignature(boolean scalarizeReceiver) { + throw new UnsupportedOperationException("scalarized parameters not yet implemented"); + } + + /** + * 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 + * @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 getScalarizedParameterNullRestricted(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 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 + * @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..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 @@ -305,6 +305,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 @@ -425,4 +427,53 @@ 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(); + } + + /** + * 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(); + } + + /** + * 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(); + } }