Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
8279822: CI: Constant pool entries in error state are not supported
Reviewed-by: goetz
Backport-of: c5c8c0644d9442846de15422285fffeb91c3e0a1
  • Loading branch information
TheRealMDoerr committed Apr 8, 2022
1 parent fcc1cc6 commit da9aa23
Show file tree
Hide file tree
Showing 10 changed files with 403 additions and 90 deletions.
6 changes: 3 additions & 3 deletions src/hotspot/share/ci/bcEscapeAnalyzer.cpp
Expand Up @@ -416,11 +416,11 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl
// Avoid calling get_constant() which will try to allocate
// unloaded constant. We need only constant's type.
int index = s.get_constant_pool_index();
constantTag tag = s.get_constant_pool_tag(index);
if (tag.is_long() || tag.is_double()) {
BasicType con_bt = s.get_basic_type_for_constant_at(index);
if (con_bt == T_LONG || con_bt == T_DOUBLE) {
// Only longs and doubles use 2 stack slots.
state.lpush();
} else if (tag.basic_type() == T_OBJECT) {
} else if (con_bt == T_OBJECT) {
state.apush(unknown_obj);
} else {
state.spush();
Expand Down
11 changes: 11 additions & 0 deletions src/hotspot/share/ci/ciConstant.hpp
Expand Up @@ -127,6 +127,17 @@ class ciConstant {
bool is_valid() const {
return basic_type() != T_ILLEGAL;
}

bool is_loaded() const {
if (is_valid()) {
if (is_reference_type(basic_type())) {
return as_object()->is_loaded();
} else {
return true;
}
}
return false;
}
// Debugging output
void print();
};
Expand Down
40 changes: 14 additions & 26 deletions src/hotspot/share/ci/ciEnv.cpp
Expand Up @@ -432,13 +432,6 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
domain = Handle(current, accessing_klass->protection_domain());
}

// setup up the proper type to return on OOM
ciKlass* fail_type;
if (sym->char_at(0) == JVM_SIGNATURE_ARRAY) {
fail_type = _unloaded_ciobjarrayklass;
} else {
fail_type = _unloaded_ciinstance_klass;
}
Klass* found_klass;
{
ttyUnlocker ttyul; // release tty lock to avoid ordering problems
Expand Down Expand Up @@ -520,15 +513,14 @@ ciKlass* ciEnv::get_klass_by_index_impl(const constantPoolHandle& cpool,
int index,
bool& is_accessible,
ciInstanceKlass* accessor) {
EXCEPTION_CONTEXT;
Klass* klass = NULL;
Symbol* klass_name = NULL;

if (cpool->tag_at(index).is_symbol()) {
klass_name = cpool->symbol_at(index);
} else {
// Check if it's resolved if it's not a symbol constant pool entry.
klass = ConstantPool::klass_at_if_loaded(cpool, index);
klass = ConstantPool::klass_at_if_loaded(cpool, index);
// Try to look it up by name.
if (klass == NULL) {
klass_name = cpool->klass_name_at(index);
Expand Down Expand Up @@ -588,7 +580,6 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
int pool_index, int cache_index,
ciInstanceKlass* accessor) {
bool ignore_will_link;
EXCEPTION_CONTEXT;
int index = pool_index;
if (cache_index >= 0) {
assert(index < 0, "only one kind of index at a time");
Expand All @@ -599,12 +590,14 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
return ciConstant(T_OBJECT, get_object(NULL));
}
BasicType bt = T_OBJECT;
if (cpool->tag_at(index).is_dynamic_constant())
if (cpool->tag_at(index).is_dynamic_constant()) {
bt = Signature::basic_type(cpool->uncached_signature_ref_at(index));
if (is_reference_type(bt)) {
} else {
}
if (!is_reference_type(bt)) {
// we have to unbox the primitive value
if (!is_java_primitive(bt)) return ciConstant();
if (!is_java_primitive(bt)) {
return ciConstant();
}
jvalue value;
BasicType bt2 = java_lang_boxing_object::get_value(obj, &value);
assert(bt2 == bt, "");
Expand Down Expand Up @@ -639,6 +632,7 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
} else if (tag.is_double()) {
return ciConstant((jdouble)cpool->double_at(index));
} else if (tag.is_string()) {
EXCEPTION_CONTEXT;
oop string = NULL;
assert(cache_index >= 0, "should have a cache index");
string = cpool->string_at(index, cache_index, THREAD);
Expand All @@ -655,24 +649,18 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
return ciConstant(T_OBJECT, constant);
}
} else if (tag.is_unresolved_klass_in_error()) {
return ciConstant();
return ciConstant(T_OBJECT, get_unloaded_klass_mirror(NULL));
} else if (tag.is_klass() || tag.is_unresolved_klass()) {
// 4881222: allow ldc to take a class type
ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore_will_link, accessor);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
record_out_of_memory_failure();
return ciConstant();
}
assert (klass->is_instance_klass() || klass->is_array_klass(),
"must be an instance or array klass ");
return ciConstant(T_OBJECT, klass->java_mirror());
} else if (tag.is_method_type()) {
} else if (tag.is_method_type() || tag.is_method_type_in_error()) {
// must execute Java code to link this CP entry into cache[i].f1
ciSymbol* signature = get_symbol(cpool->method_type_signature_at(index));
ciObject* ciobj = get_unloaded_method_type_constant(signature);
return ciConstant(T_OBJECT, ciobj);
} else if (tag.is_method_handle()) {
} else if (tag.is_method_handle() || tag.is_method_handle_in_error()) {
// must execute Java code to link this CP entry into cache[i].f1
int ref_kind = cpool->method_handle_ref_kind_at(index);
int callee_index = cpool->method_handle_klass_index_at(index);
Expand All @@ -681,10 +669,10 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
ciSymbol* signature = get_symbol(cpool->method_handle_signature_ref_at(index));
ciObject* ciobj = get_unloaded_method_handle_constant(callee, name, signature, ref_kind);
return ciConstant(T_OBJECT, ciobj);
} else if (tag.is_dynamic_constant()) {
return ciConstant();
} else if (tag.is_dynamic_constant() || tag.is_dynamic_constant_in_error()) {
return ciConstant(); // not supported
} else {
ShouldNotReachHere();
assert(false, "unknown tag: %d (%s)", tag.value(), tag.internal_name());
return ciConstant();
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/hotspot/share/ci/ciStreams.cpp
Expand Up @@ -251,6 +251,14 @@ constantTag ciBytecodeStream::get_constant_pool_tag(int index) const {
return _method->get_Method()->constants()->constant_tag_at(index);
}

// ------------------------------------------------------------------
// ciBytecodeStream::get_basic_type_for_constant_at
//
BasicType ciBytecodeStream::get_basic_type_for_constant_at(int index) const {
VM_ENTRY_MARK;
return _method->get_Method()->constants()->basic_type_for_constant_at(index);
}

// ------------------------------------------------------------------
// ciBytecodeStream::get_field_index
//
Expand Down
19 changes: 14 additions & 5 deletions src/hotspot/share/ci/ciStreams.hpp
Expand Up @@ -140,7 +140,7 @@ class ciBytecodeStream : StackObj {

bool is_wide() const { return ( _pc == _was_wide ); }

// Does this instruction contain an index which refes into the CP cache?
// Does this instruction contain an index which refers into the CP cache?
bool has_cache_index() const { return Bytecodes::uses_cp_cache(cur_bc_raw()); }

int get_index_u1() const {
Expand Down Expand Up @@ -224,18 +224,27 @@ class ciBytecodeStream : StackObj {
// constant. Do not attempt to resolve it, since that would require
// execution of Java code. If it is not resolved, return an unloaded
// object (ciConstant.as_object()->is_loaded() == false).
ciConstant get_constant();
ciConstant get_constant();
constantTag get_constant_pool_tag(int index) const;
BasicType get_basic_type_for_constant_at(int index) const;

// True if the klass-using bytecode points to an unresolved klass
bool is_unresolved_klass() const {
constantTag tag = get_constant_pool_tag(get_klass_index());
return tag.is_unresolved_klass();
}

bool is_unresolved_klass_in_error() const {
constantTag tag = get_constant_pool_tag(get_klass_index());
return tag.is_unresolved_klass_in_error();
bool is_in_error() const {
assert(cur_bc() == Bytecodes::_ldc ||
cur_bc() == Bytecodes::_ldc_w ||
cur_bc() == Bytecodes::_ldc2_w, "not supported: %s", Bytecodes::name(cur_bc()));

int index = get_constant_pool_index();
constantTag tag = get_constant_pool_tag(index);
return tag.is_unresolved_klass_in_error() ||
tag.is_method_handle_in_error() ||
tag.is_method_type_in_error() ||
tag.is_dynamic_constant_in_error();
}

// If this bytecode is one of get_field, get_static, put_field,
Expand Down
19 changes: 10 additions & 9 deletions src/hotspot/share/ci/ciTypeFlow.cpp
Expand Up @@ -720,6 +720,11 @@ void ciTypeFlow::StateVector::do_jsr(ciBytecodeStream* str) {
// ------------------------------------------------------------------
// ciTypeFlow::StateVector::do_ldc
void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) {
if (str->is_in_error()) {
trap(str, NULL, Deoptimization::make_trap_request(Deoptimization::Reason_unhandled,
Deoptimization::Action_none));
return;
}
ciConstant con = str->get_constant();
if (con.is_valid()) {
BasicType basic_type = con.basic_type();
Expand All @@ -735,14 +740,10 @@ void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) {
push_translate(ciType::make(basic_type));
}
} else {
if (str->is_unresolved_klass_in_error()) {
trap(str, NULL, Deoptimization::make_trap_request(Deoptimization::Reason_unhandled,
Deoptimization::Action_none));
} else {
// OutOfMemoryError in the CI while loading constant
push_null();
outer()->record_failure("ldc did not link");
}
// OutOfMemoryError in the CI while loading constant.
// Unresolved condy also lands here (not yet supported).
push_null();
outer()->record_failure("ldc did not link");
}
}

Expand Down Expand Up @@ -2173,7 +2174,7 @@ bool ciTypeFlow::can_trap(ciBytecodeStream& str) {
case Bytecodes::_ldc:
case Bytecodes::_ldc_w:
case Bytecodes::_ldc2_w:
return str.is_unresolved_klass_in_error();
return str.is_in_error();

case Bytecodes::_aload_0:
// These bytecodes can trap for rewriting. We need to assume that
Expand Down
38 changes: 18 additions & 20 deletions src/hotspot/share/oops/constantPool.cpp
Expand Up @@ -884,11 +884,9 @@ void ConstantPool::save_and_throw_exception(const constantPoolHandle& this_cp, i

constantTag ConstantPool::constant_tag_at(int which) {
constantTag tag = tag_at(which);
if (tag.is_dynamic_constant() ||
tag.is_dynamic_constant_in_error()) {
if (tag.is_dynamic_constant()) {
BasicType bt = basic_type_for_constant_at(which);
// dynamic constant could return an array, treat as object
return constantTag::ofBasicType(is_reference_type(bt) ? T_OBJECT : bt);
return constantTag(constantTag::type2tag(bt));
}
return tag;
}
Expand Down Expand Up @@ -975,7 +973,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
switch (tag.value()) {

case JVM_CONSTANT_UnresolvedClass:
case JVM_CONSTANT_UnresolvedClassInError:
case JVM_CONSTANT_Class:
{
assert(cache_index == _no_index_sentinel, "should not have been set");
Expand Down Expand Up @@ -1043,14 +1040,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
result_oop = string_at_impl(this_cp, index, cache_index, CHECK_NULL);
break;

case JVM_CONSTANT_DynamicInError:
case JVM_CONSTANT_MethodHandleInError:
case JVM_CONSTANT_MethodTypeInError:
{
throw_resolution_error(this_cp, index, CHECK_NULL);
break;
}

case JVM_CONSTANT_MethodHandle:
{
int ref_kind = this_cp->method_handle_ref_kind_at(index);
Expand All @@ -1064,11 +1053,14 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
callee_index, name->as_C_string(), signature->as_C_string());
}

Klass* callee = klass_at_impl(this_cp, callee_index, CHECK_NULL);
Klass* callee = klass_at_impl(this_cp, callee_index, THREAD);
if (HAS_PENDING_EXCEPTION) {
save_and_throw_exception(this_cp, index, tag, CHECK_NULL);
}

// Check constant pool method consistency
if ((callee->is_interface() && m_tag.is_method()) ||
((!callee->is_interface() && m_tag.is_interface_method()))) {
(!callee->is_interface() && m_tag.is_interface_method())) {
ResourceMark rm(THREAD);
stringStream ss;
ss.print("Inconsistent constant pool data in classfile for class %s. "
Expand All @@ -1080,17 +1072,18 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
index,
callee->is_interface() ? "CONSTANT_MethodRef" : "CONSTANT_InterfaceMethodRef",
callee->is_interface() ? "CONSTANT_InterfaceMethodRef" : "CONSTANT_MethodRef");
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string());
Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IncompatibleClassChangeError(), "%s", ss.as_string());
save_and_throw_exception(this_cp, index, tag, CHECK_NULL);
}

Klass* klass = this_cp->pool_holder();
Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
callee, name, signature,
THREAD);
result_oop = value();
if (HAS_PENDING_EXCEPTION) {
save_and_throw_exception(this_cp, index, tag, CHECK_NULL);
}
result_oop = value();
break;
}

Expand Down Expand Up @@ -1135,10 +1128,15 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL);
break;

case JVM_CONSTANT_UnresolvedClassInError:
case JVM_CONSTANT_DynamicInError:
case JVM_CONSTANT_MethodHandleInError:
case JVM_CONSTANT_MethodTypeInError:
throw_resolution_error(this_cp, index, CHECK_NULL);
break;

default:
DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
this_cp(), index, cache_index, tag.value()));
assert(false, "unexpected constant tag");
fatal("unexpected constant tag at CP %p[%d/%d] = %d", this_cp(), index, cache_index, tag.value());
break;
}

Expand Down
36 changes: 19 additions & 17 deletions src/hotspot/share/opto/parse2.cpp
Expand Up @@ -1876,33 +1876,35 @@ void Parse::do_one_bytecode() {
case Bytecodes::_bipush: push(intcon(iter().get_constant_u1())); break;
case Bytecodes::_sipush: push(intcon(iter().get_constant_u2())); break;
case Bytecodes::_aconst_null: push(null()); break;

case Bytecodes::_ldc:
case Bytecodes::_ldc_w:
case Bytecodes::_ldc2_w:
// If the constant is unresolved, run this BC once in the interpreter.
{
ciConstant constant = iter().get_constant();
if (!constant.is_valid() ||
(constant.basic_type() == T_OBJECT &&
!constant.as_object()->is_loaded())) {
int index = iter().get_constant_pool_index();
constantTag tag = iter().get_constant_pool_tag(index);
uncommon_trap(Deoptimization::make_trap_request
(Deoptimization::Reason_unloaded,
Deoptimization::Action_reinterpret,
index),
NULL, tag.internal_name());
break;
}
case Bytecodes::_ldc2_w: {
ciConstant constant = iter().get_constant();
if (constant.is_loaded()) {
assert(constant.basic_type() != T_OBJECT || constant.as_object()->is_instance(),
"must be java_mirror of klass");
const Type* con_type = Type::make_from_constant(constant);
if (con_type != NULL) {
push_node(con_type->basic_type(), makecon(con_type));
}
}
} else {
// If the constant is unresolved or in error state, run this BC in the interpreter.
if (iter().is_in_error()) {
uncommon_trap(Deoptimization::make_trap_request(Deoptimization::Reason_unhandled,
Deoptimization::Action_none),
NULL, "constant in error state", true /* must_throw */);

} else {
int index = iter().get_constant_pool_index();
uncommon_trap(Deoptimization::make_trap_request(Deoptimization::Reason_unloaded,
Deoptimization::Action_reinterpret,
index),
NULL, "unresolved constant", false /* must_throw */);
}
}
break;
}

case Bytecodes::_aload_0:
push( local(0) );
Expand Down

1 comment on commit da9aa23

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.