8213084: Rework and enhance Print[Opto]Assembly output

Reviewed-by: kvn, thartmann
This commit is contained in:
Lutz Schmidt 2019-05-21 15:51:35 +02:00
parent 6b2615be6a
commit b730805159
44 changed files with 2784 additions and 706 deletions

View File

@ -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));

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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) {

View 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");
}
}

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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

View 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);
}
}

View File

@ -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

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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();
}

View File

@ -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.

View File

@ -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

View File

@ -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 */

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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();
{

View File

@ -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());

View File

@ -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

View File

@ -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,

View File

@ -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
}

View File

@ -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);
};

View File

@ -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();

View File

@ -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()));
}

View 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]");
}

View 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

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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();
}
}

View File

@ -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.