--- old/make/data/jdwp/jdwp.spec 2019-10-04 10:49:48.000000000 -0400 +++ new/make/data/jdwp/jdwp.spec 2019-10-04 10:49:48.000000000 -0400 @@ -3252,6 +3252,7 @@ (Constant BYTE = 'B' "'B' - a byte value (1 byte).") (Constant CHAR = 'C' "'C' - a character value (2 bytes).") (Constant OBJECT = 'L' "'L' - an object (objectID size).") + (Constant INLINE_OBJECT = 'Q' "'Q' - an inline object (objectID size).") (Constant FLOAT = 'F' "'F' - a float value (4 bytes).") (Constant DOUBLE = 'D' "'D' - a double value (8 bytes).") (Constant INT = 'I' "'I' - an int value (4 bytes).") --- old/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp 2019-10-04 10:49:50.000000000 -0400 +++ new/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp 2019-10-04 10:49:50.000000000 -0400 @@ -29,6 +29,7 @@ #include "memory/resourceArea.hpp" #include "prims/jniFastGetField.hpp" #include "prims/jvm_misc.hpp" +#include "runtime/jfieldIDWorkaround.hpp" #include "runtime/safepoint.hpp" #define __ masm-> @@ -83,7 +84,7 @@ } __ mov (roffset, c_rarg2); - __ shrptr(roffset, 2); // offset + __ shrptr(roffset, jfieldIDWorkaround::offset_shift); // offset // Both robj and rtmp are clobbered by try_resolve_jobject_in_native. BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); @@ -185,7 +186,7 @@ DEBUG_ONLY(__ movl(rtmp, 0xDEADC0DE);) __ mov (roffset, c_rarg2); - __ shrptr(roffset, 2); // offset + __ shrptr(roffset, jfieldIDWorkaround::offset_shift); // offset assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); --- old/src/hotspot/share/interpreter/interpreterRuntime.cpp 2019-10-04 10:49:53.000000000 -0400 +++ new/src/hotspot/share/interpreter/interpreterRuntime.cpp 2019-10-04 10:49:52.000000000 -0400 @@ -1482,6 +1482,7 @@ if ((ik->field_access_flags(index) & JVM_ACC_FIELD_ACCESS_WATCHED) == 0) return; bool is_static = (obj == NULL); + bool is_flattened = cp_entry->is_flattened(); HandleMark hm(thread); Handle h_obj; @@ -1490,7 +1491,7 @@ h_obj = Handle(thread, obj); } InstanceKlass* cp_entry_f1 = InstanceKlass::cast(cp_entry->f1_as_klass()); - jfieldID fid = jfieldIDWorkaround::to_jfieldID(cp_entry_f1, cp_entry->f2_as_index(), is_static); + jfieldID fid = jfieldIDWorkaround::to_jfieldID(cp_entry_f1, cp_entry->f2_as_index(), is_static, is_flattened); LastFrameAccessor last_frame(thread); JvmtiExport::post_field_access(thread, last_frame.method(), last_frame.bcp(), cp_entry_f1, h_obj, fid); JRT_END @@ -1527,9 +1528,10 @@ } bool is_static = (obj == NULL); + bool is_flattened = cp_entry->is_flattened(); HandleMark hm(thread); - jfieldID fid = jfieldIDWorkaround::to_jfieldID(ik, cp_entry->f2_as_index(), is_static); + jfieldID fid = jfieldIDWorkaround::to_jfieldID(ik, cp_entry->f2_as_index(), is_static, is_flattened); jvalue fvalue; #ifdef _LP64 fvalue = *value; --- old/src/hotspot/share/prims/jni.cpp 2019-10-04 10:49:55.000000000 -0400 +++ new/src/hotspot/share/prims/jni.cpp 2019-10-04 10:49:55.000000000 -0400 @@ -58,6 +58,7 @@ #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "oops/valueArrayOop.inline.hpp" #include "oops/valueKlass.inline.hpp" #include "prims/jniCheck.hpp" #include "prims/jniExport.hpp" @@ -497,8 +498,9 @@ // The jfieldID is the offset of the field within the object // It may also have hash bits for k, if VerifyJNIFields is turned on. intptr_t offset = InstanceKlass::cast(k1)->field_offset( slot ); + bool is_flattened = InstanceKlass::cast(k1)->field_is_flattened(slot); assert(InstanceKlass::cast(k1)->contains_field_offset(offset), "stay within object"); - ret = jfieldIDWorkaround::to_instance_jfieldID(k1, offset); + ret = jfieldIDWorkaround::to_instance_jfieldID(k1, offset, is_flattened); return ret; JNI_END @@ -2050,7 +2052,7 @@ // A jfieldID for a non-static field is simply the offset of the field within the instanceOop // It may also have hash bits for k, if VerifyJNIFields is turned on. - ret = jfieldIDWorkaround::to_instance_jfieldID(k, fd.offset()); + ret = jfieldIDWorkaround::to_instance_jfieldID(k, fd.offset(), fd.is_flattened()); return ret; JNI_END @@ -2061,13 +2063,34 @@ oop o = JNIHandles::resolve_non_null(obj); Klass* k = o->klass(); int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID); + oop res = NULL; // Keep JVMTI addition small and only check enabled flag here. // jni_GetField_probe() assumes that is okay to create handles. if (JvmtiExport::should_post_field_access()) { o = JvmtiExport::jni_GetField_probe(thread, obj, o, k, fieldID, false); } - oop loaded_obj = HeapAccess::oop_load_at(o, offset); - jobject ret = JNIHandles::make_local(env, loaded_obj); + if (!jfieldIDWorkaround::is_flattened_field(fieldID)) { + res = HeapAccess::oop_load_at(o, offset); + } else { + assert(k->is_instance_klass(), "Only instance can have flattened fields"); + InstanceKlass* ik = InstanceKlass::cast(k); + fieldDescriptor fd; + ik->find_field_from_offset(offset, false, &fd); + InstanceKlass* holder = fd.field_holder(); + ValueKlass* field_vklass = ValueKlass::cast(holder->get_value_field_klass(fd.index())); + assert(field_vklass->is_initialized(), "Must be initialized at this point"); + + Handle obj_h(THREAD, o); + if (field_vklass->is_empty_value()) { + res = (instanceOop)field_vklass->default_value(); + } else { + // allocate instance + res = field_vklass->allocate_instance(CHECK_NULL); + // copy value + field_vklass->value_copy_payload_to_new_oop(((char*)(oopDesc*)obj_h()) + ik->field_offset(fd.index()), res); + } + } + jobject ret = JNIHandles::make_local(env, res); HOTSPOT_JNI_GETOBJECTFIELD_RETURN(ret); return ret; JNI_END @@ -2165,7 +2188,18 @@ field_value.l = value; o = JvmtiExport::jni_SetField_probe_nh(thread, obj, o, k, fieldID, false, 'L', (jvalue *)&field_value); } - HeapAccess::oop_store_at(o, offset, JNIHandles::resolve(value)); + if (!jfieldIDWorkaround::is_flattened_field(fieldID)) { + HeapAccess::oop_store_at(o, offset, JNIHandles::resolve(value)); + } else { + assert(k->is_instance_klass(), "Only instances can have flattened fields"); + InstanceKlass* ik = InstanceKlass::cast(k); + fieldDescriptor fd; + ik->find_field_from_offset(offset, false, &fd); + InstanceKlass* holder = fd.field_holder(); + ValueKlass* vklass = ValueKlass::cast(holder->get_value_field_klass(fd.index())); + oop v = JNIHandles::resolve_non_null(value); + vklass->value_copy_oop_to_payload(v, ((char*)(oopDesc*)o) + offset); + } HOTSPOT_JNI_SETOBJECTFIELD_RETURN(); JNI_END @@ -2602,16 +2636,28 @@ HOTSPOT_JNI_GETOBJECTARRAYELEMENT_ENTRY(env, array, index); jobject ret = NULL; DT_RETURN_MARK(GetObjectArrayElement, jobject, (const jobject&)ret); - objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); - if (a->is_within_bounds(index)) { - ret = JNIHandles::make_local(env, a->obj_at(index)); - return ret; + oop res = NULL; + arrayOop arr((arrayOop)JNIHandles::resolve_non_null(array)); + if (arr->is_within_bounds(index)) { + if (arr->is_valueArray()) { + valueArrayOop a = valueArrayOop(JNIHandles::resolve_non_null(array)); + arrayHandle ah(THREAD, a); + valueArrayHandle vah(thread, a); + res = valueArrayOopDesc::value_alloc_copy_from_index(vah, index, CHECK_NULL); + assert(res != NULL, "Must be set in one of two paths above"); + } else { + assert(arr->is_objArray(), "If not a valueArray. must be an objArray"); + objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); + res = a->obj_at(index); + } } else { ResourceMark rm(THREAD); stringStream ss; - ss.print("Index %d out of bounds for length %d", index, a->length()); + ss.print("Index %d out of bounds for length %d", index,arr->length()); THROW_MSG_0(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); } + ret = JNIHandles::make_local(env, res); + return ret; JNI_END DT_VOID_RETURN_MARK_DECL(SetObjectArrayElement @@ -2619,33 +2665,60 @@ JNI_ENTRY(void, jni_SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value)) JNIWrapper("SetObjectArrayElement"); - HOTSPOT_JNI_SETOBJECTARRAYELEMENT_ENTRY(env, array, index, value); + HOTSPOT_JNI_SETOBJECTARRAYELEMENT_ENTRY(env, array, index, value); DT_VOID_RETURN_MARK(SetObjectArrayElement); - objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); - oop v = JNIHandles::resolve(value); - if (a->is_within_bounds(index)) { - if (v == NULL || v->is_a(ObjArrayKlass::cast(a->klass())->element_klass())) { - a->obj_at_put(index, v); - } else { - ResourceMark rm(THREAD); - stringStream ss; - Klass *bottom_kl = ObjArrayKlass::cast(a->klass())->bottom_klass(); - ss.print("type mismatch: can not store %s to %s[%d]", - v->klass()->external_name(), - bottom_kl->is_typeArray_klass() ? type2name_tab[ArrayKlass::cast(bottom_kl)->element_type()] : bottom_kl->external_name(), - index); - for (int dims = ArrayKlass::cast(a->klass())->dimension(); dims > 1; --dims) { - ss.print("[]"); - } - THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); - } - } else { - ResourceMark rm(THREAD); - stringStream ss; - ss.print("Index %d out of bounds for length %d", index, a->length()); - THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); - } + bool oob = false; + int length = -1; + oop res = NULL; + arrayOop arr((arrayOop)JNIHandles::resolve_non_null(array)); + if (arr->is_within_bounds(index)) { + if (arr->is_valueArray()) { + valueArrayOop a = valueArrayOop(JNIHandles::resolve_non_null(array)); + oop v = JNIHandles::resolve(value); + ValueArrayKlass* vaklass = ValueArrayKlass::cast(a->klass()); + ValueKlass* element_vklass = vaklass->element_klass(); + if (v != NULL && v->is_a(element_vklass)) { + a->value_copy_to_index(v, index); + } else { + ResourceMark rm(THREAD); + stringStream ss; + Klass *kl = ValueArrayKlass::cast(a->klass()); + ss.print("type mismatch: can not store %s to %s[%d]", + v->klass()->external_name(), + kl->external_name(), + index); + for (int dims = ArrayKlass::cast(a->klass())->dimension(); dims > 1; --dims) { + ss.print("[]"); + } + THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); + } + } else { + assert(arr->is_objArray(), "If not a valueArray. must be an objArray"); + objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); + oop v = JNIHandles::resolve(value); + if (v == NULL || v->is_a(ObjArrayKlass::cast(a->klass())->element_klass())) { + a->obj_at_put(index, v); + } else { + ResourceMark rm(THREAD); + stringStream ss; + Klass *bottom_kl = ObjArrayKlass::cast(a->klass())->bottom_klass(); + ss.print("type mismatch: can not store %s to %s[%d]", + v->klass()->external_name(), + bottom_kl->is_typeArray_klass() ? type2name_tab[ArrayKlass::cast(bottom_kl)->element_type()] : bottom_kl->external_name(), + index); + for (int dims = ArrayKlass::cast(a->klass())->dimension(); dims > 1; --dims) { + ss.print("[]"); + } + THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); + } + } + } else { + ResourceMark rm(THREAD); + stringStream ss; + ss.print("Index %d out of bounds for length %d", index, arr->length()); + THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); + } JNI_END --- old/src/hotspot/share/prims/jvmtiEnv.cpp 2019-10-04 10:49:58.000000000 -0400 +++ new/src/hotspot/share/prims/jvmtiEnv.cpp 2019-10-04 10:49:57.000000000 -0400 @@ -2583,7 +2583,8 @@ for (FilteredFieldStream src_st(ik, true, true); !src_st.eos(); src_st.next()) { result_list[id_index--] = jfieldIDWorkaround::to_jfieldID( ik, src_st.offset(), - src_st.access_flags().is_static()); + src_st.access_flags().is_static(), + src_st.field_descriptor().is_flattened()); } assert(id_index == -1, "just checking"); // Fill in the results --- old/src/hotspot/share/prims/jvmtiImpl.cpp 2019-10-04 10:50:00.000000000 -0400 +++ new/src/hotspot/share/prims/jvmtiImpl.cpp 2019-10-04 10:49:59.000000000 -0400 @@ -588,7 +588,7 @@ assert(klass != NULL, "klass must not be NULL"); int len = (int) strlen(ty_sign); - if (ty_sign[0] == 'L' && ty_sign[len-1] == ';') { // Need pure class/interface name + if ((ty_sign[0] == 'L' || ty_sign[0] == 'Q') && ty_sign[len-1] == ';') { // Need pure class/interface name ty_sign++; len -= 2; } @@ -771,7 +771,7 @@ // since the handle will be long gone by the time the deopt // happens. The oop stored in the deferred local will be // gc'd on its own. - if (_type == T_OBJECT) { + if (_type == T_OBJECT || _type == T_VALUETYPE) { _value.l = (jobject) (JNIHandles::resolve_external_guard(_value.l)); } // Re-read the vframe so we can see that it is deoptimized @@ -788,7 +788,8 @@ case T_LONG: locals->set_long_at (_index, _value.j); break; case T_FLOAT: locals->set_float_at (_index, _value.f); break; case T_DOUBLE: locals->set_double_at(_index, _value.d); break; - case T_OBJECT: { + case T_OBJECT: + case T_VALUETYPE: { Handle ob_h(Thread::current(), JNIHandles::resolve_external_guard(_value.l)); locals->set_obj_at (_index, ob_h); break; @@ -809,7 +810,8 @@ case T_LONG: _value.j = locals->long_at (_index); break; case T_FLOAT: _value.f = locals->float_at (_index); break; case T_DOUBLE: _value.d = locals->double_at(_index); break; - case T_OBJECT: { + case T_OBJECT: + case T_VALUETYPE: { // Wrap the oop to be returned in a local JNI handle since // oops_do() no longer applies after doit() is finished. oop obj = locals->obj_at(_index)(); --- old/src/hotspot/share/runtime/jfieldIDWorkaround.hpp 2019-10-04 10:50:02.000000000 -0400 +++ new/src/hotspot/share/runtime/jfieldIDWorkaround.hpp 2019-10-04 10:50:01.000000000 -0400 @@ -46,11 +46,15 @@ // not checked, then the checked bit is zero and the rest of // the word (30 bits) contains only the offset. // + + friend class JNI_FastGetField; + private: enum { checked_bits = 1, instance_bits = 1, - address_bits = BitsPerWord - checked_bits - instance_bits, + flattened_bits = 1, + address_bits = BitsPerWord - checked_bits - instance_bits - flattened_bits, large_offset_bits = address_bits, // unioned with address small_offset_bits = 7, @@ -58,13 +62,15 @@ checked_shift = 0, instance_shift = checked_shift + checked_bits, - address_shift = instance_shift + instance_bits, + flattened_shift = instance_shift + instance_bits, + address_shift = flattened_shift + flattened_bits, offset_shift = address_shift, // unioned with address klass_shift = offset_shift + small_offset_bits, checked_mask_in_place = right_n_bits(checked_bits) << checked_shift, instance_mask_in_place = right_n_bits(instance_bits) << instance_shift, + flattened_mask_in_place = right_n_bits(flattened_bits) << flattened_shift, #ifndef _WIN64 large_offset_mask = right_n_bits(large_offset_bits), small_offset_mask = right_n_bits(small_offset_bits), @@ -107,8 +113,15 @@ return ((as_uint & instance_mask_in_place) == 0); } - static jfieldID to_instance_jfieldID(Klass* k, int offset) { - intptr_t as_uint = ((offset & large_offset_mask) << offset_shift) | instance_mask_in_place; + static bool is_flattened_field(jfieldID id) { + uintptr_t as_uint = (uintptr_t) id; + return ((as_uint & flattened_mask_in_place) != 0); + } + + static jfieldID to_instance_jfieldID(Klass* k, int offset, bool flattened) { + intptr_t as_uint = ((offset & large_offset_mask) << offset_shift) | + (flattened ? flattened_mask_in_place : 0) | + instance_mask_in_place; if (VerifyJNIFields) { as_uint |= encode_klass_hash(k, offset); } @@ -150,13 +163,13 @@ return result; } - static jfieldID to_jfieldID(InstanceKlass* k, int offset, bool is_static) { + static jfieldID to_jfieldID(InstanceKlass* k, int offset, bool is_static, bool is_flattened) { if (is_static) { JNIid *id = k->jni_id_for(offset); debug_only(id->set_is_static_field_id()); return jfieldIDWorkaround::to_static_jfieldID(id); } else { - return jfieldIDWorkaround::to_instance_jfieldID(k, offset); + return jfieldIDWorkaround::to_instance_jfieldID(k, offset, is_flattened); } } }; --- old/src/hotspot/share/runtime/vframe_hp.cpp 2019-10-04 10:50:04.000000000 -0400 +++ new/src/hotspot/share/runtime/vframe_hp.cpp 2019-10-04 10:50:03.000000000 -0400 @@ -388,6 +388,7 @@ locals->set_long_at(index, value.j); break; case T_OBJECT: + case T_VALUETYPE: { Handle obj(Thread::current(), (oop)value.l); locals->set_obj_at(index, obj); --- old/src/jdk.jdi/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java 2019-10-04 10:50:06.000000000 -0400 +++ new/src/jdk.jdi/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java 2019-10-04 10:50:05.000000000 -0400 @@ -94,7 +94,7 @@ if (PacketStream.isObjectTag(tag)) { // It's a reference type JNITypeParser parser = new JNITypeParser(componentSignature()); - List list = vm.classesByName(parser.typeName()); + List list = vm.classesBySignature(componentSignature()); Iterator iter = list.iterator(); while (iter.hasNext()) { ReferenceType type = iter.next(); --- old/src/jdk.jdi/share/classes/com/sun/tools/jdi/JNITypeParser.java 2019-10-04 10:50:08.000000000 -0400 +++ new/src/jdk.jdi/share/classes/com/sun/tools/jdi/JNITypeParser.java 2019-10-04 10:50:08.000000000 -0400 @@ -156,6 +156,7 @@ return key + nextSignature(); case (JDWP.Tag.OBJECT): + case (JDWP.Tag.INLINE_OBJECT): int endClass = signature.indexOf(SIGNATURE_ENDCLASS, currentIndex); String retVal = signature.substring(currentIndex - 1, @@ -199,6 +200,7 @@ return "char"; case (JDWP.Tag.OBJECT): + case (JDWP.Tag.INLINE_OBJECT): int endClass = signature.indexOf(SIGNATURE_ENDCLASS, currentIndex); String retVal = signature.substring(currentIndex, --- old/src/jdk.jdi/share/classes/com/sun/tools/jdi/PacketStream.java 2019-10-04 10:50:10.000000000 -0400 +++ new/src/jdk.jdi/share/classes/com/sun/tools/jdi/PacketStream.java 2019-10-04 10:50:09.000000000 -0400 @@ -650,6 +650,7 @@ static boolean isObjectTag(byte tag) { return (tag == JDWP.Tag.OBJECT) || + (tag == JDWP.Tag.INLINE_OBJECT) || (tag == JDWP.Tag.ARRAY) || (tag == JDWP.Tag.STRING) || (tag == JDWP.Tag.THREAD) || --- old/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java 2019-10-04 10:50:12.000000000 -0400 +++ new/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java 2019-10-04 10:50:12.000000000 -0400 @@ -315,6 +315,17 @@ return Collections.unmodifiableList(modules); } + List classesBySignature(String signature) { + validateVM(); + List list; + if (retrievedAllTypes) { + list = findReferenceTypes(signature); + } else { + list = retrieveClassesBySignature(signature); + } + return Collections.unmodifiableList(list); + } + public List classesByName(String className) { validateVM(); String signature = JNITypeParser.typeNameToSignature(className); @@ -1394,6 +1405,7 @@ if (object == null) { switch (tag) { case JDWP.Tag.OBJECT: + case JDWP.Tag.INLINE_OBJECT: object = new ObjectReferenceImpl(vm, id); break; case JDWP.Tag.STRING: --- old/src/jdk.jdwp.agent/share/native/libjdwp/ArrayReferenceImpl.c 2019-10-04 10:50:14.000000000 -0400 +++ new/src/jdk.jdwp.agent/share/native/libjdwp/ArrayReferenceImpl.c 2019-10-04 10:50:13.000000000 -0400 @@ -524,6 +524,7 @@ switch (componentSignature[0]) { case JDWP_TAG(OBJECT): case JDWP_TAG(ARRAY): + case JDWP_TAG(INLINE_OBJECT): serror = readObjectComponents(env, in, array, index, length); break; --- old/src/jdk.jdwp.agent/share/native/libjdwp/ArrayTypeImpl.c 2019-10-04 10:50:16.000000000 -0400 +++ new/src/jdk.jdwp.agent/share/native/libjdwp/ArrayTypeImpl.c 2019-10-04 10:50:16.000000000 -0400 @@ -230,7 +230,8 @@ componentSignature = &signature[1]; if ((componentSignature[0] == JDWP_TAG(OBJECT)) || - (componentSignature[0] == JDWP_TAG(ARRAY))) { + (componentSignature[0] == JDWP_TAG(ARRAY)) || + (componentSignature[0] == JDWP_TAG(INLINE_OBJECT))) { writeNewObjectArray(env, out, arrayClass, size, componentSignature); } else { writeNewPrimitiveArray(env, out, arrayClass, size, componentSignature); --- old/src/jdk.jdwp.agent/share/native/libjdwp/ClassTypeImpl.c 2019-10-04 10:50:19.000000000 -0400 +++ new/src/jdk.jdwp.agent/share/native/libjdwp/ClassTypeImpl.c 2019-10-04 10:50:18.000000000 -0400 @@ -63,6 +63,7 @@ switch (signature[0]) { case JDWP_TAG(ARRAY): case JDWP_TAG(OBJECT): + case JDWP_TAG(INLINE_OBJECT): value.l = inStream_readObjectRef(env, in); JNI_FUNC_PTR(env,SetStaticObjectField)(env, clazz, field, value.l); break; --- old/src/jdk.jdwp.agent/share/native/libjdwp/ObjectReferenceImpl.c 2019-10-04 10:50:21.000000000 -0400 +++ new/src/jdk.jdwp.agent/share/native/libjdwp/ObjectReferenceImpl.c 2019-10-04 10:50:20.000000000 -0400 @@ -76,6 +76,7 @@ switch (signature[0]) { case JDWP_TAG(ARRAY): case JDWP_TAG(OBJECT): + case JDWP_TAG(INLINE_OBJECT): value.l = inStream_readObjectRef(env, in); JNI_FUNC_PTR(env,SetObjectField)(env, object, field, value.l); break; --- old/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c 2019-10-04 10:50:23.000000000 -0400 +++ new/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c 2019-10-04 10:50:22.000000000 -0400 @@ -851,7 +851,7 @@ saveGlobalRef(env, clazz, pclazz); } sig = evinfo->u.field_modification.signature_type; - if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) { + if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT)) || (sig == JDWP_TAG(INLINE_OBJECT))) { if ( evinfo->u.field_modification.new_value.l != NULL ) { pobject = &(evinfo->u.field_modification.new_value.l); object = *pobject; @@ -904,7 +904,7 @@ tossGlobalRef(env, &(evinfo->u.field_modification.field_clazz)); } sig = evinfo->u.field_modification.signature_type; - if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) { + if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT)) || (sig == JDWP_TAG(INLINE_OBJECT))) { if ( evinfo->u.field_modification.new_value.l != NULL ) { tossGlobalRef(env, &(evinfo->u.field_modification.new_value.l)); } --- old/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c 2019-10-04 10:50:25.000000000 -0400 +++ new/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c 2019-10-04 10:50:24.000000000 -0400 @@ -146,7 +146,8 @@ break; } if ((argumentTag == JDWP_TAG(OBJECT)) || - (argumentTag == JDWP_TAG(ARRAY))) { + (argumentTag == JDWP_TAG(ARRAY)) || + (argumentTag == JDWP_TAG(INLINE_OBJECT))) { /* Create a global ref for any non-null argument */ if (argument->l != NULL) { saveGlobalRef(env, argument->l, &argRefs[argIndex]); @@ -179,7 +180,8 @@ argument = request->arguments; while ( argIndex < request->argumentCount ) { if ((argumentTag == JDWP_TAG(OBJECT)) || - (argumentTag == JDWP_TAG(ARRAY))) { + (argumentTag == JDWP_TAG(ARRAY)) || + (argumentTag == JDWP_TAG(INLINE_OBJECT))) { argument->l = argRefs[argIndex]; } argument++; @@ -232,7 +234,8 @@ /* Delete global argument references */ while (argIndex < request->argumentCount) { if ((argumentTag == JDWP_TAG(OBJECT)) || - (argumentTag == JDWP_TAG(ARRAY))) { + (argumentTag == JDWP_TAG(ARRAY)) || + (argumentTag == JDWP_TAG(INLINE_OBJECT))) { if (argument->l != NULL) { tossGlobalRef(env, &(argument->l)); } @@ -406,7 +409,8 @@ { switch(returnTypeTag(request->methodSignature)) { case JDWP_TAG(OBJECT): - case JDWP_TAG(ARRAY): { + case JDWP_TAG(ARRAY): + case JDWP_TAG(INLINE_OBJECT): { jobject object; JDI_ASSERT_MSG(request->clazz, "Request clazz null"); object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env, @@ -495,7 +499,8 @@ { switch(returnTypeTag(request->methodSignature)) { case JDWP_TAG(OBJECT): - case JDWP_TAG(ARRAY): { + case JDWP_TAG(ARRAY): + case JDWP_TAG(INLINE_OBJECT): { jobject object; JDI_ASSERT_MSG(request->instance, "Request instance null"); object = JNI_FUNC_PTR(env,CallObjectMethodA)(env, @@ -583,7 +588,8 @@ { switch(returnTypeTag(request->methodSignature)) { case JDWP_TAG(OBJECT): - case JDWP_TAG(ARRAY): { + case JDWP_TAG(ARRAY): + case JDWP_TAG(INLINE_OBJECT): { jobject object; JDI_ASSERT_MSG(request->clazz, "Request clazz null"); JDI_ASSERT_MSG(request->instance, "Request instance null"); @@ -807,7 +813,8 @@ * until after the return packet was sent. */ mustReleaseReturnValue = request->invokeType == INVOKE_CONSTRUCTOR || returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT) || - returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY); + returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY) || + returnTypeTag(request->methodSignature) == JDWP_TAG(INLINE_OBJECT); } /* --- old/src/jdk.jdwp.agent/share/native/libjdwp/outStream.c 2019-10-04 10:50:27.000000000 -0400 +++ new/src/jdk.jdwp.agent/share/native/libjdwp/outStream.c 2019-10-04 10:50:26.000000000 -0400 @@ -335,7 +335,7 @@ outStream_writeValue(JNIEnv *env, PacketOutputStream *out, jbyte typeKey, jvalue value) { - if (typeKey == JDWP_TAG(OBJECT)) { + if (typeKey == JDWP_TAG(OBJECT) || typeKey == JDWP_TAG(INLINE_OBJECT)) { (void)outStream_writeByte(out, specificTypeKey(env, value.l)); } else { (void)outStream_writeByte(out, typeKey); --- old/src/jdk.jdwp.agent/share/native/libjdwp/util.c 2019-10-04 10:50:29.000000000 -0400 +++ new/src/jdk.jdwp.agent/share/native/libjdwp/util.c 2019-10-04 10:50:29.000000000 -0400 @@ -292,6 +292,7 @@ jboolean isObjectTag(jbyte tag) { return (tag == JDWP_TAG(OBJECT)) || + (tag == JDWP_TAG(INLINE_OBJECT)) || (tag == JDWP_TAG(STRING)) || (tag == JDWP_TAG(THREAD)) || (tag == JDWP_TAG(THREAD_GROUP)) || @@ -350,13 +351,14 @@ * For primitive types, the type key is bounced back as is. Objects * are handled in the switch statement below. */ - if ((typeKey != JDWP_TAG(OBJECT)) && (typeKey != JDWP_TAG(ARRAY))) { + if ((typeKey != JDWP_TAG(OBJECT)) && (typeKey != JDWP_TAG(ARRAY)) && (typeKey != JDWP_TAG(INLINE_OBJECT))) { (void)outStream_writeByte(out, typeKey); } switch (typeKey) { case JDWP_TAG(OBJECT): - case JDWP_TAG(ARRAY): { + case JDWP_TAG(ARRAY): + case JDWP_TAG(INLINE_OBJECT): { jobject value = JNI_FUNC_PTR(env,GetObjectField)(env, object, field); (void)outStream_writeByte(out, specificTypeKey(env, value)); (void)outStream_writeObjectRef(env, out, value); @@ -425,13 +427,14 @@ * For primitive types, the type key is bounced back as is. Objects * are handled in the switch statement below. */ - if ((typeKey != JDWP_TAG(OBJECT)) && (typeKey != JDWP_TAG(ARRAY))) { + if ((typeKey != JDWP_TAG(OBJECT)) && (typeKey != JDWP_TAG(ARRAY)) && (typeKey != JDWP_TAG(INLINE_OBJECT))) { (void)outStream_writeByte(out, typeKey); } switch (typeKey) { case JDWP_TAG(OBJECT): - case JDWP_TAG(ARRAY): { + case JDWP_TAG(ARRAY): + case JDWP_TAG(INLINE_OBJECT): { jobject value = JNI_FUNC_PTR(env,GetStaticObjectField)(env, clazz, field); (void)outStream_writeByte(out, specificTypeKey(env, value)); (void)outStream_writeObjectRef(env, out, value);