--- old/src/hotspot/share/compiler/disassembler.cpp 2018-07-06 14:16:07.083770206 -0700 +++ new/src/hotspot/share/compiler/disassembler.cpp 2018-07-06 14:16:06.379743182 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "asm/macroAssembler.hpp" #include "ci/ciUtilities.hpp" #include "classfile/javaClasses.hpp" #include "code/codeCache.hpp" @@ -36,6 +37,7 @@ #include "runtime/os.hpp" #include "runtime/stubCodeGenerator.hpp" #include "runtime/stubRoutines.hpp" +#include "utilities/resourceHash.hpp" #include CPU_HEADER(depChecker) void* Disassembler::_library = NULL; @@ -49,7 +51,7 @@ static const char decode_instructions_virtual_name[] = "decode_instructions_virtual"; static const char decode_instructions_name[] = "decode_instructions"; static bool use_new_version = true; -#define COMMENT_COLUMN 40 LP64_ONLY(+8) /*could be an option*/ +#define COMMENT_COLUMN 52 LP64_ONLY(+8) /*could be an option*/ #define BYTES_COMMENT ";..." /* funky byte display comment */ bool Disassembler::load_library() { @@ -163,6 +165,7 @@ bool _print_bytes; address _cur_insn; int _bytes_per_line; // arch-specific formatting option + bool _print_file_name; static bool match(const char* event, const char* tag) { size_t taglen = strlen(tag); @@ -191,6 +194,51 @@ void print_insn_bytes(address pc0, address pc); void print_address(address value); + struct SourceFileInfo { + struct Link : public ResourceObj { + const char* file; + int line; + Link* next; + Link(const char* f, int l) : file(f), line(l), next(NULL) {} + }; + Link *head, *tail; + + static unsigned hash(const address& a) { + return primitive_hash
(a); + } + static bool equals(const address& a0, const address& a1) { + return primitive_equals
(a0, a1); + } + void append(const char* file, int line) { + if (tail != NULL && tail->file == file && tail->line == line) { + // Don't print duplicated lines at the same address. This could happen with C + // macros that end up having multiple "__" tokens on the same __LINE__. + return; + } + Link *link = new (ResourceObj::C_HEAP, mtInternal) Link(file, line); + if (head == NULL) { + head = tail = link; + } else { + tail->next = link; + tail = link; + } + } + SourceFileInfo(const char* file, int line) : head(NULL), tail(NULL) { + append(file, line); + } + }; + + typedef ResourceHashtable< + address, SourceFileInfo, + SourceFileInfo::hash, + SourceFileInfo::equals, + 15889, // prime number + ResourceObj::C_HEAP> SourceFileInfoTable; + + static SourceFileInfoTable _src_table; + static const char* _cached_src; + static GrowableArray* _cached_src_lines; + public: decode_env(CodeBlob* code, outputStream* output, CodeStrings c = CodeStrings(), ptrdiff_t offset = 0); @@ -212,6 +260,7 @@ _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc); // this calls reloc_string_for which calls oop::print_value_on } + print_hook_comments(pc0, _nm != NULL); // follow each complete insn by a nice newline st->cr(); } @@ -221,8 +270,93 @@ outputStream* output() { return _output; } address cur_insn() { return _cur_insn; } const char* options() { return _option_buf; } + static void hook(const char* file, int line, address pc); + void print_hook_comments(address pc, bool newline); }; +decode_env::SourceFileInfoTable decode_env::_src_table; +const char* decode_env::_cached_src = NULL; +GrowableArray* decode_env::_cached_src_lines = NULL; + +void decode_env::hook(const char* file, int line, address pc) { + // For simplication, we never free from this table. It's really not + // necessary as we add to the table only when PrintInterpreter is true, + // which means we are debugging the VM and a little bit of extra + // memory usage doesn't matter. + SourceFileInfo* found = _src_table.get(pc); + if (found != NULL) { + found->append(file, line); + } else { + SourceFileInfo sfi(file, line); + _src_table.put(pc, sfi); // sfi is copied by value + } +} + +void decode_env::print_hook_comments(address pc, bool newline) { + SourceFileInfo* found = _src_table.get(pc); + outputStream* st = output(); + if (found != NULL) { + for (SourceFileInfo::Link *link = found->head; link; link = link->next) { + const char* file = link->file; + int line = link->line; + if (_cached_src == NULL || strcmp(_cached_src, file) != 0) { + FILE* fp; + + if (_cached_src_lines != NULL) { + for (int i=0; i<_cached_src_lines->length(); i++) { + os::free((void*)_cached_src_lines->at(i)); + } + _cached_src_lines->clear(); + } else { + _cached_src_lines = new (ResourceObj::C_HEAP, mtInternal)GrowableArray(0, true); + } + + if ((fp = fopen(file, "r")) == NULL) { + _cached_src = NULL; + return; + } + _cached_src = file; + + char line[500]; // don't write lines that are too long! + while (fgets(line, sizeof(line), fp) != NULL) { + size_t len = strlen(line); + if (len > 0 && line[len-1] == '\n') { + line[len-1] = '\0'; + } + _cached_src_lines->append(os::strdup(line)); + } + fclose(fp); + _print_file_name = true; + } + + if (_print_file_name) { + // We print the file name whenever we switch to a new file, or when + // Disassembler::decode is called to disassemble a new block of code. + _print_file_name = false; + if (newline) { + st->cr(); + } + st->move_to(COMMENT_COLUMN); + st->print(";;@FILE: %s", file); + newline = true; + } + + int index = line - 1; // 1-based line number -> 0-based index. + if (index >= _cached_src_lines->length()) { + // This could happen if source file is mismatched. + } else { + const char* source_line = _cached_src_lines->at(index); + if (newline) { + st->cr(); + } + st->move_to(COMMENT_COLUMN); + st->print(";;%5d: %s", line, source_line); + newline = true; + } + } + } +} + decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c, ptrdiff_t offset) { memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields. @@ -237,6 +371,7 @@ _print_pc = true; _print_bytes = false; _bytes_per_line = Disassembler::pd_instruction_alignment(); + _print_file_name= true; // parse the global option string: collect_options(Disassembler::pd_cpu_opts()); @@ -558,3 +693,9 @@ env.decode_instructions(p, end); } + +// To prevent excessive code expansion in the interpreter generator, we +// do not inline this function into Disassembler::hook(). +void Disassembler::_hook(const char* file, int line, MacroAssembler* masm) { + decode_env::hook(file, line, masm->code_section()->end()); +}