8223320: [AOT] jck test api/javax_script/ScriptEngine/PutGet.html fails when test classes are AOTed
Materialization of primitive boxes should use caches Reviewed-by: kvn, never
This commit is contained in:
parent
7d63888ac8
commit
e47daab7b4
@ -319,3 +319,24 @@ bool AOTLoader::reconcile_dynamic_invoke(InstanceKlass* holder, int index, Metho
|
||||
vmassert(success || thread->last_frame().sender(&map).is_deoptimized_frame(), "caller not deoptimized on failure");
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
// This should be called very early during startup before any of the AOTed methods that use boxes can deoptimize.
|
||||
// Deoptimization machinery expects the caches to be present and populated.
|
||||
void AOTLoader::initialize_box_caches(TRAPS) {
|
||||
if (!UseAOT || libraries_count() == 0) {
|
||||
return;
|
||||
}
|
||||
TraceTime timer("AOT initialization of box caches", TRACETIME_LOG(Info, aot, startuptime));
|
||||
Symbol* box_classes[] = { java_lang_Boolean::symbol(), java_lang_Byte_ByteCache::symbol(),
|
||||
java_lang_Short_ShortCache::symbol(), java_lang_Character_CharacterCache::symbol(),
|
||||
java_lang_Integer_IntegerCache::symbol(), java_lang_Long_LongCache::symbol() };
|
||||
|
||||
for (unsigned i = 0; i < sizeof(box_classes) / sizeof(Symbol*); i++) {
|
||||
Klass* k = SystemDictionary::resolve_or_fail(box_classes[i], true, CHECK);
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
if (ik->is_not_initialized()) {
|
||||
ik->initialize(CHECK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ public:
|
||||
static void oops_do(OopClosure* f) NOT_AOT_RETURN;
|
||||
static void metadata_do(MetadataClosure* f) NOT_AOT_RETURN;
|
||||
static void mark_evol_dependent_methods(InstanceKlass* dependee) NOT_AOT_RETURN;
|
||||
static void initialize_box_caches(TRAPS) NOT_AOT_RETURN;
|
||||
|
||||
NOT_PRODUCT( static void print_statistics() NOT_AOT_RETURN; )
|
||||
|
||||
|
@ -4155,6 +4155,14 @@ int java_nio_Buffer::_limit_offset;
|
||||
int java_util_concurrent_locks_AbstractOwnableSynchronizer::_owner_offset;
|
||||
int reflect_ConstantPool::_oop_offset;
|
||||
int reflect_UnsafeStaticFieldAccessorImpl::_base_offset;
|
||||
int java_lang_Integer_IntegerCache::_static_cache_offset;
|
||||
int java_lang_Long_LongCache::_static_cache_offset;
|
||||
int java_lang_Character_CharacterCache::_static_cache_offset;
|
||||
int java_lang_Short_ShortCache::_static_cache_offset;
|
||||
int java_lang_Byte_ByteCache::_static_cache_offset;
|
||||
int java_lang_Boolean::_static_TRUE_offset;
|
||||
int java_lang_Boolean::_static_FALSE_offset;
|
||||
|
||||
|
||||
|
||||
#define STACKTRACEELEMENT_FIELDS_DO(macro) \
|
||||
@ -4314,6 +4322,192 @@ void java_util_concurrent_locks_AbstractOwnableSynchronizer::serialize_offsets(S
|
||||
}
|
||||
#endif
|
||||
|
||||
#define INTEGER_CACHE_FIELDS_DO(macro) \
|
||||
macro(_static_cache_offset, k, "cache", java_lang_Integer_array_signature, true)
|
||||
|
||||
void java_lang_Integer_IntegerCache::compute_offsets(InstanceKlass *k) {
|
||||
guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
|
||||
INTEGER_CACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
objArrayOop java_lang_Integer_IntegerCache::cache(InstanceKlass *ik) {
|
||||
oop base = ik->static_field_base_raw();
|
||||
return objArrayOop(base->obj_field(_static_cache_offset));
|
||||
}
|
||||
|
||||
Symbol* java_lang_Integer_IntegerCache::symbol() {
|
||||
return vmSymbols::java_lang_Integer_IntegerCache();
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void java_lang_Integer_IntegerCache::serialize_offsets(SerializeClosure* f) {
|
||||
INTEGER_CACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
||||
}
|
||||
#endif
|
||||
#undef INTEGER_CACHE_FIELDS_DO
|
||||
|
||||
jint java_lang_Integer::value(oop obj) {
|
||||
jvalue v;
|
||||
java_lang_boxing_object::get_value(obj, &v);
|
||||
return v.i;
|
||||
}
|
||||
|
||||
#define LONG_CACHE_FIELDS_DO(macro) \
|
||||
macro(_static_cache_offset, k, "cache", java_lang_Long_array_signature, true)
|
||||
|
||||
void java_lang_Long_LongCache::compute_offsets(InstanceKlass *k) {
|
||||
guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
|
||||
LONG_CACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
objArrayOop java_lang_Long_LongCache::cache(InstanceKlass *ik) {
|
||||
oop base = ik->static_field_base_raw();
|
||||
return objArrayOop(base->obj_field(_static_cache_offset));
|
||||
}
|
||||
|
||||
Symbol* java_lang_Long_LongCache::symbol() {
|
||||
return vmSymbols::java_lang_Long_LongCache();
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void java_lang_Long_LongCache::serialize_offsets(SerializeClosure* f) {
|
||||
LONG_CACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
||||
}
|
||||
#endif
|
||||
#undef LONG_CACHE_FIELDS_DO
|
||||
|
||||
jlong java_lang_Long::value(oop obj) {
|
||||
jvalue v;
|
||||
java_lang_boxing_object::get_value(obj, &v);
|
||||
return v.j;
|
||||
}
|
||||
|
||||
#define CHARACTER_CACHE_FIELDS_DO(macro) \
|
||||
macro(_static_cache_offset, k, "cache", java_lang_Character_array_signature, true)
|
||||
|
||||
void java_lang_Character_CharacterCache::compute_offsets(InstanceKlass *k) {
|
||||
guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
|
||||
CHARACTER_CACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
objArrayOop java_lang_Character_CharacterCache::cache(InstanceKlass *ik) {
|
||||
oop base = ik->static_field_base_raw();
|
||||
return objArrayOop(base->obj_field(_static_cache_offset));
|
||||
}
|
||||
|
||||
Symbol* java_lang_Character_CharacterCache::symbol() {
|
||||
return vmSymbols::java_lang_Character_CharacterCache();
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void java_lang_Character_CharacterCache::serialize_offsets(SerializeClosure* f) {
|
||||
CHARACTER_CACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
||||
}
|
||||
#endif
|
||||
#undef CHARACTER_CACHE_FIELDS_DO
|
||||
|
||||
jchar java_lang_Character::value(oop obj) {
|
||||
jvalue v;
|
||||
java_lang_boxing_object::get_value(obj, &v);
|
||||
return v.c;
|
||||
}
|
||||
|
||||
#define SHORT_CACHE_FIELDS_DO(macro) \
|
||||
macro(_static_cache_offset, k, "cache", java_lang_Short_array_signature, true)
|
||||
|
||||
void java_lang_Short_ShortCache::compute_offsets(InstanceKlass *k) {
|
||||
guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
|
||||
SHORT_CACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
objArrayOop java_lang_Short_ShortCache::cache(InstanceKlass *ik) {
|
||||
oop base = ik->static_field_base_raw();
|
||||
return objArrayOop(base->obj_field(_static_cache_offset));
|
||||
}
|
||||
|
||||
Symbol* java_lang_Short_ShortCache::symbol() {
|
||||
return vmSymbols::java_lang_Short_ShortCache();
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void java_lang_Short_ShortCache::serialize_offsets(SerializeClosure* f) {
|
||||
SHORT_CACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
||||
}
|
||||
#endif
|
||||
#undef SHORT_CACHE_FIELDS_DO
|
||||
|
||||
jshort java_lang_Short::value(oop obj) {
|
||||
jvalue v;
|
||||
java_lang_boxing_object::get_value(obj, &v);
|
||||
return v.s;
|
||||
}
|
||||
|
||||
#define BYTE_CACHE_FIELDS_DO(macro) \
|
||||
macro(_static_cache_offset, k, "cache", java_lang_Byte_array_signature, true)
|
||||
|
||||
void java_lang_Byte_ByteCache::compute_offsets(InstanceKlass *k) {
|
||||
guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
|
||||
BYTE_CACHE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
objArrayOop java_lang_Byte_ByteCache::cache(InstanceKlass *ik) {
|
||||
oop base = ik->static_field_base_raw();
|
||||
return objArrayOop(base->obj_field(_static_cache_offset));
|
||||
}
|
||||
|
||||
Symbol* java_lang_Byte_ByteCache::symbol() {
|
||||
return vmSymbols::java_lang_Byte_ByteCache();
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void java_lang_Byte_ByteCache::serialize_offsets(SerializeClosure* f) {
|
||||
BYTE_CACHE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
||||
}
|
||||
#endif
|
||||
#undef BYTE_CACHE_FIELDS_DO
|
||||
|
||||
jbyte java_lang_Byte::value(oop obj) {
|
||||
jvalue v;
|
||||
java_lang_boxing_object::get_value(obj, &v);
|
||||
return v.b;
|
||||
}
|
||||
#define BOOLEAN_FIELDS_DO(macro) \
|
||||
macro(_static_TRUE_offset, k, "TRUE", java_lang_Boolean_signature, true); \
|
||||
macro(_static_FALSE_offset, k, "FALSE", java_lang_Boolean_signature, true)
|
||||
|
||||
|
||||
void java_lang_Boolean::compute_offsets(InstanceKlass *k) {
|
||||
guarantee(k != NULL && k->is_initialized(), "must be loaded and initialized");
|
||||
BOOLEAN_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
oop java_lang_Boolean::get_TRUE(InstanceKlass *ik) {
|
||||
oop base = ik->static_field_base_raw();
|
||||
return base->obj_field(_static_TRUE_offset);
|
||||
}
|
||||
|
||||
oop java_lang_Boolean::get_FALSE(InstanceKlass *ik) {
|
||||
oop base = ik->static_field_base_raw();
|
||||
return base->obj_field(_static_FALSE_offset);
|
||||
}
|
||||
|
||||
Symbol* java_lang_Boolean::symbol() {
|
||||
return vmSymbols::java_lang_Boolean();
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void java_lang_Boolean::serialize_offsets(SerializeClosure* f) {
|
||||
BOOLEAN_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
||||
}
|
||||
#endif
|
||||
#undef BOOLEAN_CACHE_FIELDS_DO
|
||||
|
||||
jboolean java_lang_Boolean::value(oop obj) {
|
||||
jvalue v;
|
||||
java_lang_boxing_object::get_value(obj, &v);
|
||||
return v.z;
|
||||
}
|
||||
|
||||
static int member_offset(int hardcoded_offset) {
|
||||
return (hardcoded_offset * heapOopSize) + instanceOopDesc::base_offset_in_bytes();
|
||||
}
|
||||
|
@ -1497,6 +1497,94 @@ class jdk_internal_misc_UnsafeConstants : AllStatic {
|
||||
static void serialize_offsets(SerializeClosure* f) { }
|
||||
};
|
||||
|
||||
class java_lang_Integer : AllStatic {
|
||||
public:
|
||||
static jint value(oop obj);
|
||||
};
|
||||
|
||||
class java_lang_Long : AllStatic {
|
||||
public:
|
||||
static jlong value(oop obj);
|
||||
};
|
||||
|
||||
class java_lang_Character : AllStatic {
|
||||
public:
|
||||
static jchar value(oop obj);
|
||||
};
|
||||
|
||||
class java_lang_Short : AllStatic {
|
||||
public:
|
||||
static jshort value(oop obj);
|
||||
};
|
||||
|
||||
class java_lang_Byte : AllStatic {
|
||||
public:
|
||||
static jbyte value(oop obj);
|
||||
};
|
||||
|
||||
class java_lang_Boolean : AllStatic {
|
||||
private:
|
||||
static int _static_TRUE_offset;
|
||||
static int _static_FALSE_offset;
|
||||
public:
|
||||
static Symbol* symbol();
|
||||
static void compute_offsets(InstanceKlass* k);
|
||||
static oop get_TRUE(InstanceKlass *k);
|
||||
static oop get_FALSE(InstanceKlass *k);
|
||||
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
static jboolean value(oop obj);
|
||||
};
|
||||
|
||||
class java_lang_Integer_IntegerCache : AllStatic {
|
||||
private:
|
||||
static int _static_cache_offset;
|
||||
public:
|
||||
static Symbol* symbol();
|
||||
static void compute_offsets(InstanceKlass* k);
|
||||
static objArrayOop cache(InstanceKlass *k);
|
||||
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
class java_lang_Long_LongCache : AllStatic {
|
||||
private:
|
||||
static int _static_cache_offset;
|
||||
public:
|
||||
static Symbol* symbol();
|
||||
static void compute_offsets(InstanceKlass* k);
|
||||
static objArrayOop cache(InstanceKlass *k);
|
||||
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
class java_lang_Character_CharacterCache : AllStatic {
|
||||
private:
|
||||
static int _static_cache_offset;
|
||||
public:
|
||||
static Symbol* symbol();
|
||||
static void compute_offsets(InstanceKlass* k);
|
||||
static objArrayOop cache(InstanceKlass *k);
|
||||
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
class java_lang_Short_ShortCache : AllStatic {
|
||||
private:
|
||||
static int _static_cache_offset;
|
||||
public:
|
||||
static Symbol* symbol();
|
||||
static void compute_offsets(InstanceKlass* k);
|
||||
static objArrayOop cache(InstanceKlass *k);
|
||||
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
class java_lang_Byte_ByteCache : AllStatic {
|
||||
private:
|
||||
static int _static_cache_offset;
|
||||
public:
|
||||
static Symbol* symbol();
|
||||
static void compute_offsets(InstanceKlass* k);
|
||||
static objArrayOop cache(InstanceKlass *k);
|
||||
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
// Use to declare fields that need to be injected into Java classes
|
||||
// for the JVM to use. The name_index and signature_index are
|
||||
// declared in vmSymbols. The may_be_java flag is used to declare
|
||||
|
@ -442,6 +442,11 @@
|
||||
template(getProtectionDomain_name, "getProtectionDomain") \
|
||||
template(getProtectionDomain_signature, "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \
|
||||
template(java_lang_Integer_array_signature, "[Ljava/lang/Integer;") \
|
||||
template(java_lang_Long_array_signature, "[Ljava/lang/Long;") \
|
||||
template(java_lang_Character_array_signature, "[Ljava/lang/Character;") \
|
||||
template(java_lang_Short_array_signature, "[Ljava/lang/Short;") \
|
||||
template(java_lang_Byte_array_signature, "[Ljava/lang/Byte;") \
|
||||
template(java_lang_Boolean_signature, "Ljava/lang/Boolean;") \
|
||||
template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \
|
||||
template(module_entry_name, "module_entry") \
|
||||
template(resolved_references_name, "<resolved_references>") \
|
||||
|
@ -56,7 +56,7 @@ oop DebugInfoReadStream::read_oop() {
|
||||
return o;
|
||||
}
|
||||
|
||||
ScopeValue* DebugInfoReadStream::read_object_value() {
|
||||
ScopeValue* DebugInfoReadStream::read_object_value(bool is_auto_box) {
|
||||
int id = read_int();
|
||||
#ifdef ASSERT
|
||||
assert(_obj_pool != NULL, "object pool does not exist");
|
||||
@ -64,7 +64,7 @@ ScopeValue* DebugInfoReadStream::read_object_value() {
|
||||
assert(_obj_pool->at(i)->as_ObjectValue()->id() != id, "should not be read twice");
|
||||
}
|
||||
#endif
|
||||
ObjectValue* result = new ObjectValue(id);
|
||||
ObjectValue* result = is_auto_box ? new AutoBoxObjectValue(id) : new ObjectValue(id);
|
||||
// Cache the object since an object field could reference it.
|
||||
_obj_pool->push(result);
|
||||
result->read_object(this);
|
||||
@ -88,18 +88,20 @@ ScopeValue* DebugInfoReadStream::get_cached_object() {
|
||||
|
||||
enum { LOCATION_CODE = 0, CONSTANT_INT_CODE = 1, CONSTANT_OOP_CODE = 2,
|
||||
CONSTANT_LONG_CODE = 3, CONSTANT_DOUBLE_CODE = 4,
|
||||
OBJECT_CODE = 5, OBJECT_ID_CODE = 6 };
|
||||
OBJECT_CODE = 5, OBJECT_ID_CODE = 6,
|
||||
AUTO_BOX_OBJECT_CODE = 7 };
|
||||
|
||||
ScopeValue* ScopeValue::read_from(DebugInfoReadStream* stream) {
|
||||
ScopeValue* result = NULL;
|
||||
switch(stream->read_int()) {
|
||||
case LOCATION_CODE: result = new LocationValue(stream); break;
|
||||
case CONSTANT_INT_CODE: result = new ConstantIntValue(stream); break;
|
||||
case CONSTANT_OOP_CODE: result = new ConstantOopReadValue(stream); break;
|
||||
case CONSTANT_LONG_CODE: result = new ConstantLongValue(stream); break;
|
||||
case CONSTANT_DOUBLE_CODE: result = new ConstantDoubleValue(stream); break;
|
||||
case OBJECT_CODE: result = stream->read_object_value(); break;
|
||||
case OBJECT_ID_CODE: result = stream->get_cached_object(); break;
|
||||
case LOCATION_CODE: result = new LocationValue(stream); break;
|
||||
case CONSTANT_INT_CODE: result = new ConstantIntValue(stream); break;
|
||||
case CONSTANT_OOP_CODE: result = new ConstantOopReadValue(stream); break;
|
||||
case CONSTANT_LONG_CODE: result = new ConstantLongValue(stream); break;
|
||||
case CONSTANT_DOUBLE_CODE: result = new ConstantDoubleValue(stream); break;
|
||||
case OBJECT_CODE: result = stream->read_object_value(false /*is_auto_box*/); break;
|
||||
case AUTO_BOX_OBJECT_CODE: result = stream->read_object_value(true /*is_auto_box*/); break;
|
||||
case OBJECT_ID_CODE: result = stream->get_cached_object(); break;
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
return result;
|
||||
@ -142,7 +144,7 @@ void ObjectValue::write_on(DebugInfoWriteStream* stream) {
|
||||
stream->write_int(_id);
|
||||
} else {
|
||||
_visited = true;
|
||||
stream->write_int(OBJECT_CODE);
|
||||
stream->write_int(is_auto_box() ? AUTO_BOX_OBJECT_CODE : OBJECT_CODE);
|
||||
stream->write_int(_id);
|
||||
_klass->write_on(stream);
|
||||
int length = _field_values.length();
|
||||
@ -154,7 +156,7 @@ void ObjectValue::write_on(DebugInfoWriteStream* stream) {
|
||||
}
|
||||
|
||||
void ObjectValue::print_on(outputStream* st) const {
|
||||
st->print("obj[%d]", _id);
|
||||
st->print("%s[%d]", is_auto_box() ? "box_obj" : "obj", _id);
|
||||
}
|
||||
|
||||
void ObjectValue::print_fields_on(outputStream* st) const {
|
||||
|
@ -49,6 +49,7 @@ class ScopeValue: public ResourceObj {
|
||||
// Testers
|
||||
virtual bool is_location() const { return false; }
|
||||
virtual bool is_object() const { return false; }
|
||||
virtual bool is_auto_box() const { return false; }
|
||||
virtual bool is_constant_int() const { return false; }
|
||||
virtual bool is_constant_double() const { return false; }
|
||||
virtual bool is_constant_long() const { return false; }
|
||||
@ -94,13 +95,12 @@ class LocationValue: public ScopeValue {
|
||||
// An ObjectValue describes an object eliminated by escape analysis.
|
||||
|
||||
class ObjectValue: public ScopeValue {
|
||||
private:
|
||||
protected:
|
||||
int _id;
|
||||
ScopeValue* _klass;
|
||||
GrowableArray<ScopeValue*> _field_values;
|
||||
Handle _value;
|
||||
bool _visited;
|
||||
|
||||
public:
|
||||
ObjectValue(int id, ScopeValue* klass)
|
||||
: _id(id)
|
||||
@ -140,6 +140,16 @@ class ObjectValue: public ScopeValue {
|
||||
void print_fields_on(outputStream* st) const;
|
||||
};
|
||||
|
||||
class AutoBoxObjectValue : public ObjectValue {
|
||||
bool _cached;
|
||||
public:
|
||||
bool is_auto_box() const { return true; }
|
||||
bool is_cached() const { return _cached; }
|
||||
void set_cached(bool cached) { _cached = cached; }
|
||||
AutoBoxObjectValue(int id, ScopeValue* klass) : ObjectValue(id, klass), _cached(false) { }
|
||||
AutoBoxObjectValue(int id) : ObjectValue(id), _cached(false) { }
|
||||
};
|
||||
|
||||
|
||||
// A ConstantIntValue describes a constant int; i.e., the corresponding logical entity
|
||||
// is either a source constant or its computation has been constant-folded.
|
||||
@ -280,7 +290,7 @@ class DebugInfoReadStream : public CompressedReadStream {
|
||||
assert(o == NULL || o->is_metadata(), "meta data only");
|
||||
return o;
|
||||
}
|
||||
ScopeValue* read_object_value();
|
||||
ScopeValue* read_object_value(bool is_auto_box);
|
||||
ScopeValue* get_cached_object();
|
||||
// BCI encoding is mostly unsigned, but -1 is a distinguished value
|
||||
int read_bci() { return read_int() + InvocationEntryBci; }
|
||||
|
@ -988,9 +988,11 @@ GrowableArray<ScopeValue*>* CodeInstaller::record_virtual_objects(JVMCIObject de
|
||||
JVMCIObject value = JVMCIENV->get_object_at(virtualObjects, i);
|
||||
int id = jvmci_env()->get_VirtualObject_id(value);
|
||||
JVMCIObject type = jvmci_env()->get_VirtualObject_type(value);
|
||||
bool is_auto_box = jvmci_env()->get_VirtualObject_isAutoBox(value);
|
||||
Klass* klass = jvmci_env()->asKlass(type);
|
||||
oop javaMirror = klass->java_mirror();
|
||||
ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror)));
|
||||
ScopeValue *klass_sv = new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror));
|
||||
ObjectValue* sv = is_auto_box ? new AutoBoxObjectValue(id, klass_sv) : new ObjectValue(id, klass_sv);
|
||||
if (id < 0 || id >= objects->length()) {
|
||||
JVMCI_ERROR_NULL("virtual object id %d out of bounds", id);
|
||||
}
|
||||
|
@ -1213,7 +1213,7 @@ C2V_VMENTRY_NULL(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, job
|
||||
}
|
||||
}
|
||||
}
|
||||
bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), objects, CHECK_NULL);
|
||||
bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), fst.register_map(), objects, CHECK_NULL);
|
||||
Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects, realloc_failures, false);
|
||||
realloc_called = true;
|
||||
|
||||
@ -1471,7 +1471,7 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv* env, jobject, jobject _hs_
|
||||
return;
|
||||
}
|
||||
|
||||
bool realloc_failures = Deoptimization::realloc_objects(thread, fstAfterDeopt.current(), objects, CHECK);
|
||||
bool realloc_failures = Deoptimization::realloc_objects(thread, fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, CHECK);
|
||||
Deoptimization::reassign_fields(fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, realloc_failures, false);
|
||||
|
||||
for (int frame_index = 0; frame_index < virtualFrames->length(); frame_index++) {
|
||||
|
@ -309,6 +309,7 @@
|
||||
end_class \
|
||||
start_class(VirtualObject, jdk_vm_ci_code_VirtualObject) \
|
||||
int_field(VirtualObject, id) \
|
||||
boolean_field(VirtualObject, isAutoBox) \
|
||||
object_field(VirtualObject, type, "Ljdk/vm/ci/meta/ResolvedJavaType;") \
|
||||
objectarray_field(VirtualObject, values, "[Ljdk/vm/ci/meta/JavaValue;") \
|
||||
objectarray_field(VirtualObject, slotKinds, "[Ljdk/vm/ci/meta/JavaKind;") \
|
||||
|
@ -50,7 +50,10 @@
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/compilationPolicy.hpp"
|
||||
#include "runtime/deoptimization.hpp"
|
||||
#include "runtime/fieldDescriptor.hpp"
|
||||
#include "runtime/fieldDescriptor.inline.hpp"
|
||||
#include "runtime/frame.inline.hpp"
|
||||
#include "runtime/jniHandles.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "runtime/safepointVerifiers.hpp"
|
||||
@ -232,7 +235,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
||||
}
|
||||
if (objects != NULL) {
|
||||
JRT_BLOCK
|
||||
realloc_failures = realloc_objects(thread, &deoptee, objects, THREAD);
|
||||
realloc_failures = realloc_objects(thread, &deoptee, &map, objects, THREAD);
|
||||
JRT_END
|
||||
bool skip_internal = (cm != NULL) && !cm->is_compiled_by_jvmci();
|
||||
reassign_fields(&deoptee, &map, objects, realloc_failures, skip_internal);
|
||||
@ -810,8 +813,131 @@ void Deoptimization::deoptimize_all_marked() {
|
||||
Deoptimization::DeoptAction Deoptimization::_unloaded_action
|
||||
= Deoptimization::Action_reinterpret;
|
||||
|
||||
|
||||
|
||||
#if INCLUDE_JVMCI || INCLUDE_AOT
|
||||
template<typename CacheType>
|
||||
class BoxCacheBase : public CHeapObj<mtCompiler> {
|
||||
protected:
|
||||
static InstanceKlass* find_cache_klass(Symbol* klass_name, TRAPS) {
|
||||
ResourceMark rm;
|
||||
char* klass_name_str = klass_name->as_C_string();
|
||||
Klass* k = SystemDictionary::find(klass_name, Handle(), Handle(), THREAD);
|
||||
guarantee(k != NULL, "%s must be loaded", klass_name_str);
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
guarantee(ik->is_initialized(), "%s must be initialized", klass_name_str);
|
||||
CacheType::compute_offsets(ik);
|
||||
return ik;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename PrimitiveType, typename CacheType, typename BoxType> class BoxCache : public BoxCacheBase<CacheType> {
|
||||
PrimitiveType _low;
|
||||
PrimitiveType _high;
|
||||
jobject _cache;
|
||||
protected:
|
||||
static BoxCache<PrimitiveType, CacheType, BoxType> *_singleton;
|
||||
BoxCache(Thread* thread) {
|
||||
InstanceKlass* ik = BoxCacheBase<CacheType>::find_cache_klass(CacheType::symbol(), thread);
|
||||
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);
|
||||
}
|
||||
public:
|
||||
static BoxCache<PrimitiveType, CacheType, BoxType>* singleton(Thread* thread) {
|
||||
if (_singleton == NULL) {
|
||||
BoxCache<PrimitiveType, CacheType, BoxType>* s = new BoxCache<PrimitiveType, CacheType, BoxType>(thread);
|
||||
if (!Atomic::replace_if_null(s, &_singleton)) {
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
return _singleton;
|
||||
}
|
||||
oop lookup(PrimitiveType value) {
|
||||
if (_low <= value && value <= _high) {
|
||||
int offset = value - _low;
|
||||
return objArrayOop(JNIHandles::resolve_non_null(_cache))->obj_at(offset);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
typedef BoxCache<jint, java_lang_Integer_IntegerCache, java_lang_Integer> IntegerBoxCache;
|
||||
typedef BoxCache<jlong, java_lang_Long_LongCache, java_lang_Long> LongBoxCache;
|
||||
typedef BoxCache<jchar, java_lang_Character_CharacterCache, java_lang_Character> CharacterBoxCache;
|
||||
typedef BoxCache<jshort, java_lang_Short_ShortCache, java_lang_Short> ShortBoxCache;
|
||||
typedef BoxCache<jbyte, java_lang_Byte_ByteCache, java_lang_Byte> ByteBoxCache;
|
||||
|
||||
template<> BoxCache<jint, java_lang_Integer_IntegerCache, java_lang_Integer>* BoxCache<jint, java_lang_Integer_IntegerCache, java_lang_Integer>::_singleton = NULL;
|
||||
template<> BoxCache<jlong, java_lang_Long_LongCache, java_lang_Long>* BoxCache<jlong, java_lang_Long_LongCache, java_lang_Long>::_singleton = NULL;
|
||||
template<> BoxCache<jchar, java_lang_Character_CharacterCache, java_lang_Character>* BoxCache<jchar, java_lang_Character_CharacterCache, java_lang_Character>::_singleton = NULL;
|
||||
template<> BoxCache<jshort, java_lang_Short_ShortCache, java_lang_Short>* BoxCache<jshort, java_lang_Short_ShortCache, java_lang_Short>::_singleton = NULL;
|
||||
template<> BoxCache<jbyte, java_lang_Byte_ByteCache, java_lang_Byte>* BoxCache<jbyte, java_lang_Byte_ByteCache, java_lang_Byte>::_singleton = NULL;
|
||||
|
||||
class BooleanBoxCache : public BoxCacheBase<java_lang_Boolean> {
|
||||
jobject _true_cache;
|
||||
jobject _false_cache;
|
||||
protected:
|
||||
static BooleanBoxCache *_singleton;
|
||||
BooleanBoxCache(Thread *thread) {
|
||||
InstanceKlass* ik = find_cache_klass(java_lang_Boolean::symbol(), thread);
|
||||
_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);
|
||||
JNIHandles::destroy_global(_false_cache);
|
||||
}
|
||||
public:
|
||||
static BooleanBoxCache* singleton(Thread* thread) {
|
||||
if (_singleton == NULL) {
|
||||
BooleanBoxCache* s = new BooleanBoxCache(thread);
|
||||
if (!Atomic::replace_if_null(s, &_singleton)) {
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
return _singleton;
|
||||
}
|
||||
oop lookup(jboolean value) {
|
||||
if (value != 0) {
|
||||
return JNIHandles::resolve_non_null(_true_cache);
|
||||
}
|
||||
return JNIHandles::resolve_non_null(_false_cache);
|
||||
}
|
||||
};
|
||||
|
||||
BooleanBoxCache* BooleanBoxCache::_singleton = NULL;
|
||||
|
||||
oop Deoptimization::get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, TRAPS) {
|
||||
Klass* k = java_lang_Class::as_Klass(bv->klass()->as_ConstantOopReadValue()->value()());
|
||||
BasicType box_type = SystemDictionary::box_klass_type(k);
|
||||
if (box_type != T_OBJECT) {
|
||||
StackValue* value = StackValue::create_stack_value(fr, reg_map, bv->field_at(0));
|
||||
switch(box_type) {
|
||||
case T_INT: return IntegerBoxCache::singleton(THREAD)->lookup(value->get_int());
|
||||
case T_LONG: {
|
||||
StackValue* low = StackValue::create_stack_value(fr, reg_map, bv->field_at(1));
|
||||
jlong res = (jlong)low->get_int();
|
||||
return LongBoxCache::singleton(THREAD)->lookup(res);
|
||||
}
|
||||
case T_CHAR: return CharacterBoxCache::singleton(THREAD)->lookup(value->get_int());
|
||||
case T_SHORT: return ShortBoxCache::singleton(THREAD)->lookup(value->get_int());
|
||||
case T_BYTE: return ByteBoxCache::singleton(THREAD)->lookup(value->get_int());
|
||||
case T_BOOLEAN: return BooleanBoxCache::singleton(THREAD)->lookup(value->get_int());
|
||||
default:;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif // INCLUDE_JVMCI || INCLUDE_AOT
|
||||
|
||||
#if COMPILER2_OR_JVMCI
|
||||
bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS) {
|
||||
bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, TRAPS) {
|
||||
Handle pending_exception(THREAD, thread->pending_exception());
|
||||
const char* exception_file = thread->exception_file();
|
||||
int exception_line = thread->exception_line();
|
||||
@ -827,8 +953,21 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArra
|
||||
oop obj = NULL;
|
||||
|
||||
if (k->is_instance_klass()) {
|
||||
#if INCLUDE_JVMCI || INCLUDE_AOT
|
||||
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);
|
||||
if (obj != NULL) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_JVMCI || INCLUDE_AOT
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
obj = ik->allocate_instance(THREAD);
|
||||
if (obj == NULL) {
|
||||
obj = ik->allocate_instance(THREAD);
|
||||
}
|
||||
} else if (k->is_typeArray_klass()) {
|
||||
TypeArrayKlass* ak = TypeArrayKlass::cast(k);
|
||||
assert(sv->field_size() % type2size[ak->element_type()] == 0, "non-integral array length");
|
||||
@ -1101,7 +1240,12 @@ void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableAr
|
||||
if (obj.is_null()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if INCLUDE_JVMCI || INCLUDE_AOT
|
||||
// Don't reassign fields of boxes that came from a cache. Caches may be in CDS.
|
||||
if (sv->is_auto_box() && ((AutoBoxObjectValue*) sv)->is_cached()) {
|
||||
continue;
|
||||
}
|
||||
#endif // INCLUDE_JVMCI || INCLUDE_AOT
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
reassign_fields_by_klass(ik, fr, reg_map, sv, 0, obj(), skip_internal);
|
||||
|
@ -33,6 +33,7 @@ class vframeArray;
|
||||
class MonitorInfo;
|
||||
class MonitorValue;
|
||||
class ObjectValue;
|
||||
class AutoBoxObjectValue;
|
||||
class ScopeValue;
|
||||
class compiledVFrame;
|
||||
|
||||
@ -153,6 +154,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);
|
||||
#endif
|
||||
|
||||
private:
|
||||
@ -169,7 +171,7 @@ class Deoptimization : AllStatic {
|
||||
JVMCI_ONLY(public:)
|
||||
|
||||
// Support for restoring non-escaping objects
|
||||
static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS);
|
||||
static bool realloc_objects(JavaThread* thread, frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, TRAPS);
|
||||
static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type);
|
||||
static void reassign_object_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, objArrayOop obj);
|
||||
static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures, bool skip_internal);
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm.h"
|
||||
#include "aot/aotLoader.hpp"
|
||||
#include "classfile/classLoader.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/moduleEntry.hpp"
|
||||
@ -3650,6 +3651,9 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) {
|
||||
initialize_class(vmSymbols::java_lang_StackOverflowError(), CHECK);
|
||||
initialize_class(vmSymbols::java_lang_IllegalMonitorStateException(), CHECK);
|
||||
initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK);
|
||||
|
||||
// Eager box cache initialization only if AOT is on and any library is loaded.
|
||||
AOTLoader::initialize_box_caches(CHECK);
|
||||
}
|
||||
|
||||
void Threads::initialize_jsr292_core_classes(TRAPS) {
|
||||
@ -3912,6 +3916,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||
Chunk::start_chunk_pool_cleaner_task();
|
||||
}
|
||||
|
||||
|
||||
// initialize compiler(s)
|
||||
#if defined(COMPILER1) || COMPILER2_OR_JVMCI
|
||||
#if INCLUDE_JVMCI
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -43,6 +43,7 @@ public final class VirtualObject implements JavaValue {
|
||||
private JavaValue[] values;
|
||||
private JavaKind[] slotKinds;
|
||||
private final int id;
|
||||
private boolean isAutoBox;
|
||||
|
||||
/**
|
||||
* Creates a new {@link VirtualObject} for the given type, with the given fields. If
|
||||
@ -58,12 +59,33 @@ public final class VirtualObject implements JavaValue {
|
||||
* @return a new {@link VirtualObject} instance.
|
||||
*/
|
||||
public static VirtualObject get(ResolvedJavaType type, int id) {
|
||||
return new VirtualObject(type, id);
|
||||
return new VirtualObject(type, id, false);
|
||||
}
|
||||
|
||||
private VirtualObject(ResolvedJavaType type, int id) {
|
||||
/**
|
||||
* Creates a new {@link VirtualObject} for the given type, with the given fields. If
|
||||
* {@code type} is an instance class then {@code values} provides the values for the fields
|
||||
* returned by {@link ResolvedJavaType#getInstanceFields(boolean) getInstanceFields(true)}. If
|
||||
* {@code type} is an array then the length of the values array determines the reallocated array
|
||||
* length.
|
||||
*
|
||||
* @param type the type of the object whose allocation was removed during compilation. This can
|
||||
* be either an instance of an array type.
|
||||
* @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 instance.
|
||||
* @return a new {@link VirtualObject} instance.
|
||||
*/
|
||||
public static VirtualObject get(ResolvedJavaType type, int id, boolean isAutoBox) {
|
||||
return new VirtualObject(type, id, isAutoBox);
|
||||
}
|
||||
|
||||
private VirtualObject(ResolvedJavaType type, int id, boolean isAutoBox) {
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
this.isAutoBox = isAutoBox;
|
||||
}
|
||||
|
||||
private static StringBuilder appendValue(StringBuilder buf, JavaValue value, Set<VirtualObject> visited) {
|
||||
@ -143,6 +165,23 @@ public final class VirtualObject implements JavaValue {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the object is a box. For boxes the deoptimization would check if the value of
|
||||
* the box is in the cache range and try to return a cached object.
|
||||
*/
|
||||
public boolean isAutoBox() {
|
||||
return isAutoBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the box flag.
|
||||
* @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 instance.
|
||||
*/
|
||||
public void setIsAutoBox(boolean isAutoBox) {
|
||||
this.isAutoBox = isAutoBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the current set of values with a new one.
|
||||
*
|
||||
|
@ -187,6 +187,9 @@ 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).
|
||||
Object[] boxCaches = { Boolean.valueOf(false), Byte.valueOf((byte)0), Short.valueOf((short) 0), Character.valueOf((char) 0), Integer.valueOf(0), Long.valueOf(0) };
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -43,7 +43,9 @@ import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.spi.NodeValueMap;
|
||||
import org.graalvm.compiler.nodes.util.GraphUtil;
|
||||
import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
|
||||
import org.graalvm.compiler.nodes.virtual.VirtualBoxingNode;
|
||||
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
|
||||
import org.graalvm.compiler.serviceprovider.GraalServices;
|
||||
import org.graalvm.compiler.virtual.nodes.MaterializedObjectState;
|
||||
import org.graalvm.compiler.virtual.nodes.VirtualObjectState;
|
||||
|
||||
@ -154,6 +156,10 @@ public class DebugInfoBuilder {
|
||||
}
|
||||
assert checkValues(vobjValue.getType(), values, slotKinds);
|
||||
vobjValue.setValues(values, slotKinds);
|
||||
|
||||
if (vobjNode instanceof VirtualBoxingNode) {
|
||||
GraalServices.markVirtualObjectAsAutoBox(vobjValue);
|
||||
}
|
||||
}
|
||||
|
||||
virtualObjectsArray = new VirtualObject[virtualObjects.size()];
|
||||
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot.test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
public class BoxDeoptimizationTest extends GraalCompilerTest {
|
||||
private static boolean isJDK13OrLater = JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 13;
|
||||
|
||||
public static void testInteger() {
|
||||
Object[] values = {42, new Exception()};
|
||||
GraalDirectives.deoptimize();
|
||||
Assert.assertSame(values[0], Integer.valueOf(42));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
Assume.assumeTrue(isJDK13OrLater);
|
||||
test("testInteger");
|
||||
}
|
||||
|
||||
public static void testLong() {
|
||||
Object[] values = {42L, new Exception()};
|
||||
GraalDirectives.deoptimize();
|
||||
Assert.assertSame(values[0], Long.valueOf(42));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
Assume.assumeTrue(isJDK13OrLater);
|
||||
test("testLong");
|
||||
}
|
||||
|
||||
public static void testChar() {
|
||||
Object[] values = {'a', new Exception()};
|
||||
GraalDirectives.deoptimize();
|
||||
Assert.assertSame(values[0], Character.valueOf('a'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3() {
|
||||
Assume.assumeTrue(isJDK13OrLater);
|
||||
test("testChar");
|
||||
}
|
||||
|
||||
public static void testShort() {
|
||||
Object[] values = {(short) 42, new Exception()};
|
||||
GraalDirectives.deoptimize();
|
||||
Assert.assertSame(values[0], Short.valueOf((short) 42));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4() {
|
||||
Assume.assumeTrue(isJDK13OrLater);
|
||||
test("testShort");
|
||||
}
|
||||
|
||||
public static void testByte() {
|
||||
Object[] values = {(byte) 42, new Exception()};
|
||||
GraalDirectives.deoptimize();
|
||||
Assert.assertSame(values[0], Byte.valueOf((byte) 42));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test5() {
|
||||
Assume.assumeTrue(isJDK13OrLater);
|
||||
test("testByte");
|
||||
}
|
||||
|
||||
public static void testBoolean() {
|
||||
Object[] values = {true, new Exception()};
|
||||
GraalDirectives.deoptimize();
|
||||
Assert.assertSame(values[0], Boolean.valueOf(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test6() {
|
||||
Assume.assumeTrue(isJDK13OrLater);
|
||||
test("testBoolean");
|
||||
}
|
||||
}
|
@ -42,6 +42,7 @@ import java.util.function.Supplier;
|
||||
import org.graalvm.compiler.serviceprovider.SpeculationReasonGroup.SpeculationContextObject;
|
||||
|
||||
import jdk.vm.ci.code.BytecodePosition;
|
||||
import jdk.vm.ci.code.VirtualObject;
|
||||
import jdk.vm.ci.meta.ResolvedJavaField;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
@ -519,4 +520,12 @@ public final class GraalServices {
|
||||
public static double fma(double a, double b, double c) {
|
||||
return Math.fma(a, b, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag in the {@link VirtualObject} that indicates that it is a boxed primitive that
|
||||
* was produced as a result of a call to a {@code valueOf} method.
|
||||
*/
|
||||
public static void markVirtualObjectAsAutoBox(VirtualObject virtualObject) {
|
||||
virtualObject.setIsAutoBox(true);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user