--- old/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp 2019-07-16 20:29:24.362619838 -0700 +++ new/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp 2019-07-16 20:29:24.038608076 -0700 @@ -592,8 +592,8 @@ } -void LIR_Assembler::store_value_type_fields_to_buf(ciValueKlass* vk) { - __ store_value_type_fields_to_buf(vk); +int LIR_Assembler::store_value_type_fields_to_buf(ciValueKlass* vk) { + return (__ store_value_type_fields_to_buf(vk, false)); } int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { --- old/src/hotspot/cpu/x86/macroAssembler_x86.cpp 2019-07-16 20:29:25.106646845 -0700 +++ new/src/hotspot/cpu/x86/macroAssembler_x86.cpp 2019-07-16 20:29:24.782635084 -0700 @@ -5883,17 +5883,18 @@ BIND(L_end); } -void MacroAssembler::store_value_type_fields_to_buf(ciValueKlass* vk) { -#ifndef _LP64 - super_call_VM_leaf(StubRoutines::store_value_type_fields_to_buf()); -#else +int MacroAssembler::store_value_type_fields_to_buf(ciValueKlass* vk, bool from_interpreter) { // A value type might be returned. If fields are in registers we // need to allocate a value type instance and initialize it with // the value of the fields. - Label skip, slow_case; + Label skip; // We only need a new buffered value if a new one is not returned testptr(rax, 1); jcc(Assembler::zero, skip); + int call_offset = -1; + +#ifdef _LP64 + Label slow_case; // Try to allocate a new buffered value (from the heap) if (UseTLAB) { @@ -5947,9 +5948,17 @@ // call. Some oop field may be live in some registers but we can't // tell. That runtime call will take care of preserving them // across a GC if there's one. - super_call_VM_leaf(StubRoutines::store_value_type_fields_to_buf()); - bind(skip); #endif + + if (from_interpreter) { + super_call_VM_leaf(StubRoutines::store_value_type_fields_to_buf()); + } else { + call(RuntimeAddress(StubRoutines::store_value_type_fields_to_buf())); + call_offset = offset(); + } + + bind(skip); + return call_offset; } --- old/src/hotspot/cpu/x86/macroAssembler_x86.hpp 2019-07-16 20:29:25.926676611 -0700 +++ new/src/hotspot/cpu/x86/macroAssembler_x86.hpp 2019-07-16 20:29:25.590664414 -0700 @@ -1654,7 +1654,7 @@ reg_written }; - void store_value_type_fields_to_buf(ciValueKlass* vk); + int store_value_type_fields_to_buf(ciValueKlass* vk, bool from_interpreter = true); // Unpack all value type arguments passed as oops void unpack_value_args(Compile* C, bool receiver_only); --- old/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp 2019-07-16 20:29:26.654703038 -0700 +++ new/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp 2019-07-16 20:29:26.330691276 -0700 @@ -5928,11 +5928,7 @@ // make sure all code is generated masm->flush(); - // The caller may not know the register mapping of the fields of the returned value - // object, so it won't generate a valid oopmap for the call site. Hence, we can't - // do InterfaceSupport::verify_stack(). - RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, false, - /*can_verify_stack =*/false); + RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, false); return stub->entry_point(); } --- old/src/hotspot/share/c1/c1_LIR.cpp 2019-07-16 20:29:27.414730626 -0700 +++ new/src/hotspot/share/c1/c1_LIR.cpp 2019-07-16 20:29:27.086718720 -0700 @@ -1062,13 +1062,16 @@ masm->emit_call(this); } -bool LIR_OpJavaCall::maybe_return_as_fields() const { +bool LIR_OpJavaCall::maybe_return_as_fields(ciValueKlass** vk_ret) const { if (ValueTypeReturnedAsFields) { if (method()->signature()->returns_never_null()) { ciType* return_type = method()->return_type(); if (return_type->is_valuetype()) { ciValueKlass* vk = return_type->as_value_klass(); if (vk->can_be_returned_as_fields()) { + if (vk_ret != NULL) { + *vk_ret = vk; + } return true; } } @@ -1076,7 +1079,15 @@ BasicType bt = method()->return_type()->basic_type(); if (bt == T_OBJECT || bt == T_VALUETYPE) { // A value type might be returned from the call but we don't know its + // type. Either we get a buffered value (and nothing needs to be done) + // or one of the values being returned is the klass of the value type + // (RAX on x64, with LSB set to 1) and we need to allocate a value + // type instance of that type and initialize it with other values being + // returned (in other registers). // type. + if (vk_ret != NULL) { + *vk_ret = NULL; + } return true; } } --- old/src/hotspot/share/c1/c1_LIR.hpp 2019-07-16 20:29:28.138756908 -0700 +++ new/src/hotspot/share/c1/c1_LIR.hpp 2019-07-16 20:29:27.818745291 -0700 @@ -1233,7 +1233,7 @@ virtual LIR_OpJavaCall* as_OpJavaCall() { return this; } virtual void print_instr(outputStream* out) const PRODUCT_RETURN; - bool maybe_return_as_fields() const; + bool maybe_return_as_fields(ciValueKlass** vk = NULL) const; }; // -------------------------------------------------- --- old/src/hotspot/share/c1/c1_LIRAssembler.cpp 2019-07-16 20:29:28.866783334 -0700 +++ new/src/hotspot/share/c1/c1_LIRAssembler.cpp 2019-07-16 20:29:28.546771718 -0700 @@ -485,28 +485,10 @@ compilation()->set_has_method_handle_invokes(true); } - if (ValueTypeReturnedAsFields) { - ciMethod* method = op->method(); - if (method->signature()->returns_never_null()) { - ciType* return_type = method->return_type(); - if (return_type->is_valuetype()) { - ciValueKlass* vk = return_type->as_value_klass(); - if (vk->can_be_returned_as_fields()) { - store_value_type_fields_to_buf(vk); - } - } - } else if (op->is_method_handle_invoke()) { - BasicType bt = method->return_type()->basic_type(); - if (bt == T_OBJECT || bt == T_VALUETYPE) { - // A value type might be returned from the call but we don't know its - // type. Either we get a buffered value (and nothing needs to be done) - // or one of the values being returned is the klass of the value type - // (RAX on x64, with LSB set to 1) and we need to allocate a value - // type instance of that type and initialize it with other values being - // returned (in other registers). - store_value_type_fields_to_buf(NULL); - } - } + ciValueKlass* vk; + if (op->maybe_return_as_fields(&vk)) { + int offset = store_value_type_fields_to_buf(vk); + add_call_info(offset, op->info(), true); } #if defined(X86) && defined(TIERED) --- old/src/hotspot/share/c1/c1_LIRAssembler.hpp 2019-07-16 20:29:29.582809325 -0700 +++ new/src/hotspot/share/c1/c1_LIRAssembler.hpp 2019-07-16 20:29:29.258797563 -0700 @@ -242,7 +242,7 @@ void call( LIR_OpJavaCall* op, relocInfo::relocType rtype); void ic_call( LIR_OpJavaCall* op); void vtable_call( LIR_OpJavaCall* op); - void store_value_type_fields_to_buf(ciValueKlass* vk); + int store_value_type_fields_to_buf(ciValueKlass* vk); void osr_entry(); --- old/src/hotspot/share/code/codeBlob.cpp 2019-07-16 20:29:30.294835171 -0700 +++ new/src/hotspot/share/code/codeBlob.cpp 2019-07-16 20:29:29.966823264 -0700 @@ -389,11 +389,9 @@ int frame_complete, int frame_size, OopMapSet* oop_maps, - bool caller_must_gc_arguments, - bool can_verify_stack + bool caller_must_gc_arguments ) : RuntimeBlob(name, cb, sizeof(RuntimeStub), size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments) -, _can_verify_stack(can_verify_stack) { } @@ -402,15 +400,14 @@ int frame_complete, int frame_size, OopMapSet* oop_maps, - bool caller_must_gc_arguments, - bool can_verify_stack) + bool caller_must_gc_arguments) { RuntimeStub* stub = NULL; ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); unsigned int size = CodeBlob::allocation_size(cb, sizeof(RuntimeStub)); - stub = new (size) RuntimeStub(stub_name, cb, size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments, can_verify_stack); + stub = new (size) RuntimeStub(stub_name, cb, size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments); } trace_new_stub(stub, "RuntimeStub - ", stub_name); --- old/src/hotspot/share/code/codeBlob.hpp 2019-07-16 20:29:31.030861887 -0700 +++ new/src/hotspot/share/code/codeBlob.hpp 2019-07-16 20:29:30.694849691 -0700 @@ -144,8 +144,6 @@ virtual bool is_compiled() const { return false; } virtual bool is_buffered_value_type_blob() const { return false; } - virtual bool can_verify_stack() const { return false; } - inline bool is_compiled_by_c1() const { return _type == compiler_c1; }; inline bool is_compiled_by_c2() const { return _type == compiler_c2; }; inline bool is_compiled_by_jvmci() const { return _type == compiler_jvmci; }; @@ -508,10 +506,6 @@ class RuntimeStub: public RuntimeBlob { friend class VMStructs; private: - // All RuntimeStub can support InterfaceSupport::verify_stack(), except for - // the stub for SharedRuntime::store_value_type_fields_to_buf. - bool _can_verify_stack; - // Creation support RuntimeStub( const char* name, @@ -520,8 +514,7 @@ int frame_complete, int frame_size, OopMapSet* oop_maps, - bool caller_must_gc_arguments, - bool can_verify_stack + bool caller_must_gc_arguments ); // This ordinary operator delete is needed even though not used, so the @@ -538,13 +531,11 @@ int frame_complete, int frame_size, OopMapSet* oop_maps, - bool caller_must_gc_arguments, - bool can_verify_stack = true + bool caller_must_gc_arguments ); // Typing bool is_runtime_stub() const { return true; } - bool can_verify_stack() const { return _can_verify_stack; } address entry_point() const { return code_begin(); } @@ -710,8 +701,6 @@ // Typing bool is_uncommon_trap_stub() const { return true; } - bool can_verify_stack() const { return true; } - }; --- old/src/hotspot/share/runtime/interfaceSupport.cpp 2019-07-16 20:29:31.754888168 -0700 +++ new/src/hotspot/share/runtime/interfaceSupport.cpp 2019-07-16 20:29:31.430876408 -0700 @@ -264,7 +264,7 @@ // In case of exceptions we might not have a runtime_stub on // top of stack, hence, all callee-saved registers are not going // to be setup correctly, hence, we cannot do stack verify - if (cb != NULL && !cb->can_verify_stack()) return; + if (cb != NULL && !(cb->is_runtime_stub() || cb->is_uncommon_trap_stub())) return; for (; !sfs.is_done(); sfs.next()) { sfs.current()->verify(sfs.register_map()); --- old/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java 2019-07-16 20:29:32.482914596 -0700 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java 2019-07-16 20:29:32.158902834 -0700 @@ -2052,4 +2052,68 @@ Asserts.assertEQ(result, n); } } + + // C1->C2 force GC for every allocation when storing the returned + // fields back into a buffered object. + @Test(compLevel = C1) + public RefPoint test101(RefPoint rp) { + return test101_helper(rp); + } + + @ForceCompile(compLevel = C2) @DontInline + public RefPoint test101_helper(RefPoint rp) { + return rp; + } + + @DontCompile + public void test101_verifier(boolean warmup) { + int count = warmup ? 1 : 5; + for (int i=0; iC2 instead. + @Test(compLevel = C1) + public RefPoint test102(RefPoint rp) { + return test102_interp(rp); + } + + @DontCompile @DontInline + public RefPoint test102_interp(RefPoint rp) { + return test102_helper(rp); + } + + @ForceCompile(compLevel = C2) @DontInline + public RefPoint test102_helper(RefPoint rp) { + return rp; + } + + @DontCompile + public void test102_verifier(boolean warmup) { + int count = warmup ? 1 : 5; + for (int i=0; i