8208686: [AOT] JVMTI ResourceExhausted event repeated for same allocation
authordnsimon
Fri, 05 Oct 2018 20:03:14 +0200
changeset 52033 d6aa9ea2405d
parent 52032 2f7a2e7c3221
child 52034 c83bc5def0d4
8208686: [AOT] JVMTI ResourceExhausted event repeated for same allocation Reviewed-by: never, kvn, sspitsyn
src/hotspot/share/aot/aotCodeHeap.cpp
src/hotspot/share/gc/shared/memAllocator.cpp
src/hotspot/share/jvmci/jvmciRuntime.cpp
src/hotspot/share/jvmci/jvmciRuntime.hpp
src/hotspot/share/jvmci/vmStructs_jvmci.cpp
src/hotspot/share/memory/universe.cpp
src/hotspot/share/memory/universe.hpp
src/hotspot/share/oops/arrayKlass.cpp
src/hotspot/share/oops/instanceKlass.cpp
src/hotspot/share/oops/klass.cpp
src/hotspot/share/oops/klass.hpp
src/hotspot/share/oops/objArrayKlass.cpp
src/hotspot/share/oops/typeArrayKlass.cpp
src/hotspot/share/runtime/thread.cpp
src/hotspot/share/runtime/thread.hpp
src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java
--- a/src/hotspot/share/aot/aotCodeHeap.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/aot/aotCodeHeap.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -436,14 +436,19 @@
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_instance", address, JVMCIRuntime::new_instance);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_array", address, JVMCIRuntime::new_array);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_multi_array", address, JVMCIRuntime::new_multi_array);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_instance", address, JVMCIRuntime::dynamic_new_instance);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_array", address, JVMCIRuntime::dynamic_new_array);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_instance_or_null", address, JVMCIRuntime::new_instance_or_null);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_array_or_null", address, JVMCIRuntime::new_array_or_null);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_multi_array_or_null", address, JVMCIRuntime::new_multi_array_or_null);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_instance_or_null", address, JVMCIRuntime::dynamic_new_instance_or_null);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_array_or_null", address, JVMCIRuntime::dynamic_new_array_or_null);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_validate_object", address, JVMCIRuntime::validate_object);
 #if INCLUDE_G1GC
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_write_barrier_pre", address, JVMCIRuntime::write_barrier_pre);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_write_barrier_post", address, JVMCIRuntime::write_barrier_post);
 #endif
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_identity_hash_code", address, JVMCIRuntime::identity_hash_code);
-    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_instance", address, JVMCIRuntime::dynamic_new_instance);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_thread_is_interrupted", address, JVMCIRuntime::thread_is_interrupted);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_exception_handler_for_pc", address, JVMCIRuntime::exception_handler_for_pc);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_test_deoptimize_call_int", address, JVMCIRuntime::test_deoptimize_call_int);
--- a/src/hotspot/share/gc/shared/memAllocator.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/gc/shared/memAllocator.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -120,27 +120,22 @@
     return false;
   }
 
-  if (!_overhead_limit_exceeded) {
+  const char* message = _overhead_limit_exceeded ? "GC overhead limit exceeded" : "Java heap space";
+  if (!THREAD->in_retryable_allocation()) {
     // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support
-    report_java_out_of_memory("Java heap space");
+    report_java_out_of_memory(message);
 
     if (JvmtiExport::should_post_resource_exhausted()) {
       JvmtiExport::post_resource_exhausted(
         JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP,
-        "Java heap space");
+        message);
     }
-    THROW_OOP_(Universe::out_of_memory_error_java_heap(), true);
+    oop exception = _overhead_limit_exceeded ?
+        Universe::out_of_memory_error_gc_overhead_limit() :
+        Universe::out_of_memory_error_java_heap();
+    THROW_OOP_(exception, true);
   } else {
-    // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support
-    report_java_out_of_memory("GC overhead limit exceeded");
-
-    if (JvmtiExport::should_post_resource_exhausted()) {
-      JvmtiExport::post_resource_exhausted(
-        JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP,
-        "GC overhead limit exceeded");
-    }
-
-    THROW_OOP_(Universe::out_of_memory_error_gc_overhead_limit(), true);
+    THROW_OOP_(Universe::out_of_memory_error_retry(), true);
   }
 }
 
--- a/src/hotspot/share/jvmci/jvmciRuntime.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -109,22 +109,72 @@
   }
 }
 
-JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance(JavaThread* thread, Klass* klass))
+// 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");
+      _thread = thread;
+      _thread->set_in_retryable_allocation(true);
+    } else {
+      _thread = NULL;
+    }
+  }
+  ~RetryableAllocationMark() {
+    if (_thread != NULL) {
+      _thread->set_in_retryable_allocation(false);
+      JavaThread* THREAD = _thread;
+      if (HAS_PENDING_EXCEPTION) {
+        oop ex = PENDING_EXCEPTION;
+        CLEAR_PENDING_EXCEPTION;
+        oop retry_oome = Universe::out_of_memory_error_retry();
+        if (ex->is_a(retry_oome->klass()) && retry_oome != ex) {
+          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);
+      }
+    }
+  }
+};
+
+JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance_common(JavaThread* thread, Klass* klass, bool null_on_fail))
   JRT_BLOCK;
   assert(klass->is_klass(), "not a class");
   Handle holder(THREAD, klass->klass_holder()); // keep the klass alive
   InstanceKlass* ik = InstanceKlass::cast(klass);
-  ik->check_valid_for_instantiation(true, CHECK);
-  // make sure klass is initialized
-  ik->initialize(CHECK);
-  // allocate instance and return via TLS
-  oop obj = ik->allocate_instance(CHECK);
-  thread->set_vm_result(obj);
+  {
+    RetryableAllocationMark ram(thread, null_on_fail);
+    ik->check_valid_for_instantiation(true, CHECK);
+    oop obj;
+    if (null_on_fail) {
+      if (!ik->is_initialized()) {
+        // Cannot re-execute class initialization without side effects
+        // so return without attempting the initialization
+        return;
+      }
+    } else {
+      // make sure klass is initialized
+      ik->initialize(CHECK);
+    }
+    // allocate instance and return via TLS
+    obj = ik->allocate_instance(CHECK);
+    thread->set_vm_result(obj);
+  }
   JRT_BLOCK_END;
   SharedRuntime::on_slowpath_allocation_exit(thread);
 JRT_END
 
-JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_klass, jint length))
+JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array_common(JavaThread* thread, Klass* array_klass, jint length, bool null_on_fail))
   JRT_BLOCK;
   // Note: no handle for klass needed since they are not used
   //       anymore after new_objArray() and no GC can happen before.
@@ -133,10 +183,12 @@
   oop obj;
   if (array_klass->is_typeArray_klass()) {
     BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type();
+    RetryableAllocationMark ram(thread, null_on_fail);
     obj = oopFactory::new_typeArray(elt_type, length, CHECK);
   } else {
     Handle holder(THREAD, array_klass->klass_holder()); // keep the klass alive
     Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass();
+    RetryableAllocationMark ram(thread, null_on_fail);
     obj = oopFactory::new_objArray(elem_klass, length, CHECK);
   }
   thread->set_vm_result(obj);
@@ -146,8 +198,12 @@
     static int deopts = 0;
     // Alternate between deoptimizing and raising an error (which will also cause a deopt)
     if (deopts++ % 2 == 0) {
-      ResourceMark rm(THREAD);
-      THROW(vmSymbols::java_lang_OutOfMemoryError());
+      if (null_on_fail) {
+        return;
+      } else {
+        ResourceMark rm(THREAD);
+        THROW(vmSymbols::java_lang_OutOfMemoryError());
+      }
     } else {
       deopt_caller();
     }
@@ -156,32 +212,43 @@
   SharedRuntime::on_slowpath_allocation_exit(thread);
 JRT_END
 
-JRT_ENTRY(void, JVMCIRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims))
+JRT_ENTRY(void, JVMCIRuntime::new_multi_array_common(JavaThread* thread, Klass* klass, int rank, jint* dims, bool null_on_fail))
   assert(klass->is_klass(), "not a class");
   assert(rank >= 1, "rank must be nonzero");
   Handle holder(THREAD, klass->klass_holder()); // keep the klass alive
+  RetryableAllocationMark ram(thread, null_on_fail);
   oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK);
   thread->set_vm_result(obj);
 JRT_END
 
-JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length))
+JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array_common(JavaThread* thread, oopDesc* element_mirror, jint length, bool null_on_fail))
+  RetryableAllocationMark ram(thread, null_on_fail);
   oop obj = Reflection::reflect_new_array(element_mirror, length, CHECK);
   thread->set_vm_result(obj);
 JRT_END
 
-JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror))
+JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance_common(JavaThread* thread, oopDesc* type_mirror, bool null_on_fail))
   InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(type_mirror));
 
   if (klass == NULL) {
     ResourceMark rm(THREAD);
     THROW(vmSymbols::java_lang_InstantiationException());
   }
+  RetryableAllocationMark ram(thread, null_on_fail);
 
   // Create new instance (the receiver)
   klass->check_valid_for_instantiation(false, CHECK);
 
-  // Make sure klass gets initialized
-  klass->initialize(CHECK);
+  if (null_on_fail) {
+    if (!klass->is_initialized()) {
+      // Cannot re-execute class initialization without side effects
+      // so return without attempting the initialization
+      return;
+    }
+  } else {
+    // Make sure klass gets initialized
+    klass->initialize(CHECK);
+  }
 
   oop obj = klass->allocate_instance(CHECK);
   thread->set_vm_result(obj);
--- a/src/hotspot/share/jvmci/jvmciRuntime.hpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp	Fri Oct 05 20:03:14 2018 +0200
@@ -121,13 +121,35 @@
 
   static BasicType kindToBasicType(Handle kind, TRAPS);
 
-  // The following routines are all called from compiled JVMCI code
+  static void new_instance_common(JavaThread* thread, Klass* klass, bool null_on_fail);
+  static void new_array_common(JavaThread* thread, Klass* klass, jint length, bool null_on_fail);
+  static void new_multi_array_common(JavaThread* thread, Klass* klass, int rank, jint* dims, bool null_on_fail);
+  static void dynamic_new_array_common(JavaThread* thread, oopDesc* element_mirror, jint length, bool null_on_fail);
+  static void dynamic_new_instance_common(JavaThread* thread, oopDesc* type_mirror, bool null_on_fail);
+
+  // The following routines are called from compiled JVMCI code
 
-  static void new_instance(JavaThread* thread, Klass* klass);
-  static void new_array(JavaThread* thread, Klass* klass, jint length);
-  static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims);
-  static void dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length);
-  static void dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror);
+  // When allocation fails, these stubs:
+  // 1. Exercise -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError handling and also
+  //    post a JVMTI_EVENT_RESOURCE_EXHAUSTED event if the failure is an OutOfMemroyError
+  // 2. Return NULL with a pending exception.
+  // Compiled code must ensure these stubs are not called twice for the same allocation
+  // site due to the non-repeatable side effects in the case of OOME.
+  static void new_instance(JavaThread* thread, Klass* klass) { new_instance_common(thread, klass, false); }
+  static void new_array(JavaThread* thread, Klass* klass, jint length) { new_array_common(thread, klass, length, false); }
+  static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims) { new_multi_array_common(thread, klass, rank, dims, false); }
+  static void dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length) { dynamic_new_array_common(thread, element_mirror, length, false); }
+  static void dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror) { dynamic_new_instance_common(thread, type_mirror, false); }
+
+  // When allocation fails, these stubs return NULL and have no pending exception. Compiled code
+  // can use these stubs if a failed allocation will be retried (e.g., by deoptimizing and
+  // re-executing in the interpreter).
+  static void new_instance_or_null(JavaThread* thread, Klass* klass) { new_instance_common(thread, klass, true); }
+  static void new_array_or_null(JavaThread* thread, Klass* klass, jint length) { new_array_common(thread, klass, length, true); }
+  static void new_multi_array_or_null(JavaThread* thread, Klass* klass, int rank, jint* dims) { new_multi_array_common(thread, klass, rank, dims, true); }
+  static void dynamic_new_array_or_null(JavaThread* thread, oopDesc* element_mirror, jint length) { dynamic_new_array_common(thread, element_mirror, length, true); }
+  static void dynamic_new_instance_or_null(JavaThread* thread, oopDesc* type_mirror) { dynamic_new_instance_common(thread, type_mirror, true); }
+
   static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupted);
   static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3);
   static jint identity_hash_code(JavaThread* thread, oopDesc* obj);
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -622,6 +622,12 @@
   declare_function(JVMCIRuntime::dynamic_new_array) \
   declare_function(JVMCIRuntime::dynamic_new_instance) \
   \
+  declare_function(JVMCIRuntime::new_instance_or_null) \
+  declare_function(JVMCIRuntime::new_array_or_null) \
+  declare_function(JVMCIRuntime::new_multi_array_or_null) \
+  declare_function(JVMCIRuntime::dynamic_new_array_or_null) \
+  declare_function(JVMCIRuntime::dynamic_new_instance_or_null) \
+  \
   declare_function(JVMCIRuntime::thread_is_interrupted) \
   declare_function(JVMCIRuntime::vm_message) \
   declare_function(JVMCIRuntime::identity_hash_code) \
--- a/src/hotspot/share/memory/universe.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/memory/universe.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -113,6 +113,7 @@
 oop Universe::_out_of_memory_error_array_size         = NULL;
 oop Universe::_out_of_memory_error_gc_overhead_limit  = NULL;
 oop Universe::_out_of_memory_error_realloc_objects    = NULL;
+oop Universe::_out_of_memory_error_retry              = NULL;
 oop Universe::_delayed_stack_overflow_error_message   = NULL;
 objArrayOop Universe::_preallocated_out_of_memory_error_array = NULL;
 volatile jint Universe::_preallocated_out_of_memory_error_avail_count = 0;
@@ -195,6 +196,7 @@
   f->do_oop((oop*)&_out_of_memory_error_array_size);
   f->do_oop((oop*)&_out_of_memory_error_gc_overhead_limit);
   f->do_oop((oop*)&_out_of_memory_error_realloc_objects);
+  f->do_oop((oop*)&_out_of_memory_error_retry);
   f->do_oop((oop*)&_delayed_stack_overflow_error_message);
   f->do_oop((oop*)&_preallocated_out_of_memory_error_array);
   f->do_oop((oop*)&_null_ptr_exception_instance);
@@ -565,7 +567,8 @@
           (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_class_metaspace))  &&
           (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_array_size)) &&
           (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_gc_overhead_limit)) &&
-          (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_realloc_objects)));
+          (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_realloc_objects)) &&
+          (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_retry)));
 }
 
 
@@ -974,6 +977,7 @@
   Universe::_out_of_memory_error_gc_overhead_limit =
     ik->allocate_instance(CHECK_false);
   Universe::_out_of_memory_error_realloc_objects = ik->allocate_instance(CHECK_false);
+  Universe::_out_of_memory_error_retry = ik->allocate_instance(CHECK_false);
 
   // Setup preallocated cause message for delayed StackOverflowError
   if (StackReservedPages > 0) {
@@ -1019,6 +1023,9 @@
   msg = java_lang_String::create_from_str("Java heap space: failed reallocation of scalar replaced objects", CHECK_false);
   java_lang_Throwable::set_message(Universe::_out_of_memory_error_realloc_objects, msg());
 
+  msg = java_lang_String::create_from_str("Java heap space: failed retryable allocation", CHECK_false);
+  java_lang_Throwable::set_message(Universe::_out_of_memory_error_retry, msg());
+
   msg = java_lang_String::create_from_str("/ by zero", CHECK_false);
   java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg());
 
--- a/src/hotspot/share/memory/universe.hpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/memory/universe.hpp	Fri Oct 05 20:03:14 2018 +0200
@@ -148,6 +148,7 @@
   static oop          _out_of_memory_error_array_size;
   static oop          _out_of_memory_error_gc_overhead_limit;
   static oop          _out_of_memory_error_realloc_objects;
+  static oop          _out_of_memory_error_retry;
 
   // preallocated cause message for delayed StackOverflowError
   static oop          _delayed_stack_overflow_error_message;
@@ -363,6 +364,8 @@
   static oop out_of_memory_error_array_size()         { return gen_out_of_memory_error(_out_of_memory_error_array_size); }
   static oop out_of_memory_error_gc_overhead_limit()  { return gen_out_of_memory_error(_out_of_memory_error_gc_overhead_limit);  }
   static oop out_of_memory_error_realloc_objects()    { return gen_out_of_memory_error(_out_of_memory_error_realloc_objects);  }
+  // Throw default _out_of_memory_error_retry object as it will never propagate out of the VM
+  static oop out_of_memory_error_retry()              { return _out_of_memory_error_retry;  }
   static oop delayed_stack_overflow_error_message()   { return _delayed_stack_overflow_error_message; }
 
   // The particular choice of collected heap.
--- a/src/hotspot/share/oops/arrayKlass.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/oops/arrayKlass.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -130,14 +130,7 @@
 }
 
 objArrayOop ArrayKlass::allocate_arrayArray(int n, int length, TRAPS) {
-  if (length < 0) {
-    THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", length));
-  }
-  if (length > arrayOopDesc::max_array_length(T_ARRAY)) {
-    report_java_out_of_memory("Requested array size exceeds VM limit");
-    JvmtiExport::post_array_size_exhausted();
-    THROW_OOP_0(Universe::out_of_memory_error_array_size());
-  }
+  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);
   ArrayKlass* ak = ArrayKlass::cast(k);
--- a/src/hotspot/share/oops/instanceKlass.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -1201,14 +1201,7 @@
 }
 
 objArrayOop InstanceKlass::allocate_objArray(int n, int length, TRAPS) {
-  if (length < 0)  {
-    THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", length));
-  }
-  if (length > arrayOopDesc::max_array_length(T_OBJECT)) {
-    report_java_out_of_memory("Requested array size exceeds VM limit");
-    JvmtiExport::post_array_size_exhausted();
-    THROW_OOP_0(Universe::out_of_memory_error_array_size());
-  }
+  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);
   objArrayOop o = (objArrayOop)Universe::heap()->array_allocate(ak, size, length,
--- a/src/hotspot/share/oops/klass.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/oops/klass.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -611,6 +611,20 @@
   return NULL;
 }
 
+void Klass::check_array_allocation_length(int length, int max_length, TRAPS) {
+  if (length > max_length) {
+    if (!THREAD->in_retryable_allocation()) {
+      report_java_out_of_memory("Requested array size exceeds VM limit");
+      JvmtiExport::post_array_size_exhausted();
+      THROW_OOP(Universe::out_of_memory_error_array_size());
+    } else {
+      THROW_OOP(Universe::out_of_memory_error_retry());
+    }
+  } else if (length < 0) {
+    THROW_MSG(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", length));
+  }
+}
+
 oop Klass::class_loader() const { return class_loader_data()->class_loader(); }
 
 // In product mode, this function doesn't have virtual function calls so
--- a/src/hotspot/share/oops/klass.hpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/oops/klass.hpp	Fri Oct 05 20:03:14 2018 +0200
@@ -514,6 +514,9 @@
   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 or length < 0
+  static void check_array_allocation_length(int length, int max_length, TRAPS);
+
   void set_vtable_length(int len) { _vtable_len= len; }
 
   vtableEntry* start_of_vtable() const;
--- a/src/hotspot/share/oops/objArrayKlass.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/oops/objArrayKlass.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -170,19 +170,10 @@
 }
 
 objArrayOop ObjArrayKlass::allocate(int length, TRAPS) {
-  if (length >= 0) {
-    if (length <= arrayOopDesc::max_array_length(T_OBJECT)) {
-      int size = objArrayOopDesc::object_size(length);
-      return (objArrayOop)Universe::heap()->array_allocate(this, size, length,
-                                                           /* do_zero */ true, THREAD);
-    } else {
-      report_java_out_of_memory("Requested array size exceeds VM limit");
-      JvmtiExport::post_array_size_exhausted();
-      THROW_OOP_0(Universe::out_of_memory_error_array_size());
-    }
-  } 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;
--- a/src/hotspot/share/oops/typeArrayKlass.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/oops/typeArrayKlass.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -99,19 +99,10 @@
 
 typeArrayOop TypeArrayKlass::allocate_common(int length, bool do_zero, TRAPS) {
   assert(log2_element_size() >= 0, "bad scale");
-  if (length >= 0) {
-    if (length <= max_length()) {
-      size_t size = typeArrayOopDesc::object_size(layout_helper(), length);
-      return (typeArrayOop)Universe::heap()->array_allocate(this, (int)size, length,
-                                                            do_zero, CHECK_NULL);
-    } else {
-      report_java_out_of_memory("Requested array size exceeds VM limit");
-      JvmtiExport::post_array_size_exhausted();
-      THROW_OOP_0(Universe::out_of_memory_error_array_size());
-    }
-  } 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) {
--- a/src/hotspot/share/runtime/thread.cpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/runtime/thread.cpp	Fri Oct 05 20:03:14 2018 +0200
@@ -1547,6 +1547,7 @@
   _pending_failed_speculation = 0;
   _pending_transfer_to_interpreter = false;
   _adjusting_comp_level = false;
+  _in_retryable_allocation = false;
   _jvmci._alternate_call_target = NULL;
   assert(_jvmci._implicit_exception_pc == NULL, "must be");
   if (JVMCICounterSize > 0) {
--- a/src/hotspot/share/runtime/thread.hpp	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/hotspot/share/runtime/thread.hpp	Fri Oct 05 20:03:14 2018 +0200
@@ -281,6 +281,14 @@
   void leave_signal_handler() { _num_nested_signal--; }
   bool is_inside_signal_handler() const { return _num_nested_signal > 0; }
 
+  // Determines if a heap allocation failure will be retried
+  // (e.g., by deoptimizing and re-executing in the interpreter).
+  // In this case, the failed allocation must raise
+  // Universe::out_of_memory_error_retry() and omit side effects
+  // such as JVMTI events and handling -XX:+HeapDumpOnOutOfMemoryError
+  // and -XX:OnOutOfMemoryError.
+  virtual bool in_retryable_allocation() const { return false; }
+
 #ifdef ASSERT
   void set_suspendible_thread() {
     _suspendible_thread = true;
@@ -1048,6 +1056,10 @@
   // Guard for re-entrant call to JVMCIRuntime::adjust_comp_level
   bool      _adjusting_comp_level;
 
+  // True if in a runtime call from compiled code that will deoptimize
+  // and re-execute a failed heap allocation in the interpreter.
+  bool      _in_retryable_allocation;
+
   // An id of a speculation that JVMCI compiled code can use to further describe and
   // uniquely identify the  speculative optimization guarded by the uncommon trap
   long       _pending_failed_speculation;
@@ -1458,7 +1470,7 @@
 
 #if INCLUDE_JVMCI
   int  pending_deoptimization() const             { return _pending_deoptimization; }
-  long  pending_failed_speculation() const         { return _pending_failed_speculation; }
+  long pending_failed_speculation() const         { return _pending_failed_speculation; }
   bool adjusting_comp_level() const               { return _adjusting_comp_level; }
   void set_adjusting_comp_level(bool b)           { _adjusting_comp_level = b; }
   bool has_pending_monitorenter() const           { return _pending_monitorenter; }
@@ -1468,6 +1480,9 @@
   void set_pending_transfer_to_interpreter(bool b) { _pending_transfer_to_interpreter = b; }
   void set_jvmci_alternate_call_target(address a) { assert(_jvmci._alternate_call_target == NULL, "must be"); _jvmci._alternate_call_target = a; }
   void set_jvmci_implicit_exception_pc(address a) { assert(_jvmci._implicit_exception_pc == NULL, "must be"); _jvmci._implicit_exception_pc = a; }
+
+  virtual bool in_retryable_allocation() const    { return _in_retryable_allocation; }
+  void set_in_retryable_allocation(bool b)        { _in_retryable_allocation = b; }
 #endif // INCLUDE_JVMCI
 
   // Exception handling for compiled methods
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java	Fri Oct 05 20:03:14 2018 +0200
@@ -240,14 +240,20 @@
         {"JVMCIRuntime::log_printf", "_aot_jvmci_runtime_log_printf"},
         {"JVMCIRuntime::vm_message", "_aot_jvmci_runtime_vm_message"},
         {"JVMCIRuntime::new_instance", "_aot_jvmci_runtime_new_instance"},
-        {"JVMCIRuntime::log_primitive", "_aot_jvmci_runtime_log_primitive"},
+        {"JVMCIRuntime::new_array", "_aot_jvmci_runtime_new_array"},
         {"JVMCIRuntime::new_multi_array", "_aot_jvmci_runtime_new_multi_array"},
+        {"JVMCIRuntime::dynamic_new_instance", "_aot_jvmci_runtime_dynamic_new_instance"},
+        {"JVMCIRuntime::dynamic_new_array", "_aot_jvmci_runtime_dynamic_new_array"},
+        {"JVMCIRuntime::new_instance_or_null", "_aot_jvmci_runtime_new_instance_or_null"},
+        {"JVMCIRuntime::new_array_or_null", "_aot_jvmci_runtime_new_array_or_null"},
+        {"JVMCIRuntime::new_multi_array_or_null", "_aot_jvmci_runtime_new_multi_array_or_null"},
+        {"JVMCIRuntime::dynamic_new_instance_or_null", "_aot_jvmci_runtime_dynamic_new_instance_or_null"},
+        {"JVMCIRuntime::dynamic_new_array_or_null", "_aot_jvmci_runtime_dynamic_new_array_or_null"},
+        {"JVMCIRuntime::log_primitive", "_aot_jvmci_runtime_log_primitive"},
         {"JVMCIRuntime::validate_object", "_aot_jvmci_runtime_validate_object"},
-        {"JVMCIRuntime::dynamic_new_array", "_aot_jvmci_runtime_dynamic_new_array"},
         {"JVMCIRuntime::write_barrier_pre", "_aot_jvmci_runtime_write_barrier_pre"},
         {"JVMCIRuntime::identity_hash_code", "_aot_jvmci_runtime_identity_hash_code"},
         {"JVMCIRuntime::write_barrier_post", "_aot_jvmci_runtime_write_barrier_post"},
-        {"JVMCIRuntime::dynamic_new_instance", "_aot_jvmci_runtime_dynamic_new_instance"},
         {"JVMCIRuntime::thread_is_interrupted", "_aot_jvmci_runtime_thread_is_interrupted"},
         {"JVMCIRuntime::exception_handler_for_pc", "_aot_jvmci_runtime_exception_handler_for_pc"},
         {"JVMCIRuntime::test_deoptimize_call_int", "_aot_jvmci_runtime_test_deoptimize_call_int"},
@@ -256,8 +262,7 @@
         {"JVMCIRuntime::throw_klass_external_name_exception", "_aot_jvmci_runtime_throw_klass_external_name_exception"},
         {"JVMCIRuntime::throw_class_cast_exception",          "_aot_jvmci_runtime_throw_class_cast_exception"},
 
-        {"JVMCIRuntime::vm_error", "_aot_jvmci_runtime_vm_error"},
-        {"JVMCIRuntime::new_array", "_aot_jvmci_runtime_new_array"}
+        {"JVMCIRuntime::vm_error", "_aot_jvmci_runtime_vm_error"}
     };
     //@formatter:on
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Fri Oct 05 20:03:14 2018 +0200
@@ -648,11 +648,33 @@
     public final long unsafeArraycopy = getFieldValue("StubRoutines::_unsafe_arraycopy", Long.class, "address");
     public final long genericArraycopy = getFieldValue("StubRoutines::_generic_arraycopy", Long.class, "address");
 
+    // Allocation stubs that throw an exception when allocation fails
     public final long newInstanceAddress = getAddress("JVMCIRuntime::new_instance");
     public final long newArrayAddress = getAddress("JVMCIRuntime::new_array");
     public final long newMultiArrayAddress = getAddress("JVMCIRuntime::new_multi_array");
-    public final long dynamicNewArrayAddress = getAddress("JVMCIRuntime::dynamic_new_array");
-    public final long dynamicNewInstanceAddress = getAddress("JVMCIRuntime::dynamic_new_instance");
+
+    // Allocation stubs that return null when allocation fails
+    public final long newInstanceOrNullAddress = getAddress("JVMCIRuntime::new_instance_or_null", 0L);
+    public final long newArrayOrNullAddress = getAddress("JVMCIRuntime::new_array_or_null", 0L);
+    public final long newMultiArrayOrNullAddress = getAddress("JVMCIRuntime::new_multi_array_or_null", 0L);
+
+    public boolean areNullAllocationStubsAvailable() {
+        return newInstanceOrNullAddress != 0L;
+    }
+
+    /**
+     * Checks that HotSpot implements all or none of the allocate-or-null stubs.
+     */
+    private boolean checkNullAllocationStubs() {
+        if (newInstanceOrNullAddress == 0L) {
+            assert newArrayOrNullAddress == 0L;
+            assert newMultiArrayOrNullAddress == 0L;
+        } else {
+            assert newArrayOrNullAddress != 0L;
+            assert newMultiArrayOrNullAddress != 0L;
+        }
+        return true;
+    }
 
     public final long threadIsInterruptedAddress = getAddress("JVMCIRuntime::thread_is_interrupted");
     public final long vmMessageAddress = getAddress("JVMCIRuntime::vm_message");
@@ -757,6 +779,7 @@
         }
 
         assert codeEntryAlignment > 0 : codeEntryAlignment;
+        assert checkNullAllocationStubs();
         return true;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Fri Oct 05 20:03:14 2018 +0200
@@ -279,21 +279,36 @@
     public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
 
     /**
-     * New multi array stub call.
+     * New multi array stub that throws an {@link OutOfMemoryError} on allocation failure.
      */
     public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, KlassPointer.class, int.class, Word.class);
 
     /**
-     * New array stub.
+     * New multi array stub that will return null on allocation failure.
+     */
+    public static final ForeignCallDescriptor NEW_MULTI_ARRAY_OR_NULL = new ForeignCallDescriptor("new_multi_array_or_null", Object.class, KlassPointer.class, int.class, Word.class);
+
+    /**
+     * New array stub that throws an {@link OutOfMemoryError} on allocation failure.
      */
     public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, KlassPointer.class, int.class);
 
     /**
-     * New instance stub.
+     * New array stub that will return null on allocation failure.
+     */
+    public static final ForeignCallDescriptor NEW_ARRAY_OR_NULL = new ForeignCallDescriptor("new_array_or_null", Object.class, KlassPointer.class, int.class);
+
+    /**
+     * New instance stub that throws an {@link OutOfMemoryError} on allocation failure.
      */
     public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, KlassPointer.class);
 
     /**
+     * New instance stub that will return null on allocation failure.
+     */
+    public static final ForeignCallDescriptor NEW_INSTANCE_OR_NULL = new ForeignCallDescriptor("new_instance_or_null", Object.class, KlassPointer.class);
+
+    /**
      * @see ResolveConstantStubCall
      */
     public static final ForeignCallDescriptor RESOLVE_STRING_BY_SYMBOL = new ForeignCallDescriptor("resolve_string_by_symbol", Object.class, Word.class, Word.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri Oct 05 20:03:14 2018 +0200
@@ -45,8 +45,11 @@
 import static org.graalvm.compiler.hotspot.HotSpotBackend.MULTIPLY_TO_LEN;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.MUL_ADD;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY_OR_NULL;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE_OR_NULL;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY_OR_NULL;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
@@ -78,8 +81,6 @@
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_TOP_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.MonitorSnippets.MONITORENTER;
 import static org.graalvm.compiler.hotspot.replacements.MonitorSnippets.MONITOREXIT;
-import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.DYNAMIC_NEW_ARRAY;
-import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.DYNAMIC_NEW_INSTANCE;
 import static org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions.THREAD_IS_INTERRUPTED;
 import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.G1WBPOSTCALL;
 import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.G1WBPRECALL;
@@ -288,6 +289,14 @@
 
         linkForeignCall(options, providers, NEW_INSTANCE, c.newInstanceAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
         linkForeignCall(options, providers, NEW_ARRAY, c.newArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+        linkForeignCall(options, providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+
+        if (c.areNullAllocationStubsAvailable()) {
+            linkForeignCall(options, providers, NEW_INSTANCE_OR_NULL, c.newInstanceOrNullAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+            linkForeignCall(options, providers, NEW_ARRAY_OR_NULL, c.newArrayOrNullAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+            linkForeignCall(options, providers, NEW_MULTI_ARRAY_OR_NULL, c.newMultiArrayOrNullAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+        }
+
         link(new ExceptionHandlerStub(options, providers, foreignCalls.get(EXCEPTION_HANDLER)));
         link(new UnwindExceptionToCallerStub(options, providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, SAFEPOINT, REEXECUTABLE_ONLY_AFTER_EXCEPTION, any())));
         link(new VerifyOopStub(options, providers, registerStubCall(VERIFY_OOP, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS)));
@@ -305,11 +314,8 @@
         linkForeignCall(options, providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE_ONLY_AFTER_EXCEPTION, any());
         linkForeignCall(options, providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE_ONLY_AFTER_EXCEPTION, any());
         linkForeignCall(options, providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, STACK_INSPECTABLE_LEAF, REEXECUTABLE_ONLY_AFTER_EXCEPTION, any());
-        linkForeignCall(options, providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
         linkForeignCall(options, providers, NOTIFY, c.notifyAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE_ONLY_AFTER_EXCEPTION, any());
         linkForeignCall(options, providers, NOTIFY_ALL, c.notifyAllAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE_ONLY_AFTER_EXCEPTION, any());
-        linkForeignCall(options, providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE);
-        linkForeignCall(options, providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE);
         linkForeignCall(options, providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(options, providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(options, providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Fri Oct 05 18:25:15 2018 +0100
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Fri Oct 05 20:03:14 2018 +0200
@@ -24,9 +24,17 @@
 
 package org.graalvm.compiler.hotspot.replacements;
 
+import static jdk.vm.ci.meta.DeoptimizationAction.None;
+import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint;
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.core.common.calc.UnsignedMath.belowThan;
-import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY_OR_NULL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE_OR_NULL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY_OR_NULL;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_ARRAY_KLASS_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_WRITE_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
@@ -70,6 +78,7 @@
 import static org.graalvm.compiler.replacements.nodes.ExplodeLoopNode.explodeLoop;
 
 import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
 import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
@@ -80,7 +89,6 @@
 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.hotspot.HotSpotBackend;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
 import org.graalvm.compiler.hotspot.nodes.DimensionsNode;
@@ -126,8 +134,6 @@
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
-import jdk.vm.ci.meta.DeoptimizationAction;
-import jdk.vm.ci.meta.DeoptimizationReason;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
@@ -220,14 +226,25 @@
             if (counters != null && counters.stub != null) {
                 counters.stub.inc();
             }
-            result = newInstance(HotSpotBackend.NEW_INSTANCE, hub);
+            result = newInstanceStub(hub);
         }
         profileAllocation("instance", size, typeContext, options);
         return verifyOop(result);
     }
 
+    public static Object newInstanceStub(KlassPointer hub) {
+        if (useNullAllocationStubs(INJECTED_VMCONFIG)) {
+            return nonNullOrDeopt(newInstanceOrNull(NEW_INSTANCE_OR_NULL, hub));
+        } else {
+            return newInstance(NEW_INSTANCE, hub);
+        }
+    }
+
     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
-    public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
+    private static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
+
+    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = false)
+    private static native Object newInstanceOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
 
     @Snippet
     public static Object allocateInstancePIC(@ConstantParameter int size, KlassPointer hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents,
@@ -244,18 +261,18 @@
     public static Object allocateInstanceDynamic(Class<?> type, Class<?> classClass, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
                     @ConstantParameter OptionValues options, @ConstantParameter Counters counters) {
         if (probability(SLOW_PATH_PROBABILITY, type == null)) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+            DeoptimizeNode.deopt(None, RuntimeConstraint);
         }
         Class<?> nonNullType = PiNode.piCastNonNullClass(type, SnippetAnchorNode.anchor());
 
         if (probability(SLOW_PATH_PROBABILITY, DynamicNewInstanceNode.throwsInstantiationException(type, classClass))) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+            DeoptimizeNode.deopt(None, RuntimeConstraint);
         }
 
-        return PiNode.piCastToSnippetReplaceeStamp(allocateInstanceDynamicHelper(type, fillContents, threadRegister, options, counters, nonNullType));
+        return PiNode.piCastToSnippetReplaceeStamp(allocateInstanceDynamicHelper(fillContents, threadRegister, options, counters, nonNullType));
     }
 
-    private static Object allocateInstanceDynamicHelper(Class<?> type, boolean fillContents, Register threadRegister, OptionValues options, Counters counters, Class<?> nonNullType) {
+    private static Object allocateInstanceDynamicHelper(boolean fillContents, Register threadRegister, OptionValues options, Counters counters, Class<?> nonNullType) {
         KlassPointer hub = ClassGetHubNode.readClass(nonNullType);
         if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) {
             KlassPointer nonNullHub = ClassGetHubNode.piCastNonNull(hub, SnippetAnchorNode.anchor());
@@ -277,10 +294,11 @@
                     return allocateInstanceHelper(layoutHelper, nonNullHub, prototypeMarkWord, fillContents, threadRegister, false, "", options, counters);
                 }
             } else {
-                DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+                DeoptimizeNode.deopt(None, RuntimeConstraint);
             }
         }
-        return dynamicNewInstanceStub(type);
+        DeoptimizeNode.deopt(None, RuntimeConstraint);
+        return null;
     }
 
     /**
@@ -307,13 +325,30 @@
     }
 
     @Snippet
-    public static Object allocateArray(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
-                    @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext,
-                    @ConstantParameter OptionValues options, @ConstantParameter Counters counters) {
+    public static Object allocateArray(KlassPointer hub,
+                    int length,
+                    Word prototypeMarkWord,
+                    @ConstantParameter int headerSize,
+                    @ConstantParameter int log2ElementSize,
+                    @ConstantParameter boolean fillContents,
+                    @ConstantParameter Register threadRegister,
+                    @ConstantParameter boolean maybeUnroll,
+                    @ConstantParameter String typeContext,
+                    @ConstantParameter OptionValues options,
+                    @ConstantParameter Counters counters) {
         Object result = allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false, options, counters);
         return piArrayCastToSnippetReplaceeStamp(verifyOop(result), length);
     }
 
+    /**
+     * When allocating on the slow path, determines whether to use a version of the runtime call
+     * that returns {@code null} on a failed allocation instead of raising an OutOfMemoryError.
+     */
+    @Fold
+    static boolean useNullAllocationStubs(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.areNullAllocationStubsAvailable();
+    }
+
     private static Object allocateArrayImpl(KlassPointer hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, Register threadRegister,
                     boolean maybeUnroll, String typeContext, boolean skipNegativeCheck, OptionValues options, Counters counters) {
         Object result;
@@ -331,27 +366,41 @@
             }
             result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, counters);
         } else {
-            result = newArray(HotSpotBackend.NEW_ARRAY, hub, length);
+            result = newArrayStub(hub, length);
         }
         profileAllocation("array", allocationSize, typeContext, options);
         return result;
     }
 
-    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
-    public static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length);
-
-    public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class);
-    public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class);
-
-    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
-    public static native Object dynamicNewArrayStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType, int length);
-
-    public static Object dynamicNewInstanceStub(Class<?> elementType) {
-        return dynamicNewInstanceStubCall(DYNAMIC_NEW_INSTANCE, elementType);
+    public static Object newArrayStub(KlassPointer hub, int length) {
+        if (useNullAllocationStubs(INJECTED_VMCONFIG)) {
+            return nonNullOrDeopt(newArrayOrNull(NEW_ARRAY_OR_NULL, hub, length));
+        } else {
+            return newArray(NEW_ARRAY, hub, length);
+        }
     }
 
     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
-    public static native Object dynamicNewInstanceStubCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
+    private static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length);
+
+    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = false)
+    private static native Object newArrayOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length);
+
+    /**
+     * Deoptimizes if {@code obj == null} otherwise returns {@code obj}.
+     */
+    private static Object nonNullOrDeopt(Object obj) {
+        if (obj == null) {
+            DeoptimizeNode.deopt(None, RuntimeConstraint);
+        }
+        return obj;
+    }
+
+    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
+    public static native Object dynamicNewInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
+
+    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = false)
+    public static native Object dynamicNewInstanceOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
 
     @Snippet
     public static Object allocateArrayDynamic(Class<?> elementType, Class<?> voidClass, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
@@ -369,17 +418,17 @@
          */
         staticAssert(knownElementKind != JavaKind.Void, "unsupported knownElementKind");
         if (knownElementKind == JavaKind.Illegal && probability(SLOW_PATH_PROBABILITY, elementType == null || DynamicNewArrayNode.throwsIllegalArgumentException(elementType, voidClass))) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+            DeoptimizeNode.deopt(None, RuntimeConstraint);
         }
 
         KlassPointer klass = loadKlassFromObject(elementType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION);
         if (klass.isNull()) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+            DeoptimizeNode.deopt(None, RuntimeConstraint);
         }
         KlassPointer nonNullKlass = ClassGetHubNode.piCastNonNull(klass, SnippetAnchorNode.anchor());
 
         if (length < 0) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+            DeoptimizeNode.deopt(None, RuntimeConstraint);
         }
         int layoutHelper;
         if (knownElementKind == JavaKind.Illegal) {
@@ -412,24 +461,35 @@
      * Calls the runtime stub for implementing MULTIANEWARRAY.
      */
     @Snippet
-    public static Object newmultiarray(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) {
+    private static Object newmultiarray(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) {
         Word dims = DimensionsNode.allocaDimsArray(rank);
         ExplodeLoopNode.explodeLoop();
         for (int i = 0; i < rank; i++) {
             dims.writeInt(i * 4, dimensions[i], LocationIdentity.init());
         }
-        return newArrayCall(HotSpotBackend.NEW_MULTI_ARRAY, hub, rank, dims);
+        return newMultiArrayStub(hub, rank, dims);
+    }
+
+    private static Object newMultiArrayStub(KlassPointer hub, int rank, Word dims) {
+        if (useNullAllocationStubs(INJECTED_VMCONFIG)) {
+            return nonNullOrDeopt(newMultiArrayOrNull(NEW_MULTI_ARRAY_OR_NULL, hub, rank, dims));
+        } else {
+            return newMultiArray(NEW_MULTI_ARRAY, hub, rank, dims);
+        }
     }
 
     @Snippet
-    public static Object newmultiarrayPIC(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) {
+    private static Object newmultiarrayPIC(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) {
         // Array type would be resolved by dominating resolution.
         KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub);
         return newmultiarray(picHub, rank, dimensions);
     }
 
     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
-    public static native Object newArrayCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int rank, Word dims);
+    private static native Object newMultiArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int rank, Word dims);
+
+    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = false)
+    private static native Object newMultiArrayOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int rank, Word dims);
 
     /**
      * Maximum number of long stores to emit when zeroing an object with a constant size. Larger
@@ -509,17 +569,9 @@
     }
 
     /**
-     * Formats some allocated memory with an object header and zeroes out the rest. Disables asserts
-     * since they can't be compiled in stubs.
-     */
-    public static Object formatObjectForStub(KlassPointer hub, int size, Word memory, Word compileTimePrototypeMarkWord) {
-        return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, null);
-    }
-
-    /**
      * Formats some allocated memory with an object header and zeroes out the rest.
      */
-    protected static Object formatObject(KlassPointer hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, Counters counters) {
+    private static Object formatObject(KlassPointer hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, Counters counters) {
         Word prototypeMarkWord = useBiasedLocking(INJECTED_VMCONFIG) ? hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
@@ -532,7 +584,7 @@
     }
 
     @Snippet
-    protected static void verifyHeap(@ConstantParameter Register threadRegister) {
+    private static void verifyHeap(@ConstantParameter Register threadRegister) {
         Word thread = registerAsWord(threadRegister);
         Word topValue = readTlabTop(thread);
         if (!topValue.equal(WordFactory.zero())) {
@@ -546,7 +598,7 @@
     /**
      * Formats some allocated memory with an object header and zeroes out the rest.
      */
-    public static Object formatArray(KlassPointer hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll,
+    private static Object formatArray(KlassPointer hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll,
                     Counters counters) {
         memory.writeInt(arrayLengthOffset(INJECTED_VMCONFIG), length, LocationIdentity.init());
         /*