8213084: Rework and enhance Print[Opto]Assembly output
authorlucy
Tue, 21 May 2019 15:51:35 +0200
changeset 54960 e46fe26d7f77
parent 54959 00425a850a2f
child 54961 30c8a21ce002
8213084: Rework and enhance Print[Opto]Assembly output Reviewed-by: kvn, thartmann
src/hotspot/cpu/aarch64/assembler_aarch64.hpp
src/hotspot/cpu/aarch64/disassembler_aarch64.hpp
src/hotspot/cpu/arm/assembler_arm_32.hpp
src/hotspot/cpu/arm/disassembler_arm.hpp
src/hotspot/cpu/ppc/assembler_ppc.hpp
src/hotspot/cpu/ppc/disassembler_ppc.cpp
src/hotspot/cpu/ppc/disassembler_ppc.hpp
src/hotspot/cpu/ppc/vm_version_ppc.cpp
src/hotspot/cpu/s390/assembler_s390.hpp
src/hotspot/cpu/s390/assembler_s390.inline.hpp
src/hotspot/cpu/s390/disassembler_s390.cpp
src/hotspot/cpu/s390/disassembler_s390.hpp
src/hotspot/cpu/s390/s390.ad
src/hotspot/cpu/s390/vm_version_s390.cpp
src/hotspot/cpu/sparc/assembler_sparc.hpp
src/hotspot/cpu/sparc/disassembler_sparc.hpp
src/hotspot/cpu/sparc/sparc.ad
src/hotspot/cpu/x86/assembler_x86.hpp
src/hotspot/cpu/x86/disassembler_x86.hpp
src/hotspot/cpu/x86/x86_64.ad
src/hotspot/cpu/zero/assembler_zero.hpp
src/hotspot/cpu/zero/disassembler_zero.hpp
src/hotspot/share/asm/codeBuffer.cpp
src/hotspot/share/asm/codeBuffer.hpp
src/hotspot/share/code/codeBlob.cpp
src/hotspot/share/code/codeBlob.hpp
src/hotspot/share/code/exceptionHandlerTable.cpp
src/hotspot/share/code/nmethod.cpp
src/hotspot/share/code/nmethod.hpp
src/hotspot/share/code/pcDesc.cpp
src/hotspot/share/code/pcDesc.hpp
src/hotspot/share/code/vmreg.cpp
src/hotspot/share/code/vtableStubs.cpp
src/hotspot/share/compiler/abstractDisassembler.cpp
src/hotspot/share/compiler/abstractDisassembler.hpp
src/hotspot/share/compiler/disassembler.cpp
src/hotspot/share/compiler/disassembler.hpp
src/hotspot/share/compiler/oopMap.cpp
src/hotspot/share/opto/block.cpp
src/hotspot/share/opto/compile.cpp
src/hotspot/share/opto/compile.hpp
src/hotspot/share/opto/output.cpp
src/hotspot/share/runtime/stubCodeGenerator.cpp
src/hotspot/share/utilities/globalDefinitions.hpp
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp	Tue May 21 15:51:35 2019 +0200
@@ -629,6 +629,14 @@
 
   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));
--- a/src/hotspot/cpu/aarch64/disassembler_aarch64.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/aarch64/disassembler_aarch64.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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
--- a/src/hotspot/cpu/arm/assembler_arm_32.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/arm/assembler_arm_32.hpp	Tue May 21 15:51:35 2019 +0200
@@ -199,6 +199,14 @@
   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);
--- a/src/hotspot/cpu/arm/disassembler_arm.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/arm/disassembler_arm.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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
--- a/src/hotspot/cpu/ppc/assembler_ppc.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp	Tue May 21 15:51:35 2019 +0200
@@ -929,11 +929,13 @@
 
   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) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/ppc/disassembler_ppc.cpp	Tue May 21 15:51:35 2019 +0200
@@ -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");
+  }
+}
--- a/src/hotspot/cpu/ppc/disassembler_ppc.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/ppc/disassembler_ppc.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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
--- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp	Tue May 21 15:51:35 2019 +0200
@@ -708,6 +708,8 @@
   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 @@
 
   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);
--- a/src/hotspot/cpu/s390/assembler_s390.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/s390/assembler_s390.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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 @@
   //-----------------------------------------------
 
   // 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.
--- a/src/hotspot/cpu/s390/assembler_s390.inline.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/s390/assembler_s390.inline.hpp	Tue May 21 15:51:35 2019 +0200
@@ -1344,7 +1344,7 @@
 
 // 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/s390/disassembler_s390.cpp	Tue May 21 15:51:35 2019 +0200
@@ -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);
+  }
+}
--- a/src/hotspot/cpu/s390/disassembler_s390.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/s390/disassembler_s390.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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
--- a/src/hotspot/cpu/s390/s390.ad	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/s390/s390.ad	Tue May 21 15:51:35 2019 +0200
@@ -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 @@
     __ z_br(R1_ic_miss_stub_addr);
     __ bind(valid);
   }
-
 }
 
 uint MachUEPNode::size(PhaseRegAlloc *ra_) const {
@@ -4318,7 +4317,7 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
             (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 @@
     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 @@
     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 @@
              !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 @@
              !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 @@
     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 @@
     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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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_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 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 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 @@
   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 @@
   // 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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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;
--- a/src/hotspot/cpu/s390/vm_version_s390.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/s390/vm_version_s390.cpp	Tue May 21 15:51:35 2019 +0200
@@ -804,6 +804,8 @@
   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 @@
     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.
--- a/src/hotspot/cpu/sparc/assembler_sparc.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/sparc/assembler_sparc.hpp	Tue May 21 15:51:35 2019 +0200
@@ -335,6 +335,14 @@
     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);
--- a/src/hotspot/cpu/sparc/disassembler_sparc.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/sparc/disassembler_sparc.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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
--- a/src/hotspot/cpu/sparc/sparc.ad	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/sparc/sparc.ad	Tue May 21 15:51:35 2019 +0200
@@ -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 @@
 #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();
   }
--- a/src/hotspot/cpu/x86/assembler_x86.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/x86/assembler_x86.hpp	Tue May 21 15:51:35 2019 +0200
@@ -630,6 +630,17 @@
     _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.
--- a/src/hotspot/cpu/x86/disassembler_x86.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/x86/disassembler_x86.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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
--- a/src/hotspot/cpu/x86/x86_64.ad	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/x86/x86_64.ad	Tue May 21 15:51:35 2019 +0200
@@ -918,19 +918,19 @@
     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 @@
   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 @@
 
   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 @@
 %{
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 */
--- a/src/hotspot/cpu/zero/assembler_zero.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/zero/assembler_zero.hpp	Tue May 21 15:51:35 2019 +0200
@@ -37,6 +37,12 @@
 
  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 {
--- a/src/hotspot/cpu/zero/disassembler_zero.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/cpu/zero/disassembler_zero.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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
--- a/src/hotspot/share/asm/codeBuffer.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/asm/codeBuffer.cpp	Tue May 21 15:51:35 2019 +0200
@@ -86,7 +86,8 @@
 // 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 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 @@
 
 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 @@
 
 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 @@
   }
 }
 
+// Directly disassemble code buffer.
+void CodeBuffer::decode(address start, address end) {
+  ttyLocker ttyl;
+  Disassembler::decode(this, start, end, tty);
+}
+
 #endif // PRODUCT
--- a/src/hotspot/share/asm/codeBuffer.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/asm/codeBuffer.hpp	Tue May 21 15:51:35 2019 +0200
@@ -289,6 +289,7 @@
   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 @@
   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 @@
 
   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 @@
 #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 @@
     }
   }
 
+  // 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 @@
   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)
--- a/src/hotspot/share/code/codeBlob.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/code/codeBlob.cpp	Tue May 21 15:51:35 2019 +0200
@@ -183,8 +183,14 @@
     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::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();
   {
--- a/src/hotspot/share/code/codeBlob.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/code/codeBlob.hpp	Tue May 21 15:51:35 2019 +0200
@@ -211,7 +211,7 @@
   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 @@
   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());
--- a/src/hotspot/share/code/exceptionHandlerTable.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/code/exceptionHandlerTable.cpp	Tue May 21 15:51:35 2019 +0200
@@ -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 @@
 }
 
 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) {
--- a/src/hotspot/share/code/nmethod.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/code/nmethod.cpp	Tue May 21 15:51:35 2019 +0200
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "jvm.h"
+#include "asm/assembler.inline.hpp"
 #include "code/codeCache.hpp"
 #include "code/compiledIC.hpp"
 #include "code/compiledMethod.inline.hpp"
@@ -456,14 +457,17 @@
   {
     MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     int native_nmethod_size = CodeBlob::allocation_size(code_buffer, sizeof(nmethod));
+
     CodeOffsets offsets;
     offsets.set_value(CodeOffsets::Verified_Entry, vep_offset);
     offsets.set_value(CodeOffsets::Frame_Complete, frame_complete);
-    nm = new (native_nmethod_size, CompLevel_none) nmethod(method(), compiler_none, native_nmethod_size,
-                                            compile_id, &offsets,
-                                            code_buffer, frame_size,
-                                            basic_lock_owner_sp_offset,
-                                            basic_lock_sp_offset, oop_maps);
+    nm = new (native_nmethod_size, CompLevel_none)
+    nmethod(method(), compiler_none, native_nmethod_size,
+            compile_id, &offsets,
+            code_buffer, frame_size,
+            basic_lock_owner_sp_offset,
+            basic_lock_sp_offset,
+            oop_maps);
     NOT_PRODUCT(if (nm != NULL)  native_nmethod_stats.note_native_nmethod(nm));
   }
 
@@ -593,9 +597,9 @@
   _native_basic_lock_sp_offset(basic_lock_sp_offset)
 {
   {
-    int scopes_data_offset = 0;
-    int deoptimize_offset       = 0;
-    int deoptimize_mh_offset    = 0;
+    int scopes_data_offset   = 0;
+    int deoptimize_offset    = 0;
+    int deoptimize_mh_offset = 0;
 
     debug_only(NoSafepointVerifier nsv;)
     assert_locked_or_safepoint(CodeCache_lock);
@@ -658,18 +662,32 @@
       xtty->stamp();
       xtty->end_head(" address='" INTPTR_FORMAT "'", (intptr_t) this);
     }
-    // print the header part first
-    print();
-    // then print the requested information
+    // Print the header part, then print the requested information.
+    // This is both handled in decode2(), called via print_code() -> decode()
     if (PrintNativeNMethods) {
+      tty->print_cr("-------------------------- Assembly (native nmethod) ---------------------------");
       print_code();
-      if (oop_maps != NULL) {
-        oop_maps->print();
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+#if defined(SUPPORT_DATA_STRUCTS)
+      if (AbstractDisassembler::show_structs()) {
+        if (oop_maps != NULL) {
+          tty->print("oop maps:"); // oop_maps->print_on(tty) outputs a cr() at the beginning
+          oop_maps->print_on(tty);
+          tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+        }
+      }
+#endif
+    } else {
+      print(); // print the header part only.
+    }
+#if defined(SUPPORT_DATA_STRUCTS)
+    if (AbstractDisassembler::show_structs()) {
+      if (PrintRelocations) {
+        print_relocations();
+        tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
       }
     }
-    if (PrintRelocations) {
-      print_relocations();
-    }
+#endif
     if (xtty != NULL) {
       xtty->tail("print_native_nmethod");
     }
@@ -746,22 +764,21 @@
       } else {
         _deopt_mh_handler_begin = NULL;
       }
-    } else {
+    } else
 #endif
-    // Exception handler and deopt handler are in the stub section
-    assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set");
-    assert(offsets->value(CodeOffsets::Deopt     ) != -1, "must be set");
-
-    _exception_offset       = _stub_offset          + offsets->value(CodeOffsets::Exceptions);
-    _deopt_handler_begin    = (address) this + _stub_offset          + offsets->value(CodeOffsets::Deopt);
-    if (offsets->value(CodeOffsets::DeoptMH) != -1) {
-      _deopt_mh_handler_begin  = (address) this + _stub_offset          + offsets->value(CodeOffsets::DeoptMH);
-    } else {
-      _deopt_mh_handler_begin  = NULL;
+    {
+      // Exception handler and deopt handler are in the stub section
+      assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set");
+      assert(offsets->value(CodeOffsets::Deopt     ) != -1, "must be set");
+
+      _exception_offset       = _stub_offset          + offsets->value(CodeOffsets::Exceptions);
+      _deopt_handler_begin    = (address) this + _stub_offset          + offsets->value(CodeOffsets::Deopt);
+      if (offsets->value(CodeOffsets::DeoptMH) != -1) {
+        _deopt_mh_handler_begin  = (address) this + _stub_offset          + offsets->value(CodeOffsets::DeoptMH);
+      } else {
+        _deopt_mh_handler_begin  = NULL;
+      }
     }
-#if INCLUDE_JVMCI
-    }
-#endif
     if (offsets->value(CodeOffsets::UnwindHandler) != -1) {
       _unwind_handler_offset = code_offset()         + offsets->value(CodeOffsets::UnwindHandler);
     } else {
@@ -787,8 +804,7 @@
     _verified_entry_point    = code_begin()          + offsets->value(CodeOffsets::Verified_Entry);
     _osr_entry_point         = code_begin()          + offsets->value(CodeOffsets::OSR_Entry);
     _exception_cache         = NULL;
-
-    _scopes_data_begin = (address) this + scopes_data_offset;
+    _scopes_data_begin       = (address) this + scopes_data_offset;
 
     _pc_desc_container.reset_to(scopes_pcs_begin());
 
@@ -909,33 +925,72 @@
     xtty->stamp();
     xtty->end_head();
   }
-  // print the header part first
-  print();
-  // then print the requested information
+  // Print the header part, then print the requested information.
+  // This is both handled in decode2().
   if (printmethod) {
-    print_code();
-    print_pcs();
-    if (oop_maps()) {
-      oop_maps()->print();
+    HandleMark hm;
+    ResourceMark m;
+    if (is_compiled_by_c1()) {
+      tty->cr();
+      tty->print_cr("============================= C1-compiled nmethod ==============================");
+    }
+    if (is_compiled_by_jvmci()) {
+      tty->cr();
+      tty->print_cr("=========================== JVMCI-compiled nmethod =============================");
+    }
+    tty->print_cr("----------------------------------- Assembly -----------------------------------");
+    decode2(tty);
+#if defined(SUPPORT_DATA_STRUCTS)
+    if (AbstractDisassembler::show_structs()) {
+      // Print the oops from the underlying CodeBlob as well.
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+      print_oops(tty);
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+      print_metadata(tty);
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+      print_pcs();
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+      if (oop_maps() != NULL) {
+        tty->print("oop maps:"); // oop_maps()->print_on(tty) outputs a cr() at the beginning
+        oop_maps()->print_on(tty);
+        tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+      }
+    }
+#endif
+  } else {
+    print(); // print the header part only.
+  }
+
+#if defined(SUPPORT_DATA_STRUCTS)
+  if (AbstractDisassembler::show_structs()) {
+    if (printmethod || PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) {
+      print_scopes();
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+    }
+    if (printmethod || PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) {
+      print_relocations();
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+    }
+    if (printmethod || PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) {
+      print_dependencies();
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+    }
+    if (printmethod || PrintExceptionHandlers) {
+      print_handler_table();
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+      print_nul_chk_table();
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+    }
+
+    if (printmethod) {
+      print_recorded_oops();
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
+      print_recorded_metadata();
+      tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
     }
   }
-  if (printmethod || PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) {
-    print_scopes();
-  }
-  if (printmethod || PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) {
-    print_relocations();
-  }
-  if (printmethod || PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) {
-    print_dependencies();
-  }
-  if (printmethod || PrintExceptionHandlers) {
-    print_handler_table();
-    print_nul_chk_table();
-  }
-  if (printmethod) {
-    print_recorded_oops();
-    print_recorded_metadata();
-  }
+#endif
+
   if (xtty != NULL) {
     xtty->tail("print_nmethod");
   }
@@ -2062,10 +2117,9 @@
     assert(cb != NULL && cb == this, "");
     ttyLocker ttyl;
     tty->print_cr("implicit exception happened at " INTPTR_FORMAT, p2i(pc));
-    print();
+    // Print all available nmethod info.
+    print_nmethod(true);
     method()->print_codes();
-    print_code();
-    print_pcs();
   }
 #endif
   if (cont_offset == 0) {
@@ -2076,7 +2130,6 @@
 }
 
 
-
 void nmethod_init() {
   // make sure you didn't forget to adjust the filler fields
   assert(sizeof(nmethod) % oopSize == 0, "nmethod size must be multiple of a word");
@@ -2124,12 +2177,14 @@
   bool ok() { return _ok; }
   virtual void do_oop(oop* p) {
     if (oopDesc::is_oop_or_null(*p)) return;
+    // Print diagnostic information before calling print_nmethod().
+    // Assertions therein might prevent call from returning.
+    tty->print_cr("*** non-oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)",
+                  p2i(*p), p2i(p), (int)((intptr_t)p - (intptr_t)_nm));
     if (_ok) {
       _nm->print_nmethod(true);
       _ok = false;
     }
-    tty->print_cr("*** non-oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)",
-                  p2i(*p), p2i(p), (int)((intptr_t)p - (intptr_t)_nm));
   }
   virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
 };
@@ -2238,107 +2293,104 @@
 // Printing operations
 
 void nmethod::print() const {
+  ttyLocker ttyl;   // keep the following output all in one block
+  print(tty);
+}
+
+void nmethod::print(outputStream* st) const {
   ResourceMark rm;
-  ttyLocker ttyl;   // keep the following output all in one block
-
-  tty->print("Compiled method ");
+
+  st->print("Compiled method ");
 
   if (is_compiled_by_c1()) {
-    tty->print("(c1) ");
+    st->print("(c1) ");
   } else if (is_compiled_by_c2()) {
-    tty->print("(c2) ");
+    st->print("(c2) ");
   } else if (is_compiled_by_jvmci()) {
-    tty->print("(JVMCI) ");
+    st->print("(JVMCI) ");
   } else {
-    tty->print("(nm) ");
+    st->print("(n/a) ");
   }
 
   print_on(tty, NULL);
 
   if (WizardMode) {
-    tty->print("((nmethod*) " INTPTR_FORMAT ") ", p2i(this));
-    tty->print(" for method " INTPTR_FORMAT , p2i(method()));
-    tty->print(" { ");
-    tty->print_cr("%s ", state());
-    tty->print_cr("}:");
+    st->print("((nmethod*) " INTPTR_FORMAT ") ", p2i(this));
+    st->print(" for method " INTPTR_FORMAT , p2i(method()));
+    st->print(" { ");
+    st->print_cr("%s ", state());
+    st->print_cr("}:");
   }
-  if (size              () > 0) tty->print_cr(" total in heap  [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(this),
-                                              p2i(this) + size(),
-                                              size());
-  if (relocation_size   () > 0) tty->print_cr(" relocation     [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(relocation_begin()),
-                                              p2i(relocation_end()),
-                                              relocation_size());
-  if (consts_size       () > 0) tty->print_cr(" constants      [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(consts_begin()),
-                                              p2i(consts_end()),
-                                              consts_size());
-  if (insts_size        () > 0) tty->print_cr(" main code      [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(insts_begin()),
-                                              p2i(insts_end()),
-                                              insts_size());
-  if (stub_size         () > 0) tty->print_cr(" stub code      [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(stub_begin()),
-                                              p2i(stub_end()),
-                                              stub_size());
-  if (oops_size         () > 0) tty->print_cr(" oops           [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(oops_begin()),
-                                              p2i(oops_end()),
-                                              oops_size());
-  if (metadata_size      () > 0) tty->print_cr(" metadata       [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(metadata_begin()),
-                                              p2i(metadata_end()),
-                                              metadata_size());
-  if (scopes_data_size  () > 0) tty->print_cr(" scopes data    [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(scopes_data_begin()),
-                                              p2i(scopes_data_end()),
-                                              scopes_data_size());
-  if (scopes_pcs_size   () > 0) tty->print_cr(" scopes pcs     [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(scopes_pcs_begin()),
-                                              p2i(scopes_pcs_end()),
-                                              scopes_pcs_size());
-  if (dependencies_size () > 0) tty->print_cr(" dependencies   [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(dependencies_begin()),
-                                              p2i(dependencies_end()),
-                                              dependencies_size());
-  if (handler_table_size() > 0) tty->print_cr(" handler table  [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(handler_table_begin()),
-                                              p2i(handler_table_end()),
-                                              handler_table_size());
-  if (nul_chk_table_size() > 0) tty->print_cr(" nul chk table  [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(nul_chk_table_begin()),
-                                              p2i(nul_chk_table_end()),
-                                              nul_chk_table_size());
+  if (size              () > 0) st->print_cr(" total in heap  [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(this),
+                                             p2i(this) + size(),
+                                             size());
+  if (relocation_size   () > 0) st->print_cr(" relocation     [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(relocation_begin()),
+                                             p2i(relocation_end()),
+                                             relocation_size());
+  if (consts_size       () > 0) st->print_cr(" constants      [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(consts_begin()),
+                                             p2i(consts_end()),
+                                             consts_size());
+  if (insts_size        () > 0) st->print_cr(" main code      [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(insts_begin()),
+                                             p2i(insts_end()),
+                                             insts_size());
+  if (stub_size         () > 0) st->print_cr(" stub code      [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(stub_begin()),
+                                             p2i(stub_end()),
+                                             stub_size());
+  if (oops_size         () > 0) st->print_cr(" oops           [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(oops_begin()),
+                                             p2i(oops_end()),
+                                             oops_size());
+  if (metadata_size     () > 0) st->print_cr(" metadata       [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(metadata_begin()),
+                                             p2i(metadata_end()),
+                                             metadata_size());
+  if (scopes_data_size  () > 0) st->print_cr(" scopes data    [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(scopes_data_begin()),
+                                             p2i(scopes_data_end()),
+                                             scopes_data_size());
+  if (scopes_pcs_size   () > 0) st->print_cr(" scopes pcs     [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(scopes_pcs_begin()),
+                                             p2i(scopes_pcs_end()),
+                                             scopes_pcs_size());
+  if (dependencies_size () > 0) st->print_cr(" dependencies   [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(dependencies_begin()),
+                                             p2i(dependencies_end()),
+                                             dependencies_size());
+  if (handler_table_size() > 0) st->print_cr(" handler table  [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(handler_table_begin()),
+                                             p2i(handler_table_end()),
+                                             handler_table_size());
+  if (nul_chk_table_size() > 0) st->print_cr(" nul chk table  [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(nul_chk_table_begin()),
+                                             p2i(nul_chk_table_end()),
+                                             nul_chk_table_size());
 #if INCLUDE_JVMCI
-  if (speculations_size () > 0) tty->print_cr(" speculations   [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(speculations_begin()),
-                                              p2i(speculations_end()),
-                                              speculations_size());
-  if (jvmci_data_size   () > 0) tty->print_cr(" JVMCI data     [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
-                                              p2i(jvmci_data_begin()),
-                                              p2i(jvmci_data_end()),
-                                              jvmci_data_size());
+  if (speculations_size () > 0) st->print_cr(" speculations   [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(speculations_begin()),
+                                             p2i(speculations_end()),
+                                             speculations_size());
+  if (jvmci_data_size   () > 0) st->print_cr(" JVMCI data     [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                             p2i(jvmci_data_begin()),
+                                             p2i(jvmci_data_end()),
+                                             jvmci_data_size());
 #endif
 }
 
-#ifndef PRODUCT
-
-void nmethod::print_scopes() {
-  // Find the first pc desc for all scopes in the code and print it.
-  ResourceMark rm;
-  for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) {
-    if (p->scope_decode_offset() == DebugInformationRecorder::serialized_null)
-      continue;
-
-    ScopeDesc* sd = scope_desc_at(p->real_pc(this));
-    while (sd != NULL) {
-      sd->print_on(tty, p);
-      sd = sd->sender();
-    }
-  }
+void nmethod::print_code() {
+  HandleMark hm;
+  ResourceMark m;
+  ttyLocker ttyl;
+  // Call the specialized decode method of this class.
+  decode(tty);
 }
 
+#ifndef PRODUCT  // called InstanceKlass methods are available only then. Declared as PRODUCT_RETURN
+
 void nmethod::print_dependencies() {
   ResourceMark rm;
   ttyLocker ttyl;   // keep the following output all in one block
@@ -2354,57 +2406,379 @@
     deps.log_dependency();  // put it into the xml log also
   }
 }
-
-
+#endif
+
+#if defined(SUPPORT_DATA_STRUCTS)
+
+// Print the oops from the underlying CodeBlob.
+void nmethod::print_oops(outputStream* st) {
+  HandleMark hm;
+  ResourceMark m;
+  st->print("Oops:");
+  if (oops_begin() < oops_end()) {
+    st->cr();
+    for (oop* p = oops_begin(); p < oops_end(); p++) {
+      Disassembler::print_location((unsigned char*)p, (unsigned char*)oops_begin(), (unsigned char*)oops_end(), st, true, false);
+      st->print(PTR_FORMAT " ", *((uintptr_t*)p));
+      if (*p == Universe::non_oop_word()) {
+        st->print_cr("NON_OOP");
+        continue;  // skip non-oops
+      }
+      if (*p == NULL) {
+        st->print_cr("NULL-oop");
+        continue;  // skip non-oops
+      }
+      (*p)->print_value_on(st);
+      st->cr();
+    }
+  } else {
+    st->print_cr(" <list empty>");
+  }
+}
+
+// Print metadata pool.
+void nmethod::print_metadata(outputStream* st) {
+  HandleMark hm;
+  ResourceMark m;
+  st->print("Metadata:");
+  if (metadata_begin() < metadata_end()) {
+    st->cr();
+    for (Metadata** p = metadata_begin(); p < metadata_end(); p++) {
+      Disassembler::print_location((unsigned char*)p, (unsigned char*)metadata_begin(), (unsigned char*)metadata_end(), st, true, false);
+      st->print(PTR_FORMAT " ", *((uintptr_t*)p));
+      if (*p && *p != Universe::non_oop_word()) {
+        (*p)->print_value_on(st);
+      }
+      st->cr();
+    }
+  } else {
+    st->print_cr(" <list empty>");
+  }
+}
+
+#ifndef PRODUCT  // ScopeDesc::print_on() is available only then. Declared as PRODUCT_RETURN
+void nmethod::print_scopes_on(outputStream* st) {
+  // Find the first pc desc for all scopes in the code and print it.
+  ResourceMark rm;
+  st->print("scopes:");
+  if (scopes_pcs_begin() < scopes_pcs_end()) {
+    st->cr();
+    for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) {
+      if (p->scope_decode_offset() == DebugInformationRecorder::serialized_null)
+        continue;
+
+      ScopeDesc* sd = scope_desc_at(p->real_pc(this));
+      while (sd != NULL) {
+        sd->print_on(st, p);  // print output ends with a newline
+        sd = sd->sender();
+      }
+    }
+  } else {
+    st->print_cr(" <list empty>");
+  }
+}
+#endif
+
+#ifndef PRODUCT  // RelocIterator does support printing only then.
 void nmethod::print_relocations() {
   ResourceMark m;       // in case methods get printed via the debugger
   tty->print_cr("relocations:");
   RelocIterator iter(this);
   iter.print();
 }
-
-
-void nmethod::print_pcs() {
+#endif
+
+void nmethod::print_pcs_on(outputStream* st) {
   ResourceMark m;       // in case methods get printed via debugger
-  tty->print_cr("pc-bytecode offsets:");
-  for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) {
-    p->print(this);
+  st->print("pc-bytecode offsets:");
+  if (scopes_pcs_begin() < scopes_pcs_end()) {
+    st->cr();
+    for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) {
+      p->print_on(st, this);  // print output ends with a newline
+    }
+  } else {
+    st->print_cr(" <list empty>");
   }
 }
 
+void nmethod::print_handler_table() {
+  ExceptionHandlerTable(this).print();
+}
+
+void nmethod::print_nul_chk_table() {
+  ImplicitExceptionTable(this).print(code_begin());
+}
+
 void nmethod::print_recorded_oops() {
-  tty->print_cr("Recorded oops:");
-  for (int i = 0; i < oops_count(); i++) {
-    oop o = oop_at(i);
-    tty->print("#%3d: " INTPTR_FORMAT " ", i, p2i(o));
-    if (o == Universe::non_oop_word()) {
-      tty->print("non-oop word");
-    } else {
-      if (o != NULL) {
-        o->print_value();
+  const int n = oops_count();
+  const int log_n = (n<10) ? 1 : (n<100) ? 2 : (n<1000) ? 3 : (n<10000) ? 4 : 6;
+  tty->print("Recorded oops:");
+  if (n > 0) {
+    tty->cr();
+    for (int i = 0; i < n; i++) {
+      oop o = oop_at(i);
+      tty->print("#%*d: " INTPTR_FORMAT " ", log_n, i, p2i(o));
+      if (o == (oop)Universe::non_oop_word()) {
+        tty->print("non-oop word");
+      } else if (o == NULL) {
+        tty->print("NULL-oop");
       } else {
-        tty->print_cr("NULL");
+        o->print_value_on(tty);
       }
+      tty->cr();
     }
-    tty->cr();
+  } else {
+    tty->print_cr(" <list empty>");
   }
 }
 
 void nmethod::print_recorded_metadata() {
-  tty->print_cr("Recorded metadata:");
-  for (int i = 0; i < metadata_count(); i++) {
-    Metadata* m = metadata_at(i);
-    tty->print("#%3d: " INTPTR_FORMAT " ", i, p2i(m));
-    if (m == (Metadata*)Universe::non_oop_word()) {
-      tty->print("non-metadata word");
-    } else {
-      Metadata::print_value_on_maybe_null(tty, m);
+  const int n = metadata_count();
+  const int log_n = (n<10) ? 1 : (n<100) ? 2 : (n<1000) ? 3 : (n<10000) ? 4 : 6;
+  tty->print("Recorded metadata:");
+  if (n > 0) {
+    tty->cr();
+    for (int i = 0; i < n; i++) {
+      Metadata* m = metadata_at(i);
+      tty->print("#%*d: " INTPTR_FORMAT " ", log_n, i, p2i(m));
+      if (m == (Metadata*)Universe::non_oop_word()) {
+        tty->print("non-metadata word");
+      } else if (m == NULL) {
+        tty->print("NULL-oop");
+      } else {
+        Metadata::print_value_on_maybe_null(tty, m);
+      }
+      tty->cr();
     }
-    tty->cr();
+  } else {
+    tty->print_cr(" <list empty>");
   }
 }
-
-#endif // PRODUCT
+#endif
+
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+
+void nmethod::print_constant_pool(outputStream* st) {
+  //-----------------------------------
+  //---<  Print the constant pool  >---
+  //-----------------------------------
+  int consts_size = this->consts_size();
+  if ( consts_size > 0 ) {
+    unsigned char* cstart = this->consts_begin();
+    unsigned char* cp     = cstart;
+    unsigned char* cend   = cp + consts_size;
+    unsigned int   bytes_per_line = 4;
+    unsigned int   CP_alignment   = 8;
+    unsigned int   n;
+
+    st->cr();
+
+    //---<  print CP header to make clear what's printed  >---
+    if( ((uintptr_t)cp&(CP_alignment-1)) == 0 ) {
+      n = bytes_per_line;
+      st->print_cr("[Constant Pool]");
+      Disassembler::print_location(cp, cstart, cend, st, true, true);
+      Disassembler::print_hexdata(cp, n, st, true);
+      st->cr();
+    } else {
+      n = (uintptr_t)cp&(bytes_per_line-1);
+      st->print_cr("[Constant Pool (unaligned)]");
+    }
+
+    //---<  print CP contents, bytes_per_line at a time  >---
+    while (cp < cend) {
+      Disassembler::print_location(cp, cstart, cend, st, true, false);
+      Disassembler::print_hexdata(cp, n, st, false);
+      cp += n;
+      n   = bytes_per_line;
+      st->cr();
+    }
+
+    //---<  Show potential alignment gap between constant pool and code  >---
+    cend = code_begin();
+    if( cp < cend ) {
+      n = 4;
+      st->print_cr("[Code entry alignment]");
+      while (cp < cend) {
+        Disassembler::print_location(cp, cstart, cend, st, false, false);
+        cp += n;
+        st->cr();
+      }
+    }
+  } else {
+    st->print_cr("[Constant Pool (empty)]");
+  }
+  st->cr();
+}
+
+#endif
+
+// Disassemble this nmethod.
+// Print additional debug information, if requested. This could be code
+// comments, block comments, profiling counters, etc.
+// The undisassembled format is useful no disassembler library is available.
+// The resulting hex dump (with markers) can be disassembled later, or on
+// another system, when/where a disassembler library is available.
+void nmethod::decode2(outputStream* ost) const {
+
+  // Called from frame::back_trace_with_decode without ResourceMark.
+  ResourceMark rm;
+
+  // Make sure we have a valid stream to print on.
+  outputStream* st = ost ? ost : tty;
+
+#if defined(SUPPORT_ABSTRACT_ASSEMBLY) && ! defined(SUPPORT_ASSEMBLY)
+  const bool use_compressed_format    = true;
+  const bool compressed_with_comments = use_compressed_format && (AbstractDisassembler::show_comment() ||
+                                                                  AbstractDisassembler::show_block_comment());
+#else
+  const bool use_compressed_format    = Disassembler::is_abstract();
+  const bool compressed_with_comments = use_compressed_format && (AbstractDisassembler::show_comment() ||
+                                                                  AbstractDisassembler::show_block_comment());
+#endif
+
+  st->cr();
+  this->print(st);
+  st->cr();
+
+#if defined(SUPPORT_ASSEMBLY)
+  //----------------------------------
+  //---<  Print real disassembly  >---
+  //----------------------------------
+  if (! use_compressed_format) {
+    Disassembler::decode(const_cast<nmethod*>(this), st);
+    return;
+  }
+#endif
+
+#if defined(SUPPORT_ABSTRACT_ASSEMBLY)
+
+  // Compressed undisassembled disassembly format.
+  // The following stati are defined/supported:
+  //   = 0 - currently at bol() position, nothing printed yet on current line.
+  //   = 1 - currently at position after print_location().
+  //   > 1 - in the midst of printing instruction stream bytes.
+  int        compressed_format_idx    = 0;
+  int        code_comment_column      = 0;
+  const int  instr_maxlen             = Assembler::instr_maxlen();
+  const uint tabspacing               = 8;
+  unsigned char* start = this->code_begin();
+  unsigned char* p     = this->code_begin();
+  unsigned char* end   = this->code_end();
+  unsigned char* pss   = p; // start of a code section (used for offsets)
+
+  if ((start == NULL) || (end == NULL)) {
+    st->print_cr("PrintAssembly not possible due to uninitialized section pointers");
+    return;
+  }
+#endif
+
+#if defined(SUPPORT_ABSTRACT_ASSEMBLY)
+  //---<  plain abstract disassembly, no comments or anything, just section headers  >---
+  if (use_compressed_format && ! compressed_with_comments) {
+    const_cast<nmethod*>(this)->print_constant_pool(st);
+
+    //---<  Open the output (Marker for post-mortem disassembler)  >---
+    st->print_cr("[MachCode]");
+    const char* header = NULL;
+    address p0 = p;
+    while (p < end) {
+      address pp = p;
+      while ((p < end) && (header == NULL)) {
+        header = nmethod_section_label(p);
+        pp  = p;
+        p  += Assembler::instr_len(p);
+      }
+      if (pp > p0) {
+        AbstractDisassembler::decode_range_abstract(p0, pp, start, end, st, Assembler::instr_maxlen());
+        p0 = pp;
+        p  = pp;
+        header = NULL;
+      } else if (header != NULL) {
+        st->bol();
+        st->print_cr("%s", header);
+        header = NULL;
+      }
+    }
+    //---<  Close the output (Marker for post-mortem disassembler)  >---
+    st->bol();
+    st->print_cr("[/MachCode]");
+    return;
+  }
+#endif
+
+#if defined(SUPPORT_ABSTRACT_ASSEMBLY)
+  //---<  abstract disassembly with comments and section headers merged in  >---
+  if (compressed_with_comments) {
+    const_cast<nmethod*>(this)->print_constant_pool(st);
+
+    //---<  Open the output (Marker for post-mortem disassembler)  >---
+    st->print_cr("[MachCode]");
+    while ((p < end) && (p != NULL)) {
+      const int instruction_size_in_bytes = Assembler::instr_len(p);
+
+      //---<  Block comments for nmethod. Interrupts instruction stream, if any.  >---
+      // Outputs a bol() before and a cr() after, but only if a comment is printed.
+      // Prints nmethod_section_label as well.
+      if (AbstractDisassembler::show_block_comment()) {
+        print_block_comment(st, p);
+        if (st->position() == 0) {
+          compressed_format_idx = 0;
+        }
+      }
+
+      //---<  New location information after line break  >---
+      if (compressed_format_idx == 0) {
+        code_comment_column   = Disassembler::print_location(p, pss, end, st, false, false);
+        compressed_format_idx = 1;
+      }
+
+      //---<  Code comment for current instruction. Address range [p..(p+len))  >---
+      unsigned char* p_end = p + (ssize_t)instruction_size_in_bytes;
+      S390_ONLY(if (p_end > end) p_end = end;) // avoid getting past the end
+
+      if (AbstractDisassembler::show_comment() && const_cast<nmethod*>(this)->has_code_comment(p, p_end)) {
+        //---<  interrupt instruction byte stream for code comment  >---
+        if (compressed_format_idx > 1) {
+          st->cr();  // interrupt byte stream
+          st->cr();  // add an empty line
+          code_comment_column = Disassembler::print_location(p, pss, end, st, false, false);
+        }
+        const_cast<nmethod*>(this)->print_code_comment_on(st, code_comment_column, p, p_end );
+        st->bol();
+        compressed_format_idx = 0;
+      }
+
+      //---<  New location information after line break  >---
+      if (compressed_format_idx == 0) {
+        code_comment_column   = Disassembler::print_location(p, pss, end, st, false, false);
+        compressed_format_idx = 1;
+      }
+
+      //---<  Nicely align instructions for readability  >---
+      if (compressed_format_idx > 1) {
+        Disassembler::print_delimiter(st);
+      }
+
+      //---<  Now, finally, print the actual instruction bytes  >---
+      unsigned char* p0 = p;
+      p = Disassembler::decode_instruction_abstract(p, st, instruction_size_in_bytes, instr_maxlen);
+      compressed_format_idx += p - p0;
+
+      if (Disassembler::start_newline(compressed_format_idx-1)) {
+        st->cr();
+        compressed_format_idx = 0;
+      }
+    }
+    //---<  Close the output (Marker for post-mortem disassembler)  >---
+    st->bol();
+    st->print_cr("[/MachCode]");
+    return;
+  }
+#endif
+}
+
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
 
 const char* nmethod::reloc_string_for(u_char* begin, u_char* end) {
   RelocIterator iter(this, begin, end);
@@ -2414,7 +2788,9 @@
     switch (iter.type()) {
         case relocInfo::none:                  return "no_reloc";
         case relocInfo::oop_type: {
-          stringStream st;
+          // Get a non-resizable resource-allocated stringStream.
+          // Our callees make use of (nested) ResourceMarks.
+          stringStream st(NEW_RESOURCE_ARRAY(char, 1024), 1024);
           oop_Relocation* r = iter.oop_reloc();
           oop obj = r->oop_value();
           st.print("oop(");
@@ -2516,17 +2892,28 @@
   return NULL;
 }
 
-void nmethod::print_nmethod_labels(outputStream* stream, address block_begin) const {
-  if (block_begin == entry_point())             stream->print_cr("[Entry Point]");
-  if (block_begin == verified_entry_point())    stream->print_cr("[Verified Entry Point]");
-  if (JVMCI_ONLY(_exception_offset >= 0 &&) block_begin == exception_begin())         stream->print_cr("[Exception Handler]");
-  if (block_begin == stub_begin())              stream->print_cr("[Stub Code]");
-  if (JVMCI_ONLY(_deopt_handler_begin != NULL &&) block_begin == deopt_handler_begin())     stream->print_cr("[Deopt Handler Code]");
-
-  if (has_method_handle_invokes())
-    if (block_begin == deopt_mh_handler_begin())  stream->print_cr("[Deopt MH Handler Code]");
-
-  if (block_begin == consts_begin())            stream->print_cr("[Constants]");
+const char* nmethod::nmethod_section_label(address pos) const {
+  const char* label = NULL;
+  if (pos == code_begin())                                              label = "[Instructions begin]";
+  if (pos == entry_point())                                             label = "[Entry Point]";
+  if (pos == verified_entry_point())                                    label = "[Verified Entry Point]";
+  if (has_method_handle_invokes() && (pos == deopt_mh_handler_begin())) label = "[Deopt MH Handler Code]";
+  if (pos == consts_begin() && pos != insts_begin())                    label = "[Constants]";
+  // Check stub_code before checking exception_handler or deopt_handler.
+  if (pos == this->stub_begin())                                        label = "[Stub Code]";
+  if (JVMCI_ONLY(_exception_offset >= 0 &&) pos == exception_begin())           label = "[Exception Handler]";
+  if (JVMCI_ONLY(_deopt_handler_begin != NULL &&) pos == deopt_handler_begin()) label = "[Deopt Handler Code]";
+  return label;
+}
+
+void nmethod::print_nmethod_labels(outputStream* stream, address block_begin, bool print_section_labels) const {
+  if (print_section_labels) {
+    const char* label = nmethod_section_label(block_begin);
+    if (label != NULL) {
+      stream->bol();
+      stream->print_cr("%s", label);
+    }
+  }
 
   if (block_begin == entry_point()) {
     methodHandle m = method();
@@ -2623,7 +3010,24 @@
   }
 }
 
-void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, u_char* end) {
+// Returns whether this nmethod has code comments.
+bool nmethod::has_code_comment(address begin, address end) {
+  // scopes?
+  ScopeDesc* sd  = scope_desc_in(begin, end);
+  if (sd != NULL) return true;
+
+  // relocations?
+  const char* str = reloc_string_for(begin, end);
+  if (str != NULL) return true;
+
+  // implicit exceptions?
+  int cont_offset = ImplicitExceptionTable(this).at(begin - code_begin());
+  if (cont_offset != 0) return true;
+
+  return false;
+}
+
+void nmethod::print_code_comment_on(outputStream* st, int column, address begin, address end) {
   // First, find an oopmap in (begin, end].
   // We use the odd half-closed interval so that oop maps and scope descs
   // which are tied to the byte after a call are printed with the call itself.
@@ -2636,7 +3040,7 @@
       address pc = base + pair->pc_offset();
       if (pc > begin) {
         if (pc <= end) {
-          st->move_to(column);
+          st->move_to(column, 6, 0);
           st->print("; ");
           om->print_on(st);
         }
@@ -2648,7 +3052,7 @@
   // Print any debug info present at this pc.
   ScopeDesc* sd  = scope_desc_in(begin, end);
   if (sd != NULL) {
-    st->move_to(column);
+    st->move_to(column, 6, 0);
     if (sd->bci() == SynchronizationEntryBCI) {
       st->print(";*synchronization entry");
     } else if (sd->bci() == AfterBci) {
@@ -2704,8 +3108,11 @@
 
     // Print all scopes
     for (;sd != NULL; sd = sd->sender()) {
-      st->move_to(column);
+      st->move_to(column, 6, 0);
       st->print("; -");
+      if (sd->should_reexecute()) {
+        st->print(" (reexecute)");
+      }
       if (sd->method() == NULL) {
         st->print("method is NULL");
       } else {
@@ -2722,20 +3129,24 @@
   }
 
   // Print relocation information
+  // Prevent memory leak: allocating without ResourceMark.
+  ResourceMark rm;
   const char* str = reloc_string_for(begin, end);
   if (str != NULL) {
     if (sd != NULL) st->cr();
-    st->move_to(column);
+    st->move_to(column, 6, 0);
     st->print(";   {%s}", str);
   }
   int cont_offset = ImplicitExceptionTable(this).at(begin - code_begin());
   if (cont_offset != 0) {
-    st->move_to(column);
+    st->move_to(column, 6, 0);
     st->print("; implicit exception: dispatches to " INTPTR_FORMAT, p2i(code_begin() + cont_offset));
   }
 
 }
 
+#endif
+
 class DirectNativeCallWrapper: public NativeCallWrapper {
 private:
   NativeCall* _call;
@@ -2842,12 +3253,14 @@
   return CompiledDirectStaticCall::before(return_addr);
 }
 
-#ifndef PRODUCT
-
+#if defined(SUPPORT_DATA_STRUCTS)
 void nmethod::print_value_on(outputStream* st) const {
   st->print("nmethod");
   print_on(st, NULL);
 }
+#endif
+
+#ifndef PRODUCT
 
 void nmethod::print_calls(outputStream* st) {
   RelocIterator iter(this);
@@ -2869,14 +3282,6 @@
   }
 }
 
-void nmethod::print_handler_table() {
-  ExceptionHandlerTable(this).print();
-}
-
-void nmethod::print_nul_chk_table() {
-  ImplicitExceptionTable(this).print(code_begin());
-}
-
 void nmethod::print_statistics() {
   ttyLocker ttyl;
   if (xtty != NULL)  xtty->head("statistics type='nmethod'");
--- a/src/hotspot/share/code/nmethod.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/code/nmethod.hpp	Tue May 21 15:51:35 2019 +0200
@@ -377,6 +377,7 @@
   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 @@
   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 @@
 
   // 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,
--- a/src/hotspot/share/code/pcDesc.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/code/pcDesc.cpp	Tue May 21 15:51:35 2019 +0200
@@ -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 @@
   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
 }
--- a/src/hotspot/share/code/pcDesc.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/code/pcDesc.hpp	Tue May 21 15:51:35 2019 +0200
@@ -92,7 +92,8 @@
   // 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);
 };
 
--- a/src/hotspot/share/code/vmreg.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/code/vmreg.cpp	Tue May 21 15:51:35 2019 +0200
@@ -39,7 +39,7 @@
 
 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();
--- a/src/hotspot/share/code/vtableStubs.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/code/vtableStubs.cpp	Tue May 21 15:51:35 2019 +0200
@@ -80,7 +80,7 @@
 
 
 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()));
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/compiler/abstractDisassembler.cpp	Tue May 21 15:51:35 2019 +0200
@@ -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]");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/compiler/abstractDisassembler.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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
--- a/src/hotspot/share/compiler/disassembler.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/compiler/disassembler.cpp	Tue May 21 15:51:35 2019 +0200
@@ -23,7 +23,7 @@
  */
 
 #include "precompiled.hpp"
-#include "asm/macroAssembler.hpp"
+#include "asm/assembler.inline.hpp"
 #include "ci/ciUtilities.hpp"
 #include "classfile/javaClasses.hpp"
 #include "code/codeCache.hpp"
@@ -43,6 +43,7 @@
 
 void*       Disassembler::_library               = NULL;
 bool        Disassembler::_tried_to_load_library = false;
+bool        Disassembler::_library_usable        = false;
 
 // This routine is in the shared library:
 Disassembler::decode_func_virtual Disassembler::_decode_instructions_virtual = NULL;
@@ -55,127 +56,46 @@
 #define COMMENT_COLUMN  52 LP64_ONLY(+8) /*could be an option*/
 #define BYTES_COMMENT   ";..."  /* funky byte display comment */
 
-bool Disassembler::load_library() {
-  if (_decode_instructions_virtual != NULL || _decode_instructions != NULL) {
-    // Already succeeded.
-    return true;
-  }
-  if (_tried_to_load_library) {
-    // Do not try twice.
-    // To force retry in debugger: assign _tried_to_load_library=0
-    return false;
-  }
-  // Try to load it.
-  char ebuf[1024];
-  char buf[JVM_MAXPATHLEN];
-  os::jvm_path(buf, sizeof(buf));
-  int jvm_offset = -1;
-  int lib_offset = -1;
-#ifdef STATIC_BUILD
-  char* p = strrchr(buf, '/');
-  *p = '\0';
-  strcat(p, "/lib/");
-  lib_offset = jvm_offset = strlen(buf);
-#else
-  {
-    // Match "jvm[^/]*" in jvm_path.
-    const char* base = buf;
-    const char* p = strrchr(buf, *os::file_separator());
-    if (p != NULL) lib_offset = p - base + 1;
-    p = strstr(p ? p : base, "jvm");
-    if (p != NULL) jvm_offset = p - base;
-  }
-#endif
-  // Find the disassembler shared library.
-  // Search for several paths derived from libjvm, in this order:
-  // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so  (for compatibility)
-  // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
-  // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so
-  // 4. hsdis-<arch>.so  (using LD_LIBRARY_PATH)
-  if (jvm_offset >= 0) {
-    // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so
-    strcpy(&buf[jvm_offset], hsdis_library_name);
-    strcat(&buf[jvm_offset], os::dll_file_extension());
-    _library = os::dll_load(buf, ebuf, sizeof ebuf);
-    if (_library == NULL && lib_offset >= 0) {
-      // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
-      strcpy(&buf[lib_offset], hsdis_library_name);
-      strcat(&buf[lib_offset], os::dll_file_extension());
-      _library = os::dll_load(buf, ebuf, sizeof ebuf);
-    }
-    if (_library == NULL && lib_offset > 0) {
-      // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so
-      buf[lib_offset - 1] = '\0';
-      const char* p = strrchr(buf, *os::file_separator());
-      if (p != NULL) {
-        lib_offset = p - buf + 1;
-        strcpy(&buf[lib_offset], hsdis_library_name);
-        strcat(&buf[lib_offset], os::dll_file_extension());
-        _library = os::dll_load(buf, ebuf, sizeof ebuf);
-      }
-    }
-  }
-  if (_library == NULL) {
-    // 4. hsdis-<arch>.so  (using LD_LIBRARY_PATH)
-    strcpy(&buf[0], hsdis_library_name);
-    strcat(&buf[0], os::dll_file_extension());
-    _library = os::dll_load(buf, ebuf, sizeof ebuf);
-  }
-  if (_library != NULL) {
-    _decode_instructions_virtual = CAST_TO_FN_PTR(Disassembler::decode_func_virtual,
-                                          os::dll_lookup(_library, decode_instructions_virtual_name));
-  }
-  if (_decode_instructions_virtual == NULL && _library != NULL) {
-    // could not spot in new version, try old version
-    _decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func,
-                                          os::dll_lookup(_library, decode_instructions_name));
-    use_new_version = false;
-  } else {
-    use_new_version = true;
-  }
-  _tried_to_load_library = true;
-  if (_decode_instructions_virtual == NULL && _decode_instructions == NULL) {
-    tty->print_cr("Could not load %s; %s; %s", buf,
-                  ((_library != NULL)
-                   ? "entry point is missing"
-                   : (WizardMode || PrintMiscellaneous)
-                   ? (const char*)ebuf
-                   : "library not loadable"),
-                  "PrintAssembly is disabled");
-    return false;
-  }
-
-  // Success.
-  tty->print_cr("Loaded disassembler from %s", buf);
-  return true;
-}
-
-
 class decode_env {
  private:
-  nmethod*      _nm;
-  CodeBlob*     _code;
+  outputStream* _output;      // where the disassembly is directed to
+  CodeBuffer*   _codeBuffer;  // != NULL only when decoding a CodeBuffer
+  CodeBlob*     _codeBlob;    // != NULL only when decoding a CodeBlob
+  nmethod*      _nm;          // != NULL only when decoding a nmethod
   CodeStrings   _strings;
-  outputStream* _output;
-  address       _start, _end;
-  ptrdiff_t     _offset;
+  address       _start;       // != NULL when decoding a range of unknown type
+  address       _end;         // != NULL when decoding a range of unknown type
 
   char          _option_buf[512];
   char          _print_raw;
-  bool          _print_pc;
-  bool          _print_bytes;
-  address       _cur_insn;
-  int           _bytes_per_line; // arch-specific formatting option
+  address       _cur_insn;        // address of instruction currently being decoded
+  int           _bytes_per_line;  // arch-specific formatting option
+  int           _pre_decode_alignment;
+  int           _post_decode_alignment;
   bool          _print_file_name;
+  bool          _print_help;
+  bool          _helpPrinted;
+  static bool   _optionsParsed;
 
+  enum {
+    tabspacing = 8
+  };
+
+  // Check if the event matches the expected tag
+  // The tag must be a substring of the event, and
+  // the tag must be a token in the event, i.e. separated by delimiters
   static bool match(const char* event, const char* tag) {
-    size_t taglen = strlen(tag);
-    if (strncmp(event, tag, taglen) != 0)
+    size_t eventlen = strlen(event);
+    size_t taglen   = strlen(tag);
+    if (eventlen < taglen)  // size mismatch
+      return false;
+    if (strncmp(event, tag, taglen) != 0)  // string mismatch
       return false;
     char delim = event[taglen];
     return delim == '\0' || delim == ' ' || delim == '/' || delim == '=';
   }
 
+  // Merge new option string with previously recorded options
   void collect_options(const char* p) {
     if (p == NULL || p[0] == '\0')  return;
     size_t opt_so_far = strlen(_option_buf);
@@ -187,14 +107,56 @@
     char* q = fillp;
     while ((q = strpbrk(q, " \t\n")) != NULL)
       *q++ = ',';
-    // Note that multiple PrintAssemblyOptions flags accumulate with \n,
-    // which we want to be changed to a comma...
   }
 
+  void process_options(outputStream* ost);
+
   void print_insn_labels();
-  void print_insn_bytes(address pc0, address pc);
+  void print_insn_prefix();
   void print_address(address value);
 
+  // Properly initializes _start/_end. Overwritten too often if
+  // printing of instructions is called for each instruction.
+  void set_start(address s)   { _start = s; }
+  void set_end  (address e)   { _end = e; }
+  void set_nm   (nmethod* nm) { _nm = nm; }
+  void set_output(outputStream* st) { _output = st; }
+
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+  // The disassembler library (sometimes) uses tabs to nicely align the instruction operands.
+  // Depending on the mnemonic length and the column position where the
+  // mnemonic is printed, alignment may turn out to be not so nice.
+  // To improve, we assume 8-character tab spacing and left-align the mnemonic on a tab position.
+  // Instruction comments are aligned 4 tab positions to the right of the mnemonic.
+  void calculate_alignment() {
+    _pre_decode_alignment  = ((output()->position()+tabspacing-1)/tabspacing)*tabspacing;
+    _post_decode_alignment = _pre_decode_alignment + 4*tabspacing;
+  }
+
+  void start_insn(address pc) {
+    _cur_insn = pc;
+    output()->bol();
+    print_insn_labels();
+    print_insn_prefix();
+  }
+
+  void end_insn(address pc) {
+    address pc0 = cur_insn();
+    outputStream* st = output();
+
+    if (AbstractDisassembler::show_comment()) {
+      if ((_nm != NULL) && _nm->has_code_comment(pc0, pc)) {
+        _nm->print_code_comment_on(st, _post_decode_alignment, pc0, pc);
+        // this calls reloc_string_for which calls oop::print_value_on
+      }
+      print_hook_comments(pc0, _nm != NULL);
+    }
+    Disassembler::annotate(pc0, output());
+    // follow each complete insn by a nice newline
+    st->bol();
+  }
+#endif
+
   struct SourceFileInfo {
     struct Link : public CHeapObj<mtCode> {
       const char* file;
@@ -241,40 +203,28 @@
   static GrowableArray<const char*>* _cached_src_lines;
 
  public:
-  decode_env(CodeBlob* code, outputStream* output,
-             CodeStrings c = CodeStrings(), ptrdiff_t offset = 0);
-
-  address decode_instructions(address start, address end);
-
-  void start_insn(address pc) {
-    _cur_insn = pc;
-    output()->bol();
-    print_insn_labels();
-  }
+  decode_env(CodeBuffer* code, outputStream* output);
+  decode_env(CodeBlob*   code, outputStream* output, CodeStrings c = CodeStrings() /* , ptrdiff_t offset */);
+  decode_env(nmethod*    code, outputStream* output, CodeStrings c = CodeStrings());
+  // Constructor for a 'decode_env' to decode an arbitrary
+  // piece of memory, hopefully containing code.
+  decode_env(address start, address end, outputStream* output);
 
-  void end_insn(address pc) {
-    address pc0 = cur_insn();
-    outputStream* st = output();
-    if (_print_bytes && pc > pc0)
-      print_insn_bytes(pc0, pc);
-    if (_nm != NULL) {
-      _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();
-  }
+  // Add 'original_start' argument which is the the original address
+  // the instructions were located at (if this is not equal to 'start').
+  address decode_instructions(address start, address end, address original_start = NULL);
 
   address handle_event(const char* event, address arg);
 
-  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);
+  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);
 };
 
+bool decode_env::_optionsParsed = false;
+
 decode_env::SourceFileInfoTable decode_env::_src_table;
 const char* decode_env::_cached_src = NULL;
 GrowableArray<const char*>* decode_env::_cached_src_lines = NULL;
@@ -361,50 +311,185 @@
   }
 }
 
-decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c,
-                       ptrdiff_t offset) : _nm(NULL),
-                                           _start(NULL),
-                                           _end(NULL),
-                                           _option_buf(),
-                                           _print_raw('\0'),
-                                           _cur_insn(NULL) {
+decode_env::decode_env(CodeBuffer* code, outputStream* output) {
+  memset(this, 0, sizeof(*this));
+  _output = output ? output : tty;
+  _codeBlob    = NULL;
+  _codeBuffer  = code;
+  _helpPrinted = false;
+
+  process_options(_output);
+}
+
+decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) {
+   memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields.
+   _output = output ? output : tty;
+  _codeBlob    = code;
+  _codeBuffer  = NULL;
+  _helpPrinted = false;
+  if (_codeBlob != NULL && _codeBlob->is_nmethod()) {
+    _nm = (nmethod*) code;
+  }
+  _strings.copy(c);
+
+  process_options(_output);
+}
+
+decode_env::decode_env(nmethod* code, outputStream* output, CodeStrings c) {
+  memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields.
   _output = output ? output : tty;
-  _code = code;
-  if (code != NULL && code->is_nmethod())
-    _nm = (nmethod*) code;
+  _codeBlob    = NULL;
+  _codeBuffer  = NULL;
+  _nm          = code;
+  _start       = _nm->code_begin();
+  _end         = _nm->code_end();
+  _helpPrinted = false;
   _strings.copy(c);
-  _offset = offset;
+
+  process_options(_output);
+}
 
+// Constructor for a 'decode_env' to decode a memory range [start, end)
+// of unknown origin, assuming it contains code.
+decode_env::decode_env(address start, address end, outputStream* output) {
+  assert(start < end, "Range must have a positive size, [" PTR_FORMAT ".." PTR_FORMAT ").", p2i(start), p2i(end));
+  memset(this, 0, sizeof(*this));
+  _output = output ? output : tty;
+  _codeBlob    = NULL;
+  _codeBuffer  = NULL;
+  _start       = start;
+  _end         = end;
+  _helpPrinted = false;
+
+  process_options(_output);
+}
+
+void decode_env::process_options(outputStream* ost) {
   // by default, output pc but not bytes:
-  _print_pc       = true;
-  _print_bytes    = false;
-  _bytes_per_line = Disassembler::pd_instruction_alignment();
-  _print_file_name= true;
+  _print_help      = false;
+  _bytes_per_line  = Disassembler::pd_instruction_alignment();
+  _print_file_name = true;
+
+  if (_optionsParsed) return;  // parse only once
 
   // parse the global option string:
   collect_options(Disassembler::pd_cpu_opts());
   collect_options(PrintAssemblyOptions);
 
-  if (strstr(options(), "hsdis-")) {
-    if (strstr(options(), "hsdis-print-raw"))
-      _print_raw = (strstr(options(), "xml") ? 2 : 1);
-    if (strstr(options(), "hsdis-print-pc"))
-      _print_pc = !_print_pc;
-    if (strstr(options(), "hsdis-print-bytes"))
-      _print_bytes = !_print_bytes;
+  if (strstr(options(), "print-raw")) {
+    _print_raw = (strstr(options(), "xml") ? 2 : 1);
+  }
+
+  if (strstr(options(), "help")) {
+    _print_help = true;
+  }
+  if (strstr(options(), "align-instr")) {
+    AbstractDisassembler::toggle_align_instr();
+  }
+  if (strstr(options(), "show-pc")) {
+    AbstractDisassembler::toggle_show_pc();
+  }
+  if (strstr(options(), "show-offset")) {
+    AbstractDisassembler::toggle_show_offset();
+  }
+  if (strstr(options(), "show-bytes")) {
+    AbstractDisassembler::toggle_show_bytes();
+  }
+  if (strstr(options(), "show-data-hex")) {
+    AbstractDisassembler::toggle_show_data_hex();
+  }
+  if (strstr(options(), "show-data-int")) {
+    AbstractDisassembler::toggle_show_data_int();
+  }
+  if (strstr(options(), "show-data-float")) {
+    AbstractDisassembler::toggle_show_data_float();
   }
-  if (strstr(options(), "help")) {
-    tty->print_cr("PrintAssemblyOptions help:");
-    tty->print_cr("  hsdis-print-raw       test plugin by requesting raw output");
-    tty->print_cr("  hsdis-print-raw-xml   test plugin by requesting raw xml");
-    tty->print_cr("  hsdis-print-pc        turn off PC printing (on by default)");
-    tty->print_cr("  hsdis-print-bytes     turn on instruction byte output");
-    tty->print_cr("combined options: %s", options());
+  if (strstr(options(), "show-structs")) {
+    AbstractDisassembler::toggle_show_structs();
+  }
+  if (strstr(options(), "show-comment")) {
+    AbstractDisassembler::toggle_show_comment();
+  }
+  if (strstr(options(), "show-block-comment")) {
+    AbstractDisassembler::toggle_show_block_comment();
+  }
+  _optionsParsed = true;
+
+  if (_print_help && ! _helpPrinted) {
+    _helpPrinted = true;
+    ost->print_cr("PrintAssemblyOptions help:");
+    ost->print_cr("  print-raw       test plugin by requesting raw output");
+    ost->print_cr("  print-raw-xml   test plugin by requesting raw xml");
+    ost->cr();
+    ost->print_cr("  show-pc            toggle printing current pc,        currently %s", AbstractDisassembler::show_pc()            ? "ON" : "OFF");
+    ost->print_cr("  show-offset        toggle printing current offset,    currently %s", AbstractDisassembler::show_offset()        ? "ON" : "OFF");
+    ost->print_cr("  show-bytes         toggle printing instruction bytes, currently %s", AbstractDisassembler::show_bytes()         ? "ON" : "OFF");
+    ost->print_cr("  show-data-hex      toggle formatting data as hex,     currently %s", AbstractDisassembler::show_data_hex()      ? "ON" : "OFF");
+    ost->print_cr("  show-data-int      toggle formatting data as int,     currently %s", AbstractDisassembler::show_data_int()      ? "ON" : "OFF");
+    ost->print_cr("  show-data-float    toggle formatting data as float,   currently %s", AbstractDisassembler::show_data_float()    ? "ON" : "OFF");
+    ost->print_cr("  show-structs       toggle compiler data structures,   currently %s", AbstractDisassembler::show_structs()       ? "ON" : "OFF");
+    ost->print_cr("  show-comment       toggle instruction comments,       currently %s", AbstractDisassembler::show_comment()       ? "ON" : "OFF");
+    ost->print_cr("  show-block-comment toggle block comments,             currently %s", AbstractDisassembler::show_block_comment() ? "ON" : "OFF");
+    ost->print_cr("  align-instr        toggle instruction alignment,      currently %s", AbstractDisassembler::align_instr()        ? "ON" : "OFF");
+    ost->print_cr("combined options: %s", options());
   }
 }
 
+// Disassembly Event Handler.
+// This method receives events from the disassembler library hsdis
+// via event_to_env for each decoding step (installed by
+// Disassembler::decode_instructions(), replacing the default
+// callback method). This enables dumping additional info
+// and custom line formatting.
+// In a future extension, calling a custom decode method will be
+// supported. We can use such a method to decode instructions the
+// binutils decoder does not handle to our liking (suboptimal
+// formatting, incomplete information, ...).
+// Returns:
+// - NULL for all standard invocations. The function result is not
+//        examined (as of now, 20190409) by the hsdis decoder loop.
+// - next for 'insn0' invocations.
+//        next == arg: the custom decoder didn't do anything.
+//        next >  arg: the custom decoder did decode the instruction.
+//                     next points to the next undecoded instruction
+//                     (continuation point for decoder loop).
+//
+// "Normal" sequence of events:
+//  insns   - start of instruction stream decoding
+//  mach    - display architecture
+//  format  - display bytes-per-line
+//  for each instruction:
+//    insn    - start of instruction decoding
+//    insn0   - custom decoder invocation (if any)
+//    addr    - print address value
+//    /insn   - end of instruction decoding
+//  /insns  - premature end of instruction stream due to no progress
+//
 address decode_env::handle_event(const char* event, address arg) {
-  if (match(event, "insn")) {
+
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+
+  //---<  Event: end decoding loop (error, no progress)  >---
+  if (decode_env::match(event, "/insns")) {
+    // Nothing to be done here.
+    return NULL;
+  }
+
+  //---<  Event: start decoding loop  >---
+  if (decode_env::match(event, "insns")) {
+    // Nothing to be done here.
+    return NULL;
+  }
+
+  //---<  Event: finish decoding an instruction  >---
+  if (decode_env::match(event, "/insn")) {
+    output()->fill_to(_post_decode_alignment);
+    end_insn(arg);
+    return NULL;
+  }
+
+  //---<  Event: start decoding an instruction  >---
+  if (decode_env::match(event, "insn")) {
     start_insn(arg);
   } else if (match(event, "/insn")) {
     end_insn(arg);
@@ -413,26 +498,59 @@
       print_address(arg);
       return arg;
     }
-  } else if (match(event, "mach")) {
-    static char buffer[32] = { 0, };
-    if (strcmp(buffer, (const char*)arg) != 0 ||
-        strlen((const char*)arg) > sizeof(buffer) - 1) {
+    calculate_alignment();
+    output()->fill_to(_pre_decode_alignment);
+    return NULL;
+  }
+
+  //---<  Event: call custom decoder (platform specific)  >---
+  if (decode_env::match(event, "insn0")) {
+    return Disassembler::decode_instruction0(arg, output(), arg);
+  }
+
+  //---<  Event: Print address  >---
+  if (decode_env::match(event, "addr")) {
+    print_address(arg);
+    return arg;
+  }
+
+  //---<  Event: mach (inform about machine architecture)  >---
+  // This event is problematic because it messes up the output.
+  // The event is fired after the instruction address has already
+  // been printed. The decoded instruction (event "insn") is
+  // printed afterwards. That doesn't look nice.
+  if (decode_env::match(event, "mach")) {
+    guarantee(arg != NULL, "event_to_env - arg must not be NULL for event 'mach'");
+    static char buffer[64] = { 0, };
+    // Output suppressed because it messes up disassembly.
+    // Only print this when the mach changes.
+    if (false && (strcmp(buffer, (const char*)arg) != 0 ||
+                  strlen((const char*)arg) > sizeof(buffer) - 1)) {
       // Only print this when the mach changes
       strncpy(buffer, (const char*)arg, sizeof(buffer) - 1);
       buffer[sizeof(buffer) - 1] = '\0';
-      output()->print_cr("[Disassembling for mach='%s']", arg);
+      output()->print_cr("[Disassembling for mach='%s']", (const char*)arg);
     }
-  } else if (match(event, "format bytes-per-line")) {
+    return NULL;
+  }
+
+  //---<  Event: format bytes-per-line  >---
+  if (decode_env::match(event, "format bytes-per-line")) {
     _bytes_per_line = (int) (intptr_t) arg;
-  } else {
-    // ignore unrecognized markup
+    return NULL;
   }
+#endif
   return NULL;
 }
 
+static void* event_to_env(void* env_pv, const char* event, void* arg) {
+  decode_env* env = (decode_env*) env_pv;
+  return env->handle_event(event, (address) arg);
+}
+
 // called by the disassembler to print out jump targets and data addresses
 void decode_env::print_address(address adr) {
-  outputStream* st = _output;
+  outputStream* st = output();
 
   if (adr == NULL) {
     st->print("NULL");
@@ -477,9 +595,11 @@
   if (_nm == NULL) {
     // Don't do this for native methods, as the function name will be printed in
     // nmethod::reloc_string_for().
-    ResourceMark rm;
+    // Allocate the buffer on the stack instead of as RESOURCE array.
+    // In case we do DecodeErrorFile, Thread will not be initialized,
+    // causing a "assert(current != __null) failed" failure.
     const int buflen = 1024;
-    char* buf = NEW_RESOURCE_ARRAY(char, buflen);
+    char buf[buflen];
     int offset;
     if (os::dll_address_to_function_name(adr, buf, buflen, &offset)) {
       st->print(PTR_FORMAT " = %s",  p2i(adr), buf);
@@ -495,54 +615,31 @@
 }
 
 void decode_env::print_insn_labels() {
-  address p = cur_insn();
-  outputStream* st = output();
-  CodeBlob* cb = _code;
-  if (cb != NULL) {
-    cb->print_block_comment(st, p);
-  }
-  _strings.print_block_comment(st, (intptr_t)(p - _start + _offset));
-  if (_print_pc) {
-    st->print("  " PTR_FORMAT ": ", p2i(p));
+  if (AbstractDisassembler::show_block_comment()) {
+    address       p  = cur_insn();
+    outputStream* st = output();
+
+    //---<  Block comments for nmethod  >---
+    // Outputs a bol() before and a cr() after, but only if a comment is printed.
+    // Prints nmethod_section_label as well.
+    if (_nm != NULL) {
+      _nm->print_block_comment(st, p);
+    }
+    if (_codeBlob != NULL) {
+      _codeBlob->print_block_comment(st, p);
+    }
+    if (_codeBuffer != NULL) {
+      _codeBuffer->print_block_comment(st, p);
+    }
+    _strings.print_block_comment(st, (intptr_t)(p - _start));
   }
 }
 
-void decode_env::print_insn_bytes(address pc, address pc_limit) {
+void decode_env::print_insn_prefix() {
+  address       p  = cur_insn();
   outputStream* st = output();
-  size_t incr = 1;
-  size_t perline = _bytes_per_line;
-  if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int)
-      && !((uintptr_t)pc % sizeof(int))
-      && !((uintptr_t)pc_limit % sizeof(int))) {
-    incr = sizeof(int);
-    if (perline % incr)  perline += incr - (perline % incr);
-  }
-  while (pc < pc_limit) {
-    // tab to the desired column:
-    st->move_to(COMMENT_COLUMN);
-    address pc0 = pc;
-    address pc1 = pc + perline;
-    if (pc1 > pc_limit)  pc1 = pc_limit;
-    for (; pc < pc1; pc += incr) {
-      if (pc == pc0) {
-        st->print(BYTES_COMMENT);
-      } else if ((uint)(pc - pc0) % sizeof(int) == 0) {
-        st->print(" ");         // put out a space on word boundaries
-      }
-      if (incr == sizeof(int)) {
-        st->print("%08x", *(int*)pc);
-      } else {
-        st->print("%02x", (*pc)&0xFF);
-      }
-    }
-    st->cr();
-  }
-}
-
-
-static void* event_to_env(void* env_pv, const char* event, void* arg) {
-  decode_env* env = (decode_env*) env_pv;
-  return env->handle_event(event, (address) arg);
+  AbstractDisassembler::print_location(p, _start, _end, st, false, false);
+  AbstractDisassembler::print_instruction(p, Assembler::instr_len(p), Assembler::instr_maxlen(), st, true, false);
 }
 
 ATTRIBUTE_PRINTF(2, 3)
@@ -575,16 +672,31 @@
   return (int)(cnt1 - cnt0);
 }
 
-address decode_env::decode_instructions(address start, address end) {
-  _start = start; _end = end;
-
-  assert(((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment()) == 0), "misaligned insn addr");
+// The 'original_start' argument holds the the original address where
+// the instructions were located in the originating system. If zero (NULL)
+// is passed in, there is no original address.
+address decode_env::decode_instructions(address start, address end, address original_start /* = 0*/) {
+  // CodeComment in Stubs.
+  // Properly initialize _start/_end. Overwritten too often if
+  // printing of instructions is called for each instruction.
+  assert((_start == NULL) || (start == NULL) || (_start == start), "don't overwrite CTOR values");
+  assert((_end   == NULL) || (end   == NULL) || (_end   == end  ), "don't overwrite CTOR values");
+  if (start != NULL) set_start(start);
+  if (end   != NULL) set_end(end);
+  if (original_start == NULL) {
+    original_start = start;
+  }
 
-  const int show_bytes = false; // for disassembler debugging
+  //---<  Check (and correct) alignment  >---
+  // Don't check alignment of end, it is not aligned.
+  if (((uint64_t)start & ((uint64_t)Disassembler::pd_instruction_alignment() - 1)) != 0) {
+    output()->print_cr("Decode range start:" PTR_FORMAT ": ... (unaligned)", p2i(start));
+    start = (address)((uint64_t)start & ~((uint64_t)Disassembler::pd_instruction_alignment() - 1));
+  }
 
-  //_version = Disassembler::pd_cpu_version();
-
-  if (!Disassembler::can_decode()) {
+  // Trying to decode instructions doesn't make sense if we
+  // couldn't load the disassembler library.
+  if (Disassembler::is_abstract()) {
     return NULL;
   }
 
@@ -625,16 +737,177 @@
                                           options());
 }
 
+// ----------------------------------------------------------------------------
+// Disassembler
+// Used as a static wrapper for decode_env.
+// Each method will create a decode_env before decoding.
+// You can call the decode_env methods directly if you already have one.
 
-void Disassembler::decode(CodeBlob* cb, outputStream* st) {
-  ttyLocker ttyl;
-  if (!load_library())  return;
-  if (cb->is_nmethod()) {
-    decode((nmethod*)cb, st);
+
+bool Disassembler::load_library(outputStream* st) {
+  // Do not try to load multiple times. Failed once -> fails always.
+  // To force retry in debugger: assign _tried_to_load_library=0
+  if (_tried_to_load_library) {
+    return _library_usable;
+  }
+
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+  // Print to given stream, if any.
+  // Print to tty if Verbose is on and no stream given.
+  st = ((st == NULL) && Verbose) ? tty : st;
+
+  // Compute fully qualified library name.
+  char ebuf[1024];
+  char buf[JVM_MAXPATHLEN];
+  os::jvm_path(buf, sizeof(buf));
+  int jvm_offset = -1;
+  int lib_offset = -1;
+#ifdef STATIC_BUILD
+  char* p = strrchr(buf, '/');
+  *p = '\0';
+  strcat(p, "/lib/");
+  lib_offset = jvm_offset = strlen(buf);
+#else
+  {
+    // Match "libjvm" instead of "jvm" on *nix platforms. Creates better matches.
+    // Match "[lib]jvm[^/]*" in jvm_path.
+    const char* base = buf;
+    const char* p = strrchr(buf, *os::file_separator());
+#ifdef _WIN32
+    p = strstr(p ? p : base, "jvm");
+#else
+    p = strstr(p ? p : base, "libjvm");
+#endif
+    if (p != NULL) lib_offset = p - base + 1;
+    if (p != NULL) jvm_offset = p - base;
+  }
+#endif
+
+  // Find the disassembler shared library.
+  // Search for several paths derived from libjvm, in this order:
+  // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so  (for compatibility)
+  // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
+  // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so
+  // 4. hsdis-<arch>.so  (using LD_LIBRARY_PATH)
+  if (jvm_offset >= 0) {
+    // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so
+    strcpy(&buf[jvm_offset], hsdis_library_name);
+    strcat(&buf[jvm_offset], os::dll_file_extension());
+    _library = os::dll_load(buf, ebuf, sizeof ebuf);
+    if (_library == NULL && lib_offset >= 0) {
+      // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
+      strcpy(&buf[lib_offset], hsdis_library_name);
+      strcat(&buf[lib_offset], os::dll_file_extension());
+      _library = os::dll_load(buf, ebuf, sizeof ebuf);
+    }
+    if (_library == NULL && lib_offset > 0) {
+      // 3. <home>/jre/lib/<arch>/hsdis-<arch>.so
+      buf[lib_offset - 1] = '\0';
+      const char* p = strrchr(buf, *os::file_separator());
+      if (p != NULL) {
+        lib_offset = p - buf + 1;
+        strcpy(&buf[lib_offset], hsdis_library_name);
+        strcat(&buf[lib_offset], os::dll_file_extension());
+        _library = os::dll_load(buf, ebuf, sizeof ebuf);
+      }
+    }
+  }
+  if (_library == NULL) {
+    // 4. hsdis-<arch>.so  (using LD_LIBRARY_PATH)
+    strcpy(&buf[0], hsdis_library_name);
+    strcat(&buf[0], os::dll_file_extension());
+    _library = os::dll_load(buf, ebuf, sizeof ebuf);
+  }
+
+  // load the decoder function to use (new or old version).
+  if (_library != NULL) {
+    _decode_instructions_virtual = CAST_TO_FN_PTR(Disassembler::decode_func_virtual,
+                                          os::dll_lookup(_library, decode_instructions_virtual_name));
+  }
+  if (_decode_instructions_virtual == NULL && _library != NULL) {
+    // could not spot in new version, try old version
+    _decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func,
+                                          os::dll_lookup(_library, decode_instructions_name));
+    use_new_version = false;
+  } else {
+    use_new_version = true;
+  }
+  _tried_to_load_library = true;
+  _library_usable        = _decode_instructions_virtual != NULL || _decode_instructions != NULL;
+
+  // Create a dummy environment to initialize PrintAssemblyOptions.
+  // The PrintAssemblyOptions must be known for abstract disassemblies as well.
+  decode_env dummy((unsigned char*)(&buf[0]), (unsigned char*)(&buf[1]), st);
+
+  // Report problems during dll_load or dll_lookup, if any.
+  if (st != NULL) {
+    // Success.
+    if (_library_usable) {
+      st->print_cr("Loaded disassembler from %s", buf);
+    } else {
+      st->print_cr("Could not load %s; %s; %s",
+                   buf,
+                   ((_library != NULL)
+                    ? "entry point is missing"
+                    : ((WizardMode || PrintMiscellaneous)
+                       ? (const char*)ebuf
+                       : "library not loadable")),
+                   "PrintAssembly defaults to abstract disassembly.");
+    }
+  }
+#endif
+  return _library_usable;
+}
+
+
+// Directly disassemble code buffer.
+void Disassembler::decode(CodeBuffer* cb, address start, address end, outputStream* st) {
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+  //---<  Test memory before decoding  >---
+  if (!(cb->contains(start) && cb->contains(end))) {
+    //---<  Allow output suppression, but prevent writing to a NULL stream. Could happen with +PrintStubCode.  >---
+    if (st != NULL) {
+      st->print("Memory range [" PTR_FORMAT ".." PTR_FORMAT "] not contained in CodeBuffer", p2i(start), p2i(end));
+    }
     return;
   }
+  if (!os::is_readable_range(start, end)) {
+    //---<  Allow output suppression, but prevent writing to a NULL stream. Could happen with +PrintStubCode.  >---
+    if (st != NULL) {
+      st->print("Memory range [" PTR_FORMAT ".." PTR_FORMAT "] not readable", p2i(start), p2i(end));
+    }
+    return;
+  }
+
   decode_env env(cb, st);
-  env.output()->print_cr("----------------------------------------------------------------------");
+  env.output()->print_cr("--------------------------------------------------------------------------------");
+  env.output()->print("Decoding CodeBuffer (" PTR_FORMAT ")", p2i(cb));
+  if (cb->name() != NULL) {
+    env.output()->print(", name: %s,", cb->name());
+  }
+  env.output()->print_cr(" at  [" PTR_FORMAT ", " PTR_FORMAT "]  " JLONG_FORMAT " bytes", p2i(start), p2i(end), ((jlong)(end - start)));
+
+  if (is_abstract()) {
+    AbstractDisassembler::decode_abstract(start, end, env.output(), Assembler::instr_maxlen());
+  } else {
+    env.decode_instructions(start, end);
+  }
+  env.output()->print_cr("--------------------------------------------------------------------------------");
+#endif
+}
+
+// Directly disassemble code blob.
+void Disassembler::decode(CodeBlob* cb, outputStream* st, CodeStrings c) {
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+  if (cb->is_nmethod()) {
+    // If we  have an nmethod at hand,
+    // call the specialized decoder directly.
+    decode((nmethod*)cb, st, c);
+    return;
+  }
+
+  decode_env env(cb, st);
+  env.output()->print_cr("--------------------------------------------------------------------------------");
   if (cb->is_aot()) {
     env.output()->print("A ");
     if (cb->is_compiled()) {
@@ -648,57 +921,78 @@
       env.output()->print_cr("%s", cb->name());
     }
   } else {
-    env.output()->print_cr("%s", cb->name());
+    env.output()->print("Decoding CodeBlob");
+    if (cb->name() != NULL) {
+      env.output()->print(", name: %s,", cb->name());
+    }
   }
-  env.output()->print_cr(" at  [" PTR_FORMAT ", " PTR_FORMAT "]  " JLONG_FORMAT " bytes", p2i(cb->code_begin()), p2i(cb->code_end()), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*));
-  env.decode_instructions(cb->code_begin(), cb->code_end());
-}
+  env.output()->print_cr(" at  [" PTR_FORMAT ", " PTR_FORMAT "]  " JLONG_FORMAT " bytes", p2i(cb->code_begin()), p2i(cb->code_end()), ((jlong)(cb->code_end() - cb->code_begin())));
 
-void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c,
-                          ptrdiff_t offset) {
-  ttyLocker ttyl;
-  if (!load_library())  return;
-  decode_env env(CodeCache::find_blob_unsafe(start), st, c, offset);
-  env.decode_instructions(start, end);
+  if (is_abstract()) {
+    AbstractDisassembler::decode_abstract(cb->code_begin(), cb->code_end(), env.output(), Assembler::instr_maxlen());
+  } else {
+    env.decode_instructions(cb->code_begin(), cb->code_end());
+  }
+  env.output()->print_cr("--------------------------------------------------------------------------------");
+#endif
 }
 
-void Disassembler::decode(nmethod* nm, outputStream* st) {
+// Decode a nmethod.
+// This includes printing the constant pool and all code segments.
+// The nmethod data structures (oop maps, relocations and the like) are not printed.
+void Disassembler::decode(nmethod* nm, outputStream* st, CodeStrings c) {
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
   ttyLocker ttyl;
-  if (!load_library())  return;
+
   decode_env env(nm, st);
-  env.output()->print_cr("----------------------------------------------------------------------");
-
-  unsigned char* p   = nm->code_begin();
-  unsigned char* end = nm->code_end();
+  env.output()->print_cr("--------------------------------------------------------------------------------");
+  nm->print_constant_pool(env.output());
+  env.output()->print_cr("--------------------------------------------------------------------------------");
+  env.output()->cr();
+  if (is_abstract()) {
+    AbstractDisassembler::decode_abstract(nm->code_begin(), nm->code_end(), env.output(), Assembler::instr_maxlen());
+  } else {
+    env.decode_instructions(nm->code_begin(), nm->code_end());
+  }
+  env.output()->print_cr("--------------------------------------------------------------------------------");
+#endif
+}
 
-  nm->method()->method_holder()->name()->print_symbol_on(env.output());
-  env.output()->print(".");
-  nm->method()->name()->print_symbol_on(env.output());
-  nm->method()->signature()->print_symbol_on(env.output());
-#if INCLUDE_JVMCI
+// Decode a range, given as [start address, end address)
+void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c /*, ptrdiff_t offset */) {
+#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY)
+  //---<  Test memory before decoding  >---
+  if (!os::is_readable_range(start, end)) {
+    //---<  Allow output suppression, but prevent writing to a NULL stream. Could happen with +PrintStubCode.  >---
+    if (st != NULL) {
+      st->print("Memory range [" PTR_FORMAT ".." PTR_FORMAT "] not readable", p2i(start), p2i(end));
+    }
+    return;
+  }
+
+  if (is_abstract()) {
+    AbstractDisassembler::decode_abstract(start, end, st, Assembler::instr_maxlen());
+    return;
+  }
+
+// Don't do that fancy stuff. If we just have two addresses, live with it
+// and treat the memory contents as "amorphic" piece of code.
+#if 0
+  CodeBlob* cb = CodeCache::find_blob_unsafe(start);
+  if (cb != NULL) {
+    // If we  have an CodeBlob at hand,
+    // call the specialized decoder directly.
+    decode(cb, st, c);
+  } else
+#endif
   {
-    const char* jvmciName = nm->jvmci_name();
-    if (jvmciName != NULL) {
-      env.output()->print(" (%s)", jvmciName);
-    }
+    // This seems to be just a chunk of memory.
+    decode_env env(start, end, st);
+    env.output()->print_cr("--------------------------------------------------------------------------------");
+    env.decode_instructions(start, end);
+    env.output()->print_cr("--------------------------------------------------------------------------------");
   }
 #endif
-  env.output()->print_cr("  [" PTR_FORMAT ", " PTR_FORMAT "]  " JLONG_FORMAT " bytes", p2i(p), p2i(end), ((jlong)(end - p)));
-
-  // Print constant table.
-  if (nm->consts_size() > 0) {
-    nm->print_nmethod_labels(env.output(), nm->consts_begin());
-    int offset = 0;
-    for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) {
-      if ((offset % 8) == 0) {
-        env.output()->print_cr("  " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT "   " PTR64_FORMAT, p2i(p), offset, *((int32_t*) p), *((int64_t*) p));
-      } else {
-        env.output()->print_cr("  " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT,                    p2i(p), offset, *((int32_t*) p));
-      }
-    }
-  }
-
-  env.decode_instructions(p, end);
 }
 
 // To prevent excessive code expansion in the interpreter generator, we
--- a/src/hotspot/share/compiler/disassembler.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/compiler/disassembler.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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 @@
 // 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 @@
   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
--- a/src/hotspot/share/compiler/oopMap.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/compiler/oopMap.cpp	Tue May 21 15:51:35 2019 +0200
@@ -511,7 +511,7 @@
 
 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 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 @@
 
 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);
 }
--- a/src/hotspot/share/opto/block.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/opto/block.cpp	Tue May 21 15:51:35 2019 +0200
@@ -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 @@
 
 #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_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 @@
     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);
--- a/src/hotspot/share/opto/compile.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/opto/compile.cpp	Tue May 21 15:51:35 2019 +0200
@@ -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 @@
   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 @@
 #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 @@
 
 //------------------------------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 @@
       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 @@
           !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 @@
         // 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
 
--- a/src/hotspot/share/opto/compile.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/opto/compile.hpp	Tue May 21 15:51:35 2019 +0200
@@ -1348,7 +1348,13 @@
   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
--- a/src/hotspot/share/opto/output.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/opto/output.cpp	Tue May 21 15:51:35 2019 +0200
@@ -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 @@
 #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 @@
       }
 
       // 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 @@
         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 @@
     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 @@
                    "");
       }
       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 @@
     }
   }
 #endif
-
 }
 
 void Compile::FillExceptionTables(uint cnt, uint *call_returns, uint *inct_starts, Label *blk_labels) {
--- a/src/hotspot/share/runtime/stubCodeGenerator.cpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/runtime/stubCodeGenerator.cpp	Tue May 21 15:51:35 2019 +0200
@@ -60,7 +60,7 @@
   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 @@
     // 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();
   }
 }
--- a/src/hotspot/share/utilities/globalDefinitions.hpp	Tue May 21 11:45:37 2019 +0200
+++ b/src/hotspot/share/utilities/globalDefinitions.hpp	Tue May 21 15:51:35 2019 +0200
@@ -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.