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:
Igor Veresov 2016-08-22 11:47:15 -07:00
parent 06492bebc5
commit 14830c4604
2 changed files with 45 additions and 28 deletions

View file

@ -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) {
if (!ignore_return) {
state()->push(x->type(), x); 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 {

View file

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