mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 17:44:40 +02:00
8240363: Refactor Compile::Output() to its own Phase
Reviewed-by: kvn, vlivanov
This commit is contained in:
parent
6ddb0f2b2c
commit
21cd75cb98
28 changed files with 1388 additions and 1228 deletions
|
@ -1575,7 +1575,7 @@ uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const {
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
|
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
|
||||||
|
|
||||||
int Compile::ConstantTable::calculate_table_base_offset() const {
|
int ConstantTable::calculate_table_base_offset() const {
|
||||||
return 0; // absolute addressing, no offset
|
return 0; // absolute addressing, no offset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1602,9 +1602,9 @@ void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
||||||
void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
|
void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
|
|
||||||
int framesize = C->frame_slots() << LogBytesPerInt;
|
int framesize = C->output()->frame_slots() << LogBytesPerInt;
|
||||||
|
|
||||||
if (C->need_stack_bang(framesize))
|
if (C->output()->need_stack_bang(framesize))
|
||||||
st->print("# stack bang size=%d\n\t", framesize);
|
st->print("# stack bang size=%d\n\t", framesize);
|
||||||
|
|
||||||
if (framesize < ((1 << 9) + 2 * wordSize)) {
|
if (framesize < ((1 << 9) + 2 * wordSize)) {
|
||||||
|
@ -1625,7 +1625,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
// n.b. frame size includes space for return pc and rfp
|
// n.b. frame size includes space for return pc and rfp
|
||||||
const long framesize = C->frame_size_in_bytes();
|
const long framesize = C->output()->frame_size_in_bytes();
|
||||||
assert(framesize%(2*wordSize) == 0, "must preserve 2*wordSize alignment");
|
assert(framesize%(2*wordSize) == 0, "must preserve 2*wordSize alignment");
|
||||||
|
|
||||||
// insert a nop at the start of the prolog so we can patch in a
|
// insert a nop at the start of the prolog so we can patch in a
|
||||||
|
@ -1643,8 +1643,8 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
__ bind(L_skip_barrier);
|
__ bind(L_skip_barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
if (C->need_stack_bang(bangsize) && UseStackBanging)
|
if (C->output()->need_stack_bang(bangsize) && UseStackBanging)
|
||||||
__ generate_stack_overflow_check(bangsize);
|
__ generate_stack_overflow_check(bangsize);
|
||||||
|
|
||||||
__ build_frame(framesize);
|
__ build_frame(framesize);
|
||||||
|
@ -1653,12 +1653,12 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
Unimplemented();
|
Unimplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
C->set_frame_complete(cbuf.insts_size());
|
C->output()->set_frame_complete(cbuf.insts_size());
|
||||||
|
|
||||||
if (C->has_mach_constant_base_node()) {
|
if (C->has_mach_constant_base_node()) {
|
||||||
// NOTE: We set the table base offset here because users might be
|
// NOTE: We set the table base offset here because users might be
|
||||||
// emitted before MachConstantBaseNode.
|
// emitted before MachConstantBaseNode.
|
||||||
Compile::ConstantTable& constant_table = C->constant_table();
|
ConstantTable& constant_table = C->output()->constant_table();
|
||||||
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1679,7 +1679,7 @@ int MachPrologNode::reloc() const
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
|
void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
int framesize = C->frame_slots() << LogBytesPerInt;
|
int framesize = C->output()->frame_slots() << LogBytesPerInt;
|
||||||
|
|
||||||
st->print("# pop frame %d\n\t",framesize);
|
st->print("# pop frame %d\n\t",framesize);
|
||||||
|
|
||||||
|
@ -1705,7 +1705,7 @@ void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
|
||||||
void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
int framesize = C->frame_slots() << LogBytesPerInt;
|
int framesize = C->output()->frame_slots() << LogBytesPerInt;
|
||||||
|
|
||||||
__ remove_frame(framesize);
|
__ remove_frame(framesize);
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#include "opto/compile.hpp"
|
#include "opto/compile.hpp"
|
||||||
#include "opto/intrinsicnode.hpp"
|
#include "opto/intrinsicnode.hpp"
|
||||||
#include "opto/node.hpp"
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/output.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PRODUCT
|
#ifdef PRODUCT
|
||||||
|
@ -745,7 +746,7 @@ address MacroAssembler::trampoline_call(Address entry, CodeBuffer *cbuf) {
|
||||||
CompileTask* task = ciEnv::current()->task();
|
CompileTask* task = ciEnv::current()->task();
|
||||||
in_scratch_emit_size =
|
in_scratch_emit_size =
|
||||||
(task != NULL && is_c2_compile(task->comp_level()) &&
|
(task != NULL && is_c2_compile(task->comp_level()) &&
|
||||||
Compile::current()->in_scratch_emit_size());
|
Compile::current()->output()->in_scratch_emit_size());
|
||||||
#endif
|
#endif
|
||||||
if (!in_scratch_emit_size) {
|
if (!in_scratch_emit_size) {
|
||||||
address stub = emit_trampoline_stub(offset(), entry.target());
|
address stub = emit_trampoline_stub(offset(), entry.target());
|
||||||
|
|
|
@ -194,7 +194,7 @@ void emit_hi(CodeBuffer &cbuf, int val) { }
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask();
|
const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask();
|
||||||
|
|
||||||
int Compile::ConstantTable::calculate_table_base_offset() const {
|
int ConstantTable::calculate_table_base_offset() const {
|
||||||
int offset = -(size() / 2);
|
int offset = -(size() / 2);
|
||||||
// flds, fldd: 8-bit offset multiplied by 4: +/- 1024
|
// flds, fldd: 8-bit offset multiplied by 4: +/- 1024
|
||||||
// ldr, ldrb : 12-bit offset: +/- 4096
|
// ldr, ldrb : 12-bit offset: +/- 4096
|
||||||
|
@ -211,7 +211,7 @@ void MachConstantBaseNode::postalloc_expand(GrowableArray <Node *> *nodes, Phase
|
||||||
|
|
||||||
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
|
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
Compile::ConstantTable& constant_table = C->constant_table();
|
ConstantTable& constant_table = C->output()->constant_table();
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
Register r = as_Register(ra_->get_encode(this));
|
Register r = as_Register(ra_->get_encode(this));
|
||||||
|
@ -245,9 +245,9 @@ void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
|
||||||
st->print_cr("NOP"); st->print("\t");
|
st->print_cr("NOP"); st->print("\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t framesize = C->frame_size_in_bytes();
|
size_t framesize = C->output()->frame_size_in_bytes();
|
||||||
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
// Remove two words for return addr and rbp,
|
// Remove two words for return addr and rbp,
|
||||||
framesize -= 2*wordSize;
|
framesize -= 2*wordSize;
|
||||||
bangsize -= 2*wordSize;
|
bangsize -= 2*wordSize;
|
||||||
|
@ -257,7 +257,7 @@ void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
|
||||||
// some VM calls (such as call site linkage) can use several kilobytes of
|
// some VM calls (such as call site linkage) can use several kilobytes of
|
||||||
// stack. But the stack safety zone should account for that.
|
// stack. But the stack safety zone should account for that.
|
||||||
// See bugs 4446381, 4468289, 4497237.
|
// See bugs 4446381, 4468289, 4497237.
|
||||||
if (C->need_stack_bang(bangsize)) {
|
if (C->output()->need_stack_bang(bangsize)) {
|
||||||
st->print_cr("! stack bang (%d bytes)", bangsize); st->print("\t");
|
st->print_cr("! stack bang (%d bytes)", bangsize); st->print("\t");
|
||||||
}
|
}
|
||||||
st->print_cr("PUSH R_FP|R_LR_LR"); st->print("\t");
|
st->print_cr("PUSH R_FP|R_LR_LR"); st->print("\t");
|
||||||
|
@ -275,9 +275,9 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
__ nop();
|
__ nop();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t framesize = C->frame_size_in_bytes();
|
size_t framesize = C->output()->frame_size_in_bytes();
|
||||||
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
// Remove two words for return addr and fp,
|
// Remove two words for return addr and fp,
|
||||||
framesize -= 2*wordSize;
|
framesize -= 2*wordSize;
|
||||||
bangsize -= 2*wordSize;
|
bangsize -= 2*wordSize;
|
||||||
|
@ -287,7 +287,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
// some VM calls (such as call site linkage) can use several kilobytes of
|
// some VM calls (such as call site linkage) can use several kilobytes of
|
||||||
// stack. But the stack safety zone should account for that.
|
// stack. But the stack safety zone should account for that.
|
||||||
// See bugs 4446381, 4468289, 4497237.
|
// See bugs 4446381, 4468289, 4497237.
|
||||||
if (C->need_stack_bang(bangsize)) {
|
if (C->output()->need_stack_bang(bangsize)) {
|
||||||
__ arm_stack_overflow_check(bangsize, Rtemp);
|
__ arm_stack_overflow_check(bangsize, Rtemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,13 +298,13 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
|
|
||||||
// offset from scratch buffer is not valid
|
// offset from scratch buffer is not valid
|
||||||
if (strcmp(cbuf.name(), "Compile::Fill_buffer") == 0) {
|
if (strcmp(cbuf.name(), "Compile::Fill_buffer") == 0) {
|
||||||
C->set_frame_complete( __ offset() );
|
C->output()->set_frame_complete( __ offset() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (C->has_mach_constant_base_node()) {
|
if (C->has_mach_constant_base_node()) {
|
||||||
// NOTE: We set the table base offset here because users might be
|
// NOTE: We set the table base offset here because users might be
|
||||||
// emitted before MachConstantBaseNode.
|
// emitted before MachConstantBaseNode.
|
||||||
Compile::ConstantTable& constant_table = C->constant_table();
|
ConstantTable& constant_table = C->output()->constant_table();
|
||||||
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,7 +322,7 @@ int MachPrologNode::reloc() const {
|
||||||
void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
|
void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
|
|
||||||
size_t framesize = C->frame_size_in_bytes();
|
size_t framesize = C->output()->frame_size_in_bytes();
|
||||||
framesize -= 2*wordSize;
|
framesize -= 2*wordSize;
|
||||||
|
|
||||||
if (framesize != 0) {
|
if (framesize != 0) {
|
||||||
|
@ -342,7 +342,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
|
|
||||||
size_t framesize = C->frame_size_in_bytes();
|
size_t framesize = C->output()->frame_size_in_bytes();
|
||||||
framesize -= 2*wordSize;
|
framesize -= 2*wordSize;
|
||||||
if (framesize != 0) {
|
if (framesize != 0) {
|
||||||
__ add_slow(SP, SP, framesize);
|
__ add_slow(SP, SP, framesize);
|
||||||
|
@ -827,7 +827,7 @@ void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
uint BoxLockNode::size(PhaseRegAlloc *ra_) const {
|
uint BoxLockNode::size(PhaseRegAlloc *ra_) const {
|
||||||
// BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_)
|
// BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_)
|
||||||
assert(ra_ == ra_->C->regalloc(), "sanity");
|
assert(ra_ == ra_->C->regalloc(), "sanity");
|
||||||
return ra_->C->scratch_emit_size(this);
|
return ra_->C->output()->scratch_emit_size(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
|
@ -1297,7 +1297,7 @@ static inline jlong replicate_immF(float con) {
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
const RegMask& MachConstantBaseNode::_out_RegMask = BITS64_CONSTANT_TABLE_BASE_mask();
|
const RegMask& MachConstantBaseNode::_out_RegMask = BITS64_CONSTANT_TABLE_BASE_mask();
|
||||||
int Compile::ConstantTable::calculate_table_base_offset() const {
|
int ConstantTable::calculate_table_base_offset() const {
|
||||||
return 0; // absolute addressing, no offset
|
return 0; // absolute addressing, no offset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1338,10 +1338,10 @@ void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
|
void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
const long framesize = C->frame_slots() << LogBytesPerInt;
|
const long framesize = C->output()->frame_slots() << LogBytesPerInt;
|
||||||
|
|
||||||
st->print("PROLOG\n\t");
|
st->print("PROLOG\n\t");
|
||||||
if (C->need_stack_bang(framesize)) {
|
if (C->output()->need_stack_bang(framesize)) {
|
||||||
st->print("stack_overflow_check\n\t");
|
st->print("stack_overflow_check\n\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1381,7 +1381,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
const long framesize = C->frame_size_in_bytes();
|
const long framesize = C->output()->frame_size_in_bytes();
|
||||||
assert(framesize % (2 * wordSize) == 0, "must preserve 2*wordSize alignment");
|
assert(framesize % (2 * wordSize) == 0, "must preserve 2*wordSize alignment");
|
||||||
|
|
||||||
const bool method_is_frameless = false /* TODO: PPC port C->is_frameless_method()*/;
|
const bool method_is_frameless = false /* TODO: PPC port C->is_frameless_method()*/;
|
||||||
|
@ -1426,9 +1426,9 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
// use several kilobytes of stack. But the stack safety zone should
|
// use several kilobytes of stack. But the stack safety zone should
|
||||||
// account for that. See bugs 4446381, 4468289, 4497237.
|
// account for that. See bugs 4446381, 4468289, 4497237.
|
||||||
|
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
assert(bangsize >= framesize || bangsize <= 0, "stack bang size incorrect");
|
assert(bangsize >= framesize || bangsize <= 0, "stack bang size incorrect");
|
||||||
if (C->need_stack_bang(bangsize) && UseStackBanging) {
|
if (C->output()->need_stack_bang(bangsize) && UseStackBanging) {
|
||||||
// Unfortunately we cannot use the function provided in
|
// Unfortunately we cannot use the function provided in
|
||||||
// assembler.cpp as we have to emulate the pipes. So I had to
|
// assembler.cpp as we have to emulate the pipes. So I had to
|
||||||
// insert the code of generate_stack_overflow_check(), see
|
// insert the code of generate_stack_overflow_check(), see
|
||||||
|
@ -1482,7 +1482,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
bang_offset += page_size;
|
bang_offset += page_size;
|
||||||
}
|
}
|
||||||
// R11 trashed
|
// R11 trashed
|
||||||
} // C->need_stack_bang(framesize) && UseStackBanging
|
} // C->output()->need_stack_bang(framesize) && UseStackBanging
|
||||||
|
|
||||||
unsigned int bytes = (unsigned int)framesize;
|
unsigned int bytes = (unsigned int)framesize;
|
||||||
long offset = Assembler::align_addr(bytes, frame::alignment_in_bytes);
|
long offset = Assembler::align_addr(bytes, frame::alignment_in_bytes);
|
||||||
|
@ -1537,7 +1537,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
___(std) std(return_pc, _abi(lr), callers_sp);
|
___(std) std(return_pc, _abi(lr), callers_sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
C->set_frame_complete(cbuf.insts_size());
|
C->output()->set_frame_complete(cbuf.insts_size());
|
||||||
}
|
}
|
||||||
#undef ___
|
#undef ___
|
||||||
#undef ___stop
|
#undef ___stop
|
||||||
|
@ -1573,7 +1573,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
const long framesize = ((long)C->frame_slots()) << LogBytesPerInt;
|
const long framesize = ((long)C->output()->frame_slots()) << LogBytesPerInt;
|
||||||
assert(framesize >= 0, "negative frame-size?");
|
assert(framesize >= 0, "negative frame-size?");
|
||||||
|
|
||||||
const bool method_needs_polling = do_polling() && C->is_method_compilation();
|
const bool method_needs_polling = do_polling() && C->is_method_compilation();
|
||||||
|
@ -2786,7 +2786,7 @@ encode %{
|
||||||
|
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
if (!ra_->C->in_scratch_emit_size()) {
|
if (!ra_->C->output()->in_scratch_emit_size()) {
|
||||||
address const_toc_addr;
|
address const_toc_addr;
|
||||||
// Create a non-oop constant, no relocation needed.
|
// Create a non-oop constant, no relocation needed.
|
||||||
// If it is an IC, it has a virtual_call_Relocation.
|
// If it is an IC, it has a virtual_call_Relocation.
|
||||||
|
@ -3053,7 +3053,7 @@ encode %{
|
||||||
// TODO: PPC port $archOpcode(ppc64Opcode_addis);
|
// TODO: PPC port $archOpcode(ppc64Opcode_addis);
|
||||||
|
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
if (!ra_->C->in_scratch_emit_size()) {
|
if (!ra_->C->output()->in_scratch_emit_size()) {
|
||||||
intptr_t val = $src$$constant;
|
intptr_t val = $src$$constant;
|
||||||
relocInfo::relocType constant_reloc = $src->constant_reloc(); // src
|
relocInfo::relocType constant_reloc = $src->constant_reloc(); // src
|
||||||
address const_toc_addr;
|
address const_toc_addr;
|
||||||
|
@ -3791,7 +3791,7 @@ encode %{
|
||||||
|
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
if (!ra_->C->in_scratch_emit_size()) {
|
if (!ra_->C->output()->in_scratch_emit_size()) {
|
||||||
// Create a call trampoline stub for the given method.
|
// Create a call trampoline stub for the given method.
|
||||||
const address entry_point = !($meth$$method) ? 0 : (address)$meth$$method;
|
const address entry_point = !($meth$$method) ? 0 : (address)$meth$$method;
|
||||||
const address entry_point_const = __ address_constant(entry_point, RelocationHolder::none);
|
const address entry_point_const = __ address_constant(entry_point, RelocationHolder::none);
|
||||||
|
@ -6285,7 +6285,7 @@ instruct loadConL_lo(iRegLdst dst, immL src, iRegLdst base) %{
|
||||||
size(4);
|
size(4);
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
// TODO: PPC port $archOpcode(ppc64Opcode_ld);
|
// TODO: PPC port $archOpcode(ppc64Opcode_ld);
|
||||||
int offset = ra_->C->in_scratch_emit_size() ? 0 : _const_toc_offset_hi_node->_const_toc_offset;
|
int offset = ra_->C->output()->in_scratch_emit_size() ? 0 : _const_toc_offset_hi_node->_const_toc_offset;
|
||||||
__ ld($dst$$Register, MacroAssembler::largeoffset_si16_si16_lo(offset), $base$$Register);
|
__ ld($dst$$Register, MacroAssembler::largeoffset_si16_si16_lo(offset), $base$$Register);
|
||||||
%}
|
%}
|
||||||
ins_pipe(pipe_class_memory);
|
ins_pipe(pipe_class_memory);
|
||||||
|
@ -6570,7 +6570,7 @@ instruct loadConP_lo(iRegPdst dst, immP_NM src, iRegLdst base) %{
|
||||||
size(4);
|
size(4);
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
// TODO: PPC port $archOpcode(ppc64Opcode_ld);
|
// TODO: PPC port $archOpcode(ppc64Opcode_ld);
|
||||||
int offset = ra_->C->in_scratch_emit_size() ? 0 : _const_toc_offset_hi_node->_const_toc_offset;
|
int offset = ra_->C->output()->in_scratch_emit_size() ? 0 : _const_toc_offset_hi_node->_const_toc_offset;
|
||||||
__ ld($dst$$Register, MacroAssembler::largeoffset_si16_si16_lo(offset), $base$$Register);
|
__ ld($dst$$Register, MacroAssembler::largeoffset_si16_si16_lo(offset), $base$$Register);
|
||||||
%}
|
%}
|
||||||
ins_pipe(pipe_class_memory);
|
ins_pipe(pipe_class_memory);
|
||||||
|
|
|
@ -54,7 +54,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/*
|
||||||
// That's why we must use the macroassembler to generate a stub.
|
// That's why we must use the macroassembler to generate a stub.
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
address stub = __ start_a_stub(Compile::MAX_stubs_size);
|
address stub = __ start_a_stub(CompiledStaticCall::to_interp_stub_size());
|
||||||
if (stub == NULL) {
|
if (stub == NULL) {
|
||||||
return NULL; // CodeBuffer::expand failed.
|
return NULL; // CodeBuffer::expand failed.
|
||||||
}
|
}
|
||||||
|
|
|
@ -795,7 +795,7 @@ static int emit_call_reloc(MacroAssembler &_masm, intptr_t entry_point, Relocati
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
const RegMask& MachConstantBaseNode::_out_RegMask = _Z_PTR_REG_mask;
|
const RegMask& MachConstantBaseNode::_out_RegMask = _Z_PTR_REG_mask;
|
||||||
int Compile::ConstantTable::calculate_table_base_offset() const {
|
int ConstantTable::calculate_table_base_offset() const {
|
||||||
return 0; // absolute addressing, no offset
|
return 0; // absolute addressing, no offset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -840,15 +840,15 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
|
||||||
st->print("\t");
|
st->print("\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
long framesize = C->frame_size_in_bytes();
|
long framesize = C->output()->frame_size_in_bytes();
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
|
|
||||||
// Calls to C2R adapters often do not accept exceptional returns.
|
// Calls to C2R adapters often do not accept exceptional returns.
|
||||||
// We require that their callers must bang for them. But be
|
// We require that their callers must bang for them. But be
|
||||||
// careful, because some VM calls (such as call site linkage) can
|
// careful, because some VM calls (such as call site linkage) can
|
||||||
// use several kilobytes of stack. But the stack safety zone should
|
// use several kilobytes of stack. But the stack safety zone should
|
||||||
// account for that. See bugs 4446381, 4468289, 4497237.
|
// account for that. See bugs 4446381, 4468289, 4497237.
|
||||||
if (C->need_stack_bang(bangsize) && UseStackBanging) {
|
if (C->output()->need_stack_bang(bangsize) && UseStackBanging) {
|
||||||
st->print_cr("# stack bang"); st->print("\t");
|
st->print_cr("# stack bang"); st->print("\t");
|
||||||
}
|
}
|
||||||
st->print_cr("push_frame %d", (int)-framesize);
|
st->print_cr("push_frame %d", (int)-framesize);
|
||||||
|
@ -862,8 +862,8 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
|
|
||||||
__ verify_thread();
|
__ verify_thread();
|
||||||
|
|
||||||
size_t framesize = C->frame_size_in_bytes();
|
size_t framesize = C->output()->frame_size_in_bytes();
|
||||||
size_t bangsize = C->bang_size_in_bytes();
|
size_t bangsize = C->output()->bang_size_in_bytes();
|
||||||
|
|
||||||
assert(framesize % wordSize == 0, "must preserve wordSize alignment");
|
assert(framesize % wordSize == 0, "must preserve wordSize alignment");
|
||||||
|
|
||||||
|
@ -889,7 +889,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
// careful, because some VM calls (such as call site linkage) can
|
// careful, because some VM calls (such as call site linkage) can
|
||||||
// use several kilobytes of stack. But the stack safety zone should
|
// use several kilobytes of stack. But the stack safety zone should
|
||||||
// account for that. See bugs 4446381, 4468289, 4497237.
|
// account for that. See bugs 4446381, 4468289, 4497237.
|
||||||
if (C->need_stack_bang(bangsize) && UseStackBanging) {
|
if (C->output()->need_stack_bang(bangsize) && UseStackBanging) {
|
||||||
__ generate_stack_overflow_check(bangsize);
|
__ generate_stack_overflow_check(bangsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -903,7 +903,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
if (C->has_mach_constant_base_node()) {
|
if (C->has_mach_constant_base_node()) {
|
||||||
// NOTE: We set the table base offset here because users might be
|
// NOTE: We set the table base offset here because users might be
|
||||||
// emitted before MachConstantBaseNode.
|
// emitted before MachConstantBaseNode.
|
||||||
Compile::ConstantTable& constant_table = C->constant_table();
|
ConstantTable& constant_table = C->output()->constant_table();
|
||||||
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -940,7 +940,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
bool need_polling = do_polling() && C->is_method_compilation();
|
bool need_polling = do_polling() && C->is_method_compilation();
|
||||||
|
|
||||||
// Pop frame, restore return_pc, and all stuff needed by interpreter.
|
// Pop frame, restore return_pc, and all stuff needed by interpreter.
|
||||||
int frame_size_in_bytes = Assembler::align((C->frame_slots() << LogBytesPerInt), frame::alignment_in_bytes);
|
int frame_size_in_bytes = Assembler::align((C->output()->frame_slots() << LogBytesPerInt), frame::alignment_in_bytes);
|
||||||
__ pop_frame_restore_retPC(frame_size_in_bytes);
|
__ pop_frame_restore_retPC(frame_size_in_bytes);
|
||||||
|
|
||||||
if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
|
if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
|
||||||
|
@ -1257,7 +1257,7 @@ void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc * ra_) const {
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
int rem_space = 0;
|
int rem_space = 0;
|
||||||
if (!(ra_->C->in_scratch_emit_size())) {
|
if (!(ra_->C->output()->in_scratch_emit_size())) {
|
||||||
rem_space = cbuf.insts()->remaining();
|
rem_space = cbuf.insts()->remaining();
|
||||||
if (rem_space <= _count*2 + 8) {
|
if (rem_space <= _count*2 + 8) {
|
||||||
tty->print("NopNode: _count = %3.3d, remaining space before = %d", _count, rem_space);
|
tty->print("NopNode: _count = %3.3d, remaining space before = %d", _count, rem_space);
|
||||||
|
@ -1268,7 +1268,7 @@ void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc * ra_) const {
|
||||||
__ z_nop();
|
__ z_nop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(ra_->C->in_scratch_emit_size())) {
|
if (!(ra_->C->output()->in_scratch_emit_size())) {
|
||||||
if (rem_space <= _count*2 + 8) {
|
if (rem_space <= _count*2 + 8) {
|
||||||
int rem_space2 = cbuf.insts()->remaining();
|
int rem_space2 = cbuf.insts()->remaining();
|
||||||
tty->print_cr(", after = %d", rem_space2);
|
tty->print_cr(", after = %d", rem_space2);
|
||||||
|
|
|
@ -1002,7 +1002,7 @@ void emit_hi(CodeBuffer &cbuf, int val) { }
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask();
|
const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask();
|
||||||
|
|
||||||
int Compile::ConstantTable::calculate_table_base_offset() const {
|
int ConstantTable::calculate_table_base_offset() const {
|
||||||
if (UseRDPCForConstantTableBase) {
|
if (UseRDPCForConstantTableBase) {
|
||||||
// The table base offset might be less but then it fits into
|
// The table base offset might be less but then it fits into
|
||||||
// simm13 anyway and we are good (cf. MachConstantBaseNode::emit).
|
// simm13 anyway and we are good (cf. MachConstantBaseNode::emit).
|
||||||
|
@ -1023,7 +1023,7 @@ void MachConstantBaseNode::postalloc_expand(GrowableArray <Node *> *nodes, Phase
|
||||||
|
|
||||||
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
|
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
Compile::ConstantTable& constant_table = C->constant_table();
|
ConstantTable& constant_table = C->output()->constant_table();
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
Register r = as_Register(ra_->get_encode(this));
|
Register r = as_Register(ra_->get_encode(this));
|
||||||
|
@ -1128,15 +1128,15 @@ void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
|
||||||
st->print_cr("Verify_Thread"); st->print("\t");
|
st->print_cr("Verify_Thread"); st->print("\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t framesize = C->frame_size_in_bytes();
|
size_t framesize = C->output()->frame_size_in_bytes();
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
|
|
||||||
// Calls to C2R adapters often do not accept exceptional returns.
|
// Calls to C2R adapters often do not accept exceptional returns.
|
||||||
// We require that their callers must bang for them. But be careful, because
|
// We require that their callers must bang for them. But be careful, because
|
||||||
// some VM calls (such as call site linkage) can use several kilobytes of
|
// some VM calls (such as call site linkage) can use several kilobytes of
|
||||||
// stack. But the stack safety zone should account for that.
|
// stack. But the stack safety zone should account for that.
|
||||||
// See bugs 4446381, 4468289, 4497237.
|
// See bugs 4446381, 4468289, 4497237.
|
||||||
if (C->need_stack_bang(bangsize)) {
|
if (C->output()->need_stack_bang(bangsize)) {
|
||||||
st->print_cr("! stack bang (%d bytes)", bangsize); st->print("\t");
|
st->print_cr("! stack bang (%d bytes)", bangsize); st->print("\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1161,17 +1161,17 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
|
|
||||||
__ verify_thread();
|
__ verify_thread();
|
||||||
|
|
||||||
size_t framesize = C->frame_size_in_bytes();
|
size_t framesize = C->output()->frame_size_in_bytes();
|
||||||
assert(framesize >= 16*wordSize, "must have room for reg. save area");
|
assert(framesize >= 16*wordSize, "must have room for reg. save area");
|
||||||
assert(framesize%(2*wordSize) == 0, "must preserve 2*wordSize alignment");
|
assert(framesize%(2*wordSize) == 0, "must preserve 2*wordSize alignment");
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
|
|
||||||
// Calls to C2R adapters often do not accept exceptional returns.
|
// Calls to C2R adapters often do not accept exceptional returns.
|
||||||
// We require that their callers must bang for them. But be careful, because
|
// We require that their callers must bang for them. But be careful, because
|
||||||
// some VM calls (such as call site linkage) can use several kilobytes of
|
// some VM calls (such as call site linkage) can use several kilobytes of
|
||||||
// stack. But the stack safety zone should account for that.
|
// stack. But the stack safety zone should account for that.
|
||||||
// See bugs 4446381, 4468289, 4497237.
|
// See bugs 4446381, 4468289, 4497237.
|
||||||
if (C->need_stack_bang(bangsize)) {
|
if (C->output()->need_stack_bang(bangsize)) {
|
||||||
__ generate_stack_overflow_check(bangsize);
|
__ generate_stack_overflow_check(bangsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1182,12 +1182,12 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
__ add(G3, -framesize & 0x3ff, G3);
|
__ add(G3, -framesize & 0x3ff, G3);
|
||||||
__ save(SP, G3, SP);
|
__ save(SP, G3, SP);
|
||||||
}
|
}
|
||||||
C->set_frame_complete( __ offset() );
|
C->output()->set_frame_complete( __ offset() );
|
||||||
|
|
||||||
if (!UseRDPCForConstantTableBase && C->has_mach_constant_base_node()) {
|
if (!UseRDPCForConstantTableBase && C->has_mach_constant_base_node()) {
|
||||||
// NOTE: We set the table base offset here because users might be
|
// NOTE: We set the table base offset here because users might be
|
||||||
// emitted before MachConstantBaseNode.
|
// emitted before MachConstantBaseNode.
|
||||||
Compile::ConstantTable& constant_table = C->constant_table();
|
ConstantTable& constant_table = C->output()->constant_table();
|
||||||
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1570,7 +1570,7 @@ void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
uint BoxLockNode::size(PhaseRegAlloc *ra_) const {
|
uint BoxLockNode::size(PhaseRegAlloc *ra_) const {
|
||||||
// BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_)
|
// BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_)
|
||||||
assert(ra_ == ra_->C->regalloc(), "sanity");
|
assert(ra_ == ra_->C->regalloc(), "sanity");
|
||||||
return ra_->C->scratch_emit_size(this);
|
return ra_->C->output()->scratch_emit_size(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -2426,7 +2426,7 @@ encode %{
|
||||||
enc_class call_epilog %{
|
enc_class call_epilog %{
|
||||||
if( VerifyStackAtCalls ) {
|
if( VerifyStackAtCalls ) {
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
int framesize = ra_->C->frame_size_in_bytes();
|
int framesize = ra_->C->output()->frame_size_in_bytes();
|
||||||
Register temp_reg = G3;
|
Register temp_reg = G3;
|
||||||
__ add(SP, framesize, temp_reg);
|
__ add(SP, framesize, temp_reg);
|
||||||
__ cmp(temp_reg, FP);
|
__ cmp(temp_reg, FP);
|
||||||
|
@ -8854,7 +8854,7 @@ instruct jumpXtnd(iRegX switch_val, o7RegI table) %{
|
||||||
// zero offsets because they might change when
|
// zero offsets because they might change when
|
||||||
// MachConstantBaseNode decides to optimize the constant table
|
// MachConstantBaseNode decides to optimize the constant table
|
||||||
// base.
|
// base.
|
||||||
if ((constant_offset() == 0) && !Compile::current()->in_scratch_emit_size()) {
|
if ((constant_offset() == 0) && !Compile::current()->output()->in_scratch_emit_size()) {
|
||||||
table_reg = $constanttablebase;
|
table_reg = $constanttablebase;
|
||||||
} else {
|
} else {
|
||||||
table_reg = O7;
|
table_reg = O7;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "opto/compile.hpp"
|
#include "opto/compile.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
#include "opto/node.hpp"
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/output.hpp"
|
||||||
#include "opto/regalloc.hpp"
|
#include "opto/regalloc.hpp"
|
||||||
#include "utilities/align.hpp"
|
#include "utilities/align.hpp"
|
||||||
#include "utilities/debug.hpp"
|
#include "utilities/debug.hpp"
|
||||||
|
@ -126,7 +127,7 @@ IntelJccErratumAlignment::IntelJccErratumAlignment(MacroAssembler& masm, int jcc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Compile::current()->in_scratch_emit_size()) {
|
if (Compile::current()->output()->in_scratch_emit_size()) {
|
||||||
// When we measure the size of this 32 byte alignment, we apply a conservative guess.
|
// When we measure the size of this 32 byte alignment, we apply a conservative guess.
|
||||||
__ nop(jcc_size);
|
__ nop(jcc_size);
|
||||||
} else if (IntelJccErratum::is_crossing_or_ending_at_32_byte_boundary(_start_pc, _start_pc + jcc_size)) {
|
} else if (IntelJccErratum::is_crossing_or_ending_at_32_byte_boundary(_start_pc, _start_pc + jcc_size)) {
|
||||||
|
@ -141,7 +142,7 @@ IntelJccErratumAlignment::IntelJccErratumAlignment(MacroAssembler& masm, int jcc
|
||||||
|
|
||||||
IntelJccErratumAlignment::~IntelJccErratumAlignment() {
|
IntelJccErratumAlignment::~IntelJccErratumAlignment() {
|
||||||
if (!VM_Version::has_intel_jcc_erratum() ||
|
if (!VM_Version::has_intel_jcc_erratum() ||
|
||||||
Compile::current()->in_scratch_emit_size()) {
|
Compile::current()->output()->in_scratch_emit_size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -523,7 +523,7 @@ void emit_cmpfp3(MacroAssembler& _masm, Register dst) {
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
|
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
|
||||||
|
|
||||||
int Compile::ConstantTable::calculate_table_base_offset() const {
|
int ConstantTable::calculate_table_base_offset() const {
|
||||||
return 0; // absolute addressing, no offset
|
return 0; // absolute addressing, no offset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,13 +552,13 @@ void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
||||||
void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
|
|
||||||
int framesize = C->frame_size_in_bytes();
|
int framesize = C->output()->frame_size_in_bytes();
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
||||||
// Remove wordSize for return addr which is already pushed.
|
// Remove wordSize for return addr which is already pushed.
|
||||||
framesize -= wordSize;
|
framesize -= wordSize;
|
||||||
|
|
||||||
if (C->need_stack_bang(bangsize)) {
|
if (C->output()->need_stack_bang(bangsize)) {
|
||||||
framesize -= wordSize;
|
framesize -= wordSize;
|
||||||
st->print("# stack bang (%d bytes)", bangsize);
|
st->print("# stack bang (%d bytes)", bangsize);
|
||||||
st->print("\n\t");
|
st->print("\n\t");
|
||||||
|
@ -616,17 +616,17 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
int framesize = C->frame_size_in_bytes();
|
int framesize = C->output()->frame_size_in_bytes();
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
|
|
||||||
__ verified_entry(framesize, C->need_stack_bang(bangsize)?bangsize:0, C->in_24_bit_fp_mode(), C->stub_function() != NULL);
|
__ verified_entry(framesize, C->output()->need_stack_bang(bangsize)?bangsize:0, C->in_24_bit_fp_mode(), C->stub_function() != NULL);
|
||||||
|
|
||||||
C->set_frame_complete(cbuf.insts_size());
|
C->output()->set_frame_complete(cbuf.insts_size());
|
||||||
|
|
||||||
if (C->has_mach_constant_base_node()) {
|
if (C->has_mach_constant_base_node()) {
|
||||||
// NOTE: We set the table base offset here because users might be
|
// NOTE: We set the table base offset here because users might be
|
||||||
// emitted before MachConstantBaseNode.
|
// emitted before MachConstantBaseNode.
|
||||||
Compile::ConstantTable& constant_table = C->constant_table();
|
ConstantTable& constant_table = C->output()->constant_table();
|
||||||
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -643,7 +643,7 @@ int MachPrologNode::reloc() const {
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream* st ) const {
|
void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream* st ) const {
|
||||||
Compile *C = ra_->C;
|
Compile *C = ra_->C;
|
||||||
int framesize = C->frame_size_in_bytes();
|
int framesize = C->output()->frame_size_in_bytes();
|
||||||
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
||||||
// Remove two words for return addr and rbp,
|
// Remove two words for return addr and rbp,
|
||||||
framesize -= 2*wordSize;
|
framesize -= 2*wordSize;
|
||||||
|
@ -682,7 +682,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
_masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std()));
|
_masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std()));
|
||||||
}
|
}
|
||||||
|
|
||||||
int framesize = C->frame_size_in_bytes();
|
int framesize = C->output()->frame_size_in_bytes();
|
||||||
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
||||||
// Remove two words for return addr and rbp,
|
// Remove two words for return addr and rbp,
|
||||||
framesize -= 2*wordSize;
|
framesize -= 2*wordSize;
|
||||||
|
|
|
@ -785,7 +785,7 @@ void emit_fp_min_max(MacroAssembler& _masm, XMMRegister dst,
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
|
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
|
||||||
|
|
||||||
int Compile::ConstantTable::calculate_table_base_offset() const {
|
int ConstantTable::calculate_table_base_offset() const {
|
||||||
return 0; // absolute addressing, no offset
|
return 0; // absolute addressing, no offset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,13 +814,13 @@ void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
||||||
void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
|
|
||||||
int framesize = C->frame_size_in_bytes();
|
int framesize = C->output()->frame_size_in_bytes();
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
||||||
// Remove wordSize for return addr which is already pushed.
|
// Remove wordSize for return addr which is already pushed.
|
||||||
framesize -= wordSize;
|
framesize -= wordSize;
|
||||||
|
|
||||||
if (C->need_stack_bang(bangsize)) {
|
if (C->output()->need_stack_bang(bangsize)) {
|
||||||
framesize -= wordSize;
|
framesize -= wordSize;
|
||||||
st->print("# stack bang (%d bytes)", bangsize);
|
st->print("# stack bang (%d bytes)", bangsize);
|
||||||
st->print("\n\t");
|
st->print("\n\t");
|
||||||
|
@ -874,8 +874,8 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
Compile* C = ra_->C;
|
Compile* C = ra_->C;
|
||||||
MacroAssembler _masm(&cbuf);
|
MacroAssembler _masm(&cbuf);
|
||||||
|
|
||||||
int framesize = C->frame_size_in_bytes();
|
int framesize = C->output()->frame_size_in_bytes();
|
||||||
int bangsize = C->bang_size_in_bytes();
|
int bangsize = C->output()->bang_size_in_bytes();
|
||||||
|
|
||||||
if (C->clinit_barrier_on_entry()) {
|
if (C->clinit_barrier_on_entry()) {
|
||||||
assert(VM_Version::supports_fast_class_init_checks(), "sanity");
|
assert(VM_Version::supports_fast_class_init_checks(), "sanity");
|
||||||
|
@ -892,14 +892,14 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||||
__ bind(L_skip_barrier);
|
__ bind(L_skip_barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
__ verified_entry(framesize, C->need_stack_bang(bangsize)?bangsize:0, false, C->stub_function() != NULL);
|
__ verified_entry(framesize, C->output()->need_stack_bang(bangsize)?bangsize:0, false, C->stub_function() != NULL);
|
||||||
|
|
||||||
C->set_frame_complete(cbuf.insts_size());
|
C->output()->set_frame_complete(cbuf.insts_size());
|
||||||
|
|
||||||
if (C->has_mach_constant_base_node()) {
|
if (C->has_mach_constant_base_node()) {
|
||||||
// NOTE: We set the table base offset here because users might be
|
// NOTE: We set the table base offset here because users might be
|
||||||
// emitted before MachConstantBaseNode.
|
// emitted before MachConstantBaseNode.
|
||||||
Compile::ConstantTable& constant_table = C->constant_table();
|
ConstantTable& constant_table = C->output()->constant_table();
|
||||||
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -925,7 +925,7 @@ void MachEpilogNode::format(PhaseRegAlloc* ra_, outputStream* st) const
|
||||||
st->cr(); st->print("\t");
|
st->cr(); st->print("\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
int framesize = C->frame_size_in_bytes();
|
int framesize = C->output()->frame_size_in_bytes();
|
||||||
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
||||||
// Remove word for return adr already pushed
|
// Remove word for return adr already pushed
|
||||||
// and RBP
|
// and RBP
|
||||||
|
@ -966,7 +966,7 @@ void MachEpilogNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const
|
||||||
__ vzeroupper();
|
__ vzeroupper();
|
||||||
}
|
}
|
||||||
|
|
||||||
int framesize = C->frame_size_in_bytes();
|
int framesize = C->output()->frame_size_in_bytes();
|
||||||
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
|
||||||
// Remove word for return adr already pushed
|
// Remove word for return adr already pushed
|
||||||
// and RBP
|
// and RBP
|
||||||
|
|
|
@ -3374,7 +3374,7 @@ void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start code line.
|
// Start code line.
|
||||||
encoding->add_code(" _constant = C->constant_table().add");
|
encoding->add_code(" _constant = C->output()->constant_table().add");
|
||||||
|
|
||||||
// Parse everything in ( ) expression.
|
// Parse everything in ( ) expression.
|
||||||
encoding->add_code("(this, ");
|
encoding->add_code("(this, ");
|
||||||
|
|
|
@ -237,6 +237,7 @@ int main(int argc, char *argv[])
|
||||||
AD.addInclude(AD._HPP_file, "memory/allocation.hpp");
|
AD.addInclude(AD._HPP_file, "memory/allocation.hpp");
|
||||||
AD.addInclude(AD._HPP_file, "oops/compressedOops.hpp");
|
AD.addInclude(AD._HPP_file, "oops/compressedOops.hpp");
|
||||||
AD.addInclude(AD._HPP_file, "code/nativeInst.hpp");
|
AD.addInclude(AD._HPP_file, "code/nativeInst.hpp");
|
||||||
|
AD.addInclude(AD._HPP_file, "opto/output.hpp");
|
||||||
AD.addInclude(AD._HPP_file, "opto/machnode.hpp");
|
AD.addInclude(AD._HPP_file, "opto/machnode.hpp");
|
||||||
AD.addInclude(AD._HPP_file, "opto/node.hpp");
|
AD.addInclude(AD._HPP_file, "opto/node.hpp");
|
||||||
AD.addInclude(AD._HPP_file, "opto/regalloc.hpp");
|
AD.addInclude(AD._HPP_file, "opto/regalloc.hpp");
|
||||||
|
|
|
@ -2605,7 +2605,7 @@ void ArchDesc::defineEmit(FILE* fp, InstructForm& inst) {
|
||||||
|
|
||||||
// For MachConstantNodes which are ideal jump nodes, fill the jump table.
|
// For MachConstantNodes which are ideal jump nodes, fill the jump table.
|
||||||
if (inst.is_mach_constant() && inst.is_ideal_jump()) {
|
if (inst.is_mach_constant() && inst.is_ideal_jump()) {
|
||||||
fprintf(fp, " ra_->C->constant_table().fill_jump_table(cbuf, (MachConstantNode*) this, _index2label);\n");
|
fprintf(fp, " ra_->C->output()->constant_table().fill_jump_table(cbuf, (MachConstantNode*) this, _index2label);\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output each operand's offset into the array of registers.
|
// Output each operand's offset into the array of registers.
|
||||||
|
@ -2679,7 +2679,7 @@ void ArchDesc::defineEvalConstant(FILE* fp, InstructForm& inst) {
|
||||||
|
|
||||||
// For ideal jump nodes, add a jump-table entry.
|
// For ideal jump nodes, add a jump-table entry.
|
||||||
if (inst.is_ideal_jump()) {
|
if (inst.is_ideal_jump()) {
|
||||||
fprintf(fp, " _constant = C->constant_table().add_jump_table(this);\n");
|
fprintf(fp, " _constant = C->output()->constant_table().add_jump_table(this);\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If user did not define an encode section,
|
// If user did not define an encode section,
|
||||||
|
|
|
@ -395,6 +395,9 @@ public:
|
||||||
return _compiler2_objects[idx];
|
return _compiler2_objects[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AbstractCompiler* compiler1() { return _compilers[0]; }
|
||||||
|
static AbstractCompiler* compiler2() { return _compilers[1]; }
|
||||||
|
|
||||||
static bool can_remove(CompilerThread *ct, bool do_it);
|
static bool can_remove(CompilerThread *ct, bool do_it);
|
||||||
|
|
||||||
static CompileLog* get_log(CompilerThread* ct);
|
static CompileLog* get_log(CompilerThread* ct);
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "opto/macro.hpp"
|
#include "opto/macro.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
#include "opto/node.hpp"
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/output.hpp"
|
||||||
#include "opto/regalloc.hpp"
|
#include "opto/regalloc.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
#include "opto/type.hpp"
|
#include "opto/type.hpp"
|
||||||
|
@ -85,7 +86,7 @@ static ZBarrierSetC2State* barrier_set_state() {
|
||||||
|
|
||||||
ZLoadBarrierStubC2* ZLoadBarrierStubC2::create(const MachNode* node, Address ref_addr, Register ref, Register tmp, bool weak) {
|
ZLoadBarrierStubC2* ZLoadBarrierStubC2::create(const MachNode* node, Address ref_addr, Register ref, Register tmp, bool weak) {
|
||||||
ZLoadBarrierStubC2* const stub = new (Compile::current()->comp_arena()) ZLoadBarrierStubC2(node, ref_addr, ref, tmp, weak);
|
ZLoadBarrierStubC2* const stub = new (Compile::current()->comp_arena()) ZLoadBarrierStubC2(node, ref_addr, ref, tmp, weak);
|
||||||
if (!Compile::current()->in_scratch_emit_size()) {
|
if (!Compile::current()->output()->in_scratch_emit_size()) {
|
||||||
barrier_set_state()->stubs()->append(stub);
|
barrier_set_state()->stubs()->append(stub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ Label* ZLoadBarrierStubC2::entry() {
|
||||||
// However, we still need to return a label that is not bound now, but
|
// However, we still need to return a label that is not bound now, but
|
||||||
// will eventually be bound. Any lable will do, as it will only act as
|
// will eventually be bound. Any lable will do, as it will only act as
|
||||||
// a placeholder, so we return the _continuation label.
|
// a placeholder, so we return the _continuation label.
|
||||||
return Compile::current()->in_scratch_emit_size() ? &_continuation : &_entry;
|
return Compile::current()->output()->in_scratch_emit_size() ? &_continuation : &_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
Label* ZLoadBarrierStubC2::continuation() {
|
Label* ZLoadBarrierStubC2::continuation() {
|
||||||
|
@ -152,7 +153,7 @@ void ZBarrierSetC2::emit_stubs(CodeBuffer& cb) const {
|
||||||
|
|
||||||
for (int i = 0; i < stubs->length(); i++) {
|
for (int i = 0; i < stubs->length(); i++) {
|
||||||
// Make sure there is enough space in the code buffer
|
// Make sure there is enough space in the code buffer
|
||||||
if (cb.insts()->maybe_expand_to_ensure_remaining(Compile::MAX_inst_size) && cb.blob() == NULL) {
|
if (cb.insts()->maybe_expand_to_ensure_remaining(PhaseOutput::MAX_inst_size) && cb.blob() == NULL) {
|
||||||
ciEnv::current()->record_failure("CodeCache is full");
|
ciEnv::current()->record_failure("CodeCache is full");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -165,12 +166,12 @@ void ZBarrierSetC2::emit_stubs(CodeBuffer& cb) const {
|
||||||
|
|
||||||
int ZBarrierSetC2::estimate_stub_size() const {
|
int ZBarrierSetC2::estimate_stub_size() const {
|
||||||
Compile* const C = Compile::current();
|
Compile* const C = Compile::current();
|
||||||
BufferBlob* const blob = C->scratch_buffer_blob();
|
BufferBlob* const blob = C->output()->scratch_buffer_blob();
|
||||||
GrowableArray<ZLoadBarrierStubC2*>* const stubs = barrier_set_state()->stubs();
|
GrowableArray<ZLoadBarrierStubC2*>* const stubs = barrier_set_state()->stubs();
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
|
||||||
for (int i = 0; i < stubs->length(); i++) {
|
for (int i = 0; i < stubs->length(); i++) {
|
||||||
CodeBuffer cb(blob->content_begin(), (address)C->scratch_locs_memory() - blob->content_begin());
|
CodeBuffer cb(blob->content_begin(), (address)C->output()->scratch_locs_memory() - blob->content_begin());
|
||||||
MacroAssembler masm(&cb);
|
MacroAssembler masm(&cb);
|
||||||
ZBarrierSet::assembler()->generate_c2_load_barrier_stub(&masm, stubs->at(i));
|
ZBarrierSet::assembler()->generate_c2_load_barrier_stub(&masm, stubs->at(i));
|
||||||
size += cb.insts_size();
|
size += cb.insts_size();
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "opto/compile.hpp"
|
#include "opto/compile.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
|
#include "opto/output.hpp"
|
||||||
#include "opto/phase.hpp"
|
#include "opto/phase.hpp"
|
||||||
#include "opto/regalloc.hpp"
|
#include "opto/regalloc.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
|
@ -563,12 +564,12 @@ static void do_liveness(PhaseRegAlloc* regalloc, PhaseCFG* cfg, Block_List* work
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect GC mask info - where are all the OOPs?
|
// Collect GC mask info - where are all the OOPs?
|
||||||
void Compile::BuildOopMaps() {
|
void PhaseOutput::BuildOopMaps() {
|
||||||
TracePhase tp("bldOopMaps", &timers[_t_buildOopMaps]);
|
Compile::TracePhase tp("bldOopMaps", &timers[_t_buildOopMaps]);
|
||||||
// Can't resource-mark because I need to leave all those OopMaps around,
|
// Can't resource-mark because I need to leave all those OopMaps around,
|
||||||
// or else I need to resource-mark some arena other than the default.
|
// or else I need to resource-mark some arena other than the default.
|
||||||
// ResourceMark rm; // Reclaim all OopFlows when done
|
// ResourceMark rm; // Reclaim all OopFlows when done
|
||||||
int max_reg = _regalloc->_max_reg; // Current array extent
|
int max_reg = C->regalloc()->_max_reg; // Current array extent
|
||||||
|
|
||||||
Arena *A = Thread::current()->resource_area();
|
Arena *A = Thread::current()->resource_area();
|
||||||
Block_List worklist; // Worklist of pending blocks
|
Block_List worklist; // Worklist of pending blocks
|
||||||
|
@ -578,17 +579,17 @@ void Compile::BuildOopMaps() {
|
||||||
// Compute a backwards liveness per register. Needs a bitarray of
|
// Compute a backwards liveness per register. Needs a bitarray of
|
||||||
// #blocks x (#registers, rounded up to ints)
|
// #blocks x (#registers, rounded up to ints)
|
||||||
safehash = new Dict(cmpkey,hashkey,A);
|
safehash = new Dict(cmpkey,hashkey,A);
|
||||||
do_liveness( _regalloc, _cfg, &worklist, max_reg_ints, A, safehash );
|
do_liveness( C->regalloc(), C->cfg(), &worklist, max_reg_ints, A, safehash );
|
||||||
OopFlow *free_list = NULL; // Free, unused
|
OopFlow *free_list = NULL; // Free, unused
|
||||||
|
|
||||||
// Array mapping blocks to completed oopflows
|
// Array mapping blocks to completed oopflows
|
||||||
OopFlow **flows = NEW_ARENA_ARRAY(A, OopFlow*, _cfg->number_of_blocks());
|
OopFlow **flows = NEW_ARENA_ARRAY(A, OopFlow*, C->cfg()->number_of_blocks());
|
||||||
memset( flows, 0, _cfg->number_of_blocks() * sizeof(OopFlow*) );
|
memset( flows, 0, C->cfg()->number_of_blocks() * sizeof(OopFlow*) );
|
||||||
|
|
||||||
|
|
||||||
// Do the first block 'by hand' to prime the worklist
|
// Do the first block 'by hand' to prime the worklist
|
||||||
Block *entry = _cfg->get_block(1);
|
Block *entry = C->cfg()->get_block(1);
|
||||||
OopFlow *rootflow = OopFlow::make(A,max_reg,this);
|
OopFlow *rootflow = OopFlow::make(A,max_reg,C);
|
||||||
// Initialize to 'bottom' (not 'top')
|
// Initialize to 'bottom' (not 'top')
|
||||||
memset( rootflow->_callees, OptoReg::Bad, max_reg*sizeof(short) );
|
memset( rootflow->_callees, OptoReg::Bad, max_reg*sizeof(short) );
|
||||||
memset( rootflow->_defs , 0, max_reg*sizeof(Node*) );
|
memset( rootflow->_defs , 0, max_reg*sizeof(Node*) );
|
||||||
|
@ -596,7 +597,7 @@ void Compile::BuildOopMaps() {
|
||||||
|
|
||||||
// Do the first block 'by hand' to prime the worklist
|
// Do the first block 'by hand' to prime the worklist
|
||||||
rootflow->_b = entry;
|
rootflow->_b = entry;
|
||||||
rootflow->compute_reach( _regalloc, max_reg, safehash );
|
rootflow->compute_reach( C->regalloc(), max_reg, safehash );
|
||||||
for( uint i=0; i<entry->_num_succs; i++ )
|
for( uint i=0; i<entry->_num_succs; i++ )
|
||||||
worklist.push(entry->_succs[i]);
|
worklist.push(entry->_succs[i]);
|
||||||
|
|
||||||
|
@ -613,7 +614,7 @@ void Compile::BuildOopMaps() {
|
||||||
|
|
||||||
Block *b = worklist.pop();
|
Block *b = worklist.pop();
|
||||||
// Ignore root block
|
// Ignore root block
|
||||||
if (b == _cfg->get_root_block()) {
|
if (b == C->cfg()->get_root_block()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Block is already done? Happens if block has several predecessors,
|
// Block is already done? Happens if block has several predecessors,
|
||||||
|
@ -627,7 +628,7 @@ void Compile::BuildOopMaps() {
|
||||||
Block *pred = (Block*)((intptr_t)0xdeadbeef);
|
Block *pred = (Block*)((intptr_t)0xdeadbeef);
|
||||||
// Scan this block's preds to find a done predecessor
|
// Scan this block's preds to find a done predecessor
|
||||||
for (uint j = 1; j < b->num_preds(); j++) {
|
for (uint j = 1; j < b->num_preds(); j++) {
|
||||||
Block* p = _cfg->get_block_for_node(b->pred(j));
|
Block* p = C->cfg()->get_block_for_node(b->pred(j));
|
||||||
OopFlow *p_flow = flows[p->_pre_order];
|
OopFlow *p_flow = flows[p->_pre_order];
|
||||||
if( p_flow ) { // Predecessor is done
|
if( p_flow ) { // Predecessor is done
|
||||||
assert( p_flow->_b == p, "cross check" );
|
assert( p_flow->_b == p, "cross check" );
|
||||||
|
@ -674,7 +675,7 @@ void Compile::BuildOopMaps() {
|
||||||
// Now push flow forward
|
// Now push flow forward
|
||||||
flows[b->_pre_order] = flow;// Mark flow for this block
|
flows[b->_pre_order] = flow;// Mark flow for this block
|
||||||
flow->_b = b;
|
flow->_b = b;
|
||||||
flow->compute_reach( _regalloc, max_reg, safehash );
|
flow->compute_reach( C->regalloc(), max_reg, safehash );
|
||||||
|
|
||||||
// Now push children onto worklist
|
// Now push children onto worklist
|
||||||
for( i=0; i<b->_num_succs; i++ )
|
for( i=0; i<b->_num_succs; i++ )
|
||||||
|
|
|
@ -108,7 +108,7 @@ void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, Dir
|
||||||
|
|
||||||
while (!env->failing()) {
|
while (!env->failing()) {
|
||||||
// Attempt to compile while subsuming loads into machine instructions.
|
// Attempt to compile while subsuming loads into machine instructions.
|
||||||
Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis, eliminate_boxing, directive);
|
Compile C(env, target, entry_bci, subsume_loads, do_escape_analysis, eliminate_boxing, directive);
|
||||||
|
|
||||||
// Check result and retry if appropriate.
|
// Check result and retry if appropriate.
|
||||||
if (C.failure_reason() != NULL) {
|
if (C.failure_reason() != NULL) {
|
||||||
|
@ -652,7 +652,7 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt
|
||||||
|
|
||||||
int C2Compiler::initial_code_buffer_size(int const_size) {
|
int C2Compiler::initial_code_buffer_size(int const_size) {
|
||||||
// See Compile::init_scratch_buffer_blob
|
// See Compile::init_scratch_buffer_blob
|
||||||
int locs_size = sizeof(relocInfo) * Compile::MAX_locs_size;
|
int locs_size = sizeof(relocInfo) * PhaseOutput::MAX_locs_size;
|
||||||
int slop = 2 * CodeSection::end_slop(); // space between sections
|
int slop = 2 * CodeSection::end_slop(); // space between sections
|
||||||
return Compile::MAX_inst_size + Compile::MAX_stubs_size + const_size + slop + locs_size;
|
return PhaseOutput::MAX_inst_size + PhaseOutput::MAX_stubs_size + const_size + slop + locs_size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,11 +29,11 @@
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
#include "opto/live.hpp"
|
#include "opto/live.hpp"
|
||||||
|
#include "opto/machnode.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
#include "opto/phase.hpp"
|
#include "opto/phase.hpp"
|
||||||
#include "opto/regalloc.hpp"
|
#include "opto/regalloc.hpp"
|
||||||
#include "opto/regmask.hpp"
|
#include "opto/regmask.hpp"
|
||||||
#include "opto/machnode.hpp"
|
|
||||||
|
|
||||||
class Matcher;
|
class Matcher;
|
||||||
class PhaseCFG;
|
class PhaseCFG;
|
||||||
|
|
|
@ -250,7 +250,7 @@ void Compile::print_statistics() {
|
||||||
Parse::print_statistics();
|
Parse::print_statistics();
|
||||||
PhaseCCP::print_statistics();
|
PhaseCCP::print_statistics();
|
||||||
PhaseRegAlloc::print_statistics();
|
PhaseRegAlloc::print_statistics();
|
||||||
Scheduling::print_statistics();
|
PhaseOutput::print_statistics();
|
||||||
PhasePeephole::print_statistics();
|
PhasePeephole::print_statistics();
|
||||||
PhaseIdealLoop::print_statistics();
|
PhaseIdealLoop::print_statistics();
|
||||||
if (xtty != NULL) xtty->tail("statistics");
|
if (xtty != NULL) xtty->tail("statistics");
|
||||||
|
@ -262,17 +262,6 @@ void Compile::print_statistics() {
|
||||||
}
|
}
|
||||||
#endif //PRODUCT
|
#endif //PRODUCT
|
||||||
|
|
||||||
// Support for bundling info
|
|
||||||
Bundle* Compile::node_bundling(const Node *n) {
|
|
||||||
assert(valid_bundle_info(n), "oob");
|
|
||||||
return &_node_bundling_base[n->_idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Compile::valid_bundle_info(const Node *n) {
|
|
||||||
return (_node_bundling_limit > n->_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Compile::gvn_replace_by(Node* n, Node* nn) {
|
void Compile::gvn_replace_by(Node* n, Node* nn) {
|
||||||
for (DUIterator_Last imin, i = n->last_outs(imin); i >= imin; ) {
|
for (DUIterator_Last imin, i = n->last_outs(imin); i >= imin; ) {
|
||||||
Node* use = n->last_out(i);
|
Node* use = n->last_out(i);
|
||||||
|
@ -423,24 +412,6 @@ void Compile::remove_useless_nodes(Unique_Node_List &useful) {
|
||||||
debug_only(verify_graph_edges(true/*check for no_dead_code*/);)
|
debug_only(verify_graph_edges(true/*check for no_dead_code*/);)
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------frame_size_in_words-----------------------------
|
|
||||||
// frame_slots in units of words
|
|
||||||
int Compile::frame_size_in_words() const {
|
|
||||||
// shift is 0 in LP32 and 1 in LP64
|
|
||||||
const int shift = (LogBytesPerWord - LogBytesPerInt);
|
|
||||||
int words = _frame_slots >> shift;
|
|
||||||
assert( words << shift == _frame_slots, "frame size must be properly aligned in LP64" );
|
|
||||||
return words;
|
|
||||||
}
|
|
||||||
|
|
||||||
// To bang the stack of this compiled method we use the stack size
|
|
||||||
// that the interpreter would need in case of a deoptimization. This
|
|
||||||
// removes the need to bang the stack in the deoptimization blob which
|
|
||||||
// in turn simplifies stack overflow handling.
|
|
||||||
int Compile::bang_size_in_bytes() const {
|
|
||||||
return MAX2(frame_size_in_bytes() + os::extra_bang_size_in_bytes(), _interpreter_frame_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
//------------------------------CompileWrapper---------------------------------
|
//------------------------------CompileWrapper---------------------------------
|
||||||
class CompileWrapper : public StackObj {
|
class CompileWrapper : public StackObj {
|
||||||
|
@ -468,14 +439,11 @@ CompileWrapper::CompileWrapper(Compile* compile) : _compile(compile) {
|
||||||
compile->set_indexSet_free_block_list(NULL);
|
compile->set_indexSet_free_block_list(NULL);
|
||||||
compile->init_type_arena();
|
compile->init_type_arena();
|
||||||
Type::Initialize(compile);
|
Type::Initialize(compile);
|
||||||
_compile->set_scratch_buffer_blob(NULL);
|
|
||||||
_compile->begin_method();
|
_compile->begin_method();
|
||||||
_compile->clone_map().set_debug(_compile->has_method() && _compile->directive()->CloneMapDebugOption);
|
_compile->clone_map().set_debug(_compile->has_method() && _compile->directive()->CloneMapDebugOption);
|
||||||
}
|
}
|
||||||
CompileWrapper::~CompileWrapper() {
|
CompileWrapper::~CompileWrapper() {
|
||||||
_compile->end_method();
|
_compile->end_method();
|
||||||
if (_compile->scratch_buffer_blob() != NULL)
|
|
||||||
BufferBlob::free(_compile->scratch_buffer_blob());
|
|
||||||
_compile->env()->set_compiler_data(NULL);
|
_compile->env()->set_compiler_data(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,104 +488,6 @@ void Compile::print_compile_messages() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------init_scratch_buffer_blob------------------------------
|
|
||||||
// Construct a temporary BufferBlob and cache it for this compile.
|
|
||||||
void Compile::init_scratch_buffer_blob(int const_size) {
|
|
||||||
// If there is already a scratch buffer blob allocated and the
|
|
||||||
// constant section is big enough, use it. Otherwise free the
|
|
||||||
// current and allocate a new one.
|
|
||||||
BufferBlob* blob = scratch_buffer_blob();
|
|
||||||
if ((blob != NULL) && (const_size <= _scratch_const_size)) {
|
|
||||||
// Use the current blob.
|
|
||||||
} else {
|
|
||||||
if (blob != NULL) {
|
|
||||||
BufferBlob::free(blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceMark rm;
|
|
||||||
_scratch_const_size = const_size;
|
|
||||||
int size = C2Compiler::initial_code_buffer_size(const_size);
|
|
||||||
blob = BufferBlob::create("Compile::scratch_buffer", size);
|
|
||||||
// Record the buffer blob for next time.
|
|
||||||
set_scratch_buffer_blob(blob);
|
|
||||||
// Have we run out of code space?
|
|
||||||
if (scratch_buffer_blob() == NULL) {
|
|
||||||
// Let CompilerBroker disable further compilations.
|
|
||||||
record_failure("Not enough space for scratch buffer in CodeCache");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the relocation buffers
|
|
||||||
relocInfo* locs_buf = (relocInfo*) blob->content_end() - MAX_locs_size;
|
|
||||||
set_scratch_locs_memory(locs_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------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.
|
|
||||||
// All common fixed-size instructions are given a size
|
|
||||||
// method by the AD file.
|
|
||||||
// Note that the scratch buffer blob and locs memory are
|
|
||||||
// allocated at the beginning of the compile task, and
|
|
||||||
// may be shared by several calls to scratch_emit_size.
|
|
||||||
// The allocation of the scratch buffer blob is particularly
|
|
||||||
// expensive, since it has to grab the code cache lock.
|
|
||||||
BufferBlob* blob = this->scratch_buffer_blob();
|
|
||||||
assert(blob != NULL, "Initialize BufferBlob at start");
|
|
||||||
assert(blob->size() > MAX_inst_size, "sanity");
|
|
||||||
relocInfo* locs_buf = scratch_locs_memory();
|
|
||||||
address blob_begin = blob->content_begin();
|
|
||||||
address blob_end = (address)locs_buf;
|
|
||||||
assert(blob->contains(blob_end), "sanity");
|
|
||||||
CodeBuffer buf(blob_begin, blob_end - blob_begin);
|
|
||||||
buf.initialize_consts_size(_scratch_const_size);
|
|
||||||
buf.initialize_stubs_size(MAX_stubs_size);
|
|
||||||
assert(locs_buf != NULL, "sanity");
|
|
||||||
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);
|
|
||||||
// Mark as scratch buffer.
|
|
||||||
buf.consts()->set_scratch_emit();
|
|
||||||
buf.insts()->set_scratch_emit();
|
|
||||||
buf.stubs()->set_scratch_emit();
|
|
||||||
|
|
||||||
// Do the emission.
|
|
||||||
|
|
||||||
Label fakeL; // Fake label for branch instructions.
|
|
||||||
Label* saveL = NULL;
|
|
||||||
uint save_bnum = 0;
|
|
||||||
bool is_branch = n->is_MachBranch();
|
|
||||||
if (is_branch) {
|
|
||||||
MacroAssembler masm(&buf);
|
|
||||||
masm.bind(fakeL);
|
|
||||||
n->as_MachBranch()->save_label(&saveL, &save_bnum);
|
|
||||||
n->as_MachBranch()->label_set(&fakeL, 0);
|
|
||||||
}
|
|
||||||
n->emit(buf, this->regalloc());
|
|
||||||
|
|
||||||
// Emitting into the scratch buffer should not fail
|
|
||||||
assert (!failing(), "Must not have pending failure. Reason is: %s", failure_reason());
|
|
||||||
|
|
||||||
if (is_branch) // Restore label.
|
|
||||||
n->as_MachBranch()->label_set(saveL, save_bnum);
|
|
||||||
|
|
||||||
// End scratch_emit_size section.
|
|
||||||
set_in_scratch_emit_size(false);
|
|
||||||
|
|
||||||
return buf.insts_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
//------------------------------Compile standard-------------------------------
|
//------------------------------Compile standard-------------------------------
|
||||||
debug_only( int Compile::_debug_idx = 100000; )
|
debug_only( int Compile::_debug_idx = 100000; )
|
||||||
|
@ -626,7 +496,7 @@ debug_only( int Compile::_debug_idx = 100000; )
|
||||||
// the continuation bci for on stack replacement.
|
// the continuation bci for on stack replacement.
|
||||||
|
|
||||||
|
|
||||||
Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr_bci,
|
Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
|
||||||
bool subsume_loads, bool do_escape_analysis, bool eliminate_boxing, DirectiveSet* directive)
|
bool subsume_loads, bool do_escape_analysis, bool eliminate_boxing, DirectiveSet* directive)
|
||||||
: Phase(Compiler),
|
: Phase(Compiler),
|
||||||
_compile_id(ci_env->compile_id()),
|
_compile_id(ci_env->compile_id()),
|
||||||
|
@ -640,8 +510,6 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
||||||
_stub_name(NULL),
|
_stub_name(NULL),
|
||||||
_stub_entry_point(NULL),
|
_stub_entry_point(NULL),
|
||||||
_max_node_limit(MaxNodeLimit),
|
_max_node_limit(MaxNodeLimit),
|
||||||
_orig_pc_slot(0),
|
|
||||||
_orig_pc_slot_offset_in_bytes(0),
|
|
||||||
_inlining_progress(false),
|
_inlining_progress(false),
|
||||||
_inlining_incrementally(false),
|
_inlining_incrementally(false),
|
||||||
_do_cleanup(false),
|
_do_cleanup(false),
|
||||||
|
@ -683,12 +551,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
||||||
_replay_inline_data(NULL),
|
_replay_inline_data(NULL),
|
||||||
_java_calls(0),
|
_java_calls(0),
|
||||||
_inner_loops(0),
|
_inner_loops(0),
|
||||||
_interpreter_frame_size(0),
|
_interpreter_frame_size(0)
|
||||||
_node_bundling_limit(0),
|
|
||||||
_node_bundling_base(NULL),
|
|
||||||
_code_buffer("Compile::Fill_buffer"),
|
|
||||||
_scratch_const_size(-1),
|
|
||||||
_in_scratch_emit_size(false)
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
, _in_dump_cnt(0)
|
, _in_dump_cnt(0)
|
||||||
#endif
|
#endif
|
||||||
|
@ -906,9 +769,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
||||||
|
|
||||||
// Now that we know the size of all the monitors we can add a fixed slot
|
// Now that we know the size of all the monitors we can add a fixed slot
|
||||||
// for the original deopt pc.
|
// for the original deopt pc.
|
||||||
|
int next_slot = fixed_slots() + (sizeof(address) / VMRegImpl::stack_slot_size);
|
||||||
_orig_pc_slot = fixed_slots();
|
|
||||||
int next_slot = _orig_pc_slot + (sizeof(address) / VMRegImpl::stack_slot_size);
|
|
||||||
set_fixed_slots(next_slot);
|
set_fixed_slots(next_slot);
|
||||||
|
|
||||||
// Compute when to use implicit null checks. Used by matching trap based
|
// Compute when to use implicit null checks. Used by matching trap based
|
||||||
|
@ -917,41 +778,6 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
||||||
|
|
||||||
// Now generate code
|
// Now generate code
|
||||||
Code_Gen();
|
Code_Gen();
|
||||||
if (failing()) return;
|
|
||||||
|
|
||||||
// Check if we want to skip execution of all compiled code.
|
|
||||||
{
|
|
||||||
#ifndef PRODUCT
|
|
||||||
if (OptoNoExecute) {
|
|
||||||
record_method_not_compilable("+OptoNoExecute"); // Flag as failed
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
TracePhase tp("install_code", &timers[_t_registerMethod]);
|
|
||||||
|
|
||||||
if (is_osr_compilation()) {
|
|
||||||
_code_offsets.set_value(CodeOffsets::Verified_Entry, 0);
|
|
||||||
_code_offsets.set_value(CodeOffsets::OSR_Entry, _first_block_size);
|
|
||||||
} else {
|
|
||||||
_code_offsets.set_value(CodeOffsets::Verified_Entry, _first_block_size);
|
|
||||||
_code_offsets.set_value(CodeOffsets::OSR_Entry, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
env()->register_method(_method, _entry_bci,
|
|
||||||
&_code_offsets,
|
|
||||||
_orig_pc_slot_offset_in_bytes,
|
|
||||||
code_buffer(),
|
|
||||||
frame_size_in_words(), _oop_map_set,
|
|
||||||
&_handler_table, &_inc_table,
|
|
||||||
compiler,
|
|
||||||
has_unsafe_access(),
|
|
||||||
SharedRuntime::is_wide_vector(max_vector_size()),
|
|
||||||
rtm_state()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (log() != NULL) // Print code cache state into compiler log
|
|
||||||
log()->code_cache_state();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------Compile----------------------------------------
|
//------------------------------Compile----------------------------------------
|
||||||
|
@ -977,8 +803,6 @@ Compile::Compile( ciEnv* ci_env,
|
||||||
_stub_name(stub_name),
|
_stub_name(stub_name),
|
||||||
_stub_entry_point(NULL),
|
_stub_entry_point(NULL),
|
||||||
_max_node_limit(MaxNodeLimit),
|
_max_node_limit(MaxNodeLimit),
|
||||||
_orig_pc_slot(0),
|
|
||||||
_orig_pc_slot_offset_in_bytes(0),
|
|
||||||
_inlining_progress(false),
|
_inlining_progress(false),
|
||||||
_inlining_incrementally(false),
|
_inlining_incrementally(false),
|
||||||
_has_reserved_stack_access(false),
|
_has_reserved_stack_access(false),
|
||||||
|
@ -1016,9 +840,6 @@ Compile::Compile( ciEnv* ci_env,
|
||||||
_java_calls(0),
|
_java_calls(0),
|
||||||
_inner_loops(0),
|
_inner_loops(0),
|
||||||
_interpreter_frame_size(0),
|
_interpreter_frame_size(0),
|
||||||
_node_bundling_limit(0),
|
|
||||||
_node_bundling_base(NULL),
|
|
||||||
_code_buffer("Compile::Fill_buffer"),
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
_in_dump_cnt(0),
|
_in_dump_cnt(0),
|
||||||
#endif
|
#endif
|
||||||
|
@ -1053,34 +874,8 @@ Compile::Compile( ciEnv* ci_env,
|
||||||
}
|
}
|
||||||
|
|
||||||
NOT_PRODUCT( verify_graph_edges(); )
|
NOT_PRODUCT( verify_graph_edges(); )
|
||||||
|
|
||||||
Code_Gen();
|
Code_Gen();
|
||||||
if (failing()) return;
|
|
||||||
|
|
||||||
|
|
||||||
// Entry point will be accessed using compile->stub_entry_point();
|
|
||||||
if (code_buffer() == NULL) {
|
|
||||||
Matcher::soft_match_failure();
|
|
||||||
} else {
|
|
||||||
if (PrintAssembly && (WizardMode || Verbose))
|
|
||||||
tty->print_cr("### Stub::%s", stub_name);
|
|
||||||
|
|
||||||
if (!failing()) {
|
|
||||||
assert(_fixed_slots == 0, "no fixed slots used for runtime stubs");
|
|
||||||
|
|
||||||
// Make the NMethod
|
|
||||||
// For now we mark the frame as never safe for profile stackwalking
|
|
||||||
RuntimeStub *rs = RuntimeStub::new_runtime_stub(stub_name,
|
|
||||||
code_buffer(),
|
|
||||||
CodeOffsets::frame_never_safe,
|
|
||||||
// _code_offsets.value(CodeOffsets::Frame_Complete),
|
|
||||||
frame_size_in_words(),
|
|
||||||
_oop_map_set,
|
|
||||||
save_arg_registers);
|
|
||||||
assert(rs != NULL && rs->is_runtime_stub(), "sanity check");
|
|
||||||
|
|
||||||
_stub_entry_point = rs->entry_point();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------Init-------------------------------------------
|
//------------------------------Init-------------------------------------------
|
||||||
|
@ -2545,8 +2340,11 @@ void Compile::Code_Gen() {
|
||||||
|
|
||||||
// Convert Nodes to instruction bits in a buffer
|
// Convert Nodes to instruction bits in a buffer
|
||||||
{
|
{
|
||||||
TraceTime tp("output", &timers[_t_output], CITime);
|
TracePhase tp("output", &timers[_t_output]);
|
||||||
Output();
|
PhaseOutput output;
|
||||||
|
output.Output();
|
||||||
|
if (failing()) return;
|
||||||
|
output.install();
|
||||||
}
|
}
|
||||||
|
|
||||||
print_method(PHASE_FINAL_CODE);
|
print_method(PHASE_FINAL_CODE);
|
||||||
|
@ -2556,143 +2354,6 @@ void Compile::Code_Gen() {
|
||||||
_regalloc = (PhaseChaitin*)((intptr_t)0xdeadbeef);
|
_regalloc = (PhaseChaitin*)((intptr_t)0xdeadbeef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------------------dump_asm---------------------------------------
|
|
||||||
// Dump formatted assembly
|
|
||||||
#if defined(SUPPORT_OPTO_ASSEMBLY)
|
|
||||||
void Compile::dump_asm_on(outputStream* st, int* pcs, uint pc_limit) {
|
|
||||||
|
|
||||||
int pc_digits = 3; // #chars required for pc
|
|
||||||
int sb_chars = 3; // #chars for "start bundle" indicator
|
|
||||||
int tab_size = 8;
|
|
||||||
if (pcs != NULL) {
|
|
||||||
int max_pc = 0;
|
|
||||||
for (uint i = 0; i < pc_limit; i++) {
|
|
||||||
max_pc = (max_pc < pcs[i]) ? pcs[i] : max_pc;
|
|
||||||
}
|
|
||||||
pc_digits = ((max_pc < 4096) ? 3 : ((max_pc < 65536) ? 4 : ((max_pc < 65536*256) ? 6 : 8))); // #chars required for pc
|
|
||||||
}
|
|
||||||
int prefix_len = ((pc_digits + sb_chars + tab_size - 1)/tab_size)*tab_size;
|
|
||||||
|
|
||||||
bool cut_short = false;
|
|
||||||
st->print_cr("#");
|
|
||||||
st->print("# "); _tf->dump_on(st); st->cr();
|
|
||||||
st->print_cr("#");
|
|
||||||
|
|
||||||
// For all blocks
|
|
||||||
int pc = 0x0; // Program counter
|
|
||||||
char starts_bundle = ' ';
|
|
||||||
_regalloc->dump_frame();
|
|
||||||
|
|
||||||
Node *n = NULL;
|
|
||||||
for (uint i = 0; i < _cfg->number_of_blocks(); i++) {
|
|
||||||
if (VMThread::should_terminate()) {
|
|
||||||
cut_short = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Block* block = _cfg->get_block(i);
|
|
||||||
if (block->is_connector() && !Verbose) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
n = block->head();
|
|
||||||
if ((pcs != NULL) && (n->_idx < pc_limit)) {
|
|
||||||
pc = pcs[n->_idx];
|
|
||||||
st->print("%*.*x", pc_digits, pc_digits, pc);
|
|
||||||
}
|
|
||||||
st->fill_to(prefix_len);
|
|
||||||
block->dump_head(_cfg, st);
|
|
||||||
if (block->is_connector()) {
|
|
||||||
st->fill_to(prefix_len);
|
|
||||||
st->print_cr("# Empty connector block");
|
|
||||||
} else if (block->num_preds() == 2 && block->pred(1)->is_CatchProj() && block->pred(1)->as_CatchProj()->_con == CatchProjNode::fall_through_index) {
|
|
||||||
st->fill_to(prefix_len);
|
|
||||||
st->print_cr("# Block is sole successor of call");
|
|
||||||
}
|
|
||||||
|
|
||||||
// For all instructions
|
|
||||||
Node *delay = NULL;
|
|
||||||
for (uint j = 0; j < block->number_of_nodes(); j++) {
|
|
||||||
if (VMThread::should_terminate()) {
|
|
||||||
cut_short = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
n = block->get_node(j);
|
|
||||||
if (valid_bundle_info(n)) {
|
|
||||||
Bundle* bundle = node_bundling(n);
|
|
||||||
if (bundle->used_in_unconditional_delay()) {
|
|
||||||
delay = n;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (bundle->starts_bundle()) {
|
|
||||||
starts_bundle = '+';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WizardMode) {
|
|
||||||
n->dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !n->is_Region() && // Dont print in the Assembly
|
|
||||||
!n->is_Phi() && // a few noisely useless nodes
|
|
||||||
!n->is_Proj() &&
|
|
||||||
!n->is_MachTemp() &&
|
|
||||||
!n->is_SafePointScalarObject() &&
|
|
||||||
!n->is_Catch() && // Would be nice to print exception table targets
|
|
||||||
!n->is_MergeMem() && // Not very interesting
|
|
||||||
!n->is_top() && // Debug info table constants
|
|
||||||
!(n->is_Con() && !n->is_Mach())// Debug info table constants
|
|
||||||
) {
|
|
||||||
if ((pcs != NULL) && (n->_idx < pc_limit)) {
|
|
||||||
pc = pcs[n->_idx];
|
|
||||||
st->print("%*.*x", pc_digits, pc_digits, pc);
|
|
||||||
} else {
|
|
||||||
st->fill_to(pc_digits);
|
|
||||||
}
|
|
||||||
st->print(" %c ", starts_bundle);
|
|
||||||
starts_bundle = ' ';
|
|
||||||
st->fill_to(prefix_len);
|
|
||||||
n->format(_regalloc, st);
|
|
||||||
st->cr();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have an instruction with a delay slot, and have seen a delay,
|
|
||||||
// then back up and print it
|
|
||||||
if (valid_bundle_info(n) && node_bundling(n)->use_unconditional_delay()) {
|
|
||||||
// Coverity finding - Explicit null dereferenced.
|
|
||||||
guarantee(delay != NULL, "no unconditional delay instruction");
|
|
||||||
if (WizardMode) delay->dump();
|
|
||||||
|
|
||||||
if (node_bundling(delay)->starts_bundle())
|
|
||||||
starts_bundle = '+';
|
|
||||||
if ((pcs != NULL) && (n->_idx < pc_limit)) {
|
|
||||||
pc = pcs[n->_idx];
|
|
||||||
st->print("%*.*x", pc_digits, pc_digits, pc);
|
|
||||||
} else {
|
|
||||||
st->fill_to(pc_digits);
|
|
||||||
}
|
|
||||||
st->print(" %c ", starts_bundle);
|
|
||||||
starts_bundle = ' ';
|
|
||||||
st->fill_to(prefix_len);
|
|
||||||
delay->format(_regalloc, st);
|
|
||||||
st->cr();
|
|
||||||
delay = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dump the exception table as well
|
|
||||||
if( n->is_Catch() && (Verbose || WizardMode) ) {
|
|
||||||
// Print the exception table for this offset
|
|
||||||
_handler_table.print_subtable_for(pc);
|
|
||||||
}
|
|
||||||
st->bol(); // Make sure we start on a new line
|
|
||||||
}
|
|
||||||
st->cr(); // one empty line between blocks
|
|
||||||
assert(cut_short || delay == NULL, "no unconditional delay branch");
|
|
||||||
} // End of per-block dump
|
|
||||||
|
|
||||||
if (cut_short) st->print_cr("*** disassembly is cut short ***");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//------------------------------Final_Reshape_Counts---------------------------
|
//------------------------------Final_Reshape_Counts---------------------------
|
||||||
// This class defines counters to help identify when a method
|
// This class defines counters to help identify when a method
|
||||||
// may/must be executed using hardware with only 24-bit precision.
|
// may/must be executed using hardware with only 24-bit precision.
|
||||||
|
@ -3985,222 +3646,6 @@ Compile::TracePhase::~TracePhase() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
// 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_INT:
|
|
||||||
case T_FLOAT: return (_v._value.i == other._v._value.i);
|
|
||||||
case T_LONG:
|
|
||||||
case T_DOUBLE: return (_v._value.j == other._v._value.j);
|
|
||||||
case T_OBJECT:
|
|
||||||
case T_ADDRESS: return (_v._value.l == other._v._value.l);
|
|
||||||
case T_VOID: return (_v._value.l == other._v._value.l); // jump-table entries
|
|
||||||
case T_METADATA: return (_v._metadata == other._v._metadata);
|
|
||||||
default: ShouldNotReachHere(); return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int type_to_size_in_bytes(BasicType t) {
|
|
||||||
switch (t) {
|
|
||||||
case T_INT: return sizeof(jint );
|
|
||||||
case T_LONG: return sizeof(jlong );
|
|
||||||
case T_FLOAT: return sizeof(jfloat );
|
|
||||||
case T_DOUBLE: return sizeof(jdouble);
|
|
||||||
case T_METADATA: return sizeof(Metadata*);
|
|
||||||
// We use T_VOID as marker for jump-table entries (labels) which
|
|
||||||
// need an internal word relocation.
|
|
||||||
case T_VOID:
|
|
||||||
case T_ADDRESS:
|
|
||||||
case T_OBJECT: return sizeof(jobject);
|
|
||||||
default:
|
|
||||||
ShouldNotReachHere();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Compile::ConstantTable::qsort_comparator(Constant* a, Constant* b) {
|
|
||||||
// sort descending
|
|
||||||
if (a->freq() > b->freq()) return -1;
|
|
||||||
if (a->freq() < b->freq()) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Compile::ConstantTable::calculate_offsets_and_size() {
|
|
||||||
// First, sort the array by frequencies.
|
|
||||||
_constants.sort(qsort_comparator);
|
|
||||||
|
|
||||||
#ifdef ASSERT
|
|
||||||
// Make sure all jump-table entries were sorted to the end of the
|
|
||||||
// array (they have a negative frequency).
|
|
||||||
bool found_void = false;
|
|
||||||
for (int i = 0; i < _constants.length(); i++) {
|
|
||||||
Constant con = _constants.at(i);
|
|
||||||
if (con.type() == T_VOID)
|
|
||||||
found_void = true; // jump-tables
|
|
||||||
else
|
|
||||||
assert(!found_void, "wrong sorting");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int offset = 0;
|
|
||||||
for (int i = 0; i < _constants.length(); i++) {
|
|
||||||
Constant* con = _constants.adr_at(i);
|
|
||||||
|
|
||||||
// Align offset for type.
|
|
||||||
int typesize = type_to_size_in_bytes(con->type());
|
|
||||||
offset = align_up(offset, typesize);
|
|
||||||
con->set_offset(offset); // set constant's offset
|
|
||||||
|
|
||||||
if (con->type() == T_VOID) {
|
|
||||||
MachConstantNode* n = (MachConstantNode*) con->get_jobject();
|
|
||||||
offset = offset + typesize * n->outcnt(); // expand jump-table
|
|
||||||
} else {
|
|
||||||
offset = offset + typesize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Align size up to the next section start (which is insts; see
|
|
||||||
// CodeBuffer::align_at_start).
|
|
||||||
assert(_size == -1, "already set?");
|
|
||||||
_size = align_up(offset, (int)CodeEntryAlignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Compile::ConstantTable::emit(CodeBuffer& cb) {
|
|
||||||
MacroAssembler _masm(&cb);
|
|
||||||
for (int i = 0; i < _constants.length(); i++) {
|
|
||||||
Constant con = _constants.at(i);
|
|
||||||
address constant_addr = NULL;
|
|
||||||
switch (con.type()) {
|
|
||||||
case T_INT: constant_addr = _masm.int_constant( con.get_jint() ); break;
|
|
||||||
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 internal word relocation.
|
|
||||||
case T_VOID: {
|
|
||||||
MachConstantNode* n = (MachConstantNode*) con.get_jobject();
|
|
||||||
// Fill the jump-table with a dummy word. The real value is
|
|
||||||
// filled in later in fill_jump_table.
|
|
||||||
address dummy = (address) n;
|
|
||||||
constant_addr = _masm.address_constant(dummy);
|
|
||||||
// Expand jump-table
|
|
||||||
for (uint i = 1; i < n->outcnt(); i++) {
|
|
||||||
address temp_addr = _masm.address_constant(dummy + i);
|
|
||||||
assert(temp_addr, "consts section too small");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case T_METADATA: {
|
|
||||||
Metadata* obj = con.get_metadata();
|
|
||||||
int metadata_index = _masm.oop_recorder()->find_index(obj);
|
|
||||||
constant_addr = _masm.address_constant((address) obj, metadata_Relocation::spec(metadata_index));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: ShouldNotReachHere();
|
|
||||||
}
|
|
||||||
assert(constant_addr, "consts section too small");
|
|
||||||
assert((constant_addr - _masm.code()->consts()->start()) == con.offset(),
|
|
||||||
"must be: %d == %d", (int) (constant_addr - _masm.code()->consts()->start()), (int)(con.offset()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Compile::ConstantTable::find_offset(Constant& con) const {
|
|
||||||
int idx = _constants.find(con);
|
|
||||||
guarantee(idx != -1, "constant must be in constant table");
|
|
||||||
int offset = _constants.at(idx).offset();
|
|
||||||
guarantee(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()) {
|
|
||||||
_constants.adr_at(idx)->inc_freq(con.freq()); // increase the frequency by the current value
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(void) _constants.append(con);
|
|
||||||
}
|
|
||||||
|
|
||||||
Compile::Constant Compile::ConstantTable::add(MachConstantNode* n, BasicType type, jvalue value) {
|
|
||||||
Block* b = Compile::current()->cfg()->get_block_for_node(n);
|
|
||||||
Constant con(type, value, b->_freq);
|
|
||||||
add(con);
|
|
||||||
return con;
|
|
||||||
}
|
|
||||||
|
|
||||||
Compile::Constant Compile::ConstantTable::add(Metadata* metadata) {
|
|
||||||
Constant con(metadata);
|
|
||||||
add(con);
|
|
||||||
return con;
|
|
||||||
}
|
|
||||||
|
|
||||||
Compile::Constant Compile::ConstantTable::add(MachConstantNode* n, 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;
|
|
||||||
case T_METADATA: return add((Metadata*)oper->constant()); break;
|
|
||||||
default: guarantee(false, "unhandled type: %s", type2name(type));
|
|
||||||
}
|
|
||||||
return add(n, type, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Compile::Constant Compile::ConstantTable::add_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, next_jump_table_freq(), false); // Labels of a jump-table cannot be reused.
|
|
||||||
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(), "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 (uint i = 0; i < n->outcnt(); i++) {
|
|
||||||
address* constant_addr = &jump_table_base[i];
|
|
||||||
assert(*constant_addr == (((address) n) + i), "all jump-table entries must contain adjusted node pointer: " INTPTR_FORMAT " == " INTPTR_FORMAT, p2i(*constant_addr), p2i(((address) n) + i));
|
|
||||||
*constant_addr = cb.consts()->target(*labels.at(i), (address) constant_addr);
|
|
||||||
cb.consts()->relocate((address) constant_addr, relocInfo::internal_word_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------static_subtype_check-----------------------------
|
//----------------------------static_subtype_check-----------------------------
|
||||||
// Shortcut important common cases when superklass is exact:
|
// Shortcut important common cases when superklass is exact:
|
||||||
// (0) superklass is java.lang.Object (can occur in reflective code)
|
// (0) superklass is java.lang.Object (can occur in reflective code)
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
#include "asm/codeBuffer.hpp"
|
#include "asm/codeBuffer.hpp"
|
||||||
#include "ci/compilerInterface.hpp"
|
#include "ci/compilerInterface.hpp"
|
||||||
#include "code/debugInfoRec.hpp"
|
#include "code/debugInfoRec.hpp"
|
||||||
#include "code/exceptionHandlerTable.hpp"
|
|
||||||
#include "compiler/compilerOracle.hpp"
|
#include "compiler/compilerOracle.hpp"
|
||||||
#include "compiler/compileBroker.hpp"
|
#include "compiler/compileBroker.hpp"
|
||||||
#include "libadt/dict.hpp"
|
#include "libadt/dict.hpp"
|
||||||
|
@ -48,7 +47,6 @@
|
||||||
class AddPNode;
|
class AddPNode;
|
||||||
class Block;
|
class Block;
|
||||||
class Bundle;
|
class Bundle;
|
||||||
class C2Compiler;
|
|
||||||
class CallGenerator;
|
class CallGenerator;
|
||||||
class CloneMap;
|
class CloneMap;
|
||||||
class ConnectionGraph;
|
class ConnectionGraph;
|
||||||
|
@ -72,6 +70,7 @@ class PhaseIterGVN;
|
||||||
class PhaseRegAlloc;
|
class PhaseRegAlloc;
|
||||||
class PhaseCCP;
|
class PhaseCCP;
|
||||||
class PhaseCCP_DCE;
|
class PhaseCCP_DCE;
|
||||||
|
class PhaseOutput;
|
||||||
class RootNode;
|
class RootNode;
|
||||||
class relocInfo;
|
class relocInfo;
|
||||||
class Scope;
|
class Scope;
|
||||||
|
@ -240,121 +239,6 @@ class Compile : public Phase {
|
||||||
trapHistLength = MethodData::_trap_hist_limit
|
trapHistLength = MethodData::_trap_hist_limit
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constant entry of the constant table.
|
|
||||||
class Constant {
|
|
||||||
private:
|
|
||||||
BasicType _type;
|
|
||||||
union {
|
|
||||||
jvalue _value;
|
|
||||||
Metadata* _metadata;
|
|
||||||
} _v;
|
|
||||||
int _offset; // offset of this constant (in bytes) relative to the constant table base.
|
|
||||||
float _freq;
|
|
||||||
bool _can_be_reused; // true (default) if the value can be shared with other users.
|
|
||||||
|
|
||||||
public:
|
|
||||||
Constant() : _type(T_ILLEGAL), _offset(-1), _freq(0.0f), _can_be_reused(true) { _v._value.l = 0; }
|
|
||||||
Constant(BasicType type, jvalue value, float freq = 0.0f, bool can_be_reused = true) :
|
|
||||||
_type(type),
|
|
||||||
_offset(-1),
|
|
||||||
_freq(freq),
|
|
||||||
_can_be_reused(can_be_reused)
|
|
||||||
{
|
|
||||||
assert(type != T_METADATA, "wrong constructor");
|
|
||||||
_v._value = value;
|
|
||||||
}
|
|
||||||
Constant(Metadata* metadata, bool can_be_reused = true) :
|
|
||||||
_type(T_METADATA),
|
|
||||||
_offset(-1),
|
|
||||||
_freq(0.0f),
|
|
||||||
_can_be_reused(can_be_reused)
|
|
||||||
{
|
|
||||||
_v._metadata = metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const Constant& other);
|
|
||||||
|
|
||||||
BasicType type() const { return _type; }
|
|
||||||
|
|
||||||
jint get_jint() const { return _v._value.i; }
|
|
||||||
jlong get_jlong() const { return _v._value.j; }
|
|
||||||
jfloat get_jfloat() const { return _v._value.f; }
|
|
||||||
jdouble get_jdouble() const { return _v._value.d; }
|
|
||||||
jobject get_jobject() const { return _v._value.l; }
|
|
||||||
|
|
||||||
Metadata* get_metadata() const { return _v._metadata; }
|
|
||||||
|
|
||||||
int offset() const { return _offset; }
|
|
||||||
void set_offset(int offset) { _offset = offset; }
|
|
||||||
|
|
||||||
float freq() const { return _freq; }
|
|
||||||
void inc_freq(float freq) { _freq += freq; }
|
|
||||||
|
|
||||||
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.
|
|
||||||
int _nof_jump_tables; // Number of jump-tables in this constant table.
|
|
||||||
|
|
||||||
static int qsort_comparator(Constant* a, Constant* b);
|
|
||||||
|
|
||||||
// We use negative frequencies to keep the order of the
|
|
||||||
// jump-tables in which they were added. Otherwise we get into
|
|
||||||
// trouble with relocation.
|
|
||||||
float next_jump_table_freq() { return -1.0f * (++_nof_jump_tables); }
|
|
||||||
|
|
||||||
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).
|
|
||||||
_nof_jump_tables(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
int size() const { assert(_size != -1, "not calculated yet"); return _size; }
|
|
||||||
|
|
||||||
int calculate_table_base_offset() const; // AD specific
|
|
||||||
void set_table_base_offset(int x) { assert(_table_base_offset == -1 || x == _table_base_offset, "can't change"); _table_base_offset = x; }
|
|
||||||
int table_base_offset() const { assert(_table_base_offset != -1, "not set yet"); 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, "not bound yet"); return _constants.top().offset(); }
|
|
||||||
|
|
||||||
void calculate_offsets_and_size();
|
|
||||||
int find_offset(Constant& con) const;
|
|
||||||
|
|
||||||
void add(Constant& con);
|
|
||||||
Constant add(MachConstantNode* n, BasicType type, jvalue value);
|
|
||||||
Constant add(Metadata* metadata);
|
|
||||||
Constant add(MachConstantNode* n, MachOper* oper);
|
|
||||||
Constant add(MachConstantNode* n, jint i) {
|
|
||||||
jvalue value; value.i = i;
|
|
||||||
return add(n, T_INT, value);
|
|
||||||
}
|
|
||||||
Constant add(MachConstantNode* n, jlong j) {
|
|
||||||
jvalue value; value.j = j;
|
|
||||||
return add(n, T_LONG, value);
|
|
||||||
}
|
|
||||||
Constant add(MachConstantNode* n, jfloat f) {
|
|
||||||
jvalue value; value.f = f;
|
|
||||||
return add(n, T_FLOAT, value);
|
|
||||||
}
|
|
||||||
Constant add(MachConstantNode* n, jdouble d) {
|
|
||||||
jvalue value; value.d = d;
|
|
||||||
return add(n, T_DOUBLE, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jump-table
|
|
||||||
Constant add_jump_table(MachConstantNode* n);
|
|
||||||
void fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Fixed parameters to this compilation.
|
// Fixed parameters to this compilation.
|
||||||
const int _compile_id;
|
const int _compile_id;
|
||||||
|
@ -376,9 +260,6 @@ class Compile : public Phase {
|
||||||
int _fixed_slots; // count of frame slots not allocated by the register
|
int _fixed_slots; // count of frame slots not allocated by the register
|
||||||
// allocator i.e. locks, original deopt pc, etc.
|
// allocator i.e. locks, original deopt pc, etc.
|
||||||
uintx _max_node_limit; // Max unique node count during a single compilation.
|
uintx _max_node_limit; // Max unique node count during a single compilation.
|
||||||
// For deopt
|
|
||||||
int _orig_pc_slot;
|
|
||||||
int _orig_pc_slot_offset_in_bytes;
|
|
||||||
|
|
||||||
int _major_progress; // Count of something big happening
|
int _major_progress; // Count of something big happening
|
||||||
bool _inlining_progress; // progress doing incremental inlining?
|
bool _inlining_progress; // progress doing incremental inlining?
|
||||||
|
@ -457,7 +338,6 @@ class Compile : public Phase {
|
||||||
Node* _recent_alloc_ctl;
|
Node* _recent_alloc_ctl;
|
||||||
|
|
||||||
// Constant table
|
// Constant table
|
||||||
ConstantTable _constant_table; // The constant table for this compile.
|
|
||||||
MachConstantBaseNode* _mach_constant_base_node; // Constant table base node singleton.
|
MachConstantBaseNode* _mach_constant_base_node; // Constant table base node singleton.
|
||||||
|
|
||||||
|
|
||||||
|
@ -586,27 +466,12 @@ class Compile : public Phase {
|
||||||
int _inner_loops; // Number of inner loops in the method
|
int _inner_loops; // Number of inner loops in the method
|
||||||
Matcher* _matcher; // Engine to map ideal to machine instructions
|
Matcher* _matcher; // Engine to map ideal to machine instructions
|
||||||
PhaseRegAlloc* _regalloc; // Results of register allocation.
|
PhaseRegAlloc* _regalloc; // Results of register allocation.
|
||||||
int _frame_slots; // Size of total frame in stack slots
|
|
||||||
CodeOffsets _code_offsets; // Offsets into the code for various interesting entries
|
|
||||||
RegMask _FIRST_STACK_mask; // All stack slots usable for spills (depends on frame layout)
|
RegMask _FIRST_STACK_mask; // All stack slots usable for spills (depends on frame layout)
|
||||||
Arena* _indexSet_arena; // control IndexSet allocation within PhaseChaitin
|
Arena* _indexSet_arena; // control IndexSet allocation within PhaseChaitin
|
||||||
void* _indexSet_free_block_list; // free list of IndexSet bit blocks
|
void* _indexSet_free_block_list; // free list of IndexSet bit blocks
|
||||||
int _interpreter_frame_size;
|
int _interpreter_frame_size;
|
||||||
|
|
||||||
uint _node_bundling_limit;
|
PhaseOutput* _output;
|
||||||
Bundle* _node_bundling_base; // Information for instruction bundling
|
|
||||||
|
|
||||||
// Instruction bits passed off to the VM
|
|
||||||
int _method_size; // Size of nmethod code segment in bytes
|
|
||||||
CodeBuffer _code_buffer; // Where the code is assembled
|
|
||||||
int _first_block_size; // Size of unvalidated entry point code / OSR poison code
|
|
||||||
ExceptionHandlerTable _handler_table; // Table of native-code exception handlers
|
|
||||||
ImplicitExceptionTable _inc_table; // Table of implicit null checks in native code
|
|
||||||
OopMapSet* _oop_map_set; // Table of oop maps (one for each safepoint location)
|
|
||||||
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.
|
|
||||||
|
|
||||||
void reshape_address(AddPNode* n);
|
void reshape_address(AddPNode* n);
|
||||||
|
|
||||||
|
@ -618,6 +483,11 @@ class Compile : public Phase {
|
||||||
return (Compile*) ciEnv::current()->compiler_data();
|
return (Compile*) ciEnv::current()->compiler_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int interpreter_frame_size() const { return _interpreter_frame_size; }
|
||||||
|
|
||||||
|
PhaseOutput* output() const { return _output; }
|
||||||
|
void set_output(PhaseOutput* o) { _output = o; }
|
||||||
|
|
||||||
// ID for this compilation. Useful for setting breakpoints in the debugger.
|
// ID for this compilation. Useful for setting breakpoints in the debugger.
|
||||||
int compile_id() const { return _compile_id; }
|
int compile_id() const { return _compile_id; }
|
||||||
DirectiveSet* directive() const { return _directive; }
|
DirectiveSet* directive() const { return _directive; }
|
||||||
|
@ -646,6 +516,7 @@ class Compile : public Phase {
|
||||||
address stub_function() const { return _stub_function; }
|
address stub_function() const { return _stub_function; }
|
||||||
const char* stub_name() const { return _stub_name; }
|
const char* stub_name() const { return _stub_name; }
|
||||||
address stub_entry_point() const { return _stub_entry_point; }
|
address stub_entry_point() const { return _stub_entry_point; }
|
||||||
|
void set_stub_entry_point(address z) { _stub_entry_point = z; }
|
||||||
|
|
||||||
// Control of this compilation.
|
// Control of this compilation.
|
||||||
int fixed_slots() const { assert(_fixed_slots >= 0, ""); return _fixed_slots; }
|
int fixed_slots() const { assert(_fixed_slots >= 0, ""); return _fixed_slots; }
|
||||||
|
@ -936,9 +807,6 @@ class Compile : public Phase {
|
||||||
void remove_modified_node(Node* n) NOT_DEBUG_RETURN;
|
void remove_modified_node(Node* n) NOT_DEBUG_RETURN;
|
||||||
DEBUG_ONLY( Unique_Node_List* modified_nodes() const { return _modified_nodes; } )
|
DEBUG_ONLY( Unique_Node_List* modified_nodes() const { return _modified_nodes; } )
|
||||||
|
|
||||||
// Constant table
|
|
||||||
ConstantTable& constant_table() { return _constant_table; }
|
|
||||||
|
|
||||||
MachConstantBaseNode* mach_constant_base_node();
|
MachConstantBaseNode* mach_constant_base_node();
|
||||||
bool has_mach_constant_base_node() const { return _mach_constant_base_node != NULL; }
|
bool has_mach_constant_base_node() const { return _mach_constant_base_node != NULL; }
|
||||||
// Generated by adlc, true if CallNode requires MachConstantBase.
|
// Generated by adlc, true if CallNode requires MachConstantBase.
|
||||||
|
@ -1124,26 +992,16 @@ class Compile : public Phase {
|
||||||
int inner_loops() const { return _inner_loops; }
|
int inner_loops() const { return _inner_loops; }
|
||||||
Matcher* matcher() { return _matcher; }
|
Matcher* matcher() { return _matcher; }
|
||||||
PhaseRegAlloc* regalloc() { return _regalloc; }
|
PhaseRegAlloc* regalloc() { return _regalloc; }
|
||||||
int frame_slots() const { return _frame_slots; }
|
|
||||||
int frame_size_in_words() const; // frame_slots in units of the polymorphic 'words'
|
|
||||||
int frame_size_in_bytes() const { return _frame_slots << LogBytesPerInt; }
|
|
||||||
RegMask& FIRST_STACK_mask() { return _FIRST_STACK_mask; }
|
RegMask& FIRST_STACK_mask() { return _FIRST_STACK_mask; }
|
||||||
Arena* indexSet_arena() { return _indexSet_arena; }
|
Arena* indexSet_arena() { return _indexSet_arena; }
|
||||||
void* indexSet_free_block_list() { return _indexSet_free_block_list; }
|
void* indexSet_free_block_list() { return _indexSet_free_block_list; }
|
||||||
uint node_bundling_limit() { return _node_bundling_limit; }
|
DebugInformationRecorder* debug_info() { return env()->debug_info(); }
|
||||||
Bundle* node_bundling_base() { return _node_bundling_base; }
|
|
||||||
void set_node_bundling_limit(uint n) { _node_bundling_limit = n; }
|
|
||||||
void set_node_bundling_base(Bundle* b) { _node_bundling_base = b; }
|
|
||||||
bool starts_bundle(const Node *n) const;
|
|
||||||
bool need_stack_bang(int frame_size_in_bytes) const;
|
|
||||||
bool need_register_stack_bang() const;
|
|
||||||
|
|
||||||
void update_interpreter_frame_size(int size) {
|
void update_interpreter_frame_size(int size) {
|
||||||
if (_interpreter_frame_size < size) {
|
if (_interpreter_frame_size < size) {
|
||||||
_interpreter_frame_size = size;
|
_interpreter_frame_size = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int bang_size_in_bytes() const;
|
|
||||||
|
|
||||||
void set_matcher(Matcher* m) { _matcher = m; }
|
void set_matcher(Matcher* m) { _matcher = m; }
|
||||||
//void set_regalloc(PhaseRegAlloc* ra) { _regalloc = ra; }
|
//void set_regalloc(PhaseRegAlloc* ra) { _regalloc = ra; }
|
||||||
|
@ -1153,40 +1011,13 @@ class Compile : public Phase {
|
||||||
void set_java_calls(int z) { _java_calls = z; }
|
void set_java_calls(int z) { _java_calls = z; }
|
||||||
void set_inner_loops(int z) { _inner_loops = z; }
|
void set_inner_loops(int z) { _inner_loops = z; }
|
||||||
|
|
||||||
// Instruction bits passed off to the VM
|
Dependencies* dependencies() { return env()->dependencies(); }
|
||||||
int code_size() { return _method_size; }
|
|
||||||
CodeBuffer* code_buffer() { return &_code_buffer; }
|
|
||||||
int first_block_size() { return _first_block_size; }
|
|
||||||
void set_frame_complete(int off) { if (!in_scratch_emit_size()) { _code_offsets.set_value(CodeOffsets::Frame_Complete, off); } }
|
|
||||||
ExceptionHandlerTable* handler_table() { return &_handler_table; }
|
|
||||||
ImplicitExceptionTable* inc_table() { return &_inc_table; }
|
|
||||||
OopMapSet* oop_map_set() { return _oop_map_set; }
|
|
||||||
DebugInformationRecorder* debug_info() { return env()->debug_info(); }
|
|
||||||
Dependencies* dependencies() { return env()->dependencies(); }
|
|
||||||
BufferBlob* scratch_buffer_blob() { return _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 = 2048,
|
|
||||||
MAX_locs_size = 128, // number of relocInfo elements
|
|
||||||
MAX_const_size = 128,
|
|
||||||
MAX_stubs_size = 128
|
|
||||||
};
|
|
||||||
|
|
||||||
// Major entry point. Given a Scope, compile the associated method.
|
// Major entry point. Given a Scope, compile the associated method.
|
||||||
// For normal compilations, entry_bci is InvocationEntryBci. For on stack
|
// For normal compilations, entry_bci is InvocationEntryBci. For on stack
|
||||||
// replacement, entry_bci indicates the bytecode for which to compile a
|
// replacement, entry_bci indicates the bytecode for which to compile a
|
||||||
// continuation.
|
// continuation.
|
||||||
Compile(ciEnv* ci_env, C2Compiler* compiler, ciMethod* target,
|
Compile(ciEnv* ci_env, ciMethod* target,
|
||||||
int entry_bci, bool subsume_loads, bool do_escape_analysis,
|
int entry_bci, bool subsume_loads, bool do_escape_analysis,
|
||||||
bool eliminate_boxing, DirectiveSet* directive);
|
bool eliminate_boxing, DirectiveSet* directive);
|
||||||
|
|
||||||
|
@ -1221,67 +1052,8 @@ class Compile : public Phase {
|
||||||
// returns true if adr overlaps with the given alias category
|
// returns true if adr overlaps with the given alias category
|
||||||
bool can_alias(const TypePtr* adr, int alias_idx);
|
bool can_alias(const TypePtr* adr, int alias_idx);
|
||||||
|
|
||||||
// Driver for converting compiler's IR into machine code bits
|
|
||||||
void Output();
|
|
||||||
|
|
||||||
// Accessors for node bundling info.
|
|
||||||
Bundle* node_bundling(const Node *n);
|
|
||||||
bool valid_bundle_info(const Node *n);
|
|
||||||
|
|
||||||
// Schedule and Bundle the instructions
|
|
||||||
void ScheduleAndBundle();
|
|
||||||
|
|
||||||
// Build OopMaps for each GC point
|
|
||||||
void BuildOopMaps();
|
|
||||||
|
|
||||||
// Append debug info for the node "local" at safepoint node "sfpt" to the
|
|
||||||
// "array", May also consult and add to "objs", which describes the
|
|
||||||
// scalar-replaced objects.
|
|
||||||
void FillLocArray( int idx, MachSafePointNode* sfpt,
|
|
||||||
Node *local, GrowableArray<ScopeValue*> *array,
|
|
||||||
GrowableArray<ScopeValue*> *objs );
|
|
||||||
|
|
||||||
// If "objs" contains an ObjectValue whose id is "id", returns it, else NULL.
|
// If "objs" contains an ObjectValue whose id is "id", returns it, else NULL.
|
||||||
static ObjectValue* sv_for_node_id(GrowableArray<ScopeValue*> *objs, int id);
|
static ObjectValue* sv_for_node_id(GrowableArray<ScopeValue*> *objs, int id);
|
||||||
// Requres that "objs" does not contains an ObjectValue whose id matches
|
|
||||||
// that of "sv. Appends "sv".
|
|
||||||
static void set_sv_for_object_node(GrowableArray<ScopeValue*> *objs,
|
|
||||||
ObjectValue* sv );
|
|
||||||
|
|
||||||
// Process an OopMap Element while emitting nodes
|
|
||||||
void Process_OopMap_Node(MachNode *mach, int code_offset);
|
|
||||||
|
|
||||||
class BufferSizingData {
|
|
||||||
public:
|
|
||||||
int _stub;
|
|
||||||
int _code;
|
|
||||||
int _const;
|
|
||||||
int _reloc;
|
|
||||||
|
|
||||||
BufferSizingData() :
|
|
||||||
_stub(0),
|
|
||||||
_code(0),
|
|
||||||
_const(0),
|
|
||||||
_reloc(0)
|
|
||||||
{ };
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize code buffer
|
|
||||||
void estimate_buffer_size(int& const_req);
|
|
||||||
CodeBuffer* init_buffer(BufferSizingData& buf_sizes);
|
|
||||||
|
|
||||||
// Write out basic block data to code buffer
|
|
||||||
void fill_buffer(CodeBuffer* cb, uint* blk_starts);
|
|
||||||
|
|
||||||
// Determine which variable sized branches can be shortened
|
|
||||||
void shorten_branches(uint* blk_starts, BufferSizingData& buf_sizes);
|
|
||||||
|
|
||||||
// Compute the size of first NumberOfLoopInstrToAlign instructions
|
|
||||||
// at the head of a loop.
|
|
||||||
void compute_loop_first_inst_sizes();
|
|
||||||
|
|
||||||
// Compute the information for the exception tables
|
|
||||||
void FillExceptionTables(uint cnt, uint *call_returns, uint *inct_starts, Label *blk_labels);
|
|
||||||
|
|
||||||
// Stack slots that may be unused by the calling convention but must
|
// Stack slots that may be unused by the calling convention but must
|
||||||
// otherwise be preserved. On Intel this includes the return address.
|
// otherwise be preserved. On Intel this includes the return address.
|
||||||
|
@ -1364,16 +1136,6 @@ class Compile : public Phase {
|
||||||
// End-of-run dumps.
|
// End-of-run dumps.
|
||||||
static void print_statistics() PRODUCT_RETURN;
|
static void print_statistics() PRODUCT_RETURN;
|
||||||
|
|
||||||
// Dump formatted assembly
|
|
||||||
#if defined(SUPPORT_OPTO_ASSEMBLY)
|
|
||||||
void dump_asm_on(outputStream* ost, int* pcs, uint pc_limit);
|
|
||||||
void dump_asm(int* pcs = NULL, uint pc_limit = 0) { dump_asm_on(tty, pcs, pc_limit); }
|
|
||||||
#else
|
|
||||||
void dump_asm_on(outputStream* ost, int* pcs, uint pc_limit) { return; }
|
|
||||||
void dump_asm(int* pcs = NULL, uint pc_limit = 0) { return; }
|
|
||||||
#endif
|
|
||||||
void dump_pc(int *pcs, int pc_limit, Node *n);
|
|
||||||
|
|
||||||
// Verify ADLC assumptions during startup
|
// Verify ADLC assumptions during startup
|
||||||
static void adlc_verification() PRODUCT_RETURN;
|
static void adlc_verification() PRODUCT_RETURN;
|
||||||
|
|
||||||
|
|
246
src/hotspot/share/opto/constantTable.cpp
Normal file
246
src/hotspot/share/opto/constantTable.cpp
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "asm/codeBuffer.hpp"
|
||||||
|
#include "opto/block.hpp"
|
||||||
|
#include "opto/constantTable.hpp"
|
||||||
|
#include "opto/machnode.hpp"
|
||||||
|
#include "opto/output.hpp"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Two Constant's are equal when the type and the value are equal.
|
||||||
|
bool ConstantTable::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_INT:
|
||||||
|
case T_FLOAT: return (_v._value.i == other._v._value.i);
|
||||||
|
case T_LONG:
|
||||||
|
case T_DOUBLE: return (_v._value.j == other._v._value.j);
|
||||||
|
case T_OBJECT:
|
||||||
|
case T_ADDRESS: return (_v._value.l == other._v._value.l);
|
||||||
|
case T_VOID: return (_v._value.l == other._v._value.l); // jump-table entries
|
||||||
|
case T_METADATA: return (_v._metadata == other._v._metadata);
|
||||||
|
default: ShouldNotReachHere(); return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConstantTable::qsort_comparator(Constant* a, Constant* b) {
|
||||||
|
// sort descending
|
||||||
|
if (a->freq() > b->freq()) return -1;
|
||||||
|
if (a->freq() < b->freq()) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int type_to_size_in_bytes(BasicType t) {
|
||||||
|
switch (t) {
|
||||||
|
case T_INT: return sizeof(jint );
|
||||||
|
case T_LONG: return sizeof(jlong );
|
||||||
|
case T_FLOAT: return sizeof(jfloat );
|
||||||
|
case T_DOUBLE: return sizeof(jdouble);
|
||||||
|
case T_METADATA: return sizeof(Metadata*);
|
||||||
|
// We use T_VOID as marker for jump-table entries (labels) which
|
||||||
|
// need an internal word relocation.
|
||||||
|
case T_VOID:
|
||||||
|
case T_ADDRESS:
|
||||||
|
case T_OBJECT: return sizeof(jobject);
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConstantTable::calculate_offsets_and_size() {
|
||||||
|
// First, sort the array by frequencies.
|
||||||
|
_constants.sort(qsort_comparator);
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
// Make sure all jump-table entries were sorted to the end of the
|
||||||
|
// array (they have a negative frequency).
|
||||||
|
bool found_void = false;
|
||||||
|
for (int i = 0; i < _constants.length(); i++) {
|
||||||
|
Constant con = _constants.at(i);
|
||||||
|
if (con.type() == T_VOID)
|
||||||
|
found_void = true; // jump-tables
|
||||||
|
else
|
||||||
|
assert(!found_void, "wrong sorting");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < _constants.length(); i++) {
|
||||||
|
Constant* con = _constants.adr_at(i);
|
||||||
|
|
||||||
|
// Align offset for type.
|
||||||
|
int typesize = type_to_size_in_bytes(con->type());
|
||||||
|
offset = align_up(offset, typesize);
|
||||||
|
con->set_offset(offset); // set constant's offset
|
||||||
|
|
||||||
|
if (con->type() == T_VOID) {
|
||||||
|
MachConstantNode* n = (MachConstantNode*) con->get_jobject();
|
||||||
|
offset = offset + typesize * n->outcnt(); // expand jump-table
|
||||||
|
} else {
|
||||||
|
offset = offset + typesize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Align size up to the next section start (which is insts; see
|
||||||
|
// CodeBuffer::align_at_start).
|
||||||
|
assert(_size == -1, "already set?");
|
||||||
|
_size = align_up(offset, (int)CodeEntryAlignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConstantTable::emit(CodeBuffer& cb) {
|
||||||
|
MacroAssembler _masm(&cb);
|
||||||
|
for (int i = 0; i < _constants.length(); i++) {
|
||||||
|
Constant con = _constants.at(i);
|
||||||
|
address constant_addr = NULL;
|
||||||
|
switch (con.type()) {
|
||||||
|
case T_INT: constant_addr = _masm.int_constant( con.get_jint() ); break;
|
||||||
|
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 internal word relocation.
|
||||||
|
case T_VOID: {
|
||||||
|
MachConstantNode* n = (MachConstantNode*) con.get_jobject();
|
||||||
|
// Fill the jump-table with a dummy word. The real value is
|
||||||
|
// filled in later in fill_jump_table.
|
||||||
|
address dummy = (address) n;
|
||||||
|
constant_addr = _masm.address_constant(dummy);
|
||||||
|
// Expand jump-table
|
||||||
|
for (uint i = 1; i < n->outcnt(); i++) {
|
||||||
|
address temp_addr = _masm.address_constant(dummy + i);
|
||||||
|
assert(temp_addr, "consts section too small");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case T_METADATA: {
|
||||||
|
Metadata* obj = con.get_metadata();
|
||||||
|
int metadata_index = _masm.oop_recorder()->find_index(obj);
|
||||||
|
constant_addr = _masm.address_constant((address) obj, metadata_Relocation::spec(metadata_index));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
assert(constant_addr, "consts section too small");
|
||||||
|
assert((constant_addr - _masm.code()->consts()->start()) == con.offset(),
|
||||||
|
"must be: %d == %d", (int) (constant_addr - _masm.code()->consts()->start()), (int)(con.offset()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConstantTable::find_offset(Constant& con) const {
|
||||||
|
int idx = _constants.find(con);
|
||||||
|
guarantee(idx != -1, "constant must be in constant table");
|
||||||
|
int offset = _constants.at(idx).offset();
|
||||||
|
guarantee(offset != -1, "constant table not emitted yet?");
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConstantTable::add(Constant& con) {
|
||||||
|
if (con.can_be_reused()) {
|
||||||
|
int idx = _constants.find(con);
|
||||||
|
if (idx != -1 && _constants.at(idx).can_be_reused()) {
|
||||||
|
_constants.adr_at(idx)->inc_freq(con.freq()); // increase the frequency by the current value
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) _constants.append(con);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstantTable::Constant ConstantTable::add(MachConstantNode* n, BasicType type, jvalue value) {
|
||||||
|
Block* b = Compile::current()->cfg()->get_block_for_node(n);
|
||||||
|
Constant con(type, value, b->_freq);
|
||||||
|
add(con);
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstantTable::Constant ConstantTable::add(Metadata* metadata) {
|
||||||
|
Constant con(metadata);
|
||||||
|
add(con);
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstantTable::Constant ConstantTable::add(MachConstantNode* n, 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;
|
||||||
|
case T_METADATA: return add((Metadata*)oper->constant()); break;
|
||||||
|
default: guarantee(false, "unhandled type: %s", type2name(type));
|
||||||
|
}
|
||||||
|
return add(n, type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstantTable::Constant ConstantTable::add_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, next_jump_table_freq(), false); // Labels of a jump-table cannot be reused.
|
||||||
|
add(con);
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const {
|
||||||
|
// If called from Compile::scratch_emit_size do nothing.
|
||||||
|
if (Compile::current()->output()->in_scratch_emit_size()) return;
|
||||||
|
|
||||||
|
assert(labels.is_nonempty(), "must be");
|
||||||
|
assert((uint) labels.length() == n->outcnt(), "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 (uint i = 0; i < n->outcnt(); i++) {
|
||||||
|
address* constant_addr = &jump_table_base[i];
|
||||||
|
assert(*constant_addr == (((address) n) + i), "all jump-table entries must contain adjusted node pointer: " INTPTR_FORMAT " == " INTPTR_FORMAT, p2i(*constant_addr), p2i(((address) n) + i));
|
||||||
|
*constant_addr = cb.consts()->target(*labels.at(i), (address) constant_addr);
|
||||||
|
cb.consts()->relocate((address) constant_addr, relocInfo::internal_word_type);
|
||||||
|
}
|
||||||
|
}
|
151
src/hotspot/share/opto/constantTable.hpp
Normal file
151
src/hotspot/share/opto/constantTable.hpp
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, 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_OPTO_CONSTANTTABLE_HPP
|
||||||
|
#define SHARE_OPTO_CONSTANTTABLE_HPP
|
||||||
|
|
||||||
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
|
||||||
|
class CodeBuffer;
|
||||||
|
class Metadata;
|
||||||
|
class MachConstantNode;
|
||||||
|
class MachOper;
|
||||||
|
|
||||||
|
class ConstantTable {
|
||||||
|
public:
|
||||||
|
// Constant entry of the constant table.
|
||||||
|
class Constant {
|
||||||
|
private:
|
||||||
|
BasicType _type;
|
||||||
|
union {
|
||||||
|
jvalue _value;
|
||||||
|
Metadata* _metadata;
|
||||||
|
} _v;
|
||||||
|
int _offset; // offset of this constant (in bytes) relative to the constant table base.
|
||||||
|
float _freq;
|
||||||
|
bool _can_be_reused; // true (default) if the value can be shared with other users.
|
||||||
|
|
||||||
|
public:
|
||||||
|
Constant() : _type(T_ILLEGAL), _offset(-1), _freq(0.0f), _can_be_reused(true) { _v._value.l = 0; }
|
||||||
|
Constant(BasicType type, jvalue value, float freq = 0.0f, bool can_be_reused = true) :
|
||||||
|
_type(type),
|
||||||
|
_offset(-1),
|
||||||
|
_freq(freq),
|
||||||
|
_can_be_reused(can_be_reused)
|
||||||
|
{
|
||||||
|
assert(type != T_METADATA, "wrong constructor");
|
||||||
|
_v._value = value;
|
||||||
|
}
|
||||||
|
Constant(Metadata* metadata, bool can_be_reused = true) :
|
||||||
|
_type(T_METADATA),
|
||||||
|
_offset(-1),
|
||||||
|
_freq(0.0f),
|
||||||
|
_can_be_reused(can_be_reused)
|
||||||
|
{
|
||||||
|
_v._metadata = metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Constant& other);
|
||||||
|
|
||||||
|
BasicType type() const { return _type; }
|
||||||
|
|
||||||
|
jint get_jint() const { return _v._value.i; }
|
||||||
|
jlong get_jlong() const { return _v._value.j; }
|
||||||
|
jfloat get_jfloat() const { return _v._value.f; }
|
||||||
|
jdouble get_jdouble() const { return _v._value.d; }
|
||||||
|
jobject get_jobject() const { return _v._value.l; }
|
||||||
|
|
||||||
|
Metadata* get_metadata() const { return _v._metadata; }
|
||||||
|
|
||||||
|
int offset() const { return _offset; }
|
||||||
|
void set_offset(int offset) { _offset = offset; }
|
||||||
|
|
||||||
|
float freq() const { return _freq; }
|
||||||
|
void inc_freq(float freq) { _freq += freq; }
|
||||||
|
|
||||||
|
bool can_be_reused() const { return _can_be_reused; }
|
||||||
|
};
|
||||||
|
|
||||||
|
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.
|
||||||
|
int _nof_jump_tables; // Number of jump-tables in this constant table.
|
||||||
|
|
||||||
|
static int qsort_comparator(Constant* a, Constant* b);
|
||||||
|
|
||||||
|
// We use negative frequencies to keep the order of the
|
||||||
|
// jump-tables in which they were added. Otherwise we get into
|
||||||
|
// trouble with relocation.
|
||||||
|
float next_jump_table_freq() { return -1.0f * (++_nof_jump_tables); }
|
||||||
|
|
||||||
|
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).
|
||||||
|
_nof_jump_tables(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int size() const { assert(_size != -1, "not calculated yet"); return _size; }
|
||||||
|
|
||||||
|
int calculate_table_base_offset() const; // AD specific
|
||||||
|
void set_table_base_offset(int x) { assert(_table_base_offset == -1 || x == _table_base_offset, "can't change"); _table_base_offset = x; }
|
||||||
|
int table_base_offset() const { assert(_table_base_offset != -1, "not set yet"); 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, "not bound yet"); return _constants.top().offset(); }
|
||||||
|
|
||||||
|
void calculate_offsets_and_size();
|
||||||
|
int find_offset(Constant& con) const;
|
||||||
|
|
||||||
|
void add(Constant& con);
|
||||||
|
Constant add(MachConstantNode* n, BasicType type, jvalue value);
|
||||||
|
Constant add(Metadata* metadata);
|
||||||
|
Constant add(MachConstantNode* n, MachOper* oper);
|
||||||
|
Constant add(MachConstantNode* n, jint i) {
|
||||||
|
jvalue value; value.i = i;
|
||||||
|
return add(n, T_INT, value);
|
||||||
|
}
|
||||||
|
Constant add(MachConstantNode* n, jlong j) {
|
||||||
|
jvalue value; value.j = j;
|
||||||
|
return add(n, T_LONG, value);
|
||||||
|
}
|
||||||
|
Constant add(MachConstantNode* n, jfloat f) {
|
||||||
|
jvalue value; value.f = f;
|
||||||
|
return add(n, T_FLOAT, value);
|
||||||
|
}
|
||||||
|
Constant add(MachConstantNode* n, jdouble d) {
|
||||||
|
jvalue value; value.d = d;
|
||||||
|
return add(n, T_DOUBLE, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jump-table
|
||||||
|
Constant add_jump_table(MachConstantNode* n);
|
||||||
|
void fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SHARE_OPTO_CONSTANTTABLE_HPP
|
|
@ -27,6 +27,7 @@
|
||||||
#include "memory/universe.hpp"
|
#include "memory/universe.hpp"
|
||||||
#include "oops/compressedOops.hpp"
|
#include "oops/compressedOops.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
|
#include "opto/output.hpp"
|
||||||
#include "opto/regalloc.hpp"
|
#include "opto/regalloc.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
|
|
||||||
|
@ -154,7 +155,7 @@ uint MachNode::size(PhaseRegAlloc *ra_) const {
|
||||||
uint MachNode::emit_size(PhaseRegAlloc *ra_) const {
|
uint MachNode::emit_size(PhaseRegAlloc *ra_) const {
|
||||||
// Emit into a trash buffer and count bytes emitted.
|
// Emit into a trash buffer and count bytes emitted.
|
||||||
assert(ra_ == ra_->C->regalloc(), "sanity");
|
assert(ra_ == ra_->C->regalloc(), "sanity");
|
||||||
return ra_->C->scratch_emit_size(this);
|
return ra_->C->output()->scratch_emit_size(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -541,13 +542,13 @@ void MachTypeNode::dump_spec(outputStream *st) const {
|
||||||
int MachConstantNode::constant_offset() {
|
int MachConstantNode::constant_offset() {
|
||||||
// Bind the offset lazily.
|
// Bind the offset lazily.
|
||||||
if (_constant.offset() == -1) {
|
if (_constant.offset() == -1) {
|
||||||
Compile::ConstantTable& constant_table = Compile::current()->constant_table();
|
ConstantTable& constant_table = Compile::current()->output()->constant_table();
|
||||||
int offset = constant_table.find_offset(_constant);
|
int offset = constant_table.find_offset(_constant);
|
||||||
// If called from Compile::scratch_emit_size return the
|
// If called from Compile::scratch_emit_size return the
|
||||||
// pre-calculated offset.
|
// pre-calculated offset.
|
||||||
// NOTE: If the AD file does some table base offset optimizations
|
// NOTE: If the AD file does some table base offset optimizations
|
||||||
// later the AD file needs to take care of this fact.
|
// later the AD file needs to take care of this fact.
|
||||||
if (Compile::current()->in_scratch_emit_size()) {
|
if (Compile::current()->output()->in_scratch_emit_size()) {
|
||||||
return constant_table.calculate_table_base_offset() + offset;
|
return constant_table.calculate_table_base_offset() + offset;
|
||||||
}
|
}
|
||||||
_constant.set_offset(constant_table.table_base_offset() + offset);
|
_constant.set_offset(constant_table.table_base_offset() + offset);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#define SHARE_OPTO_MACHNODE_HPP
|
#define SHARE_OPTO_MACHNODE_HPP
|
||||||
|
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
|
#include "opto/constantTable.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
#include "opto/multnode.hpp"
|
#include "opto/multnode.hpp"
|
||||||
#include "opto/node.hpp"
|
#include "opto/node.hpp"
|
||||||
|
@ -447,7 +448,7 @@ public:
|
||||||
// Machine node that holds a constant which is stored in the constant table.
|
// Machine node that holds a constant which is stored in the constant table.
|
||||||
class MachConstantNode : public MachTypeNode {
|
class MachConstantNode : public MachTypeNode {
|
||||||
protected:
|
protected:
|
||||||
Compile::Constant _constant; // This node's constant.
|
ConstantTable::Constant _constant; // This node's constant.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MachConstantNode() : MachTypeNode() {
|
MachConstantNode() : MachTypeNode() {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -26,20 +26,24 @@
|
||||||
#define SHARE_OPTO_OUTPUT_HPP
|
#define SHARE_OPTO_OUTPUT_HPP
|
||||||
|
|
||||||
#include "opto/ad.hpp"
|
#include "opto/ad.hpp"
|
||||||
#include "opto/block.hpp"
|
#include "opto/constantTable.hpp"
|
||||||
#include "opto/node.hpp"
|
#include "opto/phase.hpp"
|
||||||
|
#include "code/debugInfo.hpp"
|
||||||
|
#include "code/exceptionHandlerTable.hpp"
|
||||||
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
#include "utilities/macros.hpp"
|
||||||
|
|
||||||
|
class AbstractCompiler;
|
||||||
class Arena;
|
class Arena;
|
||||||
class Bundle;
|
class Bundle;
|
||||||
class Block;
|
class Block;
|
||||||
class Block_Array;
|
class Block_Array;
|
||||||
|
class ciMethod;
|
||||||
|
class Compile;
|
||||||
|
class MachNode;
|
||||||
|
class MachSafePointNode;
|
||||||
class Node;
|
class Node;
|
||||||
class Node_Array;
|
|
||||||
class Node_List;
|
|
||||||
class PhaseCFG;
|
class PhaseCFG;
|
||||||
class PhaseChaitin;
|
|
||||||
class Pipeline_Use_Element;
|
|
||||||
class Pipeline_Use;
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
#define DEBUG_ARG(x) , x
|
#define DEBUG_ARG(x) , x
|
||||||
#else
|
#else
|
||||||
|
@ -51,167 +55,157 @@ enum {
|
||||||
initial_const_capacity = 4 * 1024
|
initial_const_capacity = 4 * 1024
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------Scheduling----------------------------------
|
class BufferSizingData {
|
||||||
// This class contains all the information necessary to implement instruction
|
public:
|
||||||
// scheduling and bundling.
|
int _stub;
|
||||||
class Scheduling {
|
int _code;
|
||||||
|
int _const;
|
||||||
|
int _reloc;
|
||||||
|
|
||||||
|
BufferSizingData() :
|
||||||
|
_stub(0),
|
||||||
|
_code(0),
|
||||||
|
_const(0),
|
||||||
|
_reloc(0)
|
||||||
|
{ };
|
||||||
|
};
|
||||||
|
|
||||||
|
class PhaseOutput : public Phase {
|
||||||
private:
|
private:
|
||||||
// Arena to use
|
// Instruction bits passed off to the VM
|
||||||
Arena *_arena;
|
int _method_size; // Size of nmethod code segment in bytes
|
||||||
|
CodeBuffer _code_buffer; // Where the code is assembled
|
||||||
|
int _first_block_size; // Size of unvalidated entry point code / OSR poison code
|
||||||
|
ExceptionHandlerTable _handler_table; // Table of native-code exception handlers
|
||||||
|
ImplicitExceptionTable _inc_table; // Table of implicit null checks in native code
|
||||||
|
OopMapSet* _oop_map_set; // Table of oop maps (one for each safepoint location)
|
||||||
|
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.
|
||||||
|
|
||||||
// Control-Flow Graph info
|
int _frame_slots; // Size of total frame in stack slots
|
||||||
PhaseCFG *_cfg;
|
CodeOffsets _code_offsets; // Offsets into the code for various interesting entries
|
||||||
|
|
||||||
// Register Allocation info
|
uint _node_bundling_limit;
|
||||||
PhaseRegAlloc *_regalloc;
|
Bundle* _node_bundling_base; // Information for instruction bundling
|
||||||
|
|
||||||
// Number of nodes in the method
|
// For deopt
|
||||||
uint _node_bundling_limit;
|
int _orig_pc_slot;
|
||||||
|
int _orig_pc_slot_offset_in_bytes;
|
||||||
|
|
||||||
// List of scheduled nodes. Generated in reverse order
|
ConstantTable _constant_table; // The constant table for this compilation unit.
|
||||||
Node_List _scheduled;
|
|
||||||
|
|
||||||
// List of nodes currently available for choosing for scheduling
|
|
||||||
Node_List _available;
|
|
||||||
|
|
||||||
// For each instruction beginning a bundle, the number of following
|
|
||||||
// nodes to be bundled with it.
|
|
||||||
Bundle *_node_bundling_base;
|
|
||||||
|
|
||||||
// Mapping from register to Node
|
|
||||||
Node_List _reg_node;
|
|
||||||
|
|
||||||
// Free list for pinch nodes.
|
|
||||||
Node_List _pinch_free_list;
|
|
||||||
|
|
||||||
// Latency from the beginning of the containing basic block (base 1)
|
|
||||||
// for each node.
|
|
||||||
unsigned short *_node_latency;
|
|
||||||
|
|
||||||
// Number of uses of this node within the containing basic block.
|
|
||||||
short *_uses;
|
|
||||||
|
|
||||||
// Schedulable portion of current block. Skips Region/Phi/CreateEx up
|
|
||||||
// front, branch+proj at end. Also skips Catch/CProj (same as
|
|
||||||
// branch-at-end), plus just-prior exception-throwing call.
|
|
||||||
uint _bb_start, _bb_end;
|
|
||||||
|
|
||||||
// Latency from the end of the basic block as scheduled
|
|
||||||
unsigned short *_current_latency;
|
|
||||||
|
|
||||||
// Remember the next node
|
|
||||||
Node *_next_node;
|
|
||||||
|
|
||||||
// Use this for an unconditional branch delay slot
|
|
||||||
Node *_unconditional_delay_slot;
|
|
||||||
|
|
||||||
// Pointer to a Nop
|
|
||||||
MachNopNode *_nop;
|
|
||||||
|
|
||||||
// Length of the current bundle, in instructions
|
|
||||||
uint _bundle_instr_count;
|
|
||||||
|
|
||||||
// Current Cycle number, for computing latencies and bundling
|
|
||||||
uint _bundle_cycle_number;
|
|
||||||
|
|
||||||
// Bundle information
|
|
||||||
Pipeline_Use_Element _bundle_use_elements[resource_count];
|
|
||||||
Pipeline_Use _bundle_use;
|
|
||||||
|
|
||||||
// Dump the available list
|
|
||||||
void dump_available() const;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Scheduling(Arena *arena, Compile &compile);
|
PhaseOutput();
|
||||||
|
~PhaseOutput();
|
||||||
|
|
||||||
// Destructor
|
// Convert Nodes to instruction bits and pass off to the VM
|
||||||
NOT_PRODUCT( ~Scheduling(); )
|
void Output();
|
||||||
|
bool need_stack_bang(int frame_size_in_bytes) const;
|
||||||
|
bool need_register_stack_bang() const;
|
||||||
|
void compute_loop_first_inst_sizes();
|
||||||
|
|
||||||
// Step ahead "i" cycles
|
void install_code(ciMethod* target,
|
||||||
void step(uint i);
|
int entry_bci,
|
||||||
|
AbstractCompiler* compiler,
|
||||||
|
bool has_unsafe_access,
|
||||||
|
bool has_wide_vectors,
|
||||||
|
RTMState rtm_state);
|
||||||
|
|
||||||
// Step ahead 1 cycle, and clear the bundle state (for example,
|
void install_stub(const char* stub_name,
|
||||||
// at a branch target)
|
bool caller_must_gc_arguments);
|
||||||
void step_and_clear();
|
|
||||||
|
|
||||||
Bundle* node_bundling(const Node *n) {
|
// Constant table
|
||||||
assert(valid_bundle_info(n), "oob");
|
ConstantTable& constant_table() { return _constant_table; }
|
||||||
return (&_node_bundling_base[n->_idx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool valid_bundle_info(const Node *n) const {
|
// The architecture description provides short branch variants for some long
|
||||||
return (_node_bundling_limit > n->_idx);
|
// branch instructions. Replace eligible long branches with short branches.
|
||||||
}
|
void shorten_branches(uint* blk_starts, BufferSizingData& buf_sizes);
|
||||||
|
ObjectValue* sv_for_node_id(GrowableArray<ScopeValue*> *objs, int id);
|
||||||
|
void set_sv_for_object_node(GrowableArray<ScopeValue*> *objs, ObjectValue* sv);
|
||||||
|
void FillLocArray( int idx, MachSafePointNode* sfpt, Node *local,
|
||||||
|
GrowableArray<ScopeValue*> *array,
|
||||||
|
GrowableArray<ScopeValue*> *objs );
|
||||||
|
|
||||||
bool starts_bundle(const Node *n) const {
|
void Process_OopMap_Node(MachNode *mach, int current_offset);
|
||||||
return (_node_bundling_limit > n->_idx && _node_bundling_base[n->_idx].starts_bundle());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do the scheduling
|
// Initialize code buffer
|
||||||
void DoScheduling();
|
void estimate_buffer_size(int& const_req);
|
||||||
|
CodeBuffer* init_buffer(BufferSizingData& buf_sizes);
|
||||||
|
|
||||||
// Compute the local latencies walking forward over the list of
|
// Write out basic block data to code buffer
|
||||||
// nodes for a basic block
|
void fill_buffer(CodeBuffer* cb, uint* blk_starts);
|
||||||
void ComputeLocalLatenciesForward(const Block *bb);
|
|
||||||
|
|
||||||
// Compute the register antidependencies within a basic block
|
// Compute the information for the exception tables
|
||||||
void ComputeRegisterAntidependencies(Block *bb);
|
void FillExceptionTables(uint cnt, uint *call_returns, uint *inct_starts, Label *blk_labels);
|
||||||
void verify_do_def( Node *n, OptoReg::Name def, const char *msg );
|
|
||||||
void verify_good_schedule( Block *b, const char *msg );
|
|
||||||
void anti_do_def( Block *b, Node *def, OptoReg::Name def_reg, int is_def );
|
|
||||||
void anti_do_use( Block *b, Node *use, OptoReg::Name use_reg );
|
|
||||||
|
|
||||||
// Add a node to the current bundle
|
// Perform instruction scheduling and bundling over the sequence of
|
||||||
void AddNodeToBundle(Node *n, const Block *bb);
|
// instructions in backwards order.
|
||||||
|
void ScheduleAndBundle();
|
||||||
|
|
||||||
// Add a node to the list of available nodes
|
void install();
|
||||||
void AddNodeToAvailableList(Node *n);
|
|
||||||
|
|
||||||
// Compute the local use count for the nodes in a block, and compute
|
// Instruction bits passed off to the VM
|
||||||
// the list of instructions with no uses in the block as available
|
int code_size() { return _method_size; }
|
||||||
void ComputeUseCount(const Block *bb);
|
CodeBuffer* code_buffer() { return &_code_buffer; }
|
||||||
|
int first_block_size() { return _first_block_size; }
|
||||||
|
void set_frame_complete(int off) { if (!in_scratch_emit_size()) { _code_offsets.set_value(CodeOffsets::Frame_Complete, off); } }
|
||||||
|
ExceptionHandlerTable* handler_table() { return &_handler_table; }
|
||||||
|
ImplicitExceptionTable* inc_table() { return &_inc_table; }
|
||||||
|
OopMapSet* oop_map_set() { return _oop_map_set; }
|
||||||
|
|
||||||
// Choose an instruction from the available list to add to the bundle
|
// Scratch buffer
|
||||||
Node * ChooseNodeToBundle();
|
BufferBlob* scratch_buffer_blob() { return _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; }
|
||||||
|
|
||||||
// See if this Node fits into the currently accumulating bundle
|
// emit to scratch blob, report resulting size
|
||||||
bool NodeFitsInBundle(Node *n);
|
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; }
|
||||||
|
|
||||||
// Decrement the use count for a node
|
enum ScratchBufferBlob {
|
||||||
void DecrementUseCounts(Node *n, const Block *bb);
|
MAX_inst_size = 2048,
|
||||||
|
MAX_locs_size = 128, // number of relocInfo elements
|
||||||
|
MAX_const_size = 128,
|
||||||
|
MAX_stubs_size = 128
|
||||||
|
};
|
||||||
|
|
||||||
// Garbage collect pinch nodes for reuse by other blocks.
|
int frame_slots() const { return _frame_slots; }
|
||||||
void garbage_collect_pinch_nodes();
|
int frame_size_in_words() const; // frame_slots in units of the polymorphic 'words'
|
||||||
// Clean up a pinch node for reuse (helper for above).
|
int frame_size_in_bytes() const { return _frame_slots << LogBytesPerInt; }
|
||||||
void cleanup_pinch( Node *pinch );
|
|
||||||
|
|
||||||
// Information for statistics gathering
|
int bang_size_in_bytes() const;
|
||||||
#ifndef PRODUCT
|
|
||||||
private:
|
|
||||||
// Gather information on size of nops relative to total
|
|
||||||
uint _branches, _unconditional_delays;
|
|
||||||
|
|
||||||
static uint _total_nop_size, _total_method_size;
|
uint node_bundling_limit();
|
||||||
static uint _total_branches, _total_unconditional_delays;
|
Bundle* node_bundling_base();
|
||||||
static uint _total_instructions_per_bundle[Pipeline::_max_instrs_per_cycle+1];
|
void set_node_bundling_limit(uint n) { _node_bundling_limit = n; }
|
||||||
|
void set_node_bundling_base(Bundle* b) { _node_bundling_base = b; }
|
||||||
|
|
||||||
public:
|
Bundle* node_bundling(const Node *n);
|
||||||
static void print_statistics();
|
bool valid_bundle_info(const Node *n);
|
||||||
|
|
||||||
static void increment_instructions_per_bundle(uint i) {
|
bool starts_bundle(const Node *n) const;
|
||||||
_total_instructions_per_bundle[i]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void increment_nop_size(uint s) {
|
// Dump formatted assembly
|
||||||
_total_nop_size += s;
|
#if defined(SUPPORT_OPTO_ASSEMBLY)
|
||||||
}
|
void dump_asm_on(outputStream* ost, int* pcs, uint pc_limit);
|
||||||
|
void dump_asm(int* pcs = NULL, uint pc_limit = 0) { dump_asm_on(tty, pcs, pc_limit); }
|
||||||
static void increment_method_size(uint s) {
|
#else
|
||||||
_total_method_size += s;
|
void dump_asm_on(outputStream* ost, int* pcs, uint pc_limit) { return; }
|
||||||
}
|
void dump_asm(int* pcs = NULL, uint pc_limit = 0) { return; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Build OopMaps for each GC point
|
||||||
|
void BuildOopMaps();
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
static void print_statistics();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_OPTO_OUTPUT_HPP
|
#endif // SHARE_OPTO_OUTPUT_HPP
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
Ideal_Loop, // Find idealized trip-counted loops
|
Ideal_Loop, // Find idealized trip-counted loops
|
||||||
Macro_Expand, // Expand macro nodes
|
Macro_Expand, // Expand macro nodes
|
||||||
Peephole, // Apply peephole optimizations
|
Peephole, // Apply peephole optimizations
|
||||||
|
Output,
|
||||||
last_phase
|
last_phase
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
|
#include "opto/output.hpp"
|
||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
#include "opto/subnode.hpp"
|
#include "opto/subnode.hpp"
|
||||||
#include "runtime/atomic.hpp"
|
#include "runtime/atomic.hpp"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue