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:
Igor Veresov 2019-06-03 13:21:02 -07:00
parent 7d63888ac8
commit e47daab7b4
18 changed files with 666 additions and 26 deletions

View file

@ -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);