# HG changeset patch # User iveresov # Date 1471891635 25200 # Node ID 607b015fd04763f0e526ca95fe8cdfbd9ad9e747 # Parent e15f80121414fe568d3a9f47f0760cf8bf71c9f1 8164122: C1: assert(false) failed: stack or locks not matching (invalid bytecodes) Summary: Ignore return value if MH intrinsic returns void Reviewed-by: roland, kvn diff -r e15f80121414 -r 607b015fd047 hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Fri Aug 19 18:51:15 2016 -0700 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Mon Aug 22 11:47:15 2016 -0700 @@ -683,6 +683,7 @@ , _cleanup_block(NULL) , _cleanup_return_prev(NULL) , _cleanup_state(NULL) + , _ignore_return(false) { if (parent != NULL) { _max_inline_size = (intx) ((float) NestedInliningSizeRatio * (float) parent->max_inline_size() / 100.0f); @@ -1445,7 +1446,7 @@ } -void GraphBuilder::method_return(Value x) { +void GraphBuilder::method_return(Value x, bool ignore_return) { if (RegisterFinalizersAtInit && method()->intrinsic_id() == vmIntrinsics::_Object_init) { call_register_finalizer(); @@ -1518,7 +1519,9 @@ int invoke_bci = state()->caller_state()->bci(); set_state(state()->caller_state()->copy_for_parsing()); if (x != NULL) { - state()->push(x->type(), x); + if (!ignore_return) { + state()->push(x->type(), x); + } if (profile_return() && x->type()->is_object_kind()) { ciMethod* caller = state()->scope()->method(); ciMethodData* md = caller->method_data_or_null(); @@ -1563,6 +1566,7 @@ append(new MemBar(lir_membar_storestore)); } + assert(!ignore_return, "Ignoring return value works only for inlining"); append(new Return(x)); } @@ -1981,7 +1985,7 @@ code == Bytecodes::_invokedynamic) { ciMethod* inline_target = (cha_monomorphic_target != NULL) ? cha_monomorphic_target : target; // 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(); clear_inline_bailout(); @@ -2611,6 +2615,8 @@ push_exception = true; } + bool ignore_return = scope_data()->ignore_return(); + while (!bailed_out() && last()->as_BlockEnd() == NULL && (code = stream()->next()) != ciBytecodeStream::EOBC() && (block_at(s.cur_bci()) == NULL || block_at(s.cur_bci()) == block())) { @@ -2806,12 +2812,12 @@ case Bytecodes::_ret : ret(s.get_index()); break; case Bytecodes::_tableswitch : table_switch(); break; case Bytecodes::_lookupswitch : lookup_switch(); break; - case Bytecodes::_ireturn : method_return(ipop()); break; - case Bytecodes::_lreturn : method_return(lpop()); break; - case Bytecodes::_freturn : method_return(fpop()); break; - case Bytecodes::_dreturn : method_return(dpop()); break; - case Bytecodes::_areturn : method_return(apop()); break; - case Bytecodes::_return : method_return(NULL ); break; + case Bytecodes::_ireturn : method_return(ipop(), ignore_return); break; + case Bytecodes::_lreturn : method_return(lpop(), ignore_return); break; + case Bytecodes::_freturn : method_return(fpop(), ignore_return); break; + case Bytecodes::_dreturn : method_return(dpop(), ignore_return); break; + case Bytecodes::_areturn : method_return(apop(), ignore_return); break; + case Bytecodes::_return : method_return(NULL , ignore_return); break; case Bytecodes::_getstatic : // fall through case Bytecodes::_putstatic : // fall through case Bytecodes::_getfield : // fall through @@ -3336,7 +3342,7 @@ } -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; // clear out any existing inline bailout condition @@ -3351,7 +3357,7 @@ // method handle invokes 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()) { compilation()->set_has_reserved_stack_access(true); } @@ -3363,7 +3369,7 @@ // handle intrinsics if (callee->intrinsic_id() != vmIntrinsics::_none && (CheckIntrinsics ? callee->intrinsic_candidate() : true)) { - if (try_inline_intrinsics(callee)) { + if (try_inline_intrinsics(callee, ignore_return)) { print_inlining(callee, "intrinsic"); if (callee->has_reserved_stack_access()) { compilation()->set_has_reserved_stack_access(true); @@ -3384,7 +3390,7 @@ if (bc == Bytecodes::_illegal) { 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()) { compilation()->set_has_reserved_stack_access(true); } @@ -3415,7 +3421,7 @@ 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(); assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); @@ -3509,14 +3515,16 @@ vmIntrinsics::can_trap(id)); // append instruction & push 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()) { 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 // the '_thread_in_vm' state because is_intrinsic_available() // accesses critical VM-internal data. @@ -3536,7 +3544,7 @@ return false; } } - build_graph_for_intrinsic(callee); + build_graph_for_intrinsic(callee, ignore_return); return true; } @@ -3691,7 +3699,7 @@ } -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"); if (CompilationPolicy::policy()->should_not_inline(compilation()->env(), callee)) { INLINE_BAILOUT("inlining prohibited by policy"); @@ -3889,6 +3897,7 @@ // Clear out bytecode stream scope_data()->set_stream(NULL); + scope_data()->set_ignore_return(ignore_return); CompileLog* log = compilation()->log(); if (log != NULL) log->head("parse method='%d'", log->identify(callee)); @@ -3958,7 +3967,7 @@ } -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(); vmIntrinsics::ID iid = callee->intrinsic_id(); switch (iid) { @@ -3972,7 +3981,8 @@ // We don't do CHA here so only inline static and statically bindable methods. if (target->is_static() || target->can_be_statically_bound()) { 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; } } else { @@ -3994,10 +4004,11 @@ ValueType* type = apop()->type(); if (type->is_constant()) { 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 // a better target. if (target->is_method_handle_intrinsic()) { - if (try_method_handle_inline(target)) { + if (try_method_handle_inline(target, ignore_return)) { return true; } } else { @@ -4032,7 +4043,7 @@ // We don't do CHA here so only inline static and statically bindable methods. if (target->is_static() || target->can_be_statically_bound()) { 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; } } else { diff -r e15f80121414 -r 607b015fd047 hotspot/src/share/vm/c1/c1_GraphBuilder.hpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp Fri Aug 19 18:51:15 2016 -0700 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp Mon Aug 22 11:47:15 2016 -0700 @@ -100,6 +100,9 @@ Instruction* _cleanup_return_prev; // Instruction before return instruction ValueStack* _cleanup_state; // State of that block (not yet pinned) + // When inlining do not push the result on the stack + bool _ignore_return; + public: ScopeData(ScopeData* parent); @@ -163,6 +166,9 @@ BlockBegin* inline_cleanup_block() const { return _cleanup_block; } Instruction* inline_cleanup_return_prev() const{ return _cleanup_return_prev; } 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 @@ -246,7 +252,7 @@ void ret(int local_index); void table_switch(); void lookup_switch(); - void method_return(Value x); + void method_return(Value x, bool ignore_return = false); void call_register_finalizer(); void access_field(Bytecodes::Code code); void invoke(Bytecodes::Code code); @@ -340,19 +346,19 @@ void inline_sync_entry(Value lock, BlockBegin* sync_handler); 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 - bool try_inline( ciMethod* callee, bool holder_known, Bytecodes::Code bc = Bytecodes::_illegal, Value receiver = NULL); - bool try_inline_intrinsics(ciMethod* callee); - bool try_inline_full( 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 ignore_return = false); + 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); const char* check_can_parse(ciMethod* callee) const; const char* should_not_inline(ciMethod* callee) const; // JSR 292 support - bool try_method_handle_inline(ciMethod* callee); + bool try_method_handle_inline(ciMethod* callee, bool ignore_return); // helpers void inline_bailout(const char* msg);