diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 4d5bf7b423e..1e3783e0628 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1056,8 +1056,10 @@ protected: char* klass_name_str = klass_name->as_C_string(); InstanceKlass* ik = SystemDictionary::find_instance_klass(thread, klass_name, Handle(), Handle()); guarantee(ik != nullptr, "%s must be loaded", klass_name_str); - guarantee(ik->is_initialized(), "%s must be initialized", klass_name_str); - CacheType::compute_offsets(ik); + if (!ik->is_in_error_state()) { + guarantee(ik->is_initialized(), "%s must be initialized", klass_name_str); + CacheType::compute_offsets(ik); + } return ik; } }; @@ -1070,11 +1072,17 @@ protected: static BoxCache *_singleton; BoxCache(Thread* thread) { InstanceKlass* ik = BoxCacheBase::find_cache_klass(thread, CacheType::symbol()); - objArrayOop cache = CacheType::cache(ik); - assert(cache->length() > 0, "Empty cache"); - _low = BoxType::value(cache->obj_at(0)); - _high = _low + cache->length() - 1; - _cache = JNIHandles::make_global(Handle(thread, cache)); + if (ik->is_in_error_state()) { + _low = 1; + _high = 0; + _cache = nullptr; + } else { + objArrayOop cache = CacheType::cache(ik); + assert(cache->length() > 0, "Empty cache"); + _low = BoxType::value(cache->obj_at(0)); + _high = _low + cache->length() - 1; + _cache = JNIHandles::make_global(Handle(thread, cache)); + } } ~BoxCache() { JNIHandles::destroy_global(_cache); @@ -1096,7 +1104,11 @@ public: } return nullptr; } - oop lookup_raw(intptr_t raw_value) { + oop lookup_raw(intptr_t raw_value, bool& cache_init_error) { + if (_cache == nullptr) { + cache_init_error = true; + return nullptr; + } // Have to cast to avoid little/big-endian problems. if (sizeof(PrimitiveType) > sizeof(jint)) { jlong value = (jlong)raw_value; @@ -1126,8 +1138,13 @@ protected: static BooleanBoxCache *_singleton; BooleanBoxCache(Thread *thread) { InstanceKlass* ik = find_cache_klass(thread, java_lang_Boolean::symbol()); - _true_cache = JNIHandles::make_global(Handle(thread, java_lang_Boolean::get_TRUE(ik))); - _false_cache = JNIHandles::make_global(Handle(thread, java_lang_Boolean::get_FALSE(ik))); + if (ik->is_in_error_state()) { + _true_cache = nullptr; + _false_cache = nullptr; + } else { + _true_cache = JNIHandles::make_global(Handle(thread, java_lang_Boolean::get_TRUE(ik))); + _false_cache = JNIHandles::make_global(Handle(thread, java_lang_Boolean::get_FALSE(ik))); + } } ~BooleanBoxCache() { JNIHandles::destroy_global(_true_cache); @@ -1143,7 +1160,11 @@ public: } return _singleton; } - oop lookup_raw(intptr_t raw_value) { + oop lookup_raw(intptr_t raw_value, bool& cache_in_error) { + if (_true_cache == nullptr) { + cache_in_error = true; + return nullptr; + } // Have to cast to avoid little/big-endian problems. jboolean value = (jboolean)*((jint*)&raw_value); return lookup(value); @@ -1158,18 +1179,18 @@ public: BooleanBoxCache* BooleanBoxCache::_singleton = nullptr; -oop Deoptimization::get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, TRAPS) { +oop Deoptimization::get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, bool& cache_init_error, TRAPS) { Klass* k = java_lang_Class::as_Klass(bv->klass()->as_ConstantOopReadValue()->value()()); BasicType box_type = vmClasses::box_klass_type(k); if (box_type != T_OBJECT) { StackValue* value = StackValue::create_stack_value(fr, reg_map, bv->field_at(box_type == T_LONG ? 1 : 0)); switch(box_type) { - case T_INT: return IntegerBoxCache::singleton(THREAD)->lookup_raw(value->get_int()); - case T_CHAR: return CharacterBoxCache::singleton(THREAD)->lookup_raw(value->get_int()); - case T_SHORT: return ShortBoxCache::singleton(THREAD)->lookup_raw(value->get_int()); - case T_BYTE: return ByteBoxCache::singleton(THREAD)->lookup_raw(value->get_int()); - case T_BOOLEAN: return BooleanBoxCache::singleton(THREAD)->lookup_raw(value->get_int()); - case T_LONG: return LongBoxCache::singleton(THREAD)->lookup_raw(value->get_int()); + case T_INT: return IntegerBoxCache::singleton(THREAD)->lookup_raw(value->get_int(), cache_init_error); + case T_CHAR: return CharacterBoxCache::singleton(THREAD)->lookup_raw(value->get_int(), cache_init_error); + case T_SHORT: return ShortBoxCache::singleton(THREAD)->lookup_raw(value->get_int(), cache_init_error); + case T_BYTE: return ByteBoxCache::singleton(THREAD)->lookup_raw(value->get_int(), cache_init_error); + case T_BOOLEAN: return BooleanBoxCache::singleton(THREAD)->lookup_raw(value->get_int(), cache_init_error); + case T_LONG: return LongBoxCache::singleton(THREAD)->lookup_raw(value->get_int(), cache_init_error); default:; } } @@ -1193,21 +1214,26 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* Klass* k = java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()()); oop obj = nullptr; + bool cache_init_error = false; if (k->is_instance_klass()) { #if INCLUDE_JVMCI CompiledMethod* cm = fr->cb()->as_compiled_method_or_null(); if (cm->is_compiled_by_jvmci() && sv->is_auto_box()) { AutoBoxObjectValue* abv = (AutoBoxObjectValue*) sv; - obj = get_cached_box(abv, fr, reg_map, THREAD); + obj = get_cached_box(abv, fr, reg_map, cache_init_error, THREAD); if (obj != nullptr) { // Set the flag to indicate the box came from a cache, so that we can skip the field reassignment for it. abv->set_cached(true); + } else if (cache_init_error) { + // Results in an OOME which is valid (as opposed to a class initialization error) + // and is fine for the rare case a cache initialization failing. + failures = true; } } #endif // INCLUDE_JVMCI InstanceKlass* ik = InstanceKlass::cast(k); - if (obj == nullptr) { + if (obj == nullptr && !cache_init_error) { #ifdef COMPILER2 if (EnableVectorSupport && VectorSupport::is_vector(ik)) { obj = VectorSupport::allocate_vector(ik, fr, reg_map, sv, THREAD); @@ -1233,7 +1259,7 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* } assert(sv->value().is_null(), "redundant reallocation"); - assert(obj != nullptr || HAS_PENDING_EXCEPTION, "allocation should succeed or we should get an exception"); + assert(obj != nullptr || HAS_PENDING_EXCEPTION || cache_init_error, "allocation should succeed or we should get an exception"); CLEAR_PENDING_EXCEPTION; sv->set_value(obj); } diff --git a/src/hotspot/share/runtime/deoptimization.hpp b/src/hotspot/share/runtime/deoptimization.hpp index 01da82b3dad..5333aeaebbd 100644 --- a/src/hotspot/share/runtime/deoptimization.hpp +++ b/src/hotspot/share/runtime/deoptimization.hpp @@ -185,7 +185,7 @@ class Deoptimization : AllStatic { #if INCLUDE_JVMCI static address deoptimize_for_missing_exception_handler(CompiledMethod* cm); - static oop get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, TRAPS); + static oop get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, bool& cache_init_error, TRAPS); #endif private: diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/VirtualObject.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/VirtualObject.java index c0904b25aca..d26b135a405 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/VirtualObject.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/VirtualObject.java @@ -74,7 +74,7 @@ public final class VirtualObject implements JavaValue { * @param id a unique id that identifies the object within the debug information for one * position in the compiled code. * @param isAutoBox a flag that tells the runtime that the object may be a boxed primitive and - * that it possibly needs to be obtained for the box cache instead of creating a new + * that it possibly needs to be obtained from the box cache instead of creating a new * instance. * @return a new {@link VirtualObject} instance. */ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index 46f0d5f00cb..9425296ae4f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -192,15 +192,6 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { // initialized. JVMCI.getRuntime(); } - // Make sure all the primitive box caches are populated (required to properly - // materialize boxed primitives - // during deoptimization). - Boolean.valueOf(false); - Byte.valueOf((byte) 0); - Short.valueOf((short) 0); - Character.valueOf((char) 0); - Integer.valueOf(0); - Long.valueOf(0); } } return result;