Hi,

Testing found a bug in the original webrev. Namely, when clearing out a pending 
exception and returning null in the JVMCI ..._or_null stubs, the 
JavaThread::_vm_result field was not being set to NULL. I've addressed this in 
v2 of the webrev:

Relative diff for bug fix:

-----------------------------------------------------------------------------------------------
-// Manages a scope in which a failed heap allocation will throw an exception.
-// The pending exception is cleared when leaving the scope.
+// Manages a scope for a JVMCI runtime call that attempts a heap allocation.
+// If there is a pending exception upon closing the scope and the runtime
+// call is of the variety where allocation failure returns NULL without an
+// exception, the following action is taken:
+//   1. The pending exception is cleared
+//   2. NULL is written to JavaThread::_vm_result
+//   3. Checks that an OutOfMemoryError is 
Universe::out_of_memory_error_retry().
 class RetryableAllocationMark: public StackObj {
  private:
   JavaThread* _thread;
  public:
   RetryableAllocationMark(JavaThread* thread, bool activate) {
     if (activate) {
-      assert(thread->in_retryable_allocation(), "retryable allocation scope is 
non-reentrant");
+      assert(!thread->in_retryable_allocation(), "retryable allocation scope 
is non-reentrant");
       _thread = thread;
       _thread->set_in_retryable_allocation(true);
     } else {
@@ -136,6 +141,7 @@
           ResourceMark rm;
           fatal("Unexpected exception in scope of retryable allocation: " 
INTPTR_FORMAT " of type %s", p2i(ex), ex->klass()->external_name());
         }
+        _thread->set_vm_result(NULL);
       }
     }
   }
-----------------------------------------------------------------------------------------------

I also took the opportunity to factor out negative array length checking:

-----------------------------------------------------------------------------------------------
diff -r 4d36f5998a8b src/hotspot/share/oops/arrayKlass.cpp
--- a/src/hotspot/share/oops/arrayKlass.cpp     Fri Oct 05 17:04:06 2018 +0200
+++ b/src/hotspot/share/oops/arrayKlass.cpp     Fri Oct 05 17:17:17 2018 +0200
@@ -130,9 +130,6 @@
 }
 
 objArrayOop ArrayKlass::allocate_arrayArray(int n, int length, TRAPS) {
-  if (length < 0) {
-    THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), 
err_msg("%d", length));
-  }
   check_array_allocation_length(length, 
arrayOopDesc::max_array_length(T_ARRAY), CHECK_0);
   int size = objArrayOopDesc::object_size(length);
   Klass* k = array_klass(n+dimension(), CHECK_0);
diff -r 4d36f5998a8b src/hotspot/share/oops/instanceKlass.cpp
--- a/src/hotspot/share/oops/instanceKlass.cpp  Fri Oct 05 17:04:06 2018 +0200
+++ b/src/hotspot/share/oops/instanceKlass.cpp  Fri Oct 05 17:17:17 2018 +0200
@@ -1201,9 +1201,6 @@
 }
 
 objArrayOop InstanceKlass::allocate_objArray(int n, int length, TRAPS) {
-  if (length < 0)  {
-    THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), 
err_msg("%d", length));
-  }
   check_array_allocation_length(length, 
arrayOopDesc::max_array_length(T_OBJECT), CHECK_NULL);
   int size = objArrayOopDesc::object_size(length);
   Klass* ak = array_klass(n, CHECK_NULL);
diff -r 4d36f5998a8b src/hotspot/share/oops/klass.cpp
--- a/src/hotspot/share/oops/klass.cpp  Fri Oct 05 17:04:06 2018 +0200
+++ b/src/hotspot/share/oops/klass.cpp  Fri Oct 05 17:17:17 2018 +0200
@@ -620,6 +620,8 @@
     } else {
       THROW_OOP(Universe::out_of_memory_error_retry());
     }
+  } else if (length < 0) {
+    THROW_MSG(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", 
length));
   }
 }
 
diff -r 4d36f5998a8b src/hotspot/share/oops/klass.hpp
--- a/src/hotspot/share/oops/klass.hpp  Fri Oct 05 17:04:06 2018 +0200
+++ b/src/hotspot/share/oops/klass.hpp  Fri Oct 05 17:17:17 2018 +0200
@@ -514,7 +514,7 @@
   virtual Klass* array_klass_impl(bool or_null, int rank, TRAPS);
   virtual Klass* array_klass_impl(bool or_null, TRAPS);
 
-  // Error handling when length > max_length
+  // Error handling when length > max_length or length < 0
   static void check_array_allocation_length(int length, int max_length, TRAPS);
 
   void set_vtable_length(int len) { _vtable_len= len; }
diff -r 4d36f5998a8b src/hotspot/share/oops/objArrayKlass.cpp
--- a/src/hotspot/share/oops/objArrayKlass.cpp  Fri Oct 05 17:04:06 2018 +0200
+++ b/src/hotspot/share/oops/objArrayKlass.cpp  Fri Oct 05 17:17:17 2018 +0200
@@ -170,14 +170,10 @@
 }
 
 objArrayOop ObjArrayKlass::allocate(int length, TRAPS) {
-  if (length >= 0) {
-    check_array_allocation_length(length, 
arrayOopDesc::max_array_length(T_OBJECT), CHECK_0);
-    int size = objArrayOopDesc::object_size(length);
-    return (objArrayOop)Universe::heap()->array_allocate(this, size, length,
-                                                         /* do_zero */ true, 
THREAD);
-  } else {
-    THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), 
err_msg("%d", length));
-  }
+  check_array_allocation_length(length, 
arrayOopDesc::max_array_length(T_OBJECT), CHECK_0);
+  int size = objArrayOopDesc::object_size(length);
+  return (objArrayOop)Universe::heap()->array_allocate(this, size, length,
+                                                       /* do_zero */ true, 
THREAD);
 }
 
 static int multi_alloc_counter = 0;
diff -r 4d36f5998a8b src/hotspot/share/oops/typeArrayKlass.cpp
--- a/src/hotspot/share/oops/typeArrayKlass.cpp Fri Oct 05 17:04:06 2018 +0200
+++ b/src/hotspot/share/oops/typeArrayKlass.cpp Fri Oct 05 17:17:17 2018 +0200
@@ -99,14 +99,10 @@
 
 typeArrayOop TypeArrayKlass::allocate_common(int length, bool do_zero, TRAPS) {
   assert(log2_element_size() >= 0, "bad scale");
-  if (length >= 0) {
-    check_array_allocation_length(length, max_length(), CHECK_NULL);
-    size_t size = typeArrayOopDesc::object_size(layout_helper(), length);
-    return (typeArrayOop)Universe::heap()->array_allocate(this, (int)size, 
length,
-                                                          do_zero, CHECK_NULL);
-  } else {
-    THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), 
err_msg("%d", length));
-  }
+  check_array_allocation_length(length, max_length(), CHECK_NULL);
+  size_t size = typeArrayOopDesc::object_size(layout_helper(), length);
+  return (typeArrayOop)Universe::heap()->array_allocate(this, (int)size, 
length,
+                                                        do_zero, CHECK_NULL);
 }
 
 oop TypeArrayKlass::multi_allocate(int rank, jint* last_size, TRAPS) {
-----------------------------------------------------------------------------------------------

Please confirm review these new changes:

http://cr.openjdk.java.net/~dnsimon/8208686v2

-Doug


> On 4 Oct 2018, at 00:20, Doug Simon <doug.si...@oracle.com> wrote:
> 
> Thanks for the reviews Serguei and Vladimir.
> 
> Unless I hear objections in the next 24 hours, I'll push this webrev.
> 
> -Doug
> 
>> On 3 Oct 2018, at 03:14, serguei.spit...@oracle.com wrote:
>> 
>> Hi Doug,
>> 
>> The JVMTI related part looks good to me.
>> Thank you for fixing it!
>> 
>> Thanks,
>> Serguei
>> 
>> On 10/2/18 1:11 AM, Doug Simon wrote:
>>> It would be great to get some input from the non-compilers teams on this 
>>> RFR.
>>> 
>>> -Doug
>>> 
>>>> On 28 Sep 2018, at 19:51, Vladimir Kozlov <vladimir.koz...@oracle.com> 
>>>> wrote:
>>>> 
>>>> To let you know, me and Tom R. did review these changes and agreed that it 
>>>> is the least intrusive changes for Hotspot shared code.
>>>> 
>>>> Thanks,
>>>> Vladimir
>>>> 
>>>> On 9/25/18 8:11 AM, Daniel D. Daugherty wrote:
>>>>> Adding serviceability-dev@... since this is JVM/TI...
>>>>> Dan
>>>>> On 9/25/18 10:48 AM, Doug Simon wrote:
>>>>>> A major design point of Graal is to treat allocations as non-side 
>>>>>> effecting to give more freedom to the optimizer by reducing the number 
>>>>>> of distinct FrameStates that need to be managed. When failing an 
>>>>>> allocation, Graal will deoptimize to the last side effecting instruction 
>>>>>> before the allocation. This mean the VM code for heap allocation will 
>>>>>> potentially be executed twice, once from Graal compiled code and then 
>>>>>> again in the interpreter. While this is perfectly fine according to the 
>>>>>> JVM specification, it can cause confusing behavior for JVMTI based 
>>>>>> tools. They will receive 2 ResourceExhausted events for a single 
>>>>>> allocation. Furthermore, the first ResourceExhausted event (on the Graal 
>>>>>> allocation slow path) might denote a bytecode instruction that performs 
>>>>>> no allocation, making it hard to debug the memory failure.
>>>>>> 
>>>>>> The proposed solution is to add an extra set of JVMCI VM runtime calls 
>>>>>> for allocation. These entry points will attempt the allocation and upon 
>>>>>> failure,
>>>>>> skip side-effects such as posting JVMTI events or handling 
>>>>>> -XX:OnOutOfMemoryError. The compiled code using these entry points is 
>>>>>> expected deoptmize on null.
>>>>>> 
>>>>>> The path from these new entry points to where allocation can fail goes 
>>>>>> through quite a bit of VM code. One could modify all these paths by:
>>>>>> * Returning null instead of throwing an exception on failure.
>>>>>> * Adding a `bool null_on_fail` argument to all relevant methods.
>>>>>> * Adding extra null checking where necessary after each call to these 
>>>>>> methods when `null_on_fail == true`.
>>>>>> This represents a significant number of changes.
>>>>>> 
>>>>>> Instead, the proposed solution introduces a new _in_retryable_allocation 
>>>>>> thread-local. This way, only the entry points and allocation routines 
>>>>>> that raise an exception need to be modified. Failure is communicated 
>>>>>> back to the new entry points by throwing a special pre-allocated OOME 
>>>>>> object (i.e., Universe::out_of_memory_error_retry()) which must not 
>>>>>> propagate back to Java code. Use of this object is not strictly 
>>>>>> necessary; it is introduced to highlight/document the special allocation 
>>>>>> mode.
>>>>>> 
>>>>>> The proposed solution is at http://cr.openjdk.java.net/~dnsimon/8208686.
>>>>>> THE JBS bug is: https://bugs.openjdk.java.net/browse/JDK-8208686
>>>>>> 
>>>>>> -Doug
>> 
> 

Reply via email to