mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8213084: Rework and enhance Print[Opto]Assembly output
Reviewed-by: kvn, thartmann
This commit is contained in:
parent
6b2615be6a
commit
b730805159
@ -629,6 +629,14 @@ public:
|
||||
|
||||
enum { instruction_size = 4 };
|
||||
|
||||
//---< calculate length of instruction >---
|
||||
// We just use the values set above.
|
||||
// instruction must start at passed address
|
||||
static unsigned int instr_len(unsigned char *instr) { return instruction_size; }
|
||||
|
||||
//---< longest instructions >---
|
||||
static unsigned int instr_maxlen() { return instruction_size; }
|
||||
|
||||
Address adjust(Register base, int offset, bool preIncrement) {
|
||||
if (preIncrement)
|
||||
return Address(Pre(base, offset));
|
||||
|
||||
@ -34,4 +34,24 @@
|
||||
return "";
|
||||
}
|
||||
|
||||
// Returns address of n-th instruction preceding addr,
|
||||
// NULL if no preceding instruction can be found.
|
||||
// On ARM(aarch64), we assume a constant instruction length.
|
||||
// It might be beneficial to check "is_readable" as we do on ppc and s390.
|
||||
static address find_prev_instr(address addr, int n_instr) {
|
||||
return addr - Assembler::instruction_size*n_instr;
|
||||
}
|
||||
|
||||
// special-case instruction decoding.
|
||||
// There may be cases where the binutils disassembler doesn't do
|
||||
// the perfect job. In those cases, decode_instruction0 may kick in
|
||||
// and do it right.
|
||||
// If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
|
||||
static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
|
||||
return here;
|
||||
}
|
||||
|
||||
// platform-specific instruction annotations (like value of loaded constants)
|
||||
static void annotate(address pc, outputStream* st) { };
|
||||
|
||||
#endif // CPU_AARCH64_DISASSEMBLER_AARCH64_HPP
|
||||
|
||||
@ -199,6 +199,14 @@ class Assembler : public AbstractAssembler {
|
||||
static const int LogInstructionSize = 2;
|
||||
static const int InstructionSize = 1 << LogInstructionSize;
|
||||
|
||||
//---< calculate length of instruction >---
|
||||
// We just use the values set above.
|
||||
// instruction must start at passed address
|
||||
static unsigned int instr_len(unsigned char *instr) { return InstructionSize; }
|
||||
|
||||
//---< longest instructions >---
|
||||
static unsigned int instr_maxlen() { return InstructionSize; }
|
||||
|
||||
static inline AsmCondition inverse(AsmCondition cond) {
|
||||
assert ((cond != al) && (cond != nv), "AL and NV conditions cannot be inversed");
|
||||
return (AsmCondition)((int)cond ^ 1);
|
||||
|
||||
@ -33,4 +33,24 @@
|
||||
return "";
|
||||
}
|
||||
|
||||
// Returns address of n-th instruction preceding addr,
|
||||
// NULL if no preceding instruction can be found.
|
||||
// On ARM, we assume a constant instruction length.
|
||||
// It might be beneficial to check "is_readable" as we do on ppc and s390.
|
||||
static address find_prev_instr(address addr, int n_instr) {
|
||||
return addr - Assembler::InstructionSize*n_instr;
|
||||
}
|
||||
|
||||
// special-case instruction decoding.
|
||||
// There may be cases where the binutils disassembler doesn't do
|
||||
// the perfect job. In those cases, decode_instruction0 may kick in
|
||||
// and do it right.
|
||||
// If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
|
||||
static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
|
||||
return here;
|
||||
}
|
||||
|
||||
// platform-specific instruction annotations (like value of loaded constants)
|
||||
static void annotate(address pc, outputStream* st) { };
|
||||
|
||||
#endif // CPU_ARM_DISASSEMBLER_ARM_HPP
|
||||
|
||||
@ -929,11 +929,13 @@ class Assembler : public AbstractAssembler {
|
||||
|
||||
enum Predict { pt = 1, pn = 0 }; // pt = predict taken
|
||||
|
||||
// Instruction must start at passed address.
|
||||
static int instr_len(unsigned char *instr) { return BytesPerInstWord; }
|
||||
//---< calculate length of instruction >---
|
||||
// With PPC64 being a RISC architecture, this always is BytesPerInstWord
|
||||
// instruction must start at passed address
|
||||
static unsigned int instr_len(unsigned char *instr) { return BytesPerInstWord; }
|
||||
|
||||
// longest instructions
|
||||
static int instr_maxlen() { return BytesPerInstWord; }
|
||||
//---< longest instructions >---
|
||||
static unsigned int instr_maxlen() { return BytesPerInstWord; }
|
||||
|
||||
// Test if x is within signed immediate range for nbits.
|
||||
static bool is_simm(int x, unsigned int nbits) {
|
||||
|
||||
201
src/hotspot/cpu/ppc/disassembler_ppc.cpp
Normal file
201
src/hotspot/cpu/ppc/disassembler_ppc.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019 SAP SE. 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 "asm/macroAssembler.inline.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "depChecker_ppc.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
|
||||
#include "gc/cms/parOopClosures.inline.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/cardTableBarrierSet.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/stubCodeGenerator.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
|
||||
// Macro to print instruction bits.
|
||||
// numbering of instruction bits on ppc64 is (highest) 0 1 ... 30 31 (lowest).
|
||||
#define print_instruction_bits(st, instruction, start_bit, end_bit) \
|
||||
{ assert((start_bit) <= (end_bit), "sanity check"); \
|
||||
for (int i=(31-(start_bit));i>=(31-(end_bit));i--) { \
|
||||
(st)->print("%d", ((instruction) >> i) & 0x1); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Macro to decode "bo" instruction bits.
|
||||
#define print_decoded_bo_bits(env, instruction, end_bit) \
|
||||
{ int bo_bits = (instruction >> (31 - (end_bit))) & 0x1f; \
|
||||
if ( ((bo_bits & 0x1c) == 0x4) || ((bo_bits & 0x1c) == 0xc) ) { \
|
||||
switch (bo_bits & 0x3) { \
|
||||
case (0 << 1) | (0 << 0): env->print("[no_hint]"); break; \
|
||||
case (0 << 1) | (1 << 0): env->print("[reserved]"); break; \
|
||||
case (1 << 1) | (0 << 0): env->print("[not_taken]"); break; \
|
||||
case (1 << 1) | (1 << 0): env->print("[taken]"); break; \
|
||||
default: break; \
|
||||
} \
|
||||
} else if ( ((bo_bits & 0x14) == 0x10) ) { \
|
||||
switch (bo_bits & 0x9) { \
|
||||
case (0 << 3) | (0 << 0): env->print("[no_hint]"); break; \
|
||||
case (0 << 3) | (1 << 0): env->print("[reserved]"); break; \
|
||||
case (1 << 3) | (0 << 0): env->print("[not_taken]"); break; \
|
||||
case (1 << 3) | (1 << 0): env->print("[taken]"); break; \
|
||||
default: break; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
// Macro to decode "bh" instruction bits.
|
||||
#define print_decoded_bh_bits(env, instruction, end_bit, is_bclr) \
|
||||
{ int bh_bits = (instruction >> (31 - (end_bit))) & 0x3; \
|
||||
if (is_bclr) { \
|
||||
switch (bh_bits) { \
|
||||
case (0 << 1) | (0 << 0): env->print("[subroutine_return]"); break; \
|
||||
case (0 << 1) | (1 << 0): env->print("[not_return_but_same]"); break; \
|
||||
case (1 << 1) | (0 << 0): env->print("[reserved]"); break; \
|
||||
case (1 << 1) | (1 << 0): env->print("[not_predictable]"); break; \
|
||||
default: break; \
|
||||
} \
|
||||
} else { \
|
||||
switch (bh_bits) { \
|
||||
case (0 << 1) | (0 << 0): env->print("[not_return_but_same]"); break; \
|
||||
case (0 << 1) | (1 << 0): env->print("[reserved]"); break; \
|
||||
case (1 << 1) | (0 << 0): env->print("[reserved]"); break; \
|
||||
case (1 << 1) | (1 << 0): env->print("[not_predictable]"); break; \
|
||||
default: break; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
address Disassembler::find_prev_instr(address here, int n_instr) {
|
||||
if (!os::is_readable_pointer(here)) return NULL; // obviously a bad location to decode
|
||||
|
||||
// Find most distant possible starting point.
|
||||
// Narrow down because we don't want to SEGV while printing.
|
||||
address start = here - n_instr*Assembler::instr_maxlen(); // starting point can't be further away.
|
||||
while ((start < here) && !os::is_readable_range(start, here)) {
|
||||
start = align_down(start, os::min_page_size()) + os::min_page_size();
|
||||
}
|
||||
if (start >= here) {
|
||||
// Strange. Can only happen with here on page boundary.
|
||||
return NULL;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
address Disassembler::decode_instruction0(address here, outputStream * st, address virtual_begin ) {
|
||||
if (is_abstract()) {
|
||||
// The disassembler library was not loaded (yet),
|
||||
// use AbstractDisassembler's decode method.
|
||||
return decode_instruction_abstract(here, st, Assembler::instr_len(here), Assembler::instr_maxlen());
|
||||
}
|
||||
|
||||
// Currently, "special decoding" doesn't work when decoding error files.
|
||||
// When decoding an instruction from a hs_err file, the given
|
||||
// instruction address 'start' points to the instruction's virtual address
|
||||
// which is not equal to the address where the instruction is located.
|
||||
// Therefore, we will either crash or decode garbage.
|
||||
if (is_decode_error_file()) {
|
||||
return here;
|
||||
}
|
||||
|
||||
//---< Decode some well-known "instructions" >---
|
||||
|
||||
address next;
|
||||
uint32_t instruction = *(uint32_t*)here;
|
||||
|
||||
// Align at next tab position.
|
||||
const uint tabspacing = 8;
|
||||
const uint pos = st->position();
|
||||
const uint aligned_pos = ((pos+tabspacing-1)/tabspacing)*tabspacing;
|
||||
st->fill_to(aligned_pos);
|
||||
|
||||
if (instruction == 0x0) {
|
||||
st->print("illtrap .data 0x0");
|
||||
next = here + Assembler::instr_len(here);
|
||||
} else if (instruction == 0xbadbabe) {
|
||||
st->print(".data 0xbadbabe");
|
||||
next = here + Assembler::instr_len(here);
|
||||
} else if (Assembler::is_endgroup(instruction)) {
|
||||
st->print("endgroup");
|
||||
next = here + Assembler::instr_len(here);
|
||||
} else {
|
||||
next = here;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
// print annotations (instruction control bits)
|
||||
void Disassembler::annotate(address here, outputStream* st) {
|
||||
// Currently, annotation doesn't work when decoding error files.
|
||||
// When decoding an instruction from a hs_err file, the given
|
||||
// instruction address 'start' points to the instruction's virtual address
|
||||
// which is not equal to the address where the instruction is located.
|
||||
// Therefore, we will either crash or decode garbage.
|
||||
if (is_decode_error_file()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t instruction = *(uint32_t*)here;
|
||||
|
||||
// Align at next tab position.
|
||||
const uint tabspacing = 8;
|
||||
const uint pos = st->position();
|
||||
const uint aligned_pos = ((pos+tabspacing-1)/tabspacing)*tabspacing;
|
||||
|
||||
if (MacroAssembler::is_bcxx(instruction)) {
|
||||
st->print(",bo=0b");
|
||||
print_instruction_bits(st, instruction, 6, 10);
|
||||
print_decoded_bo_bits(st, instruction, 10);
|
||||
} else if (MacroAssembler::is_bctr(instruction) ||
|
||||
MacroAssembler::is_bctrl(instruction) ||
|
||||
MacroAssembler::is_bclr(instruction)) {
|
||||
st->fill_to(aligned_pos);
|
||||
st->print("bo=0b");
|
||||
print_instruction_bits(st, instruction, 6, 10);
|
||||
print_decoded_bo_bits(st, instruction, 10);
|
||||
st->print(",bh=0b");
|
||||
print_instruction_bits(st, instruction, 19, 20);
|
||||
print_decoded_bh_bits(st, instruction, 20,
|
||||
!(MacroAssembler::is_bctr(instruction) ||
|
||||
MacroAssembler::is_bctrl(instruction)));
|
||||
} else if (MacroAssembler::is_trap_should_not_reach_here(instruction)) {
|
||||
st->fill_to(aligned_pos + tabspacing);
|
||||
st->print(";trap: should not reach here");
|
||||
} else if (MacroAssembler::is_trap_null_check(instruction)) {
|
||||
st->fill_to(aligned_pos + tabspacing);
|
||||
st->print(";trap: null check");
|
||||
} else if (MacroAssembler::is_trap_range_check(instruction)) {
|
||||
st->fill_to(aligned_pos + tabspacing);
|
||||
st->print(";trap: range check");
|
||||
} else if (MacroAssembler::is_trap_ic_miss_check(instruction)) {
|
||||
st->fill_to(aligned_pos + tabspacing);
|
||||
st->print(";trap: ic miss check");
|
||||
} else if (MacroAssembler::is_trap_zombie_not_entrant(instruction)) {
|
||||
st->fill_to(aligned_pos + tabspacing);
|
||||
st->print(";trap: zombie");
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2012, 2019 SAP SE. 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
|
||||
@ -34,4 +34,23 @@
|
||||
return "ppc64";
|
||||
}
|
||||
|
||||
// Find preceding instruction.
|
||||
//
|
||||
// Starting at the passed location, the n-th preceding (towards lower addresses)
|
||||
// location is searched, the contents of which - if interpreted as
|
||||
// instructions - has the passed location as n-th successor.
|
||||
// - If no such location exists, NULL is returned. The caller should then
|
||||
// terminate its search and react properly.
|
||||
static address find_prev_instr(address here, int n_instr);
|
||||
|
||||
// special-case instruction decoding.
|
||||
// There may be cases where the binutils disassembler doesn't do
|
||||
// the perfect job. In those cases, decode_instruction0 may kick in
|
||||
// and do it right.
|
||||
// If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
|
||||
static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL);
|
||||
|
||||
// platform-specific instruction annotations (like value of loaded constants)
|
||||
static void annotate(address pc, outputStream* st);
|
||||
|
||||
#endif // CPU_PPC_DISASSEMBLER_PPC_HPP
|
||||
|
||||
@ -708,6 +708,8 @@ void VM_Version::determine_section_size() {
|
||||
uint32_t *code_end = (uint32_t *)a->pc();
|
||||
a->flush();
|
||||
|
||||
cb.insts()->set_end((u_char*)code_end);
|
||||
|
||||
double loop1_seconds,loop2_seconds, rel_diff;
|
||||
uint64_t start1, stop1;
|
||||
|
||||
@ -725,10 +727,11 @@ void VM_Version::determine_section_size() {
|
||||
|
||||
rel_diff = (loop2_seconds - loop1_seconds) / loop1_seconds *100;
|
||||
|
||||
if (PrintAssembly) {
|
||||
if (PrintAssembly || PrintStubCode) {
|
||||
ttyLocker ttyl;
|
||||
tty->print_cr("Decoding section size detection stub at " INTPTR_FORMAT " before execution:", p2i(code));
|
||||
Disassembler::decode((u_char*)code, (u_char*)code_end, tty);
|
||||
// Use existing decode function. This enables the [MachCode] format which is needed to DecodeErrorFile.
|
||||
Disassembler::decode(&cb, (u_char*)code, (u_char*)code_end, tty);
|
||||
tty->print_cr("Time loop1 :%f", loop1_seconds);
|
||||
tty->print_cr("Time loop2 :%f", loop2_seconds);
|
||||
tty->print_cr("(time2 - time1) / time1 = %f %%", rel_diff);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2019 SAP SE. 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
|
||||
@ -1531,16 +1531,16 @@ class Assembler : public AbstractAssembler {
|
||||
//-----------------------------------------------
|
||||
|
||||
// Calculate length of instruction.
|
||||
static int instr_len(unsigned char *instr);
|
||||
static unsigned int instr_len(unsigned char *instr);
|
||||
|
||||
// Longest instructions are 6 bytes on z/Architecture.
|
||||
static int instr_maxlen() { return 6; }
|
||||
static unsigned int instr_maxlen() { return 6; }
|
||||
|
||||
// Average instruction is 4 bytes on z/Architecture (just a guess).
|
||||
static int instr_avglen() { return 4; }
|
||||
static unsigned int instr_avglen() { return 4; }
|
||||
|
||||
// Shortest instructions are 2 bytes on z/Architecture.
|
||||
static int instr_minlen() { return 2; }
|
||||
static unsigned int instr_minlen() { return 2; }
|
||||
|
||||
// Move instruction at pc right-justified into passed long int.
|
||||
// Return instr len in bytes as function result.
|
||||
|
||||
@ -1344,7 +1344,7 @@ inline void Assembler::z_brcl(branch_condition m, Label& L) { z_brcl(m, target(L
|
||||
|
||||
// Instruction must start at passed address.
|
||||
// Extra check for illtraps with ID.
|
||||
inline int Assembler::instr_len(unsigned char *instr) {
|
||||
inline unsigned int Assembler::instr_len(unsigned char *instr) {
|
||||
switch ((*instr) >> 6) {
|
||||
case 0: return 2;
|
||||
case 1: // fallthru
|
||||
|
||||
261
src/hotspot/cpu/s390/disassembler_s390.cpp
Normal file
261
src/hotspot/cpu/s390/disassembler_s390.cpp
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019 SAP SE. 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 "asm/assembler.inline.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "depChecker_s390.hpp"
|
||||
#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
|
||||
#include "gc/cms/parOopClosures.inline.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/cardTableBarrierSet.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/stubCodeGenerator.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
|
||||
// List of all major opcodes, as of
|
||||
// Principles of Operation, Eleventh Edition, March 2015
|
||||
bool Disassembler::valid_opcodes[] =
|
||||
{ true, true, false, false, true, true, true, true, // 0x00..07
|
||||
false, false, true, true, true, true, true, true, // 0x08..0f
|
||||
true, true, true, true, true, true, true, true, // 0x10..17
|
||||
true, true, true, true, true, true, true, true, // 0x18..1f
|
||||
true, true, true, true, true, true, true, true, // 0x20..27
|
||||
true, true, true, true, true, true, true, true, // 0x28..2f
|
||||
true, true, true, true, true, true, true, true, // 0x30..37
|
||||
true, true, true, true, true, true, true, true, // 0x38..3f
|
||||
true, true, true, true, true, true, true, true, // 0x40..47
|
||||
true, true, true, true, true, true, true, true, // 0x48..4f
|
||||
true, true, false, false, true, true, true, true, // 0x50..57
|
||||
true, true, true, true, true, true, true, true, // 0x58..5f
|
||||
true, false, false, false, false, false, false, true, // 0x60..67
|
||||
true, true, true, true, true, true, true, true, // 0x68..6f
|
||||
true, true, false, false, false, false, false, false, // 0x70..77
|
||||
true, true, true, true, true, true, true, true, // 0x78..7f
|
||||
true, false, true, true, true, true, true, true, // 0x80..87
|
||||
true, true, true, true, true, true, true, true, // 0x88..8f
|
||||
true, true, true, true, true, true, true, true, // 0x90..97
|
||||
true, true, true, true, false, false, false, false, // 0x98..9f
|
||||
false, false, false, false, false, true, false, true, // 0xa0..a7
|
||||
true, true, false, false, true, true, true, true, // 0xa8..af
|
||||
false, true, true, true, false, false, true, true, // 0xb0..b7
|
||||
false, true, true, true, false, true, true, true, // 0xb8..bf
|
||||
true, false, true, false, true, false, true, false, // 0xc0..c7
|
||||
true, false, false, false, true, false, false, false, // 0xc8..cf
|
||||
true, true, true, true, true, true, true, true, // 0xd0..d7
|
||||
false, true, true, true, true, true, true, true, // 0xd8..df
|
||||
false, true, true, true, false, true, false, true, // 0xe0..e7
|
||||
true, true, true, true, true, true, true, true, // 0xe8..ef
|
||||
true, true, true, true, false, false, false, false, // 0xf0..f7
|
||||
true, true, true, true, true, true, false, false, // 0xf8..ff
|
||||
};
|
||||
// Check for valid opcodes.
|
||||
//
|
||||
// The major opcode (one byte) at the passed location is inspected.
|
||||
// If the opcode found is assigned, the function returns true, false otherwise.
|
||||
// The true indication is not reliable. It may well be that the major opcode is
|
||||
// assigned, but there exists a minor opcode field in the instruction which
|
||||
// which has unassigned values.
|
||||
bool Disassembler::is_valid_opcode_at(address here) {
|
||||
return valid_opcodes[*here];
|
||||
}
|
||||
|
||||
// This method does plain instruction decoding, no frills.
|
||||
// It may be called before the binutils disassembler kicks in
|
||||
// to handle special cases the binutils disassembler does not.
|
||||
// Instruction address, comments, and the like have to be output by caller.
|
||||
address Disassembler::decode_instruction0(address here, outputStream * st, address virtual_begin) {
|
||||
if (is_abstract()) {
|
||||
// The disassembler library was not loaded (yet),
|
||||
// use AbstractDisassembler's decode-method.
|
||||
return decode_instruction_abstract(here, st, Assembler::instr_len(here), Assembler::instr_maxlen());
|
||||
}
|
||||
|
||||
// Currently, "special decoding" doesn't work when decoding error files.
|
||||
// When decoding an instruction from a hs_err file, the given
|
||||
// instruction address 'start' points to the instruction's virtual address
|
||||
// which is not equal to the address where the instruction is located.
|
||||
// Therefore, we will either crash or decode garbage.
|
||||
if (is_decode_error_file()) {
|
||||
return here;
|
||||
}
|
||||
|
||||
//---< Decode some well-known "instructions" >---
|
||||
|
||||
address next;
|
||||
uint16_t instruction_2bytes = *(uint16_t*)here;
|
||||
|
||||
if (Assembler::is_z_nop((long)instruction_2bytes)) {
|
||||
#if 1
|
||||
st->print("nop "); // fill up to operand column, leads to better code comment alignment
|
||||
next = here + 2;
|
||||
#else
|
||||
// Compact disassembler output. Does not work the easy way.
|
||||
// Currently unusable, search does not terminate, risk of crash.
|
||||
// TODO: rework required.
|
||||
// Terminate search loop when reaching CodeEntryAlignment-aligned offset
|
||||
// or, at the latest, when reaching the next page boundary.
|
||||
int n_nops = 0;
|
||||
while(is_same_page(here, here+2*n_nops) && Assembler::is_z_nop((long)instruction_2bytes)) {
|
||||
n_nops++;
|
||||
instruction_2bytes = *(uint16_t*)(here+2*n_nops);
|
||||
}
|
||||
if (n_nops <= 4) { // do not group few subsequent nops
|
||||
st->print("nop "); // fill up to operand column, leads to better code comment alignment
|
||||
next = here + 2;
|
||||
} else {
|
||||
st->print("nop count=%d", n_nops);
|
||||
next = here + 2*n_nops;
|
||||
}
|
||||
#endif
|
||||
} else if (Assembler::is_z_sync((long)instruction_2bytes)) {
|
||||
// Specific names. Make use of lightweight sync.
|
||||
st->print("sync ");
|
||||
if (Assembler::is_z_sync_full((long)instruction_2bytes) ) st->print("heavyweight");
|
||||
if (Assembler::is_z_sync_light((long)instruction_2bytes)) st->print("lightweight");
|
||||
next = here + 2;
|
||||
} else if (instruction_2bytes == 0x0000) {
|
||||
#if 1
|
||||
st->print("illtrap .nodata");
|
||||
next = here + 2;
|
||||
#else
|
||||
// Compact disassembler output. Does not work the easy way.
|
||||
// Currently unusable, search does not terminate, risk of crash.
|
||||
// TODO: rework required.
|
||||
// Terminate search loop when reaching CodeEntryAlignment-aligned offset
|
||||
// or, at the latest, when reaching the next page boundary.
|
||||
int n_traps = 0;
|
||||
while(is_same_page(here, here+2*n_nops) && (instruction_2bytes == 0x0000)) {
|
||||
n_traps++;
|
||||
instruction_2bytes = *(uint16_t*)(here+2*n_traps);
|
||||
}
|
||||
if (n_traps <= 4) { // do not group few subsequent illtraps
|
||||
st->print("illtrap .nodata");
|
||||
next = here + 2;
|
||||
} else {
|
||||
st->print("illtrap .nodata count=%d", n_traps);
|
||||
next = here + 2*n_traps;
|
||||
}
|
||||
#endif
|
||||
} else if ((instruction_2bytes & 0xff00) == 0x0000) {
|
||||
st->print("illtrap .data 0x%2.2x", instruction_2bytes & 0x00ff);
|
||||
next = here + 2;
|
||||
} else {
|
||||
next = here;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
// Count the instructions contained in the range [begin..end).
|
||||
// The range must exactly contain the instructions, i.e.
|
||||
// - the first instruction starts @begin
|
||||
// - the last instruction ends @(end-1)
|
||||
// The caller has to make sure that the given range is readable.
|
||||
// This function performs no safety checks!
|
||||
// Return value:
|
||||
// - The number of instructions, if there was exact containment.
|
||||
// - If there is no exact containment, a negative value is returned.
|
||||
// Its absolute value is the number of instructions from begin to end,
|
||||
// where the last instruction counted runs over the range end.
|
||||
// - 0 (zero) is returned if there was a parameter error
|
||||
// (inverted range, bad starting point).
|
||||
int Disassembler::count_instr(address begin, address end) {
|
||||
if (end < begin+2) return 0; // no instructions in range
|
||||
if (!Disassembler::is_valid_opcode_at(begin)) return 0; // bad starting point
|
||||
|
||||
address p = begin;
|
||||
int n = 0;
|
||||
while(p < end) {
|
||||
p += Assembler::instr_len(p);
|
||||
n++;
|
||||
}
|
||||
return (p == end) ? n : -n;
|
||||
}
|
||||
|
||||
// Find preceding instruction.
|
||||
//
|
||||
// Starting at the passed location, the n-th preceding (towards lower addresses)
|
||||
// instruction is searched. With variable length instructions, there may be
|
||||
// more than one solution, or no solution at all (if the passed location
|
||||
// does not point to the start of an instruction or if the storage area
|
||||
// does not contain instructions at all).
|
||||
// instructions - has the passed location as n-th successor.
|
||||
// - If multiple such locations exist between (here-n*instr_maxlen()) and here,
|
||||
// the most distant location is selected.
|
||||
// - If no such location exists, NULL is returned. The caller should then
|
||||
// terminate its search and react properly.
|
||||
// Must be placed here in disassembler_s390.cpp. It does not compile
|
||||
// in the header. There the class 'Assembler' is not available.
|
||||
address Disassembler::find_prev_instr(address here, int n_instr) {
|
||||
if (!os::is_readable_pointer(here)) return NULL; // obviously a bad location to decode
|
||||
|
||||
// Find most distant possible starting point.
|
||||
// Narrow down because we don't want to SEGV while printing.
|
||||
address start = here - n_instr*Assembler::instr_maxlen(); // starting point can't be further away.
|
||||
while ((start < here) && !os::is_readable_range(start, here)) {
|
||||
start = align_down(start, os::min_page_size()) + os::min_page_size();
|
||||
}
|
||||
if (start >= here) {
|
||||
// Strange. Can only happen with here on page boundary.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//---< Find a starting point >---
|
||||
int i_count = 0;
|
||||
while ((start < here) && ((i_count = count_instr(start, here)) <= 0)) start += 2;
|
||||
if (i_count == 0) return NULL; // There is something seriously wrong
|
||||
|
||||
//---< Narrow down distance (estimate was too large) >---
|
||||
while(i_count-- > n_instr) {
|
||||
start += Assembler::instr_len(start);
|
||||
}
|
||||
assert(n_instr >= count_instr(start, here), "just checking");
|
||||
return start;
|
||||
}
|
||||
|
||||
|
||||
// Print annotations (value of loaded constant)
|
||||
void Disassembler::annotate(address here, outputStream* st) {
|
||||
// Currently, annotation doesn't work when decoding error files.
|
||||
// When decoding an instruction from a hs_err file, the given
|
||||
// instruction address 'start' points to the instruction's virtual address
|
||||
// which is not equal to the address where the instruction is located.
|
||||
// Therefore, we will either crash or decode garbage.
|
||||
if (is_decode_error_file()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MacroAssembler::is_load_const(here)) {
|
||||
long value = MacroAssembler::get_const(here);
|
||||
const int tsize = 8;
|
||||
|
||||
st->fill_to(60);
|
||||
st->print(";const %p | %ld | %23.15e", (void *)value, value, (double)value);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2019 SAP SE. 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
|
||||
@ -27,11 +27,36 @@
|
||||
#define CPU_S390_DISASSEMBLER_S390_HPP
|
||||
|
||||
static int pd_instruction_alignment() {
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static const char* pd_cpu_opts() {
|
||||
return "zarch";
|
||||
return "s390";
|
||||
}
|
||||
|
||||
static bool valid_opcodes[256];
|
||||
static bool is_valid_opcode_at(address here);
|
||||
|
||||
// Find preceding instruction.
|
||||
//
|
||||
// Starting at the passed location, the n-th preceding (towards lower addresses)
|
||||
// location is searched, the contents of which - if interpreted as
|
||||
// instructions - has the passed location as n-th successor.
|
||||
// - If multiple such locations exist between (here-n*instr_maxlen()) and here,
|
||||
// the most distant location is selected.
|
||||
// - If no such location exists, NULL is returned. The caller should then
|
||||
// terminate its search and react properly.
|
||||
static address find_prev_instr(address here, int n_instr);
|
||||
static int count_instr(address begin, address end);
|
||||
|
||||
// special-case instruction decoding.
|
||||
// There may be cases where the binutils disassembler doesn't do
|
||||
// the perfect job. In those cases, decode_instruction0 may kick in
|
||||
// and do it right.
|
||||
// If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
|
||||
static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL);
|
||||
|
||||
// platform-specific instruction annotations (like value of loaded constants)
|
||||
static void annotate(address pc, outputStream* st);
|
||||
|
||||
#endif // CPU_S390_DISASSEMBLER_S390_HPP
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2017, SAP SE. All rights reserved.
|
||||
// Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2017, 2019 SAP SE. 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
|
||||
@ -1388,7 +1388,6 @@ void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||
__ z_br(R1_ic_miss_stub_addr);
|
||||
__ bind(valid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint MachUEPNode::size(PhaseRegAlloc *ra_) const {
|
||||
@ -4318,7 +4317,7 @@ instruct loadConI(iRegI dst, immI src) %{
|
||||
match(Set dst src);
|
||||
ins_cost(DEFAULT_COST);
|
||||
size(6);
|
||||
format %{ "LGFI $dst,$src\t # (int)" %}
|
||||
format %{ "LGFI $dst,$src\t # (int)" %}
|
||||
ins_encode %{ __ z_lgfi($dst$$Register, $src$$constant); %} // Sign-extend to 64 bit, it's at no cost.
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -4327,7 +4326,7 @@ instruct loadConI16(iRegI dst, immI16 src) %{
|
||||
match(Set dst src);
|
||||
ins_cost(DEFAULT_COST_LOW);
|
||||
size(4);
|
||||
format %{ "LGHI $dst,$src\t # (int)" %}
|
||||
format %{ "LGHI $dst,$src\t # (int)" %}
|
||||
ins_encode %{ __ z_lghi($dst$$Register, $src$$constant); %} // Sign-extend to 64 bit, it's at no cost.
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -4723,7 +4722,7 @@ instruct loadN(iRegN dst, memory mem) %{
|
||||
match(Set dst (LoadN mem));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(Z_DISP3_SIZE);
|
||||
format %{ "LoadN $dst,$mem\t# (cOop)" %}
|
||||
format %{ "LoadN $dst,$mem\t # (cOop)" %}
|
||||
opcode(LLGF_ZOPC, LLGF_ZOPC);
|
||||
ins_encode(z_form_rt_mem_opt(dst, mem));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -4734,7 +4733,7 @@ instruct loadNKlass(iRegN dst, memory mem) %{
|
||||
match(Set dst (LoadNKlass mem));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(Z_DISP3_SIZE);
|
||||
format %{ "LoadNKlass $dst,$mem\t# (klass cOop)" %}
|
||||
format %{ "LoadNKlass $dst,$mem\t # (klass cOop)" %}
|
||||
opcode(LLGF_ZOPC, LLGF_ZOPC);
|
||||
ins_encode(z_form_rt_mem_opt(dst, mem));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -4787,7 +4786,7 @@ instruct decodeLoadN(iRegP dst, memory mem) %{
|
||||
predicate(false && (CompressedOops::base()==NULL)&&(CompressedOops::shift()==0));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(Z_DISP3_SIZE);
|
||||
format %{ "DecodeLoadN $dst,$mem\t# (cOop Load+Decode)" %}
|
||||
format %{ "DecodeLoadN $dst,$mem\t # (cOop Load+Decode)" %}
|
||||
opcode(LLGF_ZOPC, LLGF_ZOPC);
|
||||
ins_encode(z_form_rt_mem_opt(dst, mem));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -4798,7 +4797,7 @@ instruct decodeLoadNKlass(iRegP dst, memory mem) %{
|
||||
predicate(false && (CompressedKlassPointers::base()==NULL)&&(CompressedKlassPointers::shift()==0));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(Z_DISP3_SIZE);
|
||||
format %{ "DecodeLoadNKlass $dst,$mem\t# (load/decode NKlass)" %}
|
||||
format %{ "DecodeLoadNKlass $dst,$mem\t # (load/decode NKlass)" %}
|
||||
opcode(LLGF_ZOPC, LLGF_ZOPC);
|
||||
ins_encode(z_form_rt_mem_opt(dst, mem));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -4826,7 +4825,7 @@ instruct decodeN(iRegP dst, iRegN src, flagsReg cr) %{
|
||||
predicate(CompressedOops::base() == NULL || !ExpandLoadingBaseDecode);
|
||||
ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST + BRANCH_COST);
|
||||
// TODO: s390 port size(VARIABLE_SIZE);
|
||||
format %{ "decodeN $dst,$src\t# (decode cOop)" %}
|
||||
format %{ "decodeN $dst,$src\t # (decode cOop)" %}
|
||||
ins_encode %{ __ oop_decoder($dst$$Register, $src$$Register, true); %}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -4850,7 +4849,7 @@ instruct decodeN_NN(iRegP dst, iRegN src, flagsReg cr) %{
|
||||
(CompressedOops::base()== NULL || !ExpandLoadingBaseDecode_NN));
|
||||
ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST);
|
||||
// TODO: s390 port size(VARIABLE_SIZE);
|
||||
format %{ "decodeN $dst,$src\t# (decode cOop NN)" %}
|
||||
format %{ "decodeN $dst,$src\t # (decode cOop NN)" %}
|
||||
ins_encode %{ __ oop_decoder($dst$$Register, $src$$Register, false); %}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -4873,7 +4872,7 @@ instruct decodeN_NN(iRegP dst, iRegN src, flagsReg cr) %{
|
||||
effect(KILL cr);
|
||||
predicate(false);
|
||||
// TODO: s390 port size(VARIABLE_SIZE);
|
||||
format %{ "decodeN $dst = ($src == 0) ? NULL : ($src << 3) + $base + pow2_offset\t# (decode cOop)" %}
|
||||
format %{ "decodeN $dst = ($src == 0) ? NULL : ($src << 3) + $base + pow2_offset\t # (decode cOop)" %}
|
||||
ins_encode %{
|
||||
__ oop_decoder($dst$$Register, $src$$Register, true, $base$$Register,
|
||||
(jlong)MacroAssembler::get_oop_base_pow2_offset((uint64_t)(intptr_t)CompressedOops::base()));
|
||||
@ -4887,7 +4886,7 @@ instruct decodeN_NN(iRegP dst, iRegN src, flagsReg cr) %{
|
||||
effect(KILL cr);
|
||||
predicate(false);
|
||||
// TODO: s390 port size(VARIABLE_SIZE);
|
||||
format %{ "decodeN $dst = ($src << 3) + $base + pow2_offset\t# (decode cOop)" %}
|
||||
format %{ "decodeN $dst = ($src << 3) + $base + pow2_offset\t # (decode cOop)" %}
|
||||
ins_encode %{
|
||||
__ oop_decoder($dst$$Register, $src$$Register, false, $base$$Register,
|
||||
(jlong)MacroAssembler::get_oop_base_pow2_offset((uint64_t)(intptr_t)CompressedOops::base()));
|
||||
@ -4937,7 +4936,7 @@ instruct encodeP(iRegN dst, iRegP src, flagsReg cr) %{
|
||||
!ExpandLoadingBaseEncode));
|
||||
ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST);
|
||||
// TODO: s390 port size(VARIABLE_SIZE);
|
||||
format %{ "encodeP $dst,$src\t# (encode cOop)" %}
|
||||
format %{ "encodeP $dst,$src\t # (encode cOop)" %}
|
||||
ins_encode %{ __ oop_encoder($dst$$Register, $src$$Register, true, Z_R1_scratch, -1, all_outs_are_Stores(this)); %}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -4960,7 +4959,7 @@ instruct encodeP_NN(iRegN dst, iRegP src, flagsReg cr) %{
|
||||
!ExpandLoadingBaseEncode_NN));
|
||||
ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST);
|
||||
// TODO: s390 port size(VARIABLE_SIZE);
|
||||
format %{ "encodeP $dst,$src\t# (encode cOop)" %}
|
||||
format %{ "encodeP $dst,$src\t # (encode cOop)" %}
|
||||
ins_encode %{ __ oop_encoder($dst$$Register, $src$$Register, false, Z_R1_scratch, -1, all_outs_are_Stores(this)); %}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -4972,7 +4971,7 @@ instruct encodeP_NN(iRegN dst, iRegP src, flagsReg cr) %{
|
||||
predicate(false);
|
||||
ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST);
|
||||
// TODO: s390 port size(VARIABLE_SIZE);
|
||||
format %{ "encodeP $dst = ($src>>3) +$base + pow2_offset\t# (encode cOop)" %}
|
||||
format %{ "encodeP $dst = ($src>>3) +$base + pow2_offset\t # (encode cOop)" %}
|
||||
ins_encode %{
|
||||
jlong offset = -(jlong)MacroAssembler::get_oop_base_pow2_offset
|
||||
(((uint64_t)(intptr_t)CompressedOops::base()) >> CompressedOops::shift());
|
||||
@ -4988,7 +4987,7 @@ instruct encodeP_NN(iRegN dst, iRegP src, flagsReg cr) %{
|
||||
predicate(false);
|
||||
ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST);
|
||||
// TODO: s390 port size(VARIABLE_SIZE);
|
||||
format %{ "encodeP $dst = ($src>>3) +$base + $pow2_offset\t# (encode cOop)" %}
|
||||
format %{ "encodeP $dst = ($src>>3) +$base + $pow2_offset\t # (encode cOop)" %}
|
||||
ins_encode %{ __ oop_encoder($dst$$Register, $src$$Register, false, $base$$Register, $pow2_offset$$constant); %}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -5041,7 +5040,7 @@ instruct storeN(memory mem, iRegN_P2N src) %{
|
||||
match(Set mem (StoreN mem src));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(Z_DISP_SIZE);
|
||||
format %{ "ST $src,$mem\t# (cOop)" %}
|
||||
format %{ "ST $src,$mem\t # (cOop)" %}
|
||||
opcode(STY_ZOPC, ST_ZOPC);
|
||||
ins_encode(z_form_rt_mem_opt(src, mem));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -5052,7 +5051,7 @@ instruct storeNKlass(memory mem, iRegN src) %{
|
||||
match(Set mem (StoreNKlass mem src));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(Z_DISP_SIZE);
|
||||
format %{ "ST $src,$mem\t# (cKlass)" %}
|
||||
format %{ "ST $src,$mem\t # (cKlass)" %}
|
||||
opcode(STY_ZOPC, ST_ZOPC);
|
||||
ins_encode(z_form_rt_mem_opt(src, mem));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -5064,7 +5063,7 @@ instruct compN_iRegN(iRegN_P2N src1, iRegN_P2N src2, flagsReg cr) %{
|
||||
match(Set cr (CmpN src1 src2));
|
||||
ins_cost(DEFAULT_COST);
|
||||
size(2);
|
||||
format %{ "CLR $src1,$src2\t# (cOop)" %}
|
||||
format %{ "CLR $src1,$src2\t # (cOop)" %}
|
||||
opcode(CLR_ZOPC);
|
||||
ins_encode(z_rrform(src1, src2));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -5074,7 +5073,7 @@ instruct compN_iRegN_immN(iRegN_P2N src1, immN src2, flagsReg cr) %{
|
||||
match(Set cr (CmpN src1 src2));
|
||||
ins_cost(DEFAULT_COST);
|
||||
size(6);
|
||||
format %{ "CLFI $src1,$src2\t# (cOop) compare immediate narrow" %}
|
||||
format %{ "CLFI $src1,$src2\t # (cOop) compare immediate narrow" %}
|
||||
ins_encode %{
|
||||
AddressLiteral cOop = __ constant_oop_address((jobject)$src2$$constant);
|
||||
__ relocate(cOop.rspec(), 1);
|
||||
@ -5087,7 +5086,7 @@ instruct compNKlass_iRegN_immN(iRegN src1, immNKlass src2, flagsReg cr) %{
|
||||
match(Set cr (CmpN src1 src2));
|
||||
ins_cost(DEFAULT_COST);
|
||||
size(6);
|
||||
format %{ "CLFI $src1,$src2\t# (NKlass) compare immediate narrow" %}
|
||||
format %{ "CLFI $src1,$src2\t # (NKlass) compare immediate narrow" %}
|
||||
ins_encode %{
|
||||
AddressLiteral NKlass = __ constant_metadata_address((Metadata*)$src2$$constant);
|
||||
__ relocate(NKlass.rspec(), 1);
|
||||
@ -5100,7 +5099,7 @@ instruct compN_iRegN_immN0(iRegN_P2N src1, immN0 src2, flagsReg cr) %{
|
||||
match(Set cr (CmpN src1 src2));
|
||||
ins_cost(DEFAULT_COST);
|
||||
size(2);
|
||||
format %{ "LTR $src1,$src2\t# (cOop) LTR because comparing against zero" %}
|
||||
format %{ "LTR $src1,$src2\t # (cOop) LTR because comparing against zero" %}
|
||||
opcode(LTR_ZOPC);
|
||||
ins_encode(z_rrform(src1, src1));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -6795,7 +6794,7 @@ instruct sllI_reg_reg(iRegI dst, iRegI src, iRegI nbits, flagsReg cr) %{
|
||||
effect(KILL cr); // R1 is killed, too.
|
||||
ins_cost(3 * DEFAULT_COST);
|
||||
size(14);
|
||||
format %{ "SLL $dst,$src,[$nbits] & 31\t# use RISC-like SLLG also for int" %}
|
||||
format %{ "SLL $dst,$src,[$nbits] & 31\t # use RISC-like SLLG also for int" %}
|
||||
ins_encode %{
|
||||
__ z_lgr(Z_R1_scratch, $nbits$$Register);
|
||||
__ z_nill(Z_R1_scratch, BitsPerJavaInteger-1);
|
||||
@ -6809,7 +6808,7 @@ instruct sllI_reg_reg(iRegI dst, iRegI src, iRegI nbits, flagsReg cr) %{
|
||||
instruct sllI_reg_imm(iRegI dst, iRegI src, immI nbits) %{
|
||||
match(Set dst (LShiftI src nbits));
|
||||
size(6);
|
||||
format %{ "SLL $dst,$src,$nbits\t# use RISC-like SLLG also for int" %}
|
||||
format %{ "SLL $dst,$src,$nbits\t # use RISC-like SLLG also for int" %}
|
||||
ins_encode %{
|
||||
int Nbit = $nbits$$constant;
|
||||
assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
|
||||
@ -7125,7 +7124,7 @@ instruct overflowSubL_reg_imm(flagsReg cr, iRegL op1, immL op2) %{
|
||||
instruct overflowNegI_rReg(flagsReg cr, immI_0 zero, iRegI op2) %{
|
||||
match(Set cr (OverflowSubI zero op2));
|
||||
effect(DEF cr, USE op2);
|
||||
format %{ "NEG $op2\t# overflow check int" %}
|
||||
format %{ "NEG $op2\t # overflow check int" %}
|
||||
ins_encode %{
|
||||
__ clear_reg(Z_R0_scratch, false, false);
|
||||
__ z_sr(Z_R0_scratch, $op2$$Register);
|
||||
@ -7136,7 +7135,7 @@ instruct overflowNegI_rReg(flagsReg cr, immI_0 zero, iRegI op2) %{
|
||||
instruct overflowNegL_rReg(flagsReg cr, immL_0 zero, iRegL op2) %{
|
||||
match(Set cr (OverflowSubL zero op2));
|
||||
effect(DEF cr, USE op2);
|
||||
format %{ "NEGG $op2\t# overflow check long" %}
|
||||
format %{ "NEGG $op2\t # overflow check long" %}
|
||||
ins_encode %{
|
||||
__ clear_reg(Z_R0_scratch, true, false);
|
||||
__ z_sgr(Z_R0_scratch, $op2$$Register);
|
||||
@ -9191,7 +9190,7 @@ instruct branchCon(cmpOp cmp, flagsReg cr, label lbl) %{
|
||||
effect(USE lbl);
|
||||
ins_cost(BRANCH_COST);
|
||||
size(4);
|
||||
format %{ "branch_con_short,$cmp $cr, $lbl" %}
|
||||
format %{ "branch_con_short,$cmp $lbl" %}
|
||||
ins_encode(z_enc_branch_con_short(cmp, lbl));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
// If set to 1 this indicates that the current instruction is a
|
||||
@ -9213,7 +9212,7 @@ instruct branchConFar(cmpOp cmp, flagsReg cr, label lbl) %{
|
||||
// Make more expensive to prefer compare_and_branch over separate instructions.
|
||||
ins_cost(2 * BRANCH_COST);
|
||||
size(6);
|
||||
format %{ "branch_con_far,$cmp $cr, $lbl" %}
|
||||
format %{ "branch_con_far,$cmp $lbl" %}
|
||||
ins_encode(z_enc_branch_con_far(cmp, lbl));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
// This is not a short variant of a branch, but the long variant..
|
||||
@ -9782,7 +9781,7 @@ instruct TailCalljmpInd(iRegP jump_target, inline_cache_regP method_oop) %{
|
||||
match(TailCall jump_target method_oop);
|
||||
ins_cost(CALL_COST);
|
||||
size(2);
|
||||
format %{ "Jmp $jump_target\t# $method_oop holds method oop" %}
|
||||
format %{ "Jmp $jump_target\t # $method_oop holds method oop" %}
|
||||
ins_encode %{ __ z_br($jump_target$$Register); %}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -10790,7 +10789,7 @@ instruct bytes_reverse_int(iRegI dst, iRegI src) %{
|
||||
predicate(UseByteReverseInstruction); // See Matcher::match_rule_supported
|
||||
ins_cost(DEFAULT_COST);
|
||||
size(4);
|
||||
format %{ "LRVR $dst,$src\t# byte reverse int" %}
|
||||
format %{ "LRVR $dst,$src\t # byte reverse int" %}
|
||||
opcode(LRVR_ZOPC);
|
||||
ins_encode(z_rreform(dst, src));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -10801,7 +10800,7 @@ instruct bytes_reverse_long(iRegL dst, iRegL src) %{
|
||||
predicate(UseByteReverseInstruction); // See Matcher::match_rule_supported
|
||||
ins_cost(DEFAULT_COST);
|
||||
// TODO: s390 port size(FIXED_SIZE);
|
||||
format %{ "LRVGR $dst,$src\t# byte reverse long" %}
|
||||
format %{ "LRVGR $dst,$src\t # byte reverse long" %}
|
||||
opcode(LRVGR_ZOPC);
|
||||
ins_encode(z_rreform(dst, src));
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -10821,8 +10820,8 @@ instruct countLeadingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr)
|
||||
effect(KILL tmp, KILL cr);
|
||||
ins_cost(3 * DEFAULT_COST);
|
||||
size(14);
|
||||
format %{ "SLLG $dst,$src,32\t# no need to always count 32 zeroes first\n\t"
|
||||
"IILH $dst,0x8000 \t# insert \"stop bit\" to force result 32 for zero src.\n\t"
|
||||
format %{ "SLLG $dst,$src,32\t # no need to always count 32 zeroes first\n\t"
|
||||
"IILH $dst,0x8000 \t # insert \"stop bit\" to force result 32 for zero src.\n\t"
|
||||
"FLOGR $dst,$dst"
|
||||
%}
|
||||
ins_encode %{
|
||||
@ -10859,7 +10858,7 @@ instruct countLeadingZerosL(revenRegI dst, iRegL src, roddRegI tmp, flagsReg cr)
|
||||
effect(KILL tmp, KILL cr);
|
||||
ins_cost(DEFAULT_COST);
|
||||
size(4);
|
||||
format %{ "FLOGR $dst,$src \t# count leading zeros (long)\n\t" %}
|
||||
format %{ "FLOGR $dst,$src \t # count leading zeros (long)\n\t" %}
|
||||
ins_encode %{ __ z_flogr($dst$$Register, $src$$Register); %}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
@ -10884,14 +10883,14 @@ instruct countTrailingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
ins_cost(8 * DEFAULT_COST);
|
||||
// TODO: s390 port size(FIXED_SIZE); // Emitted code depends on PreferLAoverADD being on/off.
|
||||
format %{ "LLGFR $dst,$src \t# clear upper 32 bits (we are dealing with int)\n\t"
|
||||
"LCGFR $tmp,$src \t# load 2's complement (32->64 bit)\n\t"
|
||||
"AGHI $dst,-1 \t# tmp1 = src-1\n\t"
|
||||
"AGHI $tmp,-1 \t# tmp2 = -src-1 = ~src\n\t"
|
||||
"NGR $dst,$tmp \t# tmp3 = tmp1&tmp2\n\t"
|
||||
"FLOGR $dst,$dst \t# count trailing zeros (int)\n\t"
|
||||
"AHI $dst,-64 \t# tmp4 = 64-(trailing zeroes)-64\n\t"
|
||||
"LCR $dst,$dst \t# res = -tmp4"
|
||||
format %{ "LLGFR $dst,$src \t # clear upper 32 bits (we are dealing with int)\n\t"
|
||||
"LCGFR $tmp,$src \t # load 2's complement (32->64 bit)\n\t"
|
||||
"AGHI $dst,-1 \t # tmp1 = src-1\n\t"
|
||||
"AGHI $tmp,-1 \t # tmp2 = -src-1 = ~src\n\t"
|
||||
"NGR $dst,$tmp \t # tmp3 = tmp1&tmp2\n\t"
|
||||
"FLOGR $dst,$dst \t # count trailing zeros (int)\n\t"
|
||||
"AHI $dst,-64 \t # tmp4 = 64-(trailing zeroes)-64\n\t"
|
||||
"LCR $dst,$dst \t # res = -tmp4"
|
||||
%}
|
||||
ins_encode %{
|
||||
Register Rdst = $dst$$Register;
|
||||
@ -10937,12 +10936,12 @@ instruct countTrailingZerosL(revenRegI dst, iRegL src, roddRegL tmp, flagsReg cr
|
||||
effect(TEMP_DEF dst, KILL tmp, KILL cr);
|
||||
ins_cost(8 * DEFAULT_COST);
|
||||
// TODO: s390 port size(FIXED_SIZE); // Emitted code depends on PreferLAoverADD being on/off.
|
||||
format %{ "LCGR $dst,$src \t# preserve src\n\t"
|
||||
"NGR $dst,$src \t#"
|
||||
"AGHI $dst,-1 \t# tmp1 = src-1\n\t"
|
||||
"FLOGR $dst,$dst \t# count trailing zeros (long), kill $tmp\n\t"
|
||||
"AHI $dst,-64 \t# tmp4 = 64-(trailing zeroes)-64\n\t"
|
||||
"LCR $dst,$dst \t#"
|
||||
format %{ "LCGR $dst,$src \t # preserve src\n\t"
|
||||
"NGR $dst,$src \t #\n\t"
|
||||
"AGHI $dst,-1 \t # tmp1 = src-1\n\t"
|
||||
"FLOGR $dst,$dst \t # count trailing zeros (long), kill $tmp\n\t"
|
||||
"AHI $dst,-64 \t # tmp4 = 64-(trailing zeroes)-64\n\t"
|
||||
"LCR $dst,$dst \t #"
|
||||
%}
|
||||
ins_encode %{
|
||||
Register Rdst = $dst$$Register;
|
||||
@ -10969,7 +10968,7 @@ instruct popCountI(iRegI dst, iRegI src, iRegI tmp, flagsReg cr) %{
|
||||
predicate(UsePopCountInstruction && VM_Version::has_PopCount());
|
||||
ins_cost(DEFAULT_COST);
|
||||
size(24);
|
||||
format %{ "POPCNT $dst,$src\t# pop count int" %}
|
||||
format %{ "POPCNT $dst,$src\t # pop count int" %}
|
||||
ins_encode %{
|
||||
Register Rdst = $dst$$Register;
|
||||
Register Rsrc = $src$$Register;
|
||||
@ -10996,7 +10995,7 @@ instruct popCountL(iRegI dst, iRegL src, iRegL tmp, flagsReg cr) %{
|
||||
predicate(UsePopCountInstruction && VM_Version::has_PopCount());
|
||||
ins_cost(DEFAULT_COST);
|
||||
// TODO: s390 port size(FIXED_SIZE);
|
||||
format %{ "POPCNT $dst,$src\t# pop count long" %}
|
||||
format %{ "POPCNT $dst,$src\t # pop count long" %}
|
||||
ins_encode %{
|
||||
Register Rdst = $dst$$Register;
|
||||
Register Rsrc = $src$$Register;
|
||||
|
||||
@ -804,6 +804,8 @@ void VM_Version::determine_features() {
|
||||
address code_end = a->pc();
|
||||
a->flush();
|
||||
|
||||
cbuf.insts()->set_end(code_end);
|
||||
|
||||
// Print the detection code.
|
||||
bool printVerbose = Verbose || PrintAssembly || PrintStubCode;
|
||||
if (printVerbose) {
|
||||
@ -812,8 +814,8 @@ void VM_Version::determine_features() {
|
||||
tty->print_cr("Stub length is %ld bytes, codebuffer reserves %d bytes, %ld bytes spare.",
|
||||
code_end-code, cbuf_size, cbuf_size-(code_end-code));
|
||||
|
||||
// Use existing decode function. This enables the [Code] format which is needed to DecodeErrorFile.
|
||||
Disassembler::decode((u_char*)code, (u_char*)code_end, tty);
|
||||
// Use existing decode function. This enables the [MachCode] format which is needed to DecodeErrorFile.
|
||||
Disassembler::decode(&cbuf, code, code_end, tty);
|
||||
}
|
||||
|
||||
// Prepare for detection code execution and clear work buffer.
|
||||
|
||||
@ -335,6 +335,14 @@ class Assembler : public AbstractAssembler {
|
||||
Lookaside = 1 << 4
|
||||
};
|
||||
|
||||
//---< calculate length of instruction >---
|
||||
// With SPARC being a RISC architecture, this always is BytesPerInstWord
|
||||
// instruction must start at passed address
|
||||
static unsigned int instr_len(unsigned char *instr) { return BytesPerInstWord; }
|
||||
|
||||
//---< longest instructions >---
|
||||
static unsigned int instr_maxlen() { return BytesPerInstWord; }
|
||||
|
||||
static bool is_in_wdisp_range(address a, address b, int nbits) {
|
||||
intptr_t d = intptr_t(b) - intptr_t(a);
|
||||
return is_simm(d, nbits + 2);
|
||||
|
||||
@ -33,4 +33,24 @@
|
||||
return "v9only";
|
||||
}
|
||||
|
||||
// Returns address of n-th instruction preceding addr,
|
||||
// NULL if no preceding instruction can be found.
|
||||
// With SPARC being a RISC architecture, this always is BytesPerInstWord
|
||||
// It might be beneficial to check "is_readable" as we do on ppc and s390.
|
||||
static address find_prev_instr(address addr, int n_instr) {
|
||||
return addr - BytesPerInstWord*n_instr;
|
||||
}
|
||||
|
||||
// special-case instruction decoding.
|
||||
// There may be cases where the binutils disassembler doesn't do
|
||||
// the perfect job. In those cases, decode_instruction0 may kick in
|
||||
// and do it right.
|
||||
// If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
|
||||
static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
|
||||
return here;
|
||||
}
|
||||
|
||||
// platform-specific instruction annotations (like value of loaded constants)
|
||||
static void annotate(address pc, outputStream* st) { };
|
||||
|
||||
#endif // CPU_SPARC_DISASSEMBLER_SPARC_HPP
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 1998, 2019, 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
|
||||
@ -1295,7 +1295,8 @@ static enum RC rc_class( OptoReg::Name reg ) {
|
||||
#ifndef PRODUCT
|
||||
ATTRIBUTE_PRINTF(2, 3)
|
||||
static void print_helper(outputStream* st, const char* format, ...) {
|
||||
if (st->position() > 0) {
|
||||
const int tab_size = 8;
|
||||
if (st->position() > tab_size) {
|
||||
st->cr();
|
||||
st->sp();
|
||||
}
|
||||
|
||||
@ -630,6 +630,17 @@ class Assembler : public AbstractAssembler {
|
||||
_true = 7
|
||||
};
|
||||
|
||||
//---< calculate length of instruction >---
|
||||
// As instruction size can't be found out easily on x86/x64,
|
||||
// we just use '4' for len and maxlen.
|
||||
// instruction must start at passed address
|
||||
static unsigned int instr_len(unsigned char *instr) { return 4; }
|
||||
|
||||
//---< longest instructions >---
|
||||
// Max instruction length is not specified in architecture documentation.
|
||||
// We could use a "safe enough" estimate (15), but just default to
|
||||
// instruction length guess from above.
|
||||
static unsigned int instr_maxlen() { return 4; }
|
||||
|
||||
// NOTE: The general philopsophy of the declarations here is that 64bit versions
|
||||
// of instructions are freely declared without the need for wrapping them an ifdef.
|
||||
|
||||
@ -33,4 +33,25 @@
|
||||
return "";
|
||||
}
|
||||
|
||||
// Returns address of n-th instruction preceding addr,
|
||||
// NULL if no preceding instruction can be found.
|
||||
// On CISC architectures, it is difficult to impossible to step
|
||||
// backwards in the instruction stream. Therefore just return NULL.
|
||||
// It might be beneficial to check "is_readable" as we do on ppc and s390.
|
||||
static address find_prev_instr(address addr, int n_instr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// special-case instruction decoding.
|
||||
// There may be cases where the binutils disassembler doesn't do
|
||||
// the perfect job. In those cases, decode_instruction0 may kick in
|
||||
// and do it right.
|
||||
// If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
|
||||
static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
|
||||
return here;
|
||||
}
|
||||
|
||||
// platform-specific instruction annotations (like value of loaded constants)
|
||||
static void annotate(address pc, outputStream* st) { };
|
||||
|
||||
#endif // CPU_X86_DISASSEMBLER_X86_HPP
|
||||
|
||||
@ -918,19 +918,19 @@ void MachEpilogNode::format(PhaseRegAlloc* ra_, outputStream* st) const
|
||||
st->print("\t");
|
||||
}
|
||||
|
||||
st->print_cr("popq rbp");
|
||||
st->print_cr("popq rbp");
|
||||
if (do_polling() && C->is_method_compilation()) {
|
||||
st->print("\t");
|
||||
if (SafepointMechanism::uses_thread_local_poll()) {
|
||||
st->print_cr("movq rscratch1, poll_offset[r15_thread] #polling_page_address\n\t"
|
||||
"testl rax, [rscratch1]\t"
|
||||
st->print_cr("movq rscratch1, poll_offset[r15_thread] #polling_page_address\n\t"
|
||||
"testl rax, [rscratch1]\t"
|
||||
"# Safepoint: poll for GC");
|
||||
} else if (Assembler::is_polling_page_far()) {
|
||||
st->print_cr("movq rscratch1, #polling_page_address\n\t"
|
||||
"testl rax, [rscratch1]\t"
|
||||
st->print_cr("movq rscratch1, #polling_page_address\n\t"
|
||||
"testl rax, [rscratch1]\t"
|
||||
"# Safepoint: poll for GC");
|
||||
} else {
|
||||
st->print_cr("testl rax, [rip + #offset_to_poll_page]\t"
|
||||
st->print_cr("testl rax, [rip + #offset_to_poll_page]\t"
|
||||
"# Safepoint: poll for GC");
|
||||
}
|
||||
}
|
||||
@ -10303,10 +10303,10 @@ instruct cadd_cmpLTMask(rRegI p, rRegI q, rRegI y, rFlagsReg cr)
|
||||
match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q)));
|
||||
effect(KILL cr);
|
||||
ins_cost(300);
|
||||
format %{ "subl $p,$q\t# cadd_cmpLTMask\n\t"
|
||||
"jge done\n\t"
|
||||
"addl $p,$y\n"
|
||||
"done: " %}
|
||||
format %{ "subl $p,$q\t# cadd_cmpLTMask\n\t"
|
||||
"jge done\n\t"
|
||||
"addl $p,$y\n"
|
||||
"done: " %}
|
||||
ins_encode %{
|
||||
Register Rp = $p$$Register;
|
||||
Register Rq = $q$$Register;
|
||||
@ -10328,10 +10328,10 @@ instruct and_cmpLTMask(rRegI p, rRegI q, rRegI y, rFlagsReg cr)
|
||||
|
||||
ins_cost(300);
|
||||
|
||||
format %{ "cmpl $p, $q\t# and_cmpLTMask\n\t"
|
||||
"jlt done\n\t"
|
||||
"xorl $y, $y\n"
|
||||
"done: " %}
|
||||
format %{ "cmpl $p, $q\t# and_cmpLTMask\n\t"
|
||||
"jlt done\n\t"
|
||||
"xorl $y, $y\n"
|
||||
"done: " %}
|
||||
ins_encode %{
|
||||
Register Rp = $p$$Register;
|
||||
Register Rq = $q$$Register;
|
||||
@ -11888,7 +11888,7 @@ instruct testU_reg(rFlagsRegU cr, rRegI src, immI0 zero)
|
||||
%{
|
||||
match(Set cr (CmpU src zero));
|
||||
|
||||
format %{ "testl $src, $src\t# unsigned" %}
|
||||
format %{ "testl $src, $src\t# unsigned" %}
|
||||
opcode(0x85);
|
||||
ins_encode(REX_reg_reg(src, src), OpcP, reg_reg(src, src));
|
||||
ins_pipe(ialu_cr_reg_imm);
|
||||
@ -12431,7 +12431,7 @@ instruct jmpConU(cmpOpU cop, rFlagsRegU cmp, label labl) %{
|
||||
effect(USE labl);
|
||||
|
||||
ins_cost(300);
|
||||
format %{ "j$cop,u $labl" %}
|
||||
format %{ "j$cop,u $labl" %}
|
||||
size(6);
|
||||
ins_encode %{
|
||||
Label* L = $labl$$label;
|
||||
@ -12445,7 +12445,7 @@ instruct jmpConUCF(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{
|
||||
effect(USE labl);
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "j$cop,u $labl" %}
|
||||
format %{ "j$cop,u $labl" %}
|
||||
size(6);
|
||||
ins_encode %{
|
||||
Label* L = $labl$$label;
|
||||
@ -12461,10 +12461,10 @@ instruct jmpConUCF2(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{
|
||||
ins_cost(200);
|
||||
format %{ $$template
|
||||
if ($cop$$cmpcode == Assembler::notEqual) {
|
||||
$$emit$$"jp,u $labl\n\t"
|
||||
$$emit$$"jp,u $labl\n\t"
|
||||
$$emit$$"j$cop,u $labl"
|
||||
} else {
|
||||
$$emit$$"jp,u done\n\t"
|
||||
$$emit$$"jp,u done\n\t"
|
||||
$$emit$$"j$cop,u $labl\n\t"
|
||||
$$emit$$"done:"
|
||||
}
|
||||
@ -12666,10 +12666,10 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{
|
||||
ins_cost(300);
|
||||
format %{ $$template
|
||||
if ($cop$$cmpcode == Assembler::notEqual) {
|
||||
$$emit$$"jp,u,s $labl\n\t"
|
||||
$$emit$$"j$cop,u,s $labl"
|
||||
$$emit$$"jp,u,s $labl\n\t"
|
||||
$$emit$$"j$cop,u,s $labl"
|
||||
} else {
|
||||
$$emit$$"jp,u,s done\n\t"
|
||||
$$emit$$"jp,u,s done\n\t"
|
||||
$$emit$$"j$cop,u,s $labl\n\t"
|
||||
$$emit$$"done:"
|
||||
}
|
||||
@ -12745,7 +12745,7 @@ instruct safePoint_poll(rFlagsReg cr)
|
||||
match(SafePoint);
|
||||
effect(KILL cr);
|
||||
|
||||
format %{ "testl rax, [rip + #offset_to_poll_page]\t"
|
||||
format %{ "testl rax, [rip + #offset_to_poll_page]\t"
|
||||
"# Safepoint: poll for GC" %}
|
||||
ins_cost(125);
|
||||
ins_encode %{
|
||||
@ -12761,7 +12761,7 @@ instruct safePoint_poll_far(rFlagsReg cr, rRegP poll)
|
||||
match(SafePoint poll);
|
||||
effect(KILL cr, USE poll);
|
||||
|
||||
format %{ "testl rax, [$poll]\t"
|
||||
format %{ "testl rax, [$poll]\t"
|
||||
"# Safepoint: poll for GC" %}
|
||||
ins_cost(125);
|
||||
ins_encode %{
|
||||
@ -12777,7 +12777,7 @@ instruct safePoint_poll_tls(rFlagsReg cr, rRegP poll)
|
||||
match(SafePoint poll);
|
||||
effect(KILL cr, USE poll);
|
||||
|
||||
format %{ "testl rax, [$poll]\t"
|
||||
format %{ "testl rax, [$poll]\t"
|
||||
"# Safepoint: poll for GC" %}
|
||||
ins_cost(125);
|
||||
size(4); /* setting an explicit size will cause debug builds to assert if size is incorrect */
|
||||
|
||||
@ -37,6 +37,12 @@ class Assembler : public AbstractAssembler {
|
||||
|
||||
public:
|
||||
void pd_patch_instruction(address branch, address target, const char* file, int line);
|
||||
|
||||
//---< calculate length of instruction >---
|
||||
static unsigned int instr_len(unsigned char *instr) { return 1; }
|
||||
|
||||
//---< longest instructions >---
|
||||
static unsigned int instr_maxlen() { return 1; }
|
||||
};
|
||||
|
||||
class MacroAssembler : public Assembler {
|
||||
|
||||
@ -34,4 +34,24 @@
|
||||
return "";
|
||||
}
|
||||
|
||||
// Returns address of n-th instruction preceding addr,
|
||||
// NULL if no preceding instruction can be found.
|
||||
// On ZERO, we assume a constant instruction length of 1 byte.
|
||||
// It might be beneficial to check "is_readable" as we do on ppc and s390.
|
||||
static address find_prev_instr(address addr, int n_instr) {
|
||||
return addr - 1*n_instr;
|
||||
}
|
||||
|
||||
// special-case instruction decoding.
|
||||
// There may be cases where the binutils disassembler doesn't do
|
||||
// the perfect job. In those cases, decode_instruction0 may kick in
|
||||
// and do it right.
|
||||
// If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
|
||||
static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
|
||||
return here;
|
||||
}
|
||||
|
||||
// platform-specific instruction annotations (like value of loaded constants)
|
||||
static void annotate(address pc, outputStream* st) { };
|
||||
|
||||
#endif // CPU_ZERO_DISASSEMBLER_ZERO_HPP
|
||||
|
||||
@ -86,7 +86,8 @@ typedef CodeBuffer::csize_t csize_t; // file-local definition
|
||||
// External buffer, in a predefined CodeBlob.
|
||||
// Important: The code_start must be taken exactly, and not realigned.
|
||||
CodeBuffer::CodeBuffer(CodeBlob* blob) {
|
||||
initialize_misc("static buffer");
|
||||
// Provide code buffer with meaningful name
|
||||
initialize_misc(blob->name());
|
||||
initialize(blob->content_begin(), blob->content_size());
|
||||
verify_section_allocation();
|
||||
}
|
||||
@ -1035,7 +1036,9 @@ void CodeSection::decode() {
|
||||
}
|
||||
|
||||
void CodeBuffer::block_comment(intptr_t offset, const char * comment) {
|
||||
_code_strings.add_comment(offset, comment);
|
||||
if (_collect_comments) {
|
||||
_code_strings.add_comment(offset, comment);
|
||||
}
|
||||
}
|
||||
|
||||
const char* CodeBuffer::code_string(const char* str) {
|
||||
@ -1148,15 +1151,23 @@ void CodeStrings::copy(CodeStrings& other) {
|
||||
|
||||
const char* CodeStrings::_prefix = " ;; "; // default: can be changed via set_prefix
|
||||
|
||||
// Check if any block comments are pending for the given offset.
|
||||
bool CodeStrings::has_block_comment(intptr_t offset) const {
|
||||
if (_strings == NULL) return false;
|
||||
CodeString* c = find(offset);
|
||||
return c != NULL;
|
||||
}
|
||||
|
||||
void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const {
|
||||
check_valid();
|
||||
if (_strings != NULL) {
|
||||
check_valid();
|
||||
if (_strings != NULL) {
|
||||
CodeString* c = find(offset);
|
||||
while (c && c->offset() == offset) {
|
||||
stream->bol();
|
||||
stream->print("%s", _prefix);
|
||||
// Don't interpret as format strings since it could contain %
|
||||
stream->print_raw_cr(c->string());
|
||||
stream->print_raw(c->string());
|
||||
stream->bol(); // advance to next line only if string didn't contain a cr() at the end.
|
||||
c = c->next_comment();
|
||||
}
|
||||
}
|
||||
@ -1186,7 +1197,7 @@ const char* CodeStrings::add_string(const char * string) {
|
||||
|
||||
void CodeBuffer::decode() {
|
||||
ttyLocker ttyl;
|
||||
Disassembler::decode(decode_begin(), insts_end());
|
||||
Disassembler::decode(decode_begin(), insts_end(), tty);
|
||||
_decode_begin = insts_end();
|
||||
}
|
||||
|
||||
@ -1217,4 +1228,10 @@ void CodeBuffer::print() {
|
||||
}
|
||||
}
|
||||
|
||||
// Directly disassemble code buffer.
|
||||
void CodeBuffer::decode(address start, address end) {
|
||||
ttyLocker ttyl;
|
||||
Disassembler::decode(this, start, end, tty);
|
||||
}
|
||||
|
||||
#endif // PRODUCT
|
||||
|
||||
@ -289,6 +289,7 @@ public:
|
||||
const char* add_string(const char * string) PRODUCT_RETURN_(return NULL;);
|
||||
|
||||
void add_comment(intptr_t offset, const char * comment) PRODUCT_RETURN;
|
||||
bool has_block_comment(intptr_t offset) const;
|
||||
void print_block_comment(outputStream* stream, intptr_t offset) const PRODUCT_RETURN;
|
||||
// MOVE strings from other to this; invalidate other.
|
||||
void assign(CodeStrings& other) PRODUCT_RETURN;
|
||||
@ -296,6 +297,7 @@ public:
|
||||
void copy(CodeStrings& other) PRODUCT_RETURN;
|
||||
// FREE strings; invalidate this.
|
||||
void free() PRODUCT_RETURN;
|
||||
|
||||
// Guarantee that _strings are used at most once; assign and free invalidate a buffer.
|
||||
inline void check_valid() const {
|
||||
#ifdef ASSERT
|
||||
@ -377,6 +379,7 @@ class CodeBuffer: public StackObj {
|
||||
|
||||
OopRecorder* _oop_recorder;
|
||||
CodeStrings _code_strings;
|
||||
bool _collect_comments; // Indicate if we need to collect block comments at all.
|
||||
OopRecorder _default_oop_recorder; // override with initialize_oop_recorder
|
||||
Arena* _overflow_arena;
|
||||
|
||||
@ -403,6 +406,14 @@ class CodeBuffer: public StackObj {
|
||||
#if INCLUDE_AOT
|
||||
_immutable_PIC = false;
|
||||
#endif
|
||||
|
||||
// Collect block comments, but restrict collection to cases where a disassembly is output.
|
||||
_collect_comments = ( PrintAssembly
|
||||
|| PrintStubCode
|
||||
|| PrintMethodHandleStubs
|
||||
|| PrintInterpreter
|
||||
|| PrintSignatureHandlers
|
||||
);
|
||||
}
|
||||
|
||||
void initialize(address code_start, csize_t code_size) {
|
||||
@ -604,6 +615,23 @@ class CodeBuffer: public StackObj {
|
||||
}
|
||||
}
|
||||
|
||||
// Directly disassemble code buffer.
|
||||
// Print the comment associated with offset on stream, if there is one.
|
||||
virtual void print_block_comment(outputStream* stream, address block_begin) {
|
||||
#ifndef PRODUCT
|
||||
intptr_t offset = (intptr_t)(block_begin - _total_start); // I assume total_start is not correct for all code sections.
|
||||
_code_strings.print_block_comment(stream, offset);
|
||||
#endif
|
||||
}
|
||||
bool has_block_comment(address block_begin) {
|
||||
#ifndef PRODUCT
|
||||
intptr_t offset = (intptr_t)(block_begin - _total_start); // I assume total_start is not correct for all code sections.
|
||||
return _code_strings.has_block_comment(offset);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Code generation
|
||||
void relocate(address at, RelocationHolder const& rspec, int format = 0) {
|
||||
_insts.relocate(at, rspec, format);
|
||||
@ -650,7 +678,8 @@ class CodeBuffer: public StackObj {
|
||||
void decode();
|
||||
void print();
|
||||
#endif
|
||||
|
||||
// Directly disassemble code buffer.
|
||||
void decode(address start, address end);
|
||||
|
||||
// The following header contains architecture-specific implementations
|
||||
#include CPU_HEADER(codeBuffer)
|
||||
|
||||
@ -183,8 +183,14 @@ void RuntimeBlob::trace_new_stub(RuntimeBlob* stub, const char* name1, const cha
|
||||
jio_snprintf(stub_id, sizeof(stub_id), "%s%s", name1, name2);
|
||||
if (PrintStubCode) {
|
||||
ttyLocker ttyl;
|
||||
tty->print_cr("- - - [BEGIN] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
tty->print_cr("Decoding %s " INTPTR_FORMAT, stub_id, (intptr_t) stub);
|
||||
Disassembler::decode(stub->code_begin(), stub->code_end());
|
||||
Disassembler::decode(stub->code_begin(), stub->code_end(), tty);
|
||||
if ((stub->oop_maps() != NULL) && AbstractDisassembler::show_structs()) {
|
||||
tty->print_cr("- - - [OOP MAPS]- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
stub->oop_maps()->print();
|
||||
}
|
||||
tty->print_cr("- - - [END] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
tty->cr();
|
||||
}
|
||||
Forte::register_stub(stub_id, stub->code_begin(), stub->code_end());
|
||||
@ -263,6 +269,7 @@ void* BufferBlob::operator new(size_t s, unsigned size) throw() {
|
||||
}
|
||||
|
||||
void BufferBlob::free(BufferBlob *blob) {
|
||||
assert(blob != NULL, "caller must check for NULL");
|
||||
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
|
||||
blob->flush();
|
||||
{
|
||||
|
||||
@ -211,7 +211,7 @@ public:
|
||||
const ImmutableOopMap* oop_map_for_return_address(address return_address);
|
||||
virtual void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) = 0;
|
||||
|
||||
// Frame support
|
||||
// Frame support. Sizes are in word units.
|
||||
int frame_size() const { return _frame_size; }
|
||||
void set_frame_size(int size) { _frame_size = size; }
|
||||
|
||||
@ -230,6 +230,10 @@ public:
|
||||
void dump_for_addr(address addr, outputStream* st, bool verbose) const;
|
||||
void print_code();
|
||||
|
||||
bool has_block_comment(address block_begin) const {
|
||||
intptr_t offset = (intptr_t)(block_begin - code_begin());
|
||||
return _strings.has_block_comment(offset);
|
||||
}
|
||||
// Print the comment associated with offset on stream, if there is one
|
||||
virtual void print_block_comment(outputStream* stream, address block_begin) const {
|
||||
intptr_t offset = (intptr_t)(block_begin - code_begin());
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2019, 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
|
||||
@ -185,10 +185,24 @@ uint ImplicitExceptionTable::at( uint exec_off ) const {
|
||||
}
|
||||
|
||||
void ImplicitExceptionTable::print(address base) const {
|
||||
tty->print("{");
|
||||
for( uint i=0; i<len(); i++ )
|
||||
tty->print("< " INTPTR_FORMAT ", " INTPTR_FORMAT " > ", p2i(base + *adr(i)), p2i(base + *(adr(i)+1)));
|
||||
tty->print_cr("}");
|
||||
const uint n = len();
|
||||
if (n > 0) {
|
||||
const uint items_per_line = 3;
|
||||
uint i;
|
||||
tty->print_cr("ImplicitExceptionTable (size = %d entries, %d bytes):", n, size_in_bytes());
|
||||
tty->print("{");
|
||||
for (i = 0; i < n; i++) {
|
||||
if (i%items_per_line == 0) {
|
||||
tty->cr();
|
||||
tty->fill_to(3);
|
||||
}
|
||||
tty->print("< " INTPTR_FORMAT ", " INTPTR_FORMAT " > ", p2i(base + *adr(i)), p2i(base + *(adr(i)+1)));
|
||||
}
|
||||
tty->bol();
|
||||
tty->print_cr("}");
|
||||
} else {
|
||||
tty->print_cr("ImplicitExceptionTable is empty");
|
||||
}
|
||||
}
|
||||
|
||||
ImplicitExceptionTable::ImplicitExceptionTable(const nmethod* nm) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -377,6 +377,7 @@ class nmethod : public CompiledMethod {
|
||||
void make_unloaded();
|
||||
|
||||
bool has_dependencies() { return dependencies_size() != 0; }
|
||||
void print_dependencies() PRODUCT_RETURN;
|
||||
void flush_dependencies(bool delete_immediately);
|
||||
bool has_flushed_dependencies() { return _has_flushed_dependencies; }
|
||||
void set_has_flushed_dependencies() {
|
||||
@ -505,18 +506,40 @@ public:
|
||||
void verify_scopes();
|
||||
void verify_interrupt_point(address interrupt_point);
|
||||
|
||||
// Disassemble this nmethod with additional debug information, e.g. information about blocks.
|
||||
void decode2(outputStream* st) const;
|
||||
void print_constant_pool(outputStream* st);
|
||||
|
||||
// Avoid hiding of parent's 'decode(outputStream*)' method.
|
||||
void decode(outputStream* st) const { decode2(st); } // just delegate here.
|
||||
|
||||
// printing support
|
||||
void print() const;
|
||||
void print(outputStream* st) const;
|
||||
void print_code();
|
||||
|
||||
#if defined(SUPPORT_DATA_STRUCTS)
|
||||
// print output in opt build for disassembler library
|
||||
void print_relocations() PRODUCT_RETURN;
|
||||
void print_pcs() PRODUCT_RETURN;
|
||||
void print_scopes() PRODUCT_RETURN;
|
||||
void print_dependencies() PRODUCT_RETURN;
|
||||
void print_value_on(outputStream* st) const PRODUCT_RETURN;
|
||||
void print_pcs() { print_pcs_on(tty); }
|
||||
void print_pcs_on(outputStream* st);
|
||||
void print_scopes() { print_scopes_on(tty); }
|
||||
void print_scopes_on(outputStream* st) PRODUCT_RETURN;
|
||||
void print_value_on(outputStream* st) const;
|
||||
void print_handler_table();
|
||||
void print_nul_chk_table();
|
||||
void print_recorded_oops();
|
||||
void print_recorded_metadata();
|
||||
|
||||
void print_oops(outputStream* st); // oops from the underlying CodeBlob.
|
||||
void print_metadata(outputStream* st); // metadata in metadata pool.
|
||||
#else
|
||||
// void print_pcs() PRODUCT_RETURN;
|
||||
void print_pcs() { return; }
|
||||
#endif
|
||||
|
||||
void print_calls(outputStream* st) PRODUCT_RETURN;
|
||||
void print_handler_table() PRODUCT_RETURN;
|
||||
void print_nul_chk_table() PRODUCT_RETURN;
|
||||
void print_recorded_oops() PRODUCT_RETURN;
|
||||
void print_recorded_metadata() PRODUCT_RETURN;
|
||||
static void print_statistics() PRODUCT_RETURN;
|
||||
|
||||
void maybe_print_nmethod(DirectiveSet* directive);
|
||||
void print_nmethod(bool print_code);
|
||||
@ -532,14 +555,21 @@ public:
|
||||
|
||||
// Prints block-level comments, including nmethod specific block labels:
|
||||
virtual void print_block_comment(outputStream* stream, address block_begin) const {
|
||||
#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
|
||||
print_nmethod_labels(stream, block_begin);
|
||||
CodeBlob::print_block_comment(stream, block_begin);
|
||||
#endif
|
||||
}
|
||||
void print_nmethod_labels(outputStream* stream, address block_begin) const;
|
||||
bool has_block_comment(address block_begin) {
|
||||
return CodeBlob::has_block_comment(block_begin);
|
||||
}
|
||||
void print_nmethod_labels(outputStream* stream, address block_begin, bool print_section_labels=true) const;
|
||||
const char* nmethod_section_label(address pos) const;
|
||||
|
||||
// returns whether this nmethod has code comments.
|
||||
bool has_code_comment(address begin, address end);
|
||||
// Prints a comment for one native instruction (reloc info, pc desc)
|
||||
void print_code_comment_on(outputStream* st, int column, address begin, address end);
|
||||
static void print_statistics() PRODUCT_RETURN;
|
||||
|
||||
// Compiler task identification. Note that all OSR methods
|
||||
// are numbered in an independent sequence if CICountOSR is true,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2019, 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
|
||||
@ -40,19 +40,24 @@ address PcDesc::real_pc(const CompiledMethod* code) const {
|
||||
return code->code_begin() + pc_offset();
|
||||
}
|
||||
|
||||
void PcDesc::print(CompiledMethod* code) {
|
||||
void PcDesc::print_on(outputStream* st, CompiledMethod* code) {
|
||||
#ifndef PRODUCT
|
||||
ResourceMark rm;
|
||||
tty->print_cr("PcDesc(pc=" PTR_FORMAT " offset=%x bits=%x):", p2i(real_pc(code)), pc_offset(), _flags);
|
||||
st->print("PcDesc(pc=" PTR_FORMAT " offset=%x bits=%x):", p2i(real_pc(code)), pc_offset(), _flags);
|
||||
|
||||
if (scope_decode_offset() == DebugInformationRecorder::serialized_null) {
|
||||
st->cr();
|
||||
return;
|
||||
}
|
||||
|
||||
int tab = 8;
|
||||
int pos = st->position() + 2; // current column plus two spaces
|
||||
pos = ((pos+tab-1)/tab)*tab;
|
||||
|
||||
for (ScopeDesc* sd = code->scope_desc_at(real_pc(code));
|
||||
sd != NULL;
|
||||
sd = sd->sender()) {
|
||||
sd->print_on(tty);
|
||||
sd->print_on(st);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -92,7 +92,8 @@ class PcDesc {
|
||||
// Returns the real pc
|
||||
address real_pc(const CompiledMethod* code) const;
|
||||
|
||||
void print(CompiledMethod* code);
|
||||
void print(CompiledMethod* code) { print_on(tty, code); }
|
||||
void print_on(outputStream* st, CompiledMethod* code);
|
||||
bool verify(CompiledMethod* code);
|
||||
};
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ const char *VMRegImpl::regName[ConcreteRegisterImpl::number_of_registers];
|
||||
|
||||
void VMRegImpl::print_on(outputStream* st) const {
|
||||
if( is_reg() ) {
|
||||
assert( VMRegImpl::regName[value()], "" );
|
||||
assert(VMRegImpl::regName[value()], "VMRegImpl::regName[" INTPTR_FORMAT "] returns NULL", value());
|
||||
st->print("%s",VMRegImpl::regName[value()]);
|
||||
} else if (is_stack()) {
|
||||
int stk = value() - stack0->value();
|
||||
|
||||
@ -80,7 +80,7 @@ void* VtableStub::operator new(size_t size, int code_size) throw() {
|
||||
|
||||
|
||||
void VtableStub::print_on(outputStream* st) const {
|
||||
st->print("vtable stub (index = %d, receiver_location = " INTX_FORMAT ", code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "[)",
|
||||
st->print("vtable stub (index = %d, receiver_location = " INTX_FORMAT ", code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "])",
|
||||
index(), p2i(receiver_location()), p2i(code_begin()), p2i(code_end()));
|
||||
}
|
||||
|
||||
|
||||
379
src/hotspot/share/compiler/abstractDisassembler.cpp
Normal file
379
src/hotspot/share/compiler/abstractDisassembler.cpp
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019 SAP SE. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// AbstractDisassembler is the base class for
|
||||
// platform-specific Disassembler classes.
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "compiler/abstractDisassembler.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
// Default values for what is being printed as line prefix when disassembling a single instruction.
|
||||
// Can be overridden by command line parameter PrintAssemblyOptions.
|
||||
bool AbstractDisassembler::_show_data_hex = true;
|
||||
bool AbstractDisassembler::_show_data_int = false;
|
||||
bool AbstractDisassembler::_show_data_float = false;
|
||||
bool AbstractDisassembler::_align_instr = false;
|
||||
bool AbstractDisassembler::_show_pc = true;
|
||||
bool AbstractDisassembler::_show_offset = false;
|
||||
bool AbstractDisassembler::_show_structs = false;
|
||||
bool AbstractDisassembler::_show_comment = false;
|
||||
bool AbstractDisassembler::_show_block_comment = false;
|
||||
#if defined(ARM) || defined(AARCH64)
|
||||
bool AbstractDisassembler::_show_bytes = false; // set "true" to see what's in memory bit by bit
|
||||
// might prove cumbersome because instr_len is hard to find on arm
|
||||
#endif
|
||||
#if defined(PPC)
|
||||
bool AbstractDisassembler::_show_bytes = false; // set "true" to see what's in memory bit by bit
|
||||
#endif
|
||||
#if defined(S390)
|
||||
bool AbstractDisassembler::_show_bytes = false; // set "true" to see what's in memory bit by bit
|
||||
#endif
|
||||
#if defined(SPARC)
|
||||
bool AbstractDisassembler::_show_bytes = false; // set "true" to see what's in memory bit by bit
|
||||
#endif
|
||||
#if defined(X86)
|
||||
bool AbstractDisassembler::_show_bytes = false; // set "true" to see what's in memory bit by bit
|
||||
// might prove cumbersome because instr_len is hard to find on x86
|
||||
#endif
|
||||
#if defined(ZERO)
|
||||
bool AbstractDisassembler::_show_bytes = false; // set "true" to see what's in memory bit by bit
|
||||
#endif
|
||||
|
||||
// Return #bytes printed. Callers may use that for output alignment.
|
||||
// Print instruction address, and offset from blob begin.
|
||||
// Offset width (2, 4, 6, 8 bytes) is adapted to size of blob.
|
||||
// Working assumption: we are at st->bol() upon entry. If not, it's the
|
||||
// caller's responsibility to guarantee proper alignment.
|
||||
int AbstractDisassembler::print_location(address here, address begin, address end, outputStream* st, bool align, bool print_header) {
|
||||
const int pos_0 = st->position();
|
||||
|
||||
if (show_pc() || show_offset()) {
|
||||
st->print(" ");
|
||||
}
|
||||
|
||||
if (show_pc()) {
|
||||
if (print_header) {
|
||||
st->print(" %*s", 18, "Address");
|
||||
} else {
|
||||
st->print(" " PTR_FORMAT, p2i(here));
|
||||
}
|
||||
}
|
||||
|
||||
if (show_offset()) {
|
||||
#ifdef ASSERT
|
||||
if ((uintptr_t)begin > (uintptr_t)here) st->print(">>begin(" PTR_FORMAT ") > here(" PTR_FORMAT ")<<", p2i(begin), p2i(here));
|
||||
if ((uintptr_t)end < (uintptr_t)here) st->print(">> end(" PTR_FORMAT ") < here(" PTR_FORMAT ")<<", p2i(end), p2i(here));
|
||||
assert((uintptr_t)begin <= (uintptr_t)end, "inverted address range");
|
||||
#endif
|
||||
const int blob_len = end - begin;
|
||||
const int offset = here - begin;
|
||||
const int width = (blob_len < (1<< 8)) ? 2 : (blob_len < (1<<16)) ? 4 : (blob_len < (1<<24)) ? 6 : 8;
|
||||
if (print_header) {
|
||||
st->print(" %*s", width+5, "offset");
|
||||
} else {
|
||||
st->print(" (+0x%*.*x)", width, width, offset);
|
||||
}
|
||||
}
|
||||
|
||||
if ((show_pc() || show_offset()) && !print_header) {
|
||||
st->print(": ");
|
||||
}
|
||||
|
||||
if (align) {
|
||||
const uint tabspacing = 8;
|
||||
const uint pos = st->position();
|
||||
const uint aligned_pos = ((pos+tabspacing-1)/tabspacing)*tabspacing /* - 1 */;
|
||||
st->fill_to(aligned_pos);
|
||||
}
|
||||
|
||||
return st->position() - pos_0;
|
||||
}
|
||||
|
||||
|
||||
// Return #bytes printed. Callers may use that for output alignment.
|
||||
// Print instruction in hexadecimal representation, using 2-byte blocks.
|
||||
// Used with real disassemblies. Not so useful with abstract disassemblies.
|
||||
int AbstractDisassembler::print_instruction(address here, int len, int max_len, outputStream* st, bool align, bool print_header) {
|
||||
if (show_bytes()) {
|
||||
const int block_bytes = 2;
|
||||
const int pos_0 = st->position();
|
||||
address pos = here;
|
||||
|
||||
//---< print instruction bytes in blocks >---
|
||||
// must print byte by byte: address might be unaligned.
|
||||
for (; pos <= here + len - block_bytes; pos += block_bytes) {
|
||||
for (address byte = pos; byte < pos + block_bytes; byte++) {
|
||||
st->print("%2.2x", *byte);
|
||||
}
|
||||
st->print(" ");
|
||||
}
|
||||
|
||||
//---< Print the remaining bytes of the instruction >---
|
||||
if ((len & (block_bytes - 1)) != 0) {
|
||||
for (; pos < here + len; pos++) {
|
||||
st->print("%2.2x", *pos);
|
||||
}
|
||||
}
|
||||
|
||||
//---< filler for shorter than max_len instructions >---
|
||||
for (int i = len+1; i < max_len; i++) {
|
||||
st->print(" ");
|
||||
}
|
||||
|
||||
st->print(" "); // separator space.
|
||||
print_delimiter(st);
|
||||
return st->position() - pos_0;
|
||||
}
|
||||
|
||||
if (align) {
|
||||
const uint tabspacing = 8;
|
||||
const uint pos = st->position();
|
||||
const uint aligned_pos = ((pos+tabspacing-1)/tabspacing)*tabspacing /* - 1 */;
|
||||
st->fill_to(aligned_pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Return #bytes printed. Callers may use that for output alignment.
|
||||
// Print data (e.g. constant pool entries) in hex format.
|
||||
// Depending on the alignment, short, int, and long entities are printed.
|
||||
// If selected, data is formatted as int/long and float/double values in addition.
|
||||
int AbstractDisassembler::print_hexdata(address here, int len, outputStream* st, bool print_header) {
|
||||
const int tsize = 8;
|
||||
const int pos_0 = st->position();
|
||||
int pos = pos_0;
|
||||
int align = ((pos+tsize-1)/tsize)*tsize;
|
||||
st->fill_to(align);
|
||||
|
||||
//---< printing hex data >---
|
||||
if (show_data_hex()) {
|
||||
switch (len) {
|
||||
case 1: if (print_header) {
|
||||
st->print("hex1");
|
||||
} else {
|
||||
st->print("0x%02x", *here);
|
||||
}
|
||||
st->fill_to(align += tsize);
|
||||
case 2: if (print_header) {
|
||||
st->print(" hex2");
|
||||
} else {
|
||||
if (((uintptr_t)(here)&0x01) == 0) {
|
||||
st->print("0x%04x", *((jushort*)here));
|
||||
}
|
||||
}
|
||||
st->fill_to(align += tsize);
|
||||
case 4: if (print_header) {
|
||||
st->print(" hex4");
|
||||
} else {
|
||||
if (((uintptr_t)(here)&0x03) == 0) {
|
||||
st->print("0x%08x", *((juint*)here));
|
||||
}
|
||||
}
|
||||
st->fill_to(align += 2*tsize);
|
||||
case 8: if (print_header) {
|
||||
st->print(" hex8");
|
||||
} else {
|
||||
if (((uintptr_t)(here)&0x07) == 0) {
|
||||
st->print(PTR_FORMAT, *((uintptr_t*)here));
|
||||
}
|
||||
}
|
||||
st->fill_to(align += 3*tsize);
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
pos = st->position();
|
||||
align = ((pos+tsize-1)/tsize)*tsize;
|
||||
st->fill_to(align);
|
||||
}
|
||||
|
||||
//---< printing int/long data >---
|
||||
if (show_data_int()) {
|
||||
switch (len) {
|
||||
case 4: if (print_header) {
|
||||
st->print(" int");
|
||||
} else {
|
||||
if (((uintptr_t)(here)&0x03) == 0) {
|
||||
st->print("%12.1d", *((jint*)here));
|
||||
}
|
||||
}
|
||||
st->fill_to(align += 2*tsize);
|
||||
case 8: if (print_header) {
|
||||
st->print(" long");
|
||||
} else {
|
||||
if (((uintptr_t)(here)&0x07) == 0) {
|
||||
st->print("%23.1ld", *((jlong*)here));
|
||||
}
|
||||
}
|
||||
st->fill_to(align += 3*tsize);
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
pos = st->position();
|
||||
align = ((pos+tsize-1)/tsize)*tsize;
|
||||
st->fill_to(align);
|
||||
}
|
||||
|
||||
//---< printing float/double data >---
|
||||
if (show_data_float()) {
|
||||
switch (len) {
|
||||
case 4: if (print_header) {
|
||||
st->print(" float");
|
||||
} else {
|
||||
if (((uintptr_t)(here)&0x03) == 0) {
|
||||
st->print("%15.7e", (double)*((float*)here));
|
||||
}
|
||||
}
|
||||
st->fill_to(align += 2*tsize);
|
||||
case 8: if (print_header) {
|
||||
st->print(" double");
|
||||
} else {
|
||||
if (((uintptr_t)(here)&0x07) == 0) {
|
||||
st->print("%23.15e", *((double*)here));
|
||||
}
|
||||
}
|
||||
st->fill_to(align += 3*tsize);
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
return st->position() - pos_0;
|
||||
}
|
||||
|
||||
|
||||
// Return #bytes printed. Callers may use that for output alignment.
|
||||
// Print an instruction delimiter.
|
||||
int AbstractDisassembler::print_delimiter(outputStream* st) {
|
||||
if (align_instr()) { st->print("| "); return 2; }
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
// Decodes the one instruction at address start in a platform-independent format.
|
||||
// Returns the start of the next instruction (which is 'start' plus 'instruction_size_in_bytes').
|
||||
// The parameter max_instr_size_in_bytes is used for output alignment purposes only.
|
||||
address AbstractDisassembler::decode_instruction_abstract(address start,
|
||||
outputStream* st,
|
||||
const int instruction_size_in_bytes,
|
||||
const int max_instr_size_in_bytes) {
|
||||
assert(instruction_size_in_bytes > 0, "no zero-size instructions!");
|
||||
assert(max_instr_size_in_bytes >= instruction_size_in_bytes, "inconsistent call parameters");
|
||||
|
||||
//---< current instruction is at the start address >---
|
||||
unsigned char* current = (unsigned char*) start;
|
||||
int filler_limit = align_instr() ? max_instr_size_in_bytes : ((instruction_size_in_bytes+abstract_instruction_bytes_per_block-1)/abstract_instruction_bytes_per_block)
|
||||
*abstract_instruction_bytes_per_block;
|
||||
|
||||
//---< print the instruction's bytes >---
|
||||
for (int i = 1; i <= instruction_size_in_bytes; i++) {
|
||||
st->print("%02x", *current);
|
||||
++current;
|
||||
if (abstract_instruction_bytes_per_block <= max_instr_size_in_bytes) {
|
||||
if (i%abstract_instruction_bytes_per_block == 0) st->print(" ");
|
||||
} else {
|
||||
if (i == instruction_size_in_bytes) st->print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
//---< print some filler spaces to column-align instructions >---
|
||||
for (int i = instruction_size_in_bytes+1; i <= filler_limit; i++) {
|
||||
st->print(" ");
|
||||
if (abstract_instruction_bytes_per_block <= max_instr_size_in_bytes) {
|
||||
if (i%abstract_instruction_bytes_per_block == 0) st->print(" ");
|
||||
} else {
|
||||
if (i == instruction_size_in_bytes) st->print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
//---< the address of the next instruction >---
|
||||
return (address) current;
|
||||
}
|
||||
|
||||
|
||||
// Decodes all instructions in the given range [start..end)
|
||||
// calling decode_instruction_abstract for each instruction.
|
||||
// The format is platform dependent only to the extend that
|
||||
// it respects the actual instruction length where possible.
|
||||
// Does not print any markers or decorators.
|
||||
void AbstractDisassembler::decode_range_abstract(address range_start, address range_end,
|
||||
address start, address end,
|
||||
outputStream* st,
|
||||
const int max_instr_size_in_bytes) {
|
||||
assert(st != NULL, "need an output stream (no default)!");
|
||||
int idx = 0;
|
||||
address pos = range_start;
|
||||
|
||||
while ((pos != NULL) && (pos < range_end)) {
|
||||
int instr_size_in_bytes = Assembler::instr_len(pos);
|
||||
|
||||
if (idx == 0) print_location(pos, start, end, st, false, false);
|
||||
else print_delimiter(st);
|
||||
|
||||
//---< print the instruction's bytes >---
|
||||
// don't access storage beyond end of range
|
||||
if (pos + instr_size_in_bytes <= range_end) {
|
||||
pos = decode_instruction_abstract(pos, st, instr_size_in_bytes, max_instr_size_in_bytes);
|
||||
} else {
|
||||
// If the range to be decoded contains garbage at the end (e.g. 0xcc initializer bytes),
|
||||
// instruction size calculation may run out of sync. Just terminate in that case.
|
||||
pos = range_end;
|
||||
}
|
||||
|
||||
idx += instr_size_in_bytes;
|
||||
if (start_newline(idx)) {
|
||||
st->cr();
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Decodes all instructions in the given range [start..end).
|
||||
// The output is enclosed in [MachCode] and [/MachCode] tags for later recognition.
|
||||
// The format is platform dependent only to the extend that
|
||||
// it respects the actual instruction length where possible.
|
||||
void AbstractDisassembler::decode_abstract(address start, address end, outputStream* ost,
|
||||
const int max_instr_size_in_bytes) {
|
||||
int idx = 0;
|
||||
address pos = start;
|
||||
|
||||
outputStream* st = (ost == NULL) ? tty : ost;
|
||||
|
||||
//---< Open the output (Marker for post-mortem disassembler) >---
|
||||
st->bol();
|
||||
st->print_cr("[MachCode]");
|
||||
|
||||
decode_range_abstract(start, end, start, end, st, max_instr_size_in_bytes);
|
||||
|
||||
//---< Close the output (Marker for post-mortem disassembler) >---
|
||||
st->bol();
|
||||
st->print_cr("[/MachCode]");
|
||||
}
|
||||
118
src/hotspot/share/compiler/abstractDisassembler.hpp
Normal file
118
src/hotspot/share/compiler/abstractDisassembler.hpp
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019 SAP SE. 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_COMPILER_ABSTRACTDISASSEMBLER_HPP
|
||||
#define SHARE_COMPILER_ABSTRACTDISASSEMBLER_HPP
|
||||
|
||||
// AbstractDisassembler is the base class for
|
||||
// platform-specific Disassembler classes.
|
||||
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class AbstractDisassembler {
|
||||
|
||||
private:
|
||||
// These are some general settings which control
|
||||
// abstract disassembly output.
|
||||
enum {
|
||||
// that many bytes are dumped in one line.
|
||||
abstract_instruction_bytes_per_line = 32,
|
||||
// instruction bytes are grouped in blocks of that many bytes.
|
||||
abstract_instruction_bytes_per_block = 2,
|
||||
// instructions have this default len.
|
||||
abstract_instruction_size_in_bytes = 1,
|
||||
// instructions have this maximum len.
|
||||
abstract_instruction_maxsize_in_bytes = 1
|
||||
};
|
||||
|
||||
static bool _align_instr; // vertical alignment of instructions in abstract disassembly
|
||||
static bool _show_pc; // print the instruction address
|
||||
static bool _show_offset; // print the instruction offset (from start of blob)
|
||||
static bool _show_bytes; // print instruction bytes
|
||||
static bool _show_data_hex; // print instruction bytes
|
||||
static bool _show_data_int; // print instruction bytes
|
||||
static bool _show_data_float; // print instruction bytes
|
||||
static bool _show_structs; // print compiler data structures (relocations, oop maps, scopes, metadata, ...)
|
||||
static bool _show_comment; // print instruction comments
|
||||
static bool _show_block_comment; // print block comments
|
||||
|
||||
public:
|
||||
// Platform-independent location and instruction formatting.
|
||||
// All functions return #characters printed.
|
||||
static int print_location(address here, address begin, address end, outputStream* st, bool align, bool print_header);
|
||||
static int print_instruction(address here, int len, int max_len, outputStream* st, bool align, bool print_header);
|
||||
static int print_hexdata(address here, int len, outputStream* st, bool print_header = false);
|
||||
static int print_delimiter(outputStream* st);
|
||||
static bool start_newline(int byte_count) { return byte_count >= abstract_instruction_bytes_per_line; }
|
||||
|
||||
static void toggle_align_instr() { _align_instr = !_align_instr; }
|
||||
static void toggle_show_pc() { _show_pc = !_show_pc; }
|
||||
static void toggle_show_offset() { _show_offset = !_show_offset; }
|
||||
static void toggle_show_bytes() { _show_bytes = !_show_bytes; }
|
||||
static void toggle_show_data_hex() { _show_data_hex = !_show_data_hex; }
|
||||
static void toggle_show_data_int() { _show_data_int = !_show_data_int; }
|
||||
static void toggle_show_data_float() { _show_data_float = !_show_data_float; }
|
||||
static void toggle_show_structs() { _show_structs = !_show_structs; }
|
||||
static void toggle_show_comment() { _show_comment = !_show_comment; }
|
||||
static void toggle_show_block_comment() { _show_block_comment = !_show_block_comment; }
|
||||
|
||||
static bool align_instr() { return _align_instr; }
|
||||
static bool show_pc() { return _show_pc; }
|
||||
static bool show_offset() { return _show_offset; }
|
||||
static bool show_bytes() { return _show_bytes; }
|
||||
static bool show_data_hex() { return _show_data_hex; }
|
||||
static bool show_data_int() { return _show_data_int; }
|
||||
static bool show_data_float() { return _show_data_float; }
|
||||
static bool show_structs() { return _show_structs; }
|
||||
static bool show_comment() { return _show_comment; }
|
||||
static bool show_block_comment() { return _show_block_comment; }
|
||||
|
||||
// Decodes the one instruction at address start in a platform-independent
|
||||
// format. Returns the start of the next instruction (which is
|
||||
// 'start' plus 'instruction_size_in_bytes'). The parameter max_instr_size_in_bytes
|
||||
// is used for output alignment purposes only.
|
||||
static address decode_instruction_abstract(address start,
|
||||
outputStream* st,
|
||||
const int instruction_size_in_bytes,
|
||||
const int max_instr_size_in_bytes = abstract_instruction_maxsize_in_bytes);
|
||||
|
||||
// Decodes all instructions in the given range [start..end)
|
||||
// calling decode_instruction_abstract for each instruction.
|
||||
// The format is platform dependent only to the extend that
|
||||
// it respects the actual instruction length where possible.
|
||||
// Does not print any markers or decorators.
|
||||
static void decode_range_abstract(address range_start, address range_end,
|
||||
address start, address end,
|
||||
outputStream* st,
|
||||
const int max_instr_size_in_bytes = abstract_instruction_maxsize_in_bytes);
|
||||
|
||||
// Decodes all instructions in the given range in a platform-independent
|
||||
// format, calling decode_instruction_abstract for each instruction.
|
||||
static void decode_abstract(address start, address end,
|
||||
outputStream* st,
|
||||
const int max_instr_size_in_bytes = abstract_instruction_maxsize_in_bytes);
|
||||
};
|
||||
|
||||
#endif // SHARE_COMPILER_ABSTRACTDISASSEMBLER_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,11 @@
|
||||
#ifndef SHARE_COMPILER_DISASSEMBLER_HPP
|
||||
#define SHARE_COMPILER_DISASSEMBLER_HPP
|
||||
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
#include "asm/assembler.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "compiler/abstractDisassembler.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
@ -34,7 +38,8 @@ class decode_env;
|
||||
// The disassembler prints out assembly code annotated
|
||||
// with Java specific information.
|
||||
|
||||
class Disassembler {
|
||||
// Disassembler inherits from AbstractDisassembler
|
||||
class Disassembler : public AbstractDisassembler {
|
||||
friend class decode_env;
|
||||
private:
|
||||
// this is the type of the dll entry point:
|
||||
@ -57,26 +62,58 @@ class Disassembler {
|
||||
static void* _library;
|
||||
// bailout
|
||||
static bool _tried_to_load_library;
|
||||
static bool _library_usable;
|
||||
// points to the decode function.
|
||||
static decode_func_virtual _decode_instructions_virtual;
|
||||
static decode_func _decode_instructions;
|
||||
// tries to load library and return whether it succedded.
|
||||
static bool load_library();
|
||||
|
||||
// tries to load library and return whether it succeeded.
|
||||
// Allow (diagnostic) output redirection.
|
||||
// No output at all if stream is NULL. Can be overridden
|
||||
// with -Verbose flag, in which case output goes to tty.
|
||||
static bool load_library(outputStream* st = NULL);
|
||||
|
||||
// Check if the two addresses are on the same page.
|
||||
static bool is_same_page(address a1, address a2) {
|
||||
return (((uintptr_t)a1 ^ (uintptr_t)a2) & (~0x0fffUL)) == 0L;
|
||||
}
|
||||
|
||||
// Machine dependent stuff
|
||||
#include CPU_HEADER(disassembler)
|
||||
|
||||
public:
|
||||
static bool can_decode() {
|
||||
ttyLocker tl;
|
||||
return (_decode_instructions_virtual != NULL) ||
|
||||
(_decode_instructions != NULL) ||
|
||||
load_library();
|
||||
// We can always decode code blobs.
|
||||
// Either we have a disassembler library available (successfully loaded)
|
||||
// or we will resort to the abstract disassembler. This method informs
|
||||
// about which decoding format is used.
|
||||
// We can also enforce using the abstract disassembler.
|
||||
static bool is_abstract() {
|
||||
if (!_tried_to_load_library /* && !UseAbstractDisassembler */) {
|
||||
load_library();
|
||||
}
|
||||
return ! _library_usable /* || UseAbstractDisassembler */; // Not available until DecodeErrorFile is supported.
|
||||
}
|
||||
static void decode(CodeBlob *cb, outputStream* st = NULL);
|
||||
static void decode(nmethod* nm, outputStream* st = NULL);
|
||||
static void decode(address begin, address end, outputStream* st = NULL,
|
||||
CodeStrings c = CodeStrings(), ptrdiff_t offset = 0);
|
||||
|
||||
// Check out if we are doing a live disassembly or a post-mortem
|
||||
// disassembly where the binary data was loaded from a hs_err file.
|
||||
static bool is_decode_error_file() {
|
||||
// Activate once post-mortem disassembly (from hs-err file) is available.
|
||||
#if 0
|
||||
return DecodeErrorFile && (strlen(DecodeErrorFile) != 0);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Directly disassemble code buffer.
|
||||
static void decode(CodeBuffer* cb, address start, address end, outputStream* st = NULL);
|
||||
// Directly disassemble code blob.
|
||||
static void decode(CodeBlob *cb, outputStream* st = NULL, CodeStrings c = CodeStrings());
|
||||
// Directly disassemble nmethod.
|
||||
static void decode(nmethod* nm, outputStream* st = NULL, CodeStrings c = CodeStrings());
|
||||
// Disassemble an arbitrary memory range.
|
||||
static void decode(address start, address end, outputStream* st = NULL, CodeStrings c = CodeStrings() /* , ptrdiff_t offset */);
|
||||
|
||||
static void _hook(const char* file, int line, class MacroAssembler* masm);
|
||||
|
||||
// This functions makes it easy to generate comments in the generated
|
||||
|
||||
@ -511,7 +511,7 @@ void OopMapValue::print() const { print_on(tty); }
|
||||
|
||||
void ImmutableOopMap::print_on(outputStream* st) const {
|
||||
OopMapValue omv;
|
||||
st->print("ImmutableOopMap{");
|
||||
st->print("ImmutableOopMap {");
|
||||
for(OopMapStream oms(this); !oms.is_done(); oms.next()) {
|
||||
omv = oms.current();
|
||||
omv.print_on(st);
|
||||
@ -523,44 +523,51 @@ void ImmutableOopMap::print() const { print_on(tty); }
|
||||
|
||||
void OopMap::print_on(outputStream* st) const {
|
||||
OopMapValue omv;
|
||||
st->print("OopMap{");
|
||||
st->print("OopMap {");
|
||||
for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) {
|
||||
omv = oms.current();
|
||||
omv.print_on(st);
|
||||
}
|
||||
st->print("off=%d}", (int) offset());
|
||||
// Print hex offset in addition.
|
||||
st->print("off=%d/0x%x}", (int) offset(), (int) offset());
|
||||
}
|
||||
|
||||
void OopMap::print() const { print_on(tty); }
|
||||
|
||||
void ImmutableOopMapSet::print_on(outputStream* st) const {
|
||||
const ImmutableOopMap* last = NULL;
|
||||
for (int i = 0; i < _count; ++i) {
|
||||
const int len = count();
|
||||
|
||||
st->print_cr("ImmutableOopMapSet contains %d OopMaps", len);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
const ImmutableOopMapPair* pair = pair_at(i);
|
||||
const ImmutableOopMap* map = pair->get_from(this);
|
||||
if (map != last) {
|
||||
st->cr();
|
||||
map->print_on(st);
|
||||
st->print("pc offsets: ");
|
||||
st->print(" pc offsets: ");
|
||||
}
|
||||
last = map;
|
||||
st->print("%d ", pair->pc_offset());
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void ImmutableOopMapSet::print() const { print_on(tty); }
|
||||
|
||||
void OopMapSet::print_on(outputStream* st) const {
|
||||
int i, len = om_count();
|
||||
const int len = om_count();
|
||||
|
||||
st->print_cr("OopMapSet contains %d OopMaps\n",len);
|
||||
st->print_cr("OopMapSet contains %d OopMaps", len);
|
||||
|
||||
for( i = 0; i < len; i++) {
|
||||
for( int i = 0; i < len; i++) {
|
||||
OopMap* m = at(i);
|
||||
st->print_cr("#%d ",i);
|
||||
m->print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void OopMapSet::print() const { print_on(tty); }
|
||||
@ -580,15 +587,17 @@ bool OopMap::equals(const OopMap* other) const {
|
||||
|
||||
const ImmutableOopMap* ImmutableOopMapSet::find_map_at_offset(int pc_offset) const {
|
||||
ImmutableOopMapPair* pairs = get_pairs();
|
||||
ImmutableOopMapPair* last = NULL;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < _count; ++i) {
|
||||
for (int i = 0; i < _count; ++i) {
|
||||
if (pairs[i].pc_offset() >= pc_offset) {
|
||||
last = &pairs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
ImmutableOopMapPair* last = &pairs[i];
|
||||
|
||||
// Heal Coverity issue: potential index out of bounds access.
|
||||
guarantee(last != NULL, "last may not be null");
|
||||
assert(last->pc_offset() == pc_offset, "oopmap not found");
|
||||
return last->get_from(this);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2019, 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
|
||||
@ -267,7 +267,7 @@ bool PhaseCFG::is_uncommon(const Block* block) {
|
||||
|
||||
#ifndef PRODUCT
|
||||
void Block::dump_bidx(const Block* orig, outputStream* st) const {
|
||||
if (_pre_order) st->print("B%d",_pre_order);
|
||||
if (_pre_order) st->print("B%d", _pre_order);
|
||||
else st->print("N%d", head()->_idx);
|
||||
|
||||
if (Verbose && orig != this) {
|
||||
@ -291,30 +291,36 @@ void Block::dump_pred(const PhaseCFG* cfg, Block* orig, outputStream* st) const
|
||||
}
|
||||
|
||||
void Block::dump_head(const PhaseCFG* cfg, outputStream* st) const {
|
||||
// Print the basic block
|
||||
// Print the basic block.
|
||||
dump_bidx(this, st);
|
||||
st->print(": #\t");
|
||||
st->print(": ");
|
||||
|
||||
// Print the incoming CFG edges and the outgoing CFG edges
|
||||
// Print the outgoing CFG edges.
|
||||
st->print("#\tout( ");
|
||||
for( uint i=0; i<_num_succs; i++ ) {
|
||||
non_connector_successor(i)->dump_bidx(_succs[i], st);
|
||||
st->print(" ");
|
||||
}
|
||||
st->print("<- ");
|
||||
|
||||
// Print the incoming CFG edges.
|
||||
st->print(") <- ");
|
||||
if( head()->is_block_start() ) {
|
||||
st->print("in( ");
|
||||
for (uint i=1; i<num_preds(); i++) {
|
||||
Node *s = pred(i);
|
||||
if (cfg != NULL) {
|
||||
Block *p = cfg->get_block_for_node(s);
|
||||
p->dump_pred(cfg, p, st);
|
||||
} else {
|
||||
while (!s->is_block_start())
|
||||
while (!s->is_block_start()) {
|
||||
s = s->in(0);
|
||||
}
|
||||
st->print("N%d ", s->_idx );
|
||||
}
|
||||
}
|
||||
st->print(") ");
|
||||
} else {
|
||||
st->print("BLOCK HEAD IS JUNK ");
|
||||
st->print("BLOCK HEAD IS JUNK ");
|
||||
}
|
||||
|
||||
// Print loop, if any
|
||||
@ -327,12 +333,15 @@ void Block::dump_head(const PhaseCFG* cfg, outputStream* st) const {
|
||||
while (bx->is_connector()) {
|
||||
bx = cfg->get_block_for_node(bx->pred(1));
|
||||
}
|
||||
st->print("\tLoop: B%d-B%d ", bhead->_pre_order, bx->_pre_order);
|
||||
st->print("Loop( B%d-B%d ", bhead->_pre_order, bx->_pre_order);
|
||||
// Dump any loop-specific bits, especially for CountedLoops.
|
||||
loop->dump_spec(st);
|
||||
st->print(")");
|
||||
} else if (has_loop_alignment()) {
|
||||
st->print(" top-of-loop");
|
||||
st->print("top-of-loop");
|
||||
}
|
||||
|
||||
// Print frequency and other optimization-relevant information
|
||||
st->print(" Freq: %g",_freq);
|
||||
if( Verbose || WizardMode ) {
|
||||
st->print(" IDom: %d/#%d", _idom ? _idom->_pre_order : 0, _dom_depth);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2019, 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
|
||||
@ -713,16 +713,19 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
||||
TraceTime t1("Total compilation time", &_t_totalCompilation, CITime, CITimeVerbose);
|
||||
TraceTime t2(NULL, &_t_methodCompilation, CITime, false);
|
||||
|
||||
#ifndef PRODUCT
|
||||
#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
|
||||
bool print_opto_assembly = directive->PrintOptoAssemblyOption;
|
||||
if (!print_opto_assembly) {
|
||||
bool print_assembly = directive->PrintAssemblyOption;
|
||||
if (print_assembly && !Disassembler::can_decode()) {
|
||||
tty->print_cr("PrintAssembly request changed to PrintOptoAssembly");
|
||||
print_opto_assembly = true;
|
||||
}
|
||||
}
|
||||
set_print_assembly(print_opto_assembly);
|
||||
// We can always print a disassembly, either abstract (hex dump) or
|
||||
// with the help of a suitable hsdis library. Thus, we should not
|
||||
// couple print_assembly and print_opto_assembly controls.
|
||||
// But: always print opto and regular assembly on compile command 'print'.
|
||||
bool print_assembly = directive->PrintAssemblyOption;
|
||||
set_print_assembly(print_opto_assembly || print_assembly);
|
||||
#else
|
||||
set_print_assembly(false); // must initialize.
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
set_parsed_irreducible_loop(false);
|
||||
|
||||
if (directive->ReplayInlineOption) {
|
||||
@ -1027,6 +1030,8 @@ Compile::Compile( ciEnv* ci_env,
|
||||
#ifndef PRODUCT
|
||||
set_print_assembly(PrintFrameConverterAssembly);
|
||||
set_parsed_irreducible_loop(false);
|
||||
#else
|
||||
set_print_assembly(false); // Must initialize.
|
||||
#endif
|
||||
set_has_irreducible_loop(false); // no loops
|
||||
|
||||
@ -2552,12 +2557,25 @@ void Compile::Code_Gen() {
|
||||
|
||||
//------------------------------dump_asm---------------------------------------
|
||||
// Dump formatted assembly
|
||||
#ifndef PRODUCT
|
||||
void Compile::dump_asm(int *pcs, uint pc_limit) {
|
||||
#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;
|
||||
tty->print_cr("#");
|
||||
tty->print("# "); _tf->dump(); tty->cr();
|
||||
tty->print_cr("#");
|
||||
st->print_cr("#");
|
||||
st->print("# "); _tf->dump_on(st); st->cr();
|
||||
st->print_cr("#");
|
||||
|
||||
// For all blocks
|
||||
int pc = 0x0; // Program counter
|
||||
@ -2575,16 +2593,18 @@ void Compile::dump_asm(int *pcs, uint pc_limit) {
|
||||
continue;
|
||||
}
|
||||
n = block->head();
|
||||
if (pcs && n->_idx < pc_limit) {
|
||||
tty->print("%3.3x ", pcs[n->_idx]);
|
||||
} else {
|
||||
tty->print(" ");
|
||||
if ((pcs != NULL) && (n->_idx < pc_limit)) {
|
||||
pc = pcs[n->_idx];
|
||||
st->print("%*.*x", pc_digits, pc_digits, pc);
|
||||
}
|
||||
block->dump_head(_cfg);
|
||||
st->fill_to(prefix_len);
|
||||
block->dump_head(_cfg, st);
|
||||
if (block->is_connector()) {
|
||||
tty->print_cr(" # Empty connector block");
|
||||
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) {
|
||||
tty->print_cr(" # Block is sole successor of call");
|
||||
st->fill_to(prefix_len);
|
||||
st->print_cr("# Block is sole successor of call");
|
||||
}
|
||||
|
||||
// For all instructions
|
||||
@ -2620,34 +2640,39 @@ void Compile::dump_asm(int *pcs, uint pc_limit) {
|
||||
!n->is_top() && // Debug info table constants
|
||||
!(n->is_Con() && !n->is_Mach())// Debug info table constants
|
||||
) {
|
||||
if (pcs && n->_idx < pc_limit)
|
||||
tty->print("%3.3x", pcs[n->_idx]);
|
||||
else
|
||||
tty->print(" ");
|
||||
tty->print(" %c ", 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 = ' ';
|
||||
tty->print("\t");
|
||||
n->format(_regalloc, tty);
|
||||
tty->cr();
|
||||
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()) {
|
||||
assert(delay != NULL, "no unconditional delay instruction");
|
||||
// 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 && n->_idx < pc_limit)
|
||||
tty->print("%3.3x", pcs[n->_idx]);
|
||||
else
|
||||
tty->print(" ");
|
||||
tty->print(" %c ", 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 = ' ';
|
||||
tty->print("\t");
|
||||
delay->format(_regalloc, tty);
|
||||
tty->cr();
|
||||
st->fill_to(prefix_len);
|
||||
delay->format(_regalloc, st);
|
||||
st->cr();
|
||||
delay = NULL;
|
||||
}
|
||||
|
||||
@ -2656,19 +2681,13 @@ void Compile::dump_asm(int *pcs, uint pc_limit) {
|
||||
// Print the exception table for this offset
|
||||
_handler_table.print_subtable_for(pc);
|
||||
}
|
||||
st->bol(); // Make sure we start on a new line
|
||||
}
|
||||
|
||||
if (pcs && n->_idx < pc_limit)
|
||||
tty->print_cr("%3.3x", pcs[n->_idx]);
|
||||
else
|
||||
tty->cr();
|
||||
|
||||
st->cr(); // one empty line between blocks
|
||||
assert(cut_short || delay == NULL, "no unconditional delay branch");
|
||||
|
||||
} // End of per-block dump
|
||||
tty->cr();
|
||||
|
||||
if (cut_short) tty->print_cr("*** disassembly is cut short ***");
|
||||
if (cut_short) st->print_cr("*** disassembly is cut short ***");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -1348,7 +1348,13 @@ class Compile : public Phase {
|
||||
static void print_statistics() PRODUCT_RETURN;
|
||||
|
||||
// Dump formatted assembly
|
||||
void dump_asm(int *pcs = NULL, uint pc_limit = 0) PRODUCT_RETURN;
|
||||
#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
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2019, 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
|
||||
@ -1106,12 +1106,17 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
|
||||
#endif
|
||||
|
||||
// Create an array of unused labels, one for each basic block, if printing is enabled
|
||||
#ifndef PRODUCT
|
||||
#if defined(SUPPORT_OPTO_ASSEMBLY)
|
||||
int *node_offsets = NULL;
|
||||
uint node_offset_limit = unique();
|
||||
|
||||
if (print_assembly())
|
||||
node_offsets = NEW_RESOURCE_ARRAY(int, node_offset_limit);
|
||||
if (print_assembly()) {
|
||||
node_offsets = NEW_RESOURCE_ARRAY(int, node_offset_limit);
|
||||
}
|
||||
if (node_offsets != NULL) {
|
||||
// We need to initialize. Unused array elements may contain garbage and mess up PrintOptoAssembly.
|
||||
memset(node_offsets, 0, node_offset_limit*sizeof(int));
|
||||
}
|
||||
#endif
|
||||
|
||||
NonSafepointEmitter non_safepoints(this); // emit non-safepoints lazily
|
||||
@ -1381,9 +1386,10 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
|
||||
}
|
||||
|
||||
// Save the offset for the listing
|
||||
#ifndef PRODUCT
|
||||
if (node_offsets && n->_idx < node_offset_limit)
|
||||
#if defined(SUPPORT_OPTO_ASSEMBLY)
|
||||
if ((node_offsets != NULL) && (n->_idx < node_offset_limit)) {
|
||||
node_offsets[n->_idx] = cb->insts_size();
|
||||
}
|
||||
#endif
|
||||
|
||||
// "Normal" instruction case
|
||||
@ -1430,9 +1436,10 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
|
||||
cb->set_insts_end(cb->insts_end() - Pipeline::instr_unit_size());
|
||||
|
||||
// Save the offset for the listing
|
||||
#ifndef PRODUCT
|
||||
if (node_offsets && delay_slot->_idx < node_offset_limit)
|
||||
#if defined(SUPPORT_OPTO_ASSEMBLY)
|
||||
if ((node_offsets != NULL) && (delay_slot->_idx < node_offset_limit)) {
|
||||
node_offsets[delay_slot->_idx] = cb->insts_size();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Support a SafePoint in the delay slot
|
||||
@ -1541,7 +1548,14 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
#if defined(SUPPORT_ABSTRACT_ASSEMBLY) || defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_OPTO_ASSEMBLY)
|
||||
if (print_assembly()) {
|
||||
tty->cr();
|
||||
tty->print_cr("============================= C2-compiled nmethod ==============================");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_OPTO_ASSEMBLY)
|
||||
// Dump the assembly code, including basic-block numbers
|
||||
if (print_assembly()) {
|
||||
ttyLocker ttyl; // keep the following output all in one block
|
||||
@ -1555,11 +1569,15 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
|
||||
"");
|
||||
}
|
||||
if (method() != NULL) {
|
||||
tty->print_cr("----------------------------------- MetaData -----------------------------------");
|
||||
method()->print_metadata();
|
||||
} else if (stub_name() != NULL) {
|
||||
tty->print_cr("Generating RuntimeStub - %s", stub_name());
|
||||
tty->print_cr("----------------------------- RuntimeStub %s -------------------------------", stub_name());
|
||||
}
|
||||
tty->cr();
|
||||
tty->print_cr("--------------------------------- OptoAssembly ---------------------------------");
|
||||
dump_asm(node_offsets, node_offset_limit);
|
||||
tty->print_cr("--------------------------------------------------------------------------------");
|
||||
if (xtty != NULL) {
|
||||
// print_metadata and dump_asm above may safepoint which makes us loose the ttylock.
|
||||
// Retake lock too make sure the end tag is coherent, and that xmlStream->pop_tag is done
|
||||
@ -1570,7 +1588,6 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void Compile::FillExceptionTables(uint cnt, uint *call_returns, uint *inct_starts, Label *blk_labels) {
|
||||
|
||||
@ -60,7 +60,7 @@ void StubCodeDesc::print_on(outputStream* st) const {
|
||||
st->print("%s", group());
|
||||
st->print("::");
|
||||
st->print("%s", name());
|
||||
st->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT "[ (%d bytes)", p2i(begin()), p2i(end()), size_in_bytes());
|
||||
st->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT "] (%d bytes)", p2i(begin()), p2i(end()), size_in_bytes());
|
||||
}
|
||||
|
||||
void StubCodeDesc::print() const { print_on(tty); }
|
||||
@ -98,9 +98,12 @@ void StubCodeGenerator::stub_epilog(StubCodeDesc* cdesc) {
|
||||
// of this stub.
|
||||
offset = cdesc->begin() - outer_cbuf->insts()->start();
|
||||
#endif
|
||||
cdesc->print();
|
||||
ttyLocker ttyl;
|
||||
tty->print_cr("- - - [BEGIN] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
cdesc->print_on(tty);
|
||||
tty->cr();
|
||||
Disassembler::decode(cdesc->begin(), cdesc->end(), NULL, cs, offset);
|
||||
Disassembler::decode(cdesc->begin(), cdesc->end(), tty, cs /*, offset */);
|
||||
tty->print_cr("- - - [END] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
tty->cr();
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +43,26 @@
|
||||
#define ATTRIBUTE_ALIGNED(x)
|
||||
#endif
|
||||
|
||||
// These are #defines to selectively turn on/off the Print(Opto)Assembly
|
||||
// capabilities. Choices should be led by a tradeoff between
|
||||
// code size and improved supportability.
|
||||
// if PRINT_ASSEMBLY then PRINT_ABSTRACT_ASSEMBLY must be true as well
|
||||
// to have a fallback in case hsdis is not available.
|
||||
#if defined(PRODUCT)
|
||||
#define SUPPORT_ABSTRACT_ASSEMBLY
|
||||
#define SUPPORT_ASSEMBLY
|
||||
#undef SUPPORT_OPTO_ASSEMBLY // Can't activate. In PRODUCT, many dump methods are missing.
|
||||
#undef SUPPORT_DATA_STRUCTS // Of limited use. In PRODUCT, many print methods are empty.
|
||||
#else
|
||||
#define SUPPORT_ABSTRACT_ASSEMBLY
|
||||
#define SUPPORT_ASSEMBLY
|
||||
#define SUPPORT_OPTO_ASSEMBLY
|
||||
#define SUPPORT_DATA_STRUCTS
|
||||
#endif
|
||||
#if defined(SUPPORT_ASSEMBLY) && !defined(SUPPORT_ABSTRACT_ASSEMBLY)
|
||||
#define SUPPORT_ABSTRACT_ASSEMBLY
|
||||
#endif
|
||||
|
||||
// This file holds all globally used constants & types, class (forward)
|
||||
// declarations and a few frequently used utility functions.
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user