mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
8164122: C1: assert(false) failed: stack or locks not matching (invalid bytecodes)
Ignore return value if MH intrinsic returns void Reviewed-by: roland, kvn
This commit is contained in:
parent
06492bebc5
commit
14830c4604
2 changed files with 45 additions and 28 deletions
|
@ -683,6 +683,7 @@ GraphBuilder::ScopeData::ScopeData(ScopeData* parent)
|
||||||
, _cleanup_block(NULL)
|
, _cleanup_block(NULL)
|
||||||
, _cleanup_return_prev(NULL)
|
, _cleanup_return_prev(NULL)
|
||||||
, _cleanup_state(NULL)
|
, _cleanup_state(NULL)
|
||||||
|
, _ignore_return(false)
|
||||||
{
|
{
|
||||||
if (parent != NULL) {
|
if (parent != NULL) {
|
||||||
_max_inline_size = (intx) ((float) NestedInliningSizeRatio * (float) parent->max_inline_size() / 100.0f);
|
_max_inline_size = (intx) ((float) NestedInliningSizeRatio * (float) parent->max_inline_size() / 100.0f);
|
||||||
|
@ -1445,7 +1446,7 @@ void GraphBuilder::call_register_finalizer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GraphBuilder::method_return(Value x) {
|
void GraphBuilder::method_return(Value x, bool ignore_return) {
|
||||||
if (RegisterFinalizersAtInit &&
|
if (RegisterFinalizersAtInit &&
|
||||||
method()->intrinsic_id() == vmIntrinsics::_Object_init) {
|
method()->intrinsic_id() == vmIntrinsics::_Object_init) {
|
||||||
call_register_finalizer();
|
call_register_finalizer();
|
||||||
|
@ -1518,7 +1519,9 @@ void GraphBuilder::method_return(Value x) {
|
||||||
int invoke_bci = state()->caller_state()->bci();
|
int invoke_bci = state()->caller_state()->bci();
|
||||||
set_state(state()->caller_state()->copy_for_parsing());
|
set_state(state()->caller_state()->copy_for_parsing());
|
||||||
if (x != NULL) {
|
if (x != NULL) {
|
||||||
state()->push(x->type(), x);
|
if (!ignore_return) {
|
||||||
|
state()->push(x->type(), x);
|
||||||
|
}
|
||||||
if (profile_return() && x->type()->is_object_kind()) {
|
if (profile_return() && x->type()->is_object_kind()) {
|
||||||
ciMethod* caller = state()->scope()->method();
|
ciMethod* caller = state()->scope()->method();
|
||||||
ciMethodData* md = caller->method_data_or_null();
|
ciMethodData* md = caller->method_data_or_null();
|
||||||
|
@ -1563,6 +1566,7 @@ void GraphBuilder::method_return(Value x) {
|
||||||
append(new MemBar(lir_membar_storestore));
|
append(new MemBar(lir_membar_storestore));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(!ignore_return, "Ignoring return value works only for inlining");
|
||||||
append(new Return(x));
|
append(new Return(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1981,7 +1985,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||||
code == Bytecodes::_invokedynamic) {
|
code == Bytecodes::_invokedynamic) {
|
||||||
ciMethod* inline_target = (cha_monomorphic_target != NULL) ? cha_monomorphic_target : target;
|
ciMethod* inline_target = (cha_monomorphic_target != NULL) ? cha_monomorphic_target : target;
|
||||||
// static binding => check if callee is ok
|
// static binding => check if callee is ok
|
||||||
bool success = try_inline(inline_target, (cha_monomorphic_target != NULL) || (exact_target != NULL), code, better_receiver);
|
bool success = try_inline(inline_target, (cha_monomorphic_target != NULL) || (exact_target != NULL), false, code, better_receiver);
|
||||||
|
|
||||||
CHECK_BAILOUT();
|
CHECK_BAILOUT();
|
||||||
clear_inline_bailout();
|
clear_inline_bailout();
|
||||||
|
@ -2611,6 +2615,8 @@ BlockEnd* GraphBuilder::iterate_bytecodes_for_block(int bci) {
|
||||||
push_exception = true;
|
push_exception = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ignore_return = scope_data()->ignore_return();
|
||||||
|
|
||||||
while (!bailed_out() && last()->as_BlockEnd() == NULL &&
|
while (!bailed_out() && last()->as_BlockEnd() == NULL &&
|
||||||
(code = stream()->next()) != ciBytecodeStream::EOBC() &&
|
(code = stream()->next()) != ciBytecodeStream::EOBC() &&
|
||||||
(block_at(s.cur_bci()) == NULL || block_at(s.cur_bci()) == block())) {
|
(block_at(s.cur_bci()) == NULL || block_at(s.cur_bci()) == block())) {
|
||||||
|
@ -2806,12 +2812,12 @@ BlockEnd* GraphBuilder::iterate_bytecodes_for_block(int bci) {
|
||||||
case Bytecodes::_ret : ret(s.get_index()); break;
|
case Bytecodes::_ret : ret(s.get_index()); break;
|
||||||
case Bytecodes::_tableswitch : table_switch(); break;
|
case Bytecodes::_tableswitch : table_switch(); break;
|
||||||
case Bytecodes::_lookupswitch : lookup_switch(); break;
|
case Bytecodes::_lookupswitch : lookup_switch(); break;
|
||||||
case Bytecodes::_ireturn : method_return(ipop()); break;
|
case Bytecodes::_ireturn : method_return(ipop(), ignore_return); break;
|
||||||
case Bytecodes::_lreturn : method_return(lpop()); break;
|
case Bytecodes::_lreturn : method_return(lpop(), ignore_return); break;
|
||||||
case Bytecodes::_freturn : method_return(fpop()); break;
|
case Bytecodes::_freturn : method_return(fpop(), ignore_return); break;
|
||||||
case Bytecodes::_dreturn : method_return(dpop()); break;
|
case Bytecodes::_dreturn : method_return(dpop(), ignore_return); break;
|
||||||
case Bytecodes::_areturn : method_return(apop()); break;
|
case Bytecodes::_areturn : method_return(apop(), ignore_return); break;
|
||||||
case Bytecodes::_return : method_return(NULL ); break;
|
case Bytecodes::_return : method_return(NULL , ignore_return); break;
|
||||||
case Bytecodes::_getstatic : // fall through
|
case Bytecodes::_getstatic : // fall through
|
||||||
case Bytecodes::_putstatic : // fall through
|
case Bytecodes::_putstatic : // fall through
|
||||||
case Bytecodes::_getfield : // fall through
|
case Bytecodes::_getfield : // fall through
|
||||||
|
@ -3336,7 +3342,7 @@ int GraphBuilder::recursive_inline_level(ciMethod* cur_callee) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Code bc, Value receiver) {
|
bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, bool ignore_return, Bytecodes::Code bc, Value receiver) {
|
||||||
const char* msg = NULL;
|
const char* msg = NULL;
|
||||||
|
|
||||||
// clear out any existing inline bailout condition
|
// clear out any existing inline bailout condition
|
||||||
|
@ -3351,7 +3357,7 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co
|
||||||
|
|
||||||
// method handle invokes
|
// method handle invokes
|
||||||
if (callee->is_method_handle_intrinsic()) {
|
if (callee->is_method_handle_intrinsic()) {
|
||||||
if (try_method_handle_inline(callee)) {
|
if (try_method_handle_inline(callee, ignore_return)) {
|
||||||
if (callee->has_reserved_stack_access()) {
|
if (callee->has_reserved_stack_access()) {
|
||||||
compilation()->set_has_reserved_stack_access(true);
|
compilation()->set_has_reserved_stack_access(true);
|
||||||
}
|
}
|
||||||
|
@ -3363,7 +3369,7 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co
|
||||||
// handle intrinsics
|
// handle intrinsics
|
||||||
if (callee->intrinsic_id() != vmIntrinsics::_none &&
|
if (callee->intrinsic_id() != vmIntrinsics::_none &&
|
||||||
(CheckIntrinsics ? callee->intrinsic_candidate() : true)) {
|
(CheckIntrinsics ? callee->intrinsic_candidate() : true)) {
|
||||||
if (try_inline_intrinsics(callee)) {
|
if (try_inline_intrinsics(callee, ignore_return)) {
|
||||||
print_inlining(callee, "intrinsic");
|
print_inlining(callee, "intrinsic");
|
||||||
if (callee->has_reserved_stack_access()) {
|
if (callee->has_reserved_stack_access()) {
|
||||||
compilation()->set_has_reserved_stack_access(true);
|
compilation()->set_has_reserved_stack_access(true);
|
||||||
|
@ -3384,7 +3390,7 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co
|
||||||
if (bc == Bytecodes::_illegal) {
|
if (bc == Bytecodes::_illegal) {
|
||||||
bc = code();
|
bc = code();
|
||||||
}
|
}
|
||||||
if (try_inline_full(callee, holder_known, bc, receiver)) {
|
if (try_inline_full(callee, holder_known, ignore_return, bc, receiver)) {
|
||||||
if (callee->has_reserved_stack_access()) {
|
if (callee->has_reserved_stack_access()) {
|
||||||
compilation()->set_has_reserved_stack_access(true);
|
compilation()->set_has_reserved_stack_access(true);
|
||||||
}
|
}
|
||||||
|
@ -3415,7 +3421,7 @@ const char* GraphBuilder::should_not_inline(ciMethod* callee) const {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphBuilder::build_graph_for_intrinsic(ciMethod* callee) {
|
void GraphBuilder::build_graph_for_intrinsic(ciMethod* callee, bool ignore_return) {
|
||||||
vmIntrinsics::ID id = callee->intrinsic_id();
|
vmIntrinsics::ID id = callee->intrinsic_id();
|
||||||
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
||||||
|
|
||||||
|
@ -3509,14 +3515,16 @@ void GraphBuilder::build_graph_for_intrinsic(ciMethod* callee) {
|
||||||
vmIntrinsics::can_trap(id));
|
vmIntrinsics::can_trap(id));
|
||||||
// append instruction & push result
|
// append instruction & push result
|
||||||
Value value = append_split(result);
|
Value value = append_split(result);
|
||||||
if (result_type != voidType) push(result_type, value);
|
if (result_type != voidType && !ignore_return) {
|
||||||
|
push(result_type, value);
|
||||||
|
}
|
||||||
|
|
||||||
if (callee != method() && profile_return() && result_type->is_object_kind()) {
|
if (callee != method() && profile_return() && result_type->is_object_kind()) {
|
||||||
profile_return_type(result, callee);
|
profile_return_type(result, callee);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
|
bool GraphBuilder::try_inline_intrinsics(ciMethod* callee, bool ignore_return) {
|
||||||
// For calling is_intrinsic_available we need to transition to
|
// For calling is_intrinsic_available we need to transition to
|
||||||
// the '_thread_in_vm' state because is_intrinsic_available()
|
// the '_thread_in_vm' state because is_intrinsic_available()
|
||||||
// accesses critical VM-internal data.
|
// accesses critical VM-internal data.
|
||||||
|
@ -3536,7 +3544,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
build_graph_for_intrinsic(callee);
|
build_graph_for_intrinsic(callee, ignore_return);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3691,7 +3699,7 @@ void GraphBuilder::fill_sync_handler(Value lock, BlockBegin* sync_handler, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecodes::Code bc, Value receiver) {
|
bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, bool ignore_return, Bytecodes::Code bc, Value receiver) {
|
||||||
assert(!callee->is_native(), "callee must not be native");
|
assert(!callee->is_native(), "callee must not be native");
|
||||||
if (CompilationPolicy::policy()->should_not_inline(compilation()->env(), callee)) {
|
if (CompilationPolicy::policy()->should_not_inline(compilation()->env(), callee)) {
|
||||||
INLINE_BAILOUT("inlining prohibited by policy");
|
INLINE_BAILOUT("inlining prohibited by policy");
|
||||||
|
@ -3889,6 +3897,7 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
|
||||||
|
|
||||||
// Clear out bytecode stream
|
// Clear out bytecode stream
|
||||||
scope_data()->set_stream(NULL);
|
scope_data()->set_stream(NULL);
|
||||||
|
scope_data()->set_ignore_return(ignore_return);
|
||||||
|
|
||||||
CompileLog* log = compilation()->log();
|
CompileLog* log = compilation()->log();
|
||||||
if (log != NULL) log->head("parse method='%d'", log->identify(callee));
|
if (log != NULL) log->head("parse method='%d'", log->identify(callee));
|
||||||
|
@ -3958,7 +3967,7 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool GraphBuilder::try_method_handle_inline(ciMethod* callee) {
|
bool GraphBuilder::try_method_handle_inline(ciMethod* callee, bool ignore_return) {
|
||||||
ValueStack* state_before = copy_state_before();
|
ValueStack* state_before = copy_state_before();
|
||||||
vmIntrinsics::ID iid = callee->intrinsic_id();
|
vmIntrinsics::ID iid = callee->intrinsic_id();
|
||||||
switch (iid) {
|
switch (iid) {
|
||||||
|
@ -3972,7 +3981,8 @@ bool GraphBuilder::try_method_handle_inline(ciMethod* callee) {
|
||||||
// We don't do CHA here so only inline static and statically bindable methods.
|
// We don't do CHA here so only inline static and statically bindable methods.
|
||||||
if (target->is_static() || target->can_be_statically_bound()) {
|
if (target->is_static() || target->can_be_statically_bound()) {
|
||||||
Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
|
Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
|
||||||
if (try_inline(target, /*holder_known*/ true, bc)) {
|
ignore_return = ignore_return || (callee->return_type()->is_void() && !target->return_type()->is_void());
|
||||||
|
if (try_inline(target, /*holder_known*/ true, ignore_return, bc)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -3994,10 +4004,11 @@ bool GraphBuilder::try_method_handle_inline(ciMethod* callee) {
|
||||||
ValueType* type = apop()->type();
|
ValueType* type = apop()->type();
|
||||||
if (type->is_constant()) {
|
if (type->is_constant()) {
|
||||||
ciMethod* target = type->as_ObjectType()->constant_value()->as_member_name()->get_vmtarget();
|
ciMethod* target = type->as_ObjectType()->constant_value()->as_member_name()->get_vmtarget();
|
||||||
|
ignore_return = ignore_return || (callee->return_type()->is_void() && !target->return_type()->is_void());
|
||||||
// If the target is another method handle invoke, try to recursively get
|
// If the target is another method handle invoke, try to recursively get
|
||||||
// a better target.
|
// a better target.
|
||||||
if (target->is_method_handle_intrinsic()) {
|
if (target->is_method_handle_intrinsic()) {
|
||||||
if (try_method_handle_inline(target)) {
|
if (try_method_handle_inline(target, ignore_return)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -4032,7 +4043,7 @@ bool GraphBuilder::try_method_handle_inline(ciMethod* callee) {
|
||||||
// We don't do CHA here so only inline static and statically bindable methods.
|
// We don't do CHA here so only inline static and statically bindable methods.
|
||||||
if (target->is_static() || target->can_be_statically_bound()) {
|
if (target->is_static() || target->can_be_statically_bound()) {
|
||||||
Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
|
Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
|
||||||
if (try_inline(target, /*holder_known*/ true, bc)) {
|
if (try_inline(target, /*holder_known*/ true, ignore_return, bc)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -100,6 +100,9 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
|
||||||
Instruction* _cleanup_return_prev; // Instruction before return instruction
|
Instruction* _cleanup_return_prev; // Instruction before return instruction
|
||||||
ValueStack* _cleanup_state; // State of that block (not yet pinned)
|
ValueStack* _cleanup_state; // State of that block (not yet pinned)
|
||||||
|
|
||||||
|
// When inlining do not push the result on the stack
|
||||||
|
bool _ignore_return;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScopeData(ScopeData* parent);
|
ScopeData(ScopeData* parent);
|
||||||
|
|
||||||
|
@ -163,6 +166,9 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
|
||||||
BlockBegin* inline_cleanup_block() const { return _cleanup_block; }
|
BlockBegin* inline_cleanup_block() const { return _cleanup_block; }
|
||||||
Instruction* inline_cleanup_return_prev() const{ return _cleanup_return_prev; }
|
Instruction* inline_cleanup_return_prev() const{ return _cleanup_return_prev; }
|
||||||
ValueStack* inline_cleanup_state() const { return _cleanup_state; }
|
ValueStack* inline_cleanup_state() const { return _cleanup_state; }
|
||||||
|
|
||||||
|
bool ignore_return() const { return _ignore_return; }
|
||||||
|
void set_ignore_return(bool ignore_return) { _ignore_return = ignore_return; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// for all GraphBuilders
|
// for all GraphBuilders
|
||||||
|
@ -246,7 +252,7 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
|
||||||
void ret(int local_index);
|
void ret(int local_index);
|
||||||
void table_switch();
|
void table_switch();
|
||||||
void lookup_switch();
|
void lookup_switch();
|
||||||
void method_return(Value x);
|
void method_return(Value x, bool ignore_return = false);
|
||||||
void call_register_finalizer();
|
void call_register_finalizer();
|
||||||
void access_field(Bytecodes::Code code);
|
void access_field(Bytecodes::Code code);
|
||||||
void invoke(Bytecodes::Code code);
|
void invoke(Bytecodes::Code code);
|
||||||
|
@ -340,19 +346,19 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
|
||||||
void inline_sync_entry(Value lock, BlockBegin* sync_handler);
|
void inline_sync_entry(Value lock, BlockBegin* sync_handler);
|
||||||
void fill_sync_handler(Value lock, BlockBegin* sync_handler, bool default_handler = false);
|
void fill_sync_handler(Value lock, BlockBegin* sync_handler, bool default_handler = false);
|
||||||
|
|
||||||
void build_graph_for_intrinsic(ciMethod* callee);
|
void build_graph_for_intrinsic(ciMethod* callee, bool ignore_return);
|
||||||
|
|
||||||
// inliners
|
// inliners
|
||||||
bool try_inline( ciMethod* callee, bool holder_known, Bytecodes::Code bc = Bytecodes::_illegal, Value receiver = NULL);
|
bool try_inline( ciMethod* callee, bool holder_known, bool ignore_return, Bytecodes::Code bc = Bytecodes::_illegal, Value receiver = NULL);
|
||||||
bool try_inline_intrinsics(ciMethod* callee);
|
bool try_inline_intrinsics(ciMethod* callee, bool ignore_return = false);
|
||||||
bool try_inline_full( ciMethod* callee, bool holder_known, Bytecodes::Code bc = Bytecodes::_illegal, Value receiver = NULL);
|
bool try_inline_full( ciMethod* callee, bool holder_known, bool ignore_return, Bytecodes::Code bc = Bytecodes::_illegal, Value receiver = NULL);
|
||||||
bool try_inline_jsr(int jsr_dest_bci);
|
bool try_inline_jsr(int jsr_dest_bci);
|
||||||
|
|
||||||
const char* check_can_parse(ciMethod* callee) const;
|
const char* check_can_parse(ciMethod* callee) const;
|
||||||
const char* should_not_inline(ciMethod* callee) const;
|
const char* should_not_inline(ciMethod* callee) const;
|
||||||
|
|
||||||
// JSR 292 support
|
// JSR 292 support
|
||||||
bool try_method_handle_inline(ciMethod* callee);
|
bool try_method_handle_inline(ciMethod* callee, bool ignore_return);
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
void inline_bailout(const char* msg);
|
void inline_bailout(const char* msg);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue