diff options
author | twisti <none@none> | 2010-12-03 01:34:31 -0800 |
---|---|---|
committer | twisti <none@none> | 2010-12-03 01:34:31 -0800 |
commit | 7519ccef5207260cf08b6719d6f15a0dec23f01a (patch) | |
tree | 18754063293c32ad2ef1540da2417c0327196480 /src/share/vm/opto | |
parent | 8d885e9a6cc86571bcf87be42bcabcfe9f4a60fd (diff) |
6961690: load oops from constant table on SPARC
Summary: oops should be loaded from the constant table of an nmethod instead of materializing them with a long code sequence.
Reviewed-by: never, kvn
Diffstat (limited to 'src/share/vm/opto')
-rw-r--r-- | src/share/vm/opto/c2_globals.hpp | 3 | ||||
-rw-r--r-- | src/share/vm/opto/compile.cpp | 252 | ||||
-rw-r--r-- | src/share/vm/opto/compile.hpp | 98 | ||||
-rw-r--r-- | src/share/vm/opto/gcm.cpp | 2 | ||||
-rw-r--r-- | src/share/vm/opto/machnode.cpp | 14 | ||||
-rw-r--r-- | src/share/vm/opto/machnode.hpp | 62 | ||||
-rw-r--r-- | src/share/vm/opto/matcher.hpp | 4 | ||||
-rw-r--r-- | src/share/vm/opto/node.hpp | 14 | ||||
-rw-r--r-- | src/share/vm/opto/output.cpp | 84 | ||||
-rw-r--r-- | src/share/vm/opto/postaloc.cpp | 13 |
10 files changed, 501 insertions, 45 deletions
diff --git a/src/share/vm/opto/c2_globals.hpp b/src/share/vm/opto/c2_globals.hpp index 2bdc1a04a..fe516dff5 100644 --- a/src/share/vm/opto/c2_globals.hpp +++ b/src/share/vm/opto/c2_globals.hpp @@ -284,6 +284,9 @@ develop(bool, SparcV9RegsHiBitsZero, true, \ "Assume Sparc V9 I&L registers on V8+ systems are zero-extended") \ \ + product(bool, UseRDPCForConstantTableBase, false, \ + "Use Sparc RDPC instruction for the constant table base.") \ + \ develop(intx, PrintIdealGraphLevel, 0, \ "Print ideal graph to XML file / network interface. " \ "By default attempts to connect to the visualizer on a socket.") \ diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp index 972cc34ae..0ca15e168 100644 --- a/src/share/vm/opto/compile.cpp +++ b/src/share/vm/opto/compile.cpp @@ -75,6 +75,18 @@ # include "adfiles/ad_zero.hpp" #endif + +// -------------------- Compile::mach_constant_base_node ----------------------- +// Constant table base node singleton. +MachConstantBaseNode* Compile::mach_constant_base_node() { + if (_mach_constant_base_node == NULL) { + _mach_constant_base_node = new (C) MachConstantBaseNode(); + _mach_constant_base_node->add_req(C->root()); + } + return _mach_constant_base_node; +} + + /// Support for intrinsics. // Return the index at which m must be inserted (or already exists). @@ -432,13 +444,14 @@ void Compile::print_compile_messages() { } -void Compile::init_scratch_buffer_blob() { - if( scratch_buffer_blob() != NULL ) return; +void Compile::init_scratch_buffer_blob(int const_size) { + if (scratch_buffer_blob() != NULL) return; // Construct a temporary CodeBuffer to have it construct a BufferBlob // Cache this BufferBlob for this compile. ResourceMark rm; - int size = (MAX_inst_size + MAX_stubs_size + MAX_const_size); + _scratch_const_size = const_size; + int size = (MAX_inst_size + MAX_stubs_size + _scratch_const_size); BufferBlob* blob = BufferBlob::create("Compile::scratch_buffer", size); // Record the buffer blob for next time. set_scratch_buffer_blob(blob); @@ -455,9 +468,19 @@ void Compile::init_scratch_buffer_blob() { } +void Compile::clear_scratch_buffer_blob() { + assert(scratch_buffer_blob(), "no BufferBlob set"); + set_scratch_buffer_blob(NULL); + set_scratch_locs_memory(NULL); +} + + //-----------------------scratch_emit_size------------------------------------- // Helper function that computes size by emitting code uint Compile::scratch_emit_size(const Node* n) { + // Start scratch_emit_size section. + set_in_scratch_emit_size(true); + // Emit into a trash buffer and count bytes emitted. // This is a pretty expensive way to compute a size, // but it works well enough if seldom used. @@ -476,13 +499,20 @@ uint Compile::scratch_emit_size(const Node* n) { address blob_end = (address)locs_buf; assert(blob->content_contains(blob_end), "sanity"); CodeBuffer buf(blob_begin, blob_end - blob_begin); - buf.initialize_consts_size(MAX_const_size); + buf.initialize_consts_size(_scratch_const_size); buf.initialize_stubs_size(MAX_stubs_size); assert(locs_buf != NULL, "sanity"); - int lsize = MAX_locs_size / 2; - buf.insts()->initialize_shared_locs(&locs_buf[0], lsize); - buf.stubs()->initialize_shared_locs(&locs_buf[lsize], lsize); + int lsize = MAX_locs_size / 3; + buf.consts()->initialize_shared_locs(&locs_buf[lsize * 0], lsize); + buf.insts()->initialize_shared_locs( &locs_buf[lsize * 1], lsize); + buf.stubs()->initialize_shared_locs( &locs_buf[lsize * 2], lsize); + + // Do the emission. n->emit(buf, this->regalloc()); + + // End scratch_emit_size section. + set_in_scratch_emit_size(false); + return buf.insts_size(); } @@ -516,10 +546,13 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr _orig_pc_slot(0), _orig_pc_slot_offset_in_bytes(0), _has_method_handle_invokes(false), + _mach_constant_base_node(NULL), _node_bundling_limit(0), _node_bundling_base(NULL), _java_calls(0), _inner_loops(0), + _scratch_const_size(-1), + _in_scratch_emit_size(false), #ifndef PRODUCT _trace_opto_output(TraceOptoOutput || method()->has_option("TraceOptoOutput")), _printer(IdealGraphPrinter::printer()), @@ -783,6 +816,7 @@ Compile::Compile( ciEnv* ci_env, _failure_reason(NULL), _code_buffer("Compile::Fill_buffer"), _has_method_handle_invokes(false), + _mach_constant_base_node(NULL), _node_bundling_limit(0), _node_bundling_base(NULL), _java_calls(0), @@ -2862,3 +2896,207 @@ Compile::TracePhase::~TracePhase() { _log->done("phase nodes='%d'", C->unique()); } } + +//============================================================================= +// Two Constant's are equal when the type and the value are equal. +bool Compile::Constant::operator==(const Constant& other) { + if (type() != other.type() ) return false; + if (can_be_reused() != other.can_be_reused()) return false; + // For floating point values we compare the bit pattern. + switch (type()) { + case T_FLOAT: return (_value.i == other._value.i); + case T_LONG: + case T_DOUBLE: return (_value.j == other._value.j); + case T_OBJECT: + case T_ADDRESS: return (_value.l == other._value.l); + case T_VOID: return (_value.l == other._value.l); // jump-table entries + default: ShouldNotReachHere(); + } + return false; +} + +// Emit constants grouped in the following order: +static BasicType type_order[] = { + T_FLOAT, // 32-bit + T_OBJECT, // 32 or 64-bit + T_ADDRESS, // 32 or 64-bit + T_DOUBLE, // 64-bit + T_LONG, // 64-bit + T_VOID, // 32 or 64-bit (jump-tables are at the end of the constant table for code emission reasons) + T_ILLEGAL +}; + +static int type_to_size_in_bytes(BasicType t) { + switch (t) { + case T_LONG: return sizeof(jlong ); + case T_FLOAT: return sizeof(jfloat ); + case T_DOUBLE: return sizeof(jdouble); + // We use T_VOID as marker for jump-table entries (labels) which + // need an interal word relocation. + case T_VOID: + case T_ADDRESS: + case T_OBJECT: return sizeof(jobject); + } + + ShouldNotReachHere(); + return -1; +} + +void Compile::ConstantTable::calculate_offsets_and_size() { + int size = 0; + for (int t = 0; type_order[t] != T_ILLEGAL; t++) { + BasicType type = type_order[t]; + + for (int i = 0; i < _constants.length(); i++) { + Constant con = _constants.at(i); + if (con.type() != type) continue; // Skip other types. + + // Align size for type. + int typesize = type_to_size_in_bytes(con.type()); + size = align_size_up(size, typesize); + + // Set offset. + con.set_offset(size); + _constants.at_put(i, con); + + // Add type size. + size = size + typesize; + } + } + + // Align size up to the next section start (which is insts; see + // CodeBuffer::align_at_start). + assert(_size == -1, "already set?"); + _size = align_size_up(size, CodeEntryAlignment); + + if (Matcher::constant_table_absolute_addressing) { + set_table_base_offset(0); // No table base offset required + } else { + if (UseRDPCForConstantTableBase) { + // table base offset is set in MachConstantBaseNode::emit + } else { + // When RDPC is not used, the table base is set into the middle of + // the constant table. + int half_size = _size / 2; + assert(half_size * 2 == _size, "sanity"); + set_table_base_offset(-half_size); + } + } +} + +void Compile::ConstantTable::emit(CodeBuffer& cb) { + MacroAssembler _masm(&cb); + for (int t = 0; type_order[t] != T_ILLEGAL; t++) { + BasicType type = type_order[t]; + + for (int i = 0; i < _constants.length(); i++) { + Constant con = _constants.at(i); + if (con.type() != type) continue; // Skip other types. + + address constant_addr; + switch (con.type()) { + case T_LONG: constant_addr = _masm.long_constant( con.get_jlong() ); break; + case T_FLOAT: constant_addr = _masm.float_constant( con.get_jfloat() ); break; + case T_DOUBLE: constant_addr = _masm.double_constant(con.get_jdouble()); break; + case T_OBJECT: { + jobject obj = con.get_jobject(); + int oop_index = _masm.oop_recorder()->find_index(obj); + constant_addr = _masm.address_constant((address) obj, oop_Relocation::spec(oop_index)); + break; + } + case T_ADDRESS: { + address addr = (address) con.get_jobject(); + constant_addr = _masm.address_constant(addr); + break; + } + // We use T_VOID as marker for jump-table entries (labels) which + // need an interal word relocation. + case T_VOID: { + // Write a dummy word. The real value is filled in later + // in fill_jump_table_in_constant_table. + address addr = (address) con.get_jobject(); + constant_addr = _masm.address_constant(addr); + break; + } + default: ShouldNotReachHere(); + } + assert(constant_addr != NULL, "consts section too small"); + assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), err_msg("must be: %d == %d", constant_addr - _masm.code()->consts()->start(), con.offset())); + } + } +} + +int Compile::ConstantTable::find_offset(Constant& con) const { + int idx = _constants.find(con); + assert(idx != -1, "constant must be in constant table"); + int offset = _constants.at(idx).offset(); + assert(offset != -1, "constant table not emitted yet?"); + return offset; +} + +void Compile::ConstantTable::add(Constant& con) { + if (con.can_be_reused()) { + int idx = _constants.find(con); + if (idx != -1 && _constants.at(idx).can_be_reused()) { + return; + } + } + (void) _constants.append(con); +} + +Compile::Constant Compile::ConstantTable::add(BasicType type, jvalue value) { + Constant con(type, value); + add(con); + return con; +} + +Compile::Constant Compile::ConstantTable::add(MachOper* oper) { + jvalue value; + BasicType type = oper->type()->basic_type(); + switch (type) { + case T_LONG: value.j = oper->constantL(); break; + case T_FLOAT: value.f = oper->constantF(); break; + case T_DOUBLE: value.d = oper->constantD(); break; + case T_OBJECT: + case T_ADDRESS: value.l = (jobject) oper->constant(); break; + default: ShouldNotReachHere(); + } + return add(type, value); +} + +Compile::Constant Compile::ConstantTable::allocate_jump_table(MachConstantNode* n) { + jvalue value; + // We can use the node pointer here to identify the right jump-table + // as this method is called from Compile::Fill_buffer right before + // the MachNodes are emitted and the jump-table is filled (means the + // MachNode pointers do not change anymore). + value.l = (jobject) n; + Constant con(T_VOID, value, false); // Labels of a jump-table cannot be reused. + for (uint i = 0; i < n->outcnt(); i++) { + add(con); + } + return con; +} + +void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const { + // If called from Compile::scratch_emit_size do nothing. + if (Compile::current()->in_scratch_emit_size()) return; + + assert(labels.is_nonempty(), "must be"); + assert((uint) labels.length() == n->outcnt(), err_msg("must be equal: %d == %d", labels.length(), n->outcnt())); + + // Since MachConstantNode::constant_offset() also contains + // table_base_offset() we need to subtract the table_base_offset() + // to get the plain offset into the constant table. + int offset = n->constant_offset() - table_base_offset(); + + MacroAssembler _masm(&cb); + address* jump_table_base = (address*) (_masm.code()->consts()->start() + offset); + + for (int i = 0; i < labels.length(); i++) { + address* constant_addr = &jump_table_base[i]; + assert(*constant_addr == (address) n, "all jump-table entries must contain node pointer"); + *constant_addr = cb.consts()->target(*labels.at(i), (address) constant_addr); + cb.consts()->relocate((address) constant_addr, relocInfo::internal_word_type); + } +} diff --git a/src/share/vm/opto/compile.hpp b/src/share/vm/opto/compile.hpp index 9ec26ac70..36d09aca4 100644 --- a/src/share/vm/opto/compile.hpp +++ b/src/share/vm/opto/compile.hpp @@ -48,7 +48,10 @@ class ConnectionGraph; class InlineTree; class Int_Array; class Matcher; +class MachConstantNode; +class MachConstantBaseNode; class MachNode; +class MachOper; class MachSafePointNode; class Node; class Node_Array; @@ -139,6 +142,81 @@ class Compile : public Phase { trapHistLength = methodDataOopDesc::_trap_hist_limit }; + // Constant entry of the constant table. + class Constant { + private: + BasicType _type; + jvalue _value; + int _offset; // offset of this constant (in bytes) relative to the constant table base. + bool _can_be_reused; // true (default) if the value can be shared with other users. + + public: + Constant() : _type(T_ILLEGAL), _offset(-1), _can_be_reused(true) { _value.l = 0; } + Constant(BasicType type, jvalue value, bool can_be_reused = true) : + _type(type), + _value(value), + _offset(-1), + _can_be_reused(can_be_reused) + {} + + bool operator==(const Constant& other); + + BasicType type() const { return _type; } + + jlong get_jlong() const { return _value.j; } + jfloat get_jfloat() const { return _value.f; } + jdouble get_jdouble() const { return _value.d; } + jobject get_jobject() const { return _value.l; } + + int offset() const { return _offset; } + void set_offset(int offset) { _offset = offset; } + + bool can_be_reused() const { return _can_be_reused; } + }; + + // Constant table. + class ConstantTable { + private: + GrowableArray<Constant> _constants; // Constants of this table. + int _size; // Size in bytes the emitted constant table takes (including padding). + int _table_base_offset; // Offset of the table base that gets added to the constant offsets. + + public: + ConstantTable() : + _size(-1), + _table_base_offset(-1) // We can use -1 here since the constant table is always bigger than 2 bytes (-(size / 2), see MachConstantBaseNode::emit). + {} + + int size() const { assert(_size != -1, "size not yet calculated"); return _size; } + + void set_table_base_offset(int x) { assert(_table_base_offset == -1, "set only once"); _table_base_offset = x; } + int table_base_offset() const { assert(_table_base_offset != -1, "table base offset not yet set"); return _table_base_offset; } + + void emit(CodeBuffer& cb); + + // Returns the offset of the last entry (the top) of the constant table. + int top_offset() const { assert(_constants.top().offset() != -1, "constant not yet bound"); return _constants.top().offset(); } + + void calculate_offsets_and_size(); + int find_offset(Constant& con) const; + + void add(Constant& con); + Constant add(BasicType type, jvalue value); + Constant add(MachOper* oper); + Constant add(jfloat f) { + jvalue value; value.f = f; + return add(T_FLOAT, value); + } + Constant add(jdouble d) { + jvalue value; value.d = d; + return add(T_DOUBLE, value); + } + + // Jump table + Constant allocate_jump_table(MachConstantNode* n); + void fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const; + }; + private: // Fixed parameters to this compilation. const int _compile_id; @@ -212,6 +290,11 @@ class Compile : public Phase { Node* _recent_alloc_obj; Node* _recent_alloc_ctl; + // Constant table + ConstantTable _constant_table; // The constant table for this compile. + MachConstantBaseNode* _mach_constant_base_node; // Constant table base node singleton. + + // Blocked array of debugging and profiling information, // tracked per node. enum { _log2_node_notes_block_size = 8, @@ -272,6 +355,8 @@ class Compile : public Phase { static int _CompiledZap_count; // counter compared against CompileZap[First/Last] BufferBlob* _scratch_buffer_blob; // For temporary code buffers. relocInfo* _scratch_locs_memory; // For temporary code buffers. + int _scratch_const_size; // For temporary code buffers. + bool _in_scratch_emit_size; // true when in scratch_emit_size. public: // Accessors @@ -454,6 +539,12 @@ class Compile : public Phase { _recent_alloc_obj = obj; } + // Constant table + ConstantTable& constant_table() { return _constant_table; } + + MachConstantBaseNode* mach_constant_base_node(); + bool has_mach_constant_base_node() const { return _mach_constant_base_node != NULL; } + // Handy undefined Node Node* top() const { return _top; } @@ -605,13 +696,16 @@ class Compile : public Phase { Dependencies* dependencies() { return env()->dependencies(); } static int CompiledZap_count() { return _CompiledZap_count; } BufferBlob* scratch_buffer_blob() { return _scratch_buffer_blob; } - void init_scratch_buffer_blob(); + void init_scratch_buffer_blob(int const_size); + void clear_scratch_buffer_blob(); void set_scratch_buffer_blob(BufferBlob* b) { _scratch_buffer_blob = b; } relocInfo* scratch_locs_memory() { return _scratch_locs_memory; } void set_scratch_locs_memory(relocInfo* b) { _scratch_locs_memory = b; } // emit to scratch blob, report resulting size uint scratch_emit_size(const Node* n); + void set_in_scratch_emit_size(bool x) { _in_scratch_emit_size = x; } + bool in_scratch_emit_size() const { return _in_scratch_emit_size; } enum ScratchBufferBlob { MAX_inst_size = 1024, @@ -692,7 +786,7 @@ class Compile : public Phase { void Fill_buffer(); // Determine which variable sized branches can be shortened - void Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size, int& const_size); + void Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size); // Compute the size of first NumberOfLoopInstrToAlign instructions // at the head of a loop. diff --git a/src/share/vm/opto/gcm.cpp b/src/share/vm/opto/gcm.cpp index 6a6a18e73..1a0116445 100644 --- a/src/share/vm/opto/gcm.cpp +++ b/src/share/vm/opto/gcm.cpp @@ -89,7 +89,7 @@ void PhaseCFG::replace_block_proj_ctrl( Node *n ) { assert(in0 != NULL, "Only control-dependent"); const Node *p = in0->is_block_proj(); if (p != NULL && p != n) { // Control from a block projection? - assert(!n->pinned() || n->is_SafePointScalarObject(), "only SafePointScalarObject pinned node is expected here"); + assert(!n->pinned() || n->is_MachConstantBase() || n->is_SafePointScalarObject(), "only pinned MachConstantBase or SafePointScalarObject node is expected here"); // Find trailing Region Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block uint j = 0; diff --git a/src/share/vm/opto/machnode.cpp b/src/share/vm/opto/machnode.cpp index 179116287..6242c66aa 100644 --- a/src/share/vm/opto/machnode.cpp +++ b/src/share/vm/opto/machnode.cpp @@ -489,6 +489,20 @@ void MachTypeNode::dump_spec(outputStream *st) const { } #endif + +//============================================================================= +int MachConstantNode::constant_offset() { + int offset = _constant.offset(); + // Bind the offset lazily. + if (offset == -1) { + Compile::ConstantTable& constant_table = Compile::current()->constant_table(); + offset = constant_table.table_base_offset() + constant_table.find_offset(_constant); + _constant.set_offset(offset); + } + return offset; +} + + //============================================================================= #ifndef PRODUCT void MachNullCheckNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { diff --git a/src/share/vm/opto/machnode.hpp b/src/share/vm/opto/machnode.hpp index 633a9b143..d947bb871 100644 --- a/src/share/vm/opto/machnode.hpp +++ b/src/share/vm/opto/machnode.hpp @@ -231,9 +231,6 @@ public: // Return number of relocatable values contained in this instruction virtual int reloc() const { return 0; } - // Return number of words used for double constants in this instruction - virtual int const_size() const { return 0; } - // Hash and compare over operands. Used to do GVN on machine Nodes. virtual uint hash() const; virtual uint cmp( const Node &n ) const; @@ -348,6 +345,65 @@ public: #endif }; +//------------------------------MachConstantBaseNode-------------------------- +// Machine node that represents the base address of the constant table. +class MachConstantBaseNode : public MachIdealNode { +public: + static const RegMask& _out_RegMask; // We need the out_RegMask statically in MachConstantNode::in_RegMask(). + +public: + MachConstantBaseNode() : MachIdealNode() { + init_class_id(Class_MachConstantBase); + } + virtual const class Type* bottom_type() const { return TypeRawPtr::NOTNULL; } + virtual uint ideal_reg() const { return Op_RegP; } + virtual uint oper_input_base() const { return 1; } + + virtual void emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const; + virtual uint size(PhaseRegAlloc* ra_) const; + virtual bool pinned() const { return UseRDPCForConstantTableBase; } + + static const RegMask& static_out_RegMask() { return _out_RegMask; } + virtual const RegMask& out_RegMask() const { return static_out_RegMask(); } + +#ifndef PRODUCT + virtual const char* Name() const { return "MachConstantBaseNode"; } + virtual void format(PhaseRegAlloc*, outputStream* st) const; +#endif +}; + +//------------------------------MachConstantNode------------------------------- +// Machine node that holds a constant which is stored in the constant table. +class MachConstantNode : public MachNode { +protected: + Compile::Constant _constant; // This node's constant. + +public: + MachConstantNode() : MachNode() { + init_class_id(Class_MachConstant); + } + + virtual void eval_constant(Compile* C) { +#ifdef ASSERT + tty->print("missing MachConstantNode eval_constant function: "); + dump(); +#endif + ShouldNotCallThis(); + } + + virtual const RegMask &in_RegMask(uint idx) const { + if (idx == mach_constant_base_node_input()) + return MachConstantBaseNode::static_out_RegMask(); + return MachNode::in_RegMask(idx); + } + + // Input edge of MachConstantBaseNode. + uint mach_constant_base_node_input() const { return req() - 1; } + + int constant_offset(); + int constant_offset() const { return ((MachConstantNode*) this)->constant_offset(); } +}; + //------------------------------MachUEPNode----------------------------------- // Machine Unvalidated Entry Point Node class MachUEPNode : public MachIdealNode { diff --git a/src/share/vm/opto/matcher.hpp b/src/share/vm/opto/matcher.hpp index 6e8f04c5c..c1627c60f 100644 --- a/src/share/vm/opto/matcher.hpp +++ b/src/share/vm/opto/matcher.hpp @@ -365,6 +365,10 @@ public: // registers? True for Intel but false for most RISCs static const bool clone_shift_expressions; + // Should constant table entries be accessed with loads using + // absolute addressing? True for x86 but false for most RISCs. + static const bool constant_table_absolute_addressing; + static bool narrow_oop_use_complex_address(); // Generate implicit null check for narrow oops if it can fold diff --git a/src/share/vm/opto/node.hpp b/src/share/vm/opto/node.hpp index c1aaf3600..67bcf90f2 100644 --- a/src/share/vm/opto/node.hpp +++ b/src/share/vm/opto/node.hpp @@ -81,6 +81,8 @@ class MachCallLeafNode; class MachCallNode; class MachCallRuntimeNode; class MachCallStaticJavaNode; +class MachConstantBaseNode; +class MachConstantNode; class MachIfNode; class MachNode; class MachNullCheckNode; @@ -566,10 +568,12 @@ public: DEFINE_CLASS_ID(MachCallDynamicJava, MachCallJava, 1) DEFINE_CLASS_ID(MachCallRuntime, MachCall, 1) DEFINE_CLASS_ID(MachCallLeaf, MachCallRuntime, 0) - DEFINE_CLASS_ID(MachSpillCopy, Mach, 1) - DEFINE_CLASS_ID(MachNullCheck, Mach, 2) - DEFINE_CLASS_ID(MachIf, Mach, 3) - DEFINE_CLASS_ID(MachTemp, Mach, 4) + DEFINE_CLASS_ID(MachSpillCopy, Mach, 1) + DEFINE_CLASS_ID(MachNullCheck, Mach, 2) + DEFINE_CLASS_ID(MachIf, Mach, 3) + DEFINE_CLASS_ID(MachTemp, Mach, 4) + DEFINE_CLASS_ID(MachConstantBase, Mach, 5) + DEFINE_CLASS_ID(MachConstant, Mach, 6) DEFINE_CLASS_ID(Proj, Node, 2) DEFINE_CLASS_ID(CatchProj, Proj, 0) @@ -734,6 +738,8 @@ public: DEFINE_CLASS_QUERY(MachCallLeaf) DEFINE_CLASS_QUERY(MachCallRuntime) DEFINE_CLASS_QUERY(MachCallStaticJava) + DEFINE_CLASS_QUERY(MachConstantBase) + DEFINE_CLASS_QUERY(MachConstant) DEFINE_CLASS_QUERY(MachIf) DEFINE_CLASS_QUERY(MachNullCheck) DEFINE_CLASS_QUERY(MachReturn) diff --git a/src/share/vm/opto/output.cpp b/src/share/vm/opto/output.cpp index 015b8f69a..e2ddd974f 100644 --- a/src/share/vm/opto/output.cpp +++ b/src/share/vm/opto/output.cpp @@ -61,11 +61,6 @@ void Compile::Output() { // RootNode goes assert( _cfg->_broot->_nodes.size() == 0, "" ); - // Initialize the space for the BufferBlob used to find and verify - // instruction size in MachNode::emit_size() - init_scratch_buffer_blob(); - if (failing()) return; // Out of memory - // The number of new nodes (mostly MachNop) is proportional to // the number of java calls and inner loops which are aligned. if ( C->check_node_count((NodeLimitFudgeFactor + C->java_calls()*3 + @@ -333,7 +328,7 @@ void Compile::compute_loop_first_inst_sizes() { //----------------------Shorten_branches--------------------------------------- // The architecture description provides short branch variants for some long // branch instructions. Replace eligible long branches with short branches. -void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size, int& const_size) { +void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size) { // fill in the nop array for bundling computations MachNode *_nop_list[Bundle::_nop_count]; @@ -353,12 +348,11 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i // Size in bytes of all relocation entries, including those in local stubs. // Start with 2-bytes of reloc info for the unvalidated entry point reloc_size = 1; // Number of relocation entries - const_size = 0; // size of fp constants in words // Make three passes. The first computes pessimistic blk_starts, - // relative jmp_end, reloc_size and const_size information. - // The second performs short branch substitution using the pessimistic - // sizing. The third inserts nops where needed. + // relative jmp_end and reloc_size information. The second performs + // short branch substitution using the pessimistic sizing. The + // third inserts nops where needed. Node *nj; // tmp @@ -381,7 +375,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i MachNode *mach = nj->as_Mach(); blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding reloc_size += mach->reloc(); - const_size += mach->const_size(); if( mach->is_MachCall() ) { MachCallNode *mcall = mach->as_MachCall(); // This destination address is NOT PC-relative @@ -398,10 +391,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i if (min_offset_from_last_call == 0) { blk_size += nop_size; } - } else if (mach->ideal_Opcode() == Op_Jump) { - const_size += b->_num_succs; // Address table size - // The size is valid even for 64 bit since it is - // multiplied by 2*jintSize on this method exit. } } min_offset_from_last_call += inst_size; @@ -562,10 +551,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i // a relocation index. // The CodeBuffer will expand the locs array if this estimate is too low. reloc_size *= 10 / sizeof(relocInfo); - - // Adjust const_size to number of bytes - const_size *= 2*jintSize; // both float and double take two words per entry - } //------------------------------FillLocArray----------------------------------- @@ -1102,10 +1087,39 @@ void Compile::Fill_buffer() { blk_labels[i].init(); } + if (has_mach_constant_base_node()) { + // Fill the constant table. + // Note: This must happen before Shorten_branches. + for (i = 0; i < _cfg->_num_blocks; i++) { + Block* b = _cfg->_blocks[i]; + + for (uint j = 0; j < b->_nodes.size(); j++) { + Node* n = b->_nodes[j]; + + // If the node is a MachConstantNode evaluate the constant + // value section. + if (n->is_MachConstant()) { + MachConstantNode* machcon = n->as_MachConstant(); + machcon->eval_constant(C); + } + } + } + + // Calculate the offsets of the constants and the size of the + // constant table (including the padding to the next section). + constant_table().calculate_offsets_and_size(); + const_req = constant_table().size(); + } + + // Initialize the space for the BufferBlob used to find and verify + // instruction size in MachNode::emit_size() + init_scratch_buffer_blob(const_req); + if (failing()) return; // Out of memory + // If this machine supports different size branch offsets, then pre-compute // the length of the blocks if( _matcher->is_short_branch_offset(-1, 0) ) { - Shorten_branches(blk_labels, code_req, locs_req, stub_req, const_req); + Shorten_branches(blk_labels, code_req, locs_req, stub_req); labels_not_set = false; } @@ -1121,12 +1135,12 @@ void Compile::Fill_buffer() { code_req = const_req = stub_req = exception_handler_req = deopt_handler_req = 0x10; // force expansion int total_req = + const_req + code_req + pad_req + stub_req + exception_handler_req + - deopt_handler_req + // deopt handler - const_req; + deopt_handler_req; // deopt handler if (has_method_handle_invokes()) total_req += deopt_handler_req; // deopt MH handler @@ -1180,6 +1194,11 @@ void Compile::Fill_buffer() { NonSafepointEmitter non_safepoints(this); // emit non-safepoints lazily + // Emit the constant table. + if (has_mach_constant_base_node()) { + constant_table().emit(*cb); + } + // ------------------ // Now fill in the code buffer Node *delay_slot = NULL; @@ -1196,12 +1215,13 @@ void Compile::Fill_buffer() { cb->flush_bundle(true); // Define the label at the beginning of the basic block - if( labels_not_set ) - MacroAssembler(cb).bind( blk_labels[b->_pre_order] ); - - else - assert( blk_labels[b->_pre_order].loc_pos() == cb->insts_size(), - "label position does not match code offset" ); + if (labels_not_set) { + MacroAssembler(cb).bind(blk_labels[b->_pre_order]); + } else { + assert(blk_labels[b->_pre_order].loc_pos() == cb->insts_size(), + err_msg("label position does not match code offset: %d != %d", + blk_labels[b->_pre_order].loc_pos(), cb->insts_size())); + } uint last_inst = b->_nodes.size(); @@ -1718,9 +1738,17 @@ void Compile::ScheduleAndBundle() { // Create a data structure for all the scheduling information Scheduling scheduling(Thread::current()->resource_area(), *this); + // Initialize the space for the BufferBlob used to find and verify + // instruction size in MachNode::emit_size() + init_scratch_buffer_blob(MAX_const_size); + if (failing()) return; // Out of memory + // Walk backwards over each basic block, computing the needed alignment // Walk over all the basic blocks scheduling.DoScheduling(); + + // Clear the BufferBlob used for scheduling. + clear_scratch_buffer_blob(); } //------------------------------ComputeLocalLatenciesForward------------------- diff --git a/src/share/vm/opto/postaloc.cpp b/src/share/vm/opto/postaloc.cpp index c901f611f..897d5102c 100644 --- a/src/share/vm/opto/postaloc.cpp +++ b/src/share/vm/opto/postaloc.cpp @@ -200,6 +200,19 @@ int PhaseChaitin::elide_copy( Node *n, int k, Block *current_block, Node_List &v // then reloaded BUT survives in a register the whole way. Node *val = skip_copies(n->in(k)); + if (val == x && nk_idx != 0 && + regnd[nk_reg] != NULL && regnd[nk_reg] != x && + n2lidx(x) == n2lidx(regnd[nk_reg])) { + // When rematerialzing nodes and stretching lifetimes, the + // allocator will reuse the original def for multidef LRG instead + // of the current reaching def because it can't know it's safe to + // do so. After allocation completes if they are in the same LRG + // then it should use the current reaching def instead. + n->set_req(k, regnd[nk_reg]); + blk_adjust += yank_if_dead(val, current_block, &value, ®nd); + val = skip_copies(n->in(k)); + } + if( val == x ) return blk_adjust; // No progress? bool single = is_single_register(val->ideal_reg()); |