changeset 57417:a4b4f60e7812 lworld

8232108: [lworld] Reflective method invocation with scalarized return is not GC safe Reviewed-by: roland
author thartmann
date Fri, 11 Oct 2019 14:14:53 +0200
parents 85f25a764824
children d982735091b9
files src/hotspot/cpu/x86/stubGenerator_x86_64.cpp src/hotspot/share/runtime/init.cpp src/hotspot/share/runtime/javaCalls.cpp test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java
diffstat 4 files changed, 37 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp	Fri Oct 11 14:13:17 2019 +0200
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp	Fri Oct 11 14:14:53 2019 +0200
@@ -419,12 +419,17 @@
       // 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()));
+      // Load pack handler address
+      __ andptr(rax, -2);
+      __ movptr(rax, Address(rax, InstanceKlass::adr_valueklass_fixed_block_offset()));
+      __ movptr(rbx, Address(rax, ValueKlass::pack_handler_offset()));
+      // Resolve pre-allocated buffer from JNI handle
       __ movptr(rax, Address(r13, 0));
+      __ resolve_jobject(rax /* value */,
+                         r15_thread /* thread */,
+                         r12 /* tmp */);
+      __ movptr(Address(r13, 0), rax);
+      // Call pack handler to initialize the buffer
       __ call(rbx);
       __ jmp(exit);
     }
--- a/src/hotspot/share/runtime/init.cpp	Fri Oct 11 14:13:17 2019 +0200
+++ b/src/hotspot/share/runtime/init.cpp	Fri Oct 11 14:14:53 2019 +0200
@@ -114,12 +114,11 @@
   codeCache_init();
   VM_Version_init();
   VMRegImpl::set_regName();  // need this before generate_stubs (for printing oop maps).
-  stubRoutines_init1();
-  jint status = universe_init();  // dependent on codeCache_init and
-                                  // stubRoutines_init1 and metaspace_init.
+  jint status = universe_init();  // dependent on codeCache_init and metaspace_init.
   if (status != JNI_OK)
     return status;
 
+  stubRoutines_init1();
   gc_barrier_stubs_init();   // depends on universe_init, must be before interpreter_init
   interpreter_init();        // before any methods loaded
   invocationCounter_init();  // before any methods loaded
--- a/src/hotspot/share/runtime/javaCalls.cpp	Fri Oct 11 14:13:17 2019 +0200
+++ b/src/hotspot/share/runtime/javaCalls.cpp	Fri Oct 11 14:14:53 2019 +0200
@@ -441,21 +441,22 @@
   }
 #endif
 
-  Handle vt;
+  jobject value_buffer = NULL;
   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);
+    if (vk->can_be_returned_as_fields()) {
+      oop instance = vk->allocate_instance(CHECK);
+      value_buffer = JNIHandles::make_local(thread, instance);
+      result->set_jobject(value_buffer);
+    }
   }
 
   // do call
   { JavaCallWrapper link(method, receiver, result, CHECK);
     { HandleMark hm(thread);  // HandleMark used by HandleMarkCleaner
 
-      if (vt() != NULL) {
-        result->set_jobject((jobject)vt());
-      }
       // 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());
@@ -489,6 +490,7 @@
   if (oop_result_flag) {
     result->set_jobject((jobject)thread->vm_result());
     thread->set_vm_result(NULL);
+    JNIHandles::destroy_local(value_buffer);
   }
 }
 
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java	Fri Oct 11 14:13:17 2019 +0200
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java	Fri Oct 11 14:14:53 2019 +0200
@@ -741,4 +741,22 @@
         long result = test35(vt, rI, rI, rI, rI);
         Asserts.assertEQ(result, vt.hash()+10004*rI);
     }
+
+    // Same as test31 but with GC in callee to verify that the
+    // pre-allocated buffer for the returned inline type remains valid.
+    MyValue3 test36_vt;
+
+    @Test
+    public MyValue3 test36() {
+        MyValue3 result = MyValue3.create();
+        test36_vt = result;
+        System.gc();
+        return result;
+    }
+
+    @DontCompile
+    public void test36_verifier(boolean warmup) throws Exception {
+        MyValue3 vt = (MyValue3)TestCallingConvention.class.getDeclaredMethod("test36").invoke(this);
+        test36_vt.verify(vt);
+    }
 }