--- old/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp 2019-07-02 16:16:30.000000000 +0200 +++ new/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp 2019-07-02 16:16:25.000000000 +0200 @@ -416,9 +416,17 @@ // handle return types different from T_INT __ BIND(is_value); if (ValueTypeReturnedAsFields) { - // Handle value type returned as fields - __ store_value_type_fields_to_buf(NULL); - __ movptr(r13, result); + // Check for flattened return value + __ testptr(rax, 1); + __ jcc(Assembler::zero, is_long); + // Initialize pre-allocated buffer + __ mov(rbx, rax); + __ andptr(rbx, -2); + __ movptr(rbx, Address(rbx, InstanceKlass::adr_valueklass_fixed_block_offset())); + __ movptr(rbx, Address(rbx, ValueKlass::pack_handler_offset())); + __ movptr(rax, Address(r13, 0)); + __ call(rbx); + __ jmp(exit); } __ BIND(is_long); __ movq(Address(r13, 0), rax); --- old/src/hotspot/share/oops/method.cpp 2019-07-02 16:16:35.000000000 +0200 +++ new/src/hotspot/share/oops/method.cpp 2019-07-02 16:16:30.000000000 +0200 @@ -505,7 +505,6 @@ return rtf.type(); } -#ifdef ASSERT // ValueKlass the method is declared to return. This must not // safepoint as it is called with references live on the stack at // locations the GC is unaware of. @@ -524,7 +523,6 @@ assert(k != NULL && !thread->has_pending_exception(), "can't resolve klass"); return ValueKlass::cast(k); } -#endif bool Method::is_empty_method() const { return code_size() == 1 --- old/src/hotspot/share/oops/method.hpp 2019-07-02 16:16:40.000000000 +0200 +++ new/src/hotspot/share/oops/method.hpp 2019-07-02 16:16:35.000000000 +0200 @@ -614,9 +614,7 @@ Symbol* klass_name() const; // returns the name of the method holder BasicType result_type() const; // type of the method result bool may_return_oop() const { BasicType r = result_type(); return (r == T_OBJECT || r == T_ARRAY || r == T_VALUETYPE); } -#ifdef ASSERT ValueKlass* returned_value_type(Thread* thread) const; -#endif // Checked exceptions thrown by this method (resolved to mirrors) objArrayHandle resolved_checked_exceptions(TRAPS) { return resolved_checked_exceptions_impl(this, THREAD); } --- old/src/hotspot/share/runtime/javaCalls.cpp 2019-07-02 16:16:45.000000000 +0200 +++ new/src/hotspot/share/runtime/javaCalls.cpp 2019-07-02 16:16:41.000000000 +0200 @@ -411,7 +411,7 @@ BasicType result_type = runtime_type_from(result); bool oop_result_flag = (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY || result->get_type() == T_VALUETYPE); - + // NOTE: if we move the computation of the result_val_address inside // the call to call_stub, the optimizer produces wrong code. intptr_t* result_val_address = (intptr_t*)(result->get_value_addr()); @@ -449,11 +449,23 @@ } #endif + Handle vt; + if (ValueTypeReturnedAsFields && result->get_type() == T_VALUETYPE) { + // Pre allocate buffered value in case the result is returned + // flattened by compiled code + ValueKlass* vk = method->returned_value_type(thread); + vt = vk->allocate_instance_handle(CHECK); + } + // do call { JavaCallWrapper link(method, receiver, result, CHECK); { HandleMark hm(thread); // HandleMark used by HandleMarkCleaner - StubRoutines::call_stub()( + if (vt() != NULL) { + result->set_jobject((jobject)vt()); + } + + StubRoutines::call_stub()( (address)&link, // (intptr_t*)&(result->_value), // see NOTE above (compiler problem) result_val_address, // see NOTE above (compiler problem) --- old/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java 2019-07-02 16:16:50.000000000 +0200 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java 2019-07-02 16:16:45.000000000 +0200 @@ -590,8 +590,6 @@ String result = test28(); } -// TODO enable once JDK-8224110 and JDK-8224211 are fixed -/* // Test calling a method returning a value type as fields via reflection MyValue3 test29_vt = MyValue3.create(); @@ -616,7 +614,7 @@ @DontCompile public void test30_verifier(boolean warmup) throws Exception { MyValue3[] array = new MyValue3[1]; - MyValue3 vt = (MyValue3)TestCallingConvention.class.getDeclaredMethod("test30", MyValue3[].class).invoke(this, array); + MyValue3 vt = (MyValue3)TestCallingConvention.class.getDeclaredMethod("test30", MyValue3[].class).invoke(this, (Object)array); array[0].verify(vt); } @@ -634,7 +632,6 @@ MyValue3 vt = (MyValue3)TestCallingConvention.class.getDeclaredMethod("test31").invoke(this); test31_vt.verify(vt); } -*/ // Test deoptimization at call return with return value in registers. Same as test14, except the interpreted method // is called via a MethodHandle.