| /* |
| * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #ifndef SHARE_VM_C1_C1_CODESTUBS_HPP |
| #define SHARE_VM_C1_C1_CODESTUBS_HPP |
| |
| #include "c1/c1_FrameMap.hpp" |
| #include "c1/c1_IR.hpp" |
| #include "c1/c1_Instruction.hpp" |
| #include "c1/c1_LIR.hpp" |
| #include "c1/c1_Runtime1.hpp" |
| #include "code/nativeInst.hpp" |
| #include "utilities/growableArray.hpp" |
| #include "utilities/macros.hpp" |
| |
| class CodeEmitInfo; |
| class LIR_Assembler; |
| class LIR_OpVisitState; |
| |
| // CodeStubs are little 'out-of-line' pieces of code that |
| // usually handle slow cases of operations. All code stubs |
| // are collected and code is emitted at the end of the |
| // nmethod. |
| |
| class CodeStub: public CompilationResourceObj { |
| protected: |
| Label _entry; // label at the stub entry point |
| Label _continuation; // label where stub continues, if any |
| |
| public: |
| CodeStub() {} |
| |
| // code generation |
| void assert_no_unbound_labels() { assert(!_entry.is_unbound() && !_continuation.is_unbound(), "unbound label"); } |
| virtual void emit_code(LIR_Assembler* e) = 0; |
| virtual CodeEmitInfo* info() const { return NULL; } |
| virtual bool is_exception_throw_stub() const { return false; } |
| virtual bool is_range_check_stub() const { return false; } |
| virtual bool is_divbyzero_stub() const { return false; } |
| virtual bool is_simple_exception_stub() const { return false; } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const = 0; |
| #endif |
| |
| // label access |
| Label* entry() { return &_entry; } |
| Label* continuation() { return &_continuation; } |
| // for LIR |
| virtual void visit(LIR_OpVisitState* visit) { |
| #ifndef PRODUCT |
| if (LIRTracePeephole && Verbose) { |
| tty->print("no visitor for "); |
| print_name(tty); |
| tty->cr(); |
| } |
| #endif |
| } |
| }; |
| |
| class CodeStubList: public GrowableArray<CodeStub*> { |
| public: |
| CodeStubList(): GrowableArray<CodeStub*>() {} |
| |
| void append(CodeStub* stub) { |
| if (!contains(stub)) { |
| GrowableArray<CodeStub*>::append(stub); |
| } |
| } |
| }; |
| |
| class CounterOverflowStub: public CodeStub { |
| private: |
| CodeEmitInfo* _info; |
| int _bci; |
| LIR_Opr _method; |
| |
| public: |
| CounterOverflowStub(CodeEmitInfo* info, int bci, LIR_Opr method) : _info(info), _bci(bci), _method(method) { |
| } |
| |
| virtual void emit_code(LIR_Assembler* e); |
| |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(_info); |
| visitor->do_input(_method); |
| } |
| |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("CounterOverflowStub"); } |
| #endif // PRODUCT |
| |
| }; |
| |
| class ConversionStub: public CodeStub { |
| private: |
| Bytecodes::Code _bytecode; |
| LIR_Opr _input; |
| LIR_Opr _result; |
| |
| static float float_zero; |
| static double double_zero; |
| public: |
| ConversionStub(Bytecodes::Code bytecode, LIR_Opr input, LIR_Opr result) |
| : _bytecode(bytecode), _input(input), _result(result) { |
| } |
| |
| Bytecodes::Code bytecode() { return _bytecode; } |
| LIR_Opr input() { return _input; } |
| LIR_Opr result() { return _result; } |
| |
| virtual void emit_code(LIR_Assembler* e); |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(); |
| visitor->do_input(_input); |
| visitor->do_output(_result); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("ConversionStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| // Throws ArrayIndexOutOfBoundsException by default but can be |
| // configured to throw IndexOutOfBoundsException in constructor |
| class RangeCheckStub: public CodeStub { |
| private: |
| CodeEmitInfo* _info; |
| LIR_Opr _index; |
| bool _throw_index_out_of_bounds_exception; |
| |
| public: |
| RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, bool throw_index_out_of_bounds_exception = false); |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual bool is_exception_throw_stub() const { return true; } |
| virtual bool is_range_check_stub() const { return true; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(_info); |
| visitor->do_input(_index); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("RangeCheckStub"); } |
| #endif // PRODUCT |
| }; |
| |
| // stub used when predicate fails and deoptimization is needed |
| class PredicateFailedStub: public CodeStub { |
| private: |
| CodeEmitInfo* _info; |
| |
| public: |
| PredicateFailedStub(CodeEmitInfo* info); |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(_info); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("PredicateFailedStub"); } |
| #endif // PRODUCT |
| }; |
| |
| class DivByZeroStub: public CodeStub { |
| private: |
| CodeEmitInfo* _info; |
| int _offset; |
| |
| public: |
| DivByZeroStub(CodeEmitInfo* info) |
| : _info(info), _offset(-1) { |
| } |
| DivByZeroStub(int offset, CodeEmitInfo* info) |
| : _info(info), _offset(offset) { |
| } |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual bool is_exception_throw_stub() const { return true; } |
| virtual bool is_divbyzero_stub() const { return true; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(_info); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("DivByZeroStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| class ImplicitNullCheckStub: public CodeStub { |
| private: |
| CodeEmitInfo* _info; |
| int _offset; |
| |
| public: |
| ImplicitNullCheckStub(int offset, CodeEmitInfo* info) |
| : _offset(offset), _info(info) { |
| } |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual bool is_exception_throw_stub() const { return true; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(_info); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("ImplicitNullCheckStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| class NewInstanceStub: public CodeStub { |
| private: |
| ciInstanceKlass* _klass; |
| LIR_Opr _klass_reg; |
| LIR_Opr _result; |
| CodeEmitInfo* _info; |
| Runtime1::StubID _stub_id; |
| |
| public: |
| NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id); |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(_info); |
| visitor->do_input(_klass_reg); |
| visitor->do_output(_result); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("NewInstanceStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| class NewTypeArrayStub: public CodeStub { |
| private: |
| LIR_Opr _klass_reg; |
| LIR_Opr _length; |
| LIR_Opr _result; |
| CodeEmitInfo* _info; |
| |
| public: |
| NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info); |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(_info); |
| visitor->do_input(_klass_reg); |
| visitor->do_input(_length); |
| assert(_result->is_valid(), "must be valid"); visitor->do_output(_result); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("NewTypeArrayStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| class NewObjectArrayStub: public CodeStub { |
| private: |
| LIR_Opr _klass_reg; |
| LIR_Opr _length; |
| LIR_Opr _result; |
| CodeEmitInfo* _info; |
| |
| public: |
| NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info); |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(_info); |
| visitor->do_input(_klass_reg); |
| visitor->do_input(_length); |
| assert(_result->is_valid(), "must be valid"); visitor->do_output(_result); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("NewObjectArrayStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| class MonitorAccessStub: public CodeStub { |
| protected: |
| LIR_Opr _obj_reg; |
| LIR_Opr _lock_reg; |
| |
| public: |
| MonitorAccessStub(LIR_Opr obj_reg, LIR_Opr lock_reg) { |
| _obj_reg = obj_reg; |
| _lock_reg = lock_reg; |
| } |
| |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("MonitorAccessStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| class MonitorEnterStub: public MonitorAccessStub { |
| private: |
| CodeEmitInfo* _info; |
| |
| public: |
| MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info); |
| |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_input(_obj_reg); |
| visitor->do_input(_lock_reg); |
| visitor->do_slow_case(_info); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("MonitorEnterStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| class MonitorExitStub: public MonitorAccessStub { |
| private: |
| bool _compute_lock; |
| int _monitor_ix; |
| |
| public: |
| MonitorExitStub(LIR_Opr lock_reg, bool compute_lock, int monitor_ix) |
| : MonitorAccessStub(LIR_OprFact::illegalOpr, lock_reg), |
| _compute_lock(compute_lock), _monitor_ix(monitor_ix) { } |
| virtual void emit_code(LIR_Assembler* e); |
| virtual void visit(LIR_OpVisitState* visitor) { |
| assert(_obj_reg->is_illegal(), "unused"); |
| if (_compute_lock) { |
| visitor->do_temp(_lock_reg); |
| } else { |
| visitor->do_input(_lock_reg); |
| } |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("MonitorExitStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| class PatchingStub: public CodeStub { |
| public: |
| enum PatchID { |
| access_field_id, |
| load_klass_id, |
| load_mirror_id, |
| load_appendix_id |
| }; |
| enum constants { |
| patch_info_size = 3 |
| }; |
| private: |
| PatchID _id; |
| address _pc_start; |
| int _bytes_to_copy; |
| Label _patched_code_entry; |
| Label _patch_site_entry; |
| Label _patch_site_continuation; |
| Register _obj; |
| CodeEmitInfo* _info; |
| int _index; // index of the patchable oop or Klass* in nmethod oop or metadata table if needed |
| static int _patch_info_offset; |
| |
| void align_patch_site(MacroAssembler* masm); |
| |
| public: |
| static int patch_info_offset() { return _patch_info_offset; } |
| |
| PatchingStub(MacroAssembler* masm, PatchID id, int index = -1): |
| _id(id) |
| , _info(NULL) |
| , _index(index) { |
| if (os::is_MP()) { |
| // force alignment of patch sites on MP hardware so we |
| // can guarantee atomic writes to the patch site. |
| align_patch_site(masm); |
| } |
| _pc_start = masm->pc(); |
| masm->bind(_patch_site_entry); |
| } |
| |
| void install(MacroAssembler* masm, LIR_PatchCode patch_code, Register obj, CodeEmitInfo* info) { |
| _info = info; |
| _obj = obj; |
| masm->bind(_patch_site_continuation); |
| _bytes_to_copy = masm->pc() - pc_start(); |
| if (_id == PatchingStub::access_field_id) { |
| // embed a fixed offset to handle long patches which need to be offset by a word. |
| // the patching code will just add the field offset field to this offset so |
| // that we can refernce either the high or low word of a double word field. |
| int field_offset = 0; |
| switch (patch_code) { |
| case lir_patch_low: field_offset = lo_word_offset_in_bytes; break; |
| case lir_patch_high: field_offset = hi_word_offset_in_bytes; break; |
| case lir_patch_normal: field_offset = 0; break; |
| default: ShouldNotReachHere(); |
| } |
| NativeMovRegMem* n_move = nativeMovRegMem_at(pc_start()); |
| n_move->set_offset(field_offset); |
| } else if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) { |
| assert(_obj != noreg, "must have register object for load_klass/load_mirror"); |
| #ifdef ASSERT |
| // verify that we're pointing at a NativeMovConstReg |
| nativeMovConstReg_at(pc_start()); |
| #endif |
| } else { |
| ShouldNotReachHere(); |
| } |
| assert(_bytes_to_copy <= (masm->pc() - pc_start()), "not enough bytes"); |
| } |
| |
| address pc_start() const { return _pc_start; } |
| PatchID id() const { return _id; } |
| |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(_info); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("PatchingStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| //------------------------------------------------------------------------------ |
| // DeoptimizeStub |
| // |
| class DeoptimizeStub : public CodeStub { |
| private: |
| CodeEmitInfo* _info; |
| jint _trap_request; |
| |
| public: |
| DeoptimizeStub(CodeEmitInfo* info, Deoptimization::DeoptReason reason, Deoptimization::DeoptAction action) : |
| _info(new CodeEmitInfo(info)), _trap_request(Deoptimization::make_trap_request(reason, action)) {} |
| |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual bool is_exception_throw_stub() const { return true; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| visitor->do_slow_case(_info); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("DeoptimizeStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| class SimpleExceptionStub: public CodeStub { |
| private: |
| LIR_Opr _obj; |
| Runtime1::StubID _stub; |
| CodeEmitInfo* _info; |
| |
| public: |
| SimpleExceptionStub(Runtime1::StubID stub, LIR_Opr obj, CodeEmitInfo* info): |
| _obj(obj), _info(info), _stub(stub) { |
| } |
| |
| void set_obj(LIR_Opr obj) { |
| _obj = obj; |
| } |
| |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _info; } |
| virtual bool is_exception_throw_stub() const { return true; } |
| virtual bool is_simple_exception_stub() const { return true; } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| if (_obj->is_valid()) visitor->do_input(_obj); |
| visitor->do_slow_case(_info); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("SimpleExceptionStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| |
| class ArrayStoreExceptionStub: public SimpleExceptionStub { |
| private: |
| CodeEmitInfo* _info; |
| |
| public: |
| ArrayStoreExceptionStub(LIR_Opr obj, CodeEmitInfo* info): SimpleExceptionStub(Runtime1::throw_array_store_exception_id, obj, info) {} |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("ArrayStoreExceptionStub"); } |
| #endif // PRODUCT |
| }; |
| |
| |
| class ArrayCopyStub: public CodeStub { |
| private: |
| LIR_OpArrayCopy* _op; |
| |
| public: |
| ArrayCopyStub(LIR_OpArrayCopy* op): _op(op) { } |
| |
| LIR_Opr src() const { return _op->src(); } |
| LIR_Opr src_pos() const { return _op->src_pos(); } |
| LIR_Opr dst() const { return _op->dst(); } |
| LIR_Opr dst_pos() const { return _op->dst_pos(); } |
| LIR_Opr length() const { return _op->length(); } |
| LIR_Opr tmp() const { return _op->tmp(); } |
| |
| virtual void emit_code(LIR_Assembler* e); |
| virtual CodeEmitInfo* info() const { return _op->info(); } |
| virtual void visit(LIR_OpVisitState* visitor) { |
| // don't pass in the code emit info since it's processed in the fast path |
| visitor->do_slow_case(); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("ArrayCopyStub"); } |
| #endif // PRODUCT |
| }; |
| |
| ////////////////////////////////////////////////////////////////////////////////////////// |
| #if INCLUDE_ALL_GCS |
| |
| // Code stubs for Garbage-First barriers. |
| class G1PreBarrierStub: public CodeStub { |
| private: |
| bool _do_load; |
| LIR_Opr _addr; |
| LIR_Opr _pre_val; |
| LIR_PatchCode _patch_code; |
| CodeEmitInfo* _info; |
| |
| public: |
| // Version that _does_ generate a load of the previous value from addr. |
| // addr (the address of the field to be read) must be a LIR_Address |
| // pre_val (a temporary register) must be a register; |
| G1PreBarrierStub(LIR_Opr addr, LIR_Opr pre_val, LIR_PatchCode patch_code, CodeEmitInfo* info) : |
| _addr(addr), _pre_val(pre_val), _do_load(true), |
| _patch_code(patch_code), _info(info) |
| { |
| assert(_pre_val->is_register(), "should be temporary register"); |
| assert(_addr->is_address(), "should be the address of the field"); |
| } |
| |
| // Version that _does not_ generate load of the previous value; the |
| // previous value is assumed to have already been loaded into pre_val. |
| G1PreBarrierStub(LIR_Opr pre_val) : |
| _addr(LIR_OprFact::illegalOpr), _pre_val(pre_val), _do_load(false), |
| _patch_code(lir_patch_none), _info(NULL) |
| { |
| assert(_pre_val->is_register(), "should be a register"); |
| } |
| |
| LIR_Opr addr() const { return _addr; } |
| LIR_Opr pre_val() const { return _pre_val; } |
| LIR_PatchCode patch_code() const { return _patch_code; } |
| CodeEmitInfo* info() const { return _info; } |
| bool do_load() const { return _do_load; } |
| |
| virtual void emit_code(LIR_Assembler* e); |
| virtual void visit(LIR_OpVisitState* visitor) { |
| if (_do_load) { |
| // don't pass in the code emit info since it's processed in the fast |
| // path |
| if (_info != NULL) |
| visitor->do_slow_case(_info); |
| else |
| visitor->do_slow_case(); |
| |
| visitor->do_input(_addr); |
| visitor->do_temp(_pre_val); |
| } else { |
| visitor->do_slow_case(); |
| visitor->do_input(_pre_val); |
| } |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("G1PreBarrierStub"); } |
| #endif // PRODUCT |
| }; |
| |
| class G1PostBarrierStub: public CodeStub { |
| private: |
| LIR_Opr _addr; |
| LIR_Opr _new_val; |
| |
| public: |
| // addr (the address of the object head) and new_val must be registers. |
| G1PostBarrierStub(LIR_Opr addr, LIR_Opr new_val): _addr(addr), _new_val(new_val) { } |
| |
| LIR_Opr addr() const { return _addr; } |
| LIR_Opr new_val() const { return _new_val; } |
| |
| virtual void emit_code(LIR_Assembler* e); |
| virtual void visit(LIR_OpVisitState* visitor) { |
| // don't pass in the code emit info since it's processed in the fast path |
| visitor->do_slow_case(); |
| visitor->do_input(_addr); |
| visitor->do_input(_new_val); |
| } |
| #ifndef PRODUCT |
| virtual void print_name(outputStream* out) const { out->print("G1PostBarrierStub"); } |
| #endif // PRODUCT |
| }; |
| |
| #endif // INCLUDE_ALL_GCS |
| ////////////////////////////////////////////////////////////////////////////////////////// |
| |
| #endif // SHARE_VM_C1_C1_CODESTUBS_HPP |