From 63cadc56420c73719e7a08587984bf5d96d3b063 Mon Sep 17 00:00:00 2001
From: miaozhuojun <mouzhuojun@huawei.com>
Date: Sat, 11 Sep 2021 14:48:00 +0800
Subject: [PATCH 23/23] JDK debug version crash when using AppCDS

Summary: <AppCDS> : JDK debug version crash when using AppCDS
LLT: ./jdk8u-dev/hotspot/test/runtime/NMT/NMTWithCDS.java
Patch Type: huawei
Bug url: NA
---
 .../vm/interpreterGenerator_aarch64.hpp       |   2 -
 .../vm/templateInterpreter_aarch64.cpp        | 144 +++++++++---------
 .../vm/templateInterpreter_aarch64.hpp        |  72 +++++++++
 .../share/vm/interpreter/cppInterpreter.cpp   |  13 +-
 .../share/vm/interpreter/cppInterpreter.hpp   |   3 +-
 .../src/share/vm/interpreter/interpreter.cpp  |  19 +--
 .../vm/interpreter/templateInterpreter.cpp    |  14 +-
 .../vm/interpreter/templateInterpreter.hpp    |   3 +-
 hotspot/src/share/vm/memory/universe.cpp      |   8 +
 hotspot/src/share/vm/runtime/init.cpp         |   6 +-
 10 files changed, 165 insertions(+), 119 deletions(-)

diff --git a/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp
index a275a6a99..40af38a79 100644
--- a/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp
+++ b/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp
@@ -50,8 +50,6 @@ void generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpa
   address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind);
   void lock_method(void);
   void generate_stack_overflow_check(void);
-  void load_String_value(Register src, Register dst);
-  void load_String_offset(Register src, Register dst);
   void emit_array_address(Register src, Register idx, Register dst, BasicType type);
   address generate_Dgemm_dgemm_entry();
   address generate_Dgemv_dgemv_entry();
diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
index b5f56fd03..f356fbf81 100644
--- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
@@ -849,27 +849,6 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret
   return generate_native_entry(false);
 }
 
-// Access the char-array of String
-void InterpreterGenerator::load_String_value(Register src, Register dst) {
-  //  Need to cooperate with JDK-8243996
-  int value_offset = java_lang_String::value_offset_in_bytes();
-
-  __ add(src, src, value_offset);
-  __ load_heap_oop(dst, Address(src));
-}
-
-void InterpreterGenerator::load_String_offset(Register src, Register dst) {
-  __ mov(dst, 0);
-
-  // Get String value offset, because of order of initialization for Interpreter,
-  // we have to hardcode the offset for String value. (JDK-8243996)
-  if (java_lang_String::has_offset_field()) {
-    int offset_offset = java_lang_String::offset_offset_in_bytes();
-    __ add(src, src, offset_offset);
-    __ ldrw(dst, Address(src));
-  }
-}
-
 void InterpreterGenerator::emit_array_address(Register src, Register idx,
                                               Register dst, BasicType type) {
   int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type);
@@ -900,7 +879,7 @@ void InterpreterGenerator::emit_array_address(Register src, Register idx,
  *
  */
 address InterpreterGenerator::generate_Dgemm_dgemm_entry() {
-  if (!UseF2jBLASIntrinsics || (StubRoutines::dgemmDgemm() == NULL)) return NULL;
+  if (StubRoutines::dgemmDgemm() == NULL) return NULL;
 
   address entry = __ pc();
 
@@ -917,19 +896,29 @@ address InterpreterGenerator::generate_Dgemm_dgemm_entry() {
   const Register lda        = c_rarg6;
   const Register B          = c_rarg7;
   const FloatRegister beta  = c_farg1;
-  const Register tmp1       = rscratch1;
-  const Register tmp2       = rscratch2;
-
-  // trana
-  __ ldr(ta, Address(esp, 17 * wordSize));
-  load_String_value(ta, tmp1);
-  load_String_offset(ta, tmp2);
-  emit_array_address(tmp1, tmp2, ta, T_CHAR);
-  // tranb
-  __ ldr(tb, Address(esp, 16 * wordSize));
-  load_String_value(tb, tmp1);
-  load_String_offset(tb, tmp2);
-  emit_array_address(tmp1, tmp2, tb, T_CHAR);
+
+  // trana/tranb
+  __ ldr(r0, Address(esp, 17 * wordSize));
+  __ ldr(r1, Address(esp, 16 * wordSize));
+
+  // Get String value offset, because of order of initialization for Interpreter,
+  // we have to hardcode the offset for String value and offset. These instructions
+  // generated there will be patched in interpreter_patch after java.lang.String has
+  // been loaded.
+  // load String offset
+  __ mov(r2, 0);    // __ ldrw(r2, Address(r0, java_lang_String::offset_offset_in_bytes()))
+  __ mov(r3, 0);    // __ ldrw(r3, Address(r1, java_lang_String::offset_offset_in_bytes()))
+
+  // load String value
+  __ mov(r4, 0xc);  // __ mov(r4, java_lang_String::value_offset_in_bytes())
+  __ add(r0, r0, r4);
+  __ load_heap_oop(r0, Address(r0));
+  __ add(r1, r1, r4);
+  __ load_heap_oop(r1, Address(r1));
+
+  emit_array_address(r0, r2, ta, T_CHAR);
+  emit_array_address(r1, r3, tb, T_CHAR);
+
   // m, n, k
   __ ldrw(m, Address(esp, 15 * wordSize));
   __ ldrw(n, Address(esp, 14 * wordSize));
@@ -937,16 +926,15 @@ address InterpreterGenerator::generate_Dgemm_dgemm_entry() {
   // alpha
   __ ldrd(alpha, Address(esp, 11 * wordSize));
   // A
-  __ ldr(tmp1, Address(esp, 10 * wordSize));
-  __ mov(tmp2, 0);
-  __ ldrw(tmp2, Address(esp, 9 * wordSize));
-  emit_array_address(tmp1, tmp2, A, T_DOUBLE);
+  __ ldr(r5, Address(esp, 10 * wordSize));
+  __ ldrw(r6, Address(esp, 9 * wordSize));
+  emit_array_address(r5, r6, A, T_DOUBLE);
   // lda
   __ ldrw(lda, Address(esp, 8 * wordSize));
   // B
-  __ ldr(tmp1, Address(esp, 7 * wordSize));
-  __ ldrw(tmp2, Address(esp, 6 * wordSize));
-  emit_array_address(tmp1, tmp2, B, T_DOUBLE);
+  __ ldr(rscratch1, Address(esp, 7 * wordSize));
+  __ ldrw(rscratch2, Address(esp, 6 * wordSize));
+  emit_array_address(rscratch1, rscratch2, B, T_DOUBLE);
   // beta
   __ ldrd(beta, Address(esp, 3 * wordSize));
   // Start pushing arguments to machine stack.
@@ -960,22 +948,22 @@ address InterpreterGenerator::generate_Dgemm_dgemm_entry() {
   __ andr(sp, r13, -16);
   __ str(lr, Address(sp, -wordSize));
   // ldc
-  __ ldrw(tmp1, Address(esp, 0x0));
-  __ strw(tmp1, Address(sp, 2 * -wordSize));
+  __ ldrw(rscratch1, Address(esp, 0x0));
+  __ strw(rscratch1, Address(sp, 2 * -wordSize));
   // C
-  __ ldr(tmp1, Address(esp, 2 * wordSize));
-  __ ldrw(tmp2, Address(esp, wordSize));
-  emit_array_address(tmp1, tmp2, tmp1, T_DOUBLE);
-  __ str(tmp1, Address(sp, 3 * -wordSize));
+  __ ldr(rscratch1, Address(esp, 2 * wordSize));
+  __ ldrw(rscratch2, Address(esp, wordSize));
+  emit_array_address(rscratch1, rscratch2, rscratch1, T_DOUBLE);
+  __ str(rscratch1, Address(sp, 3 * -wordSize));
   // ldb
-  __ ldrw(tmp2, Address(esp, 5 * wordSize));
-  __ strw(tmp2, Address(sp, 4 * -wordSize));
+  __ ldrw(rscratch2, Address(esp, 5 * wordSize));
+  __ strw(rscratch2, Address(sp, 4 * -wordSize));
 
   // Call function
   __ add(sp, sp, 4 * -wordSize);
   address fn = CAST_FROM_FN_PTR(address, StubRoutines::dgemmDgemm());
-  __ mov(tmp1, fn);
-  __ blr(tmp1);
+  __ mov(rscratch1, fn);
+  __ blr(rscratch1);
 
   __ ldr(lr, Address(sp, 3 * wordSize));
   // For assert(Rd != sp || imm % 16 == 0)
@@ -1001,9 +989,6 @@ address InterpreterGenerator::generate_Dgemv_dgemv_entry() {
   const FloatRegister alpha = v0;              // alpha
   const FloatRegister beta = v1;               // beta
 
-  const Register tmp1 = rscratch1;
-  const Register tmp2 = rscratch2;
-
   // esp: expression stack of caller
   // dgemv parameter ---> the position in stack ---> move to register
   // | char* trans  |        | esp + 15 |                |  r0  |
@@ -1032,10 +1017,21 @@ address InterpreterGenerator::generate_Dgemv_dgemv_entry() {
 
 
   // trans
-  __ ldr(trans, Address(esp, 15 * wordSize));
-  load_String_value(trans, tmp1);
-  load_String_offset(trans, tmp2);
-  emit_array_address(tmp1, tmp2, trans, T_CHAR);
+  __ ldr(r0, Address(esp, 15 * wordSize));
+
+  // Get String value offset, because of order of initialization for Interpreter,
+  // we have to hardcode the offset for String value and offset. These instructions
+  // generated there will be patched in interpreter_patch after java.lang.String has
+  // been loaded.
+  // load String offset
+  __ mov(r1, 0);       // __ ldrw(r1, Address(r0, java_lang_String::offset_offset_in_bytes()))
+
+  // load String value
+  __ mov(r2, 0xc);     // __ mov(r2, java_lang_String::value_offset_in_bytes())
+  __ add(r0, r0, r2);
+  __ load_heap_oop(r0, Address(r0));
+  emit_array_address(r0, r1, trans, T_CHAR);
+
   // m, n
   __ ldrw(m, Address(esp, 14 * wordSize));
   __ ldrw(n, Address(esp, 13 * wordSize));
@@ -1044,19 +1040,17 @@ address InterpreterGenerator::generate_Dgemv_dgemv_entry() {
   __ ldrd(alpha, Address(esp, 11 * wordSize));
 
   // a
-  __ ldr(tmp1, Address(esp, 10 * wordSize));
-  __ mov(tmp2, zr);
-  __ ldrw(tmp2, Address(esp, 9 * wordSize));
-  emit_array_address(tmp1, tmp2, a, T_DOUBLE);
+  __ ldr(r3, Address(esp, 10 * wordSize));
+  __ ldrw(r4, Address(esp, 9 * wordSize));
+  emit_array_address(r3, r4, a, T_DOUBLE);
 
   // lda
   __ ldrw(lda, Address(esp, 8 * wordSize));
 
   // x
-  __ ldr(tmp1, Address(esp, 7 * wordSize));
-  __ mov(tmp2, zr);
-  __ ldrw(tmp2, Address(esp, 6 * wordSize));
-  emit_array_address(tmp1, tmp2, x, T_DOUBLE);
+  __ ldr(r5, Address(esp, 7 * wordSize));
+  __ ldrw(r6, Address(esp, 6 * wordSize));
+  emit_array_address(r5, r6, x, T_DOUBLE);
 
   // incx
   __ ldrw(incx, Address(esp, 5 * wordSize));
@@ -1065,25 +1059,24 @@ address InterpreterGenerator::generate_Dgemv_dgemv_entry() {
   __ ldrd(beta, Address(esp, 3 * wordSize));
 
   // y
-  __ ldr(tmp1, Address(esp, 2 * wordSize));
-  __ mov(tmp2, zr);
-  __ ldrw(tmp2, Address(esp, wordSize));
-  emit_array_address(tmp1, tmp2, y, T_DOUBLE);
+  __ ldr(rscratch1, Address(esp, 2 * wordSize));
+  __ ldrw(rscratch2, Address(esp, wordSize));
+  emit_array_address(rscratch1, rscratch2, y, T_DOUBLE);
 
   // resume sp, restore lr
   __ andr(sp, r13, -16);
   __ str(lr, Address(sp, -wordSize));
 
   // incy, push on stack
-  __ ldrw(tmp1, Address(esp, 0));
-  __ strw(tmp1, Address(sp, 2 * -wordSize));
+  __ ldrw(rscratch1, Address(esp, 0));
+  __ strw(rscratch1, Address(sp, 2 * -wordSize));
 
   __ add(sp, sp, -2 * wordSize);
 
   // call function
   address fn = CAST_FROM_FN_PTR(address, StubRoutines::dgemvDgemv());
-  __ mov(tmp1, fn);
-  __ blr(tmp1);
+  __ mov(rscratch1, fn);
+  __ blr(rscratch1);
 
   // resume lr
   __ ldr(lr, Address(sp, wordSize));
@@ -1960,7 +1953,6 @@ void AbstractInterpreter::layout_activation(Method* method,
     method->constants()->cache();
 }
 
-
 //-----------------------------------------------------------------------------
 // Exceptions
 
diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.hpp
index 36e1aa89d..3ca17e3c4 100644
--- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.hpp
+++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.hpp
@@ -28,6 +28,78 @@
 #define CPU_AARCH64_VM_TEMPLATEINTERPRETER_AARCH64_HPP
 
 
+  public:
+  static void patch_method(AbstractInterpreter::MethodKind kind) {
+    unsigned value_offset = java_lang_String::value_offset_in_bytes();
+    unsigned offset_offset = 0;
+    address entry = entry_for_kind(kind);
+
+    if (entry == NULL) {
+      return;
+    }
+
+    switch (kind) {
+    case AbstractInterpreter::org_netlib_blas_Dgemm_dgemm:
+      if (StubRoutines::_dgemmDgemm == NULL) {
+        break;
+      }
+      // 0 : ldr x0, [x20, #136]
+      // 1 : ldr x1, [x20, #128]
+      // 2 : mov x2, #0x0  ==================>  ldr w2, [x0, <java_lang_String::value_offset_in_bytes()>]
+      // 3 : mov x3, #0x0  ==================>  ldr w3, [x1, <java_lang_String::value_offset_in_bytes()>]
+      // 4 : orr x4, xzr, #0xc  =============>  orr x4, xzr, <java_lang_String::value_offset_in_bytes()>
+      if (java_lang_String::has_offset_field()) {
+        guarantee(Instruction_aarch64::extract(((unsigned*)entry)[2], 31, 23) == 0b110100101 &&
+               Instruction_aarch64::extract(((unsigned*)entry)[3], 31, 23) == 0b110100101,
+               "wrong insns in patch");
+        offset_offset = java_lang_String::offset_offset_in_bytes();
+        // ldr w2, [x0, <java_lang_String::value_offset_in_bytes()>]
+        address tmp = entry + 4 * 2;
+        Instruction_aarch64::patch(tmp, 31, 22, 0b1011100101);         // opc
+        Instruction_aarch64::patch(tmp, 21, 10, offset_offset >> 2);   // imm12
+        Instruction_aarch64::patch(tmp, 9, 5, 0);                      // Rn
+        Instruction_aarch64::patch(tmp, 4, 0, 2);                      // Rt
+        // ldr w3, [x1, <java_lang_String::value_offset_in_bytes()>]
+        tmp = entry + 4 * 3;
+        Instruction_aarch64::patch(tmp, 31, 22, 0b1011100101);         // opc
+        Instruction_aarch64::patch(tmp, 21, 10, offset_offset >> 2);   // imm12
+        Instruction_aarch64::patch(tmp, 9, 5, 1);                      // Rn
+        Instruction_aarch64::patch(tmp, 4, 0, 3);                      // Rt
+      }
+      guarantee(Instruction_aarch64::extract(((unsigned*)entry)[4], 31, 23) == 0b101100100 &&
+             Instruction_aarch64::extract(((unsigned*)entry)[4], 9, 0) == 0b1111100100, "wrong insns in patch");
+      Instruction_aarch64::patch(entry + 4 * 4, 22, 10,
+                                 (uint64_t)encode_logical_immediate(false, (uint64_t)value_offset));   // imm16
+      ICache::invalidate_range(entry, 4 * 5);
+      break;
+    case AbstractInterpreter::org_netlib_blas_Dgemv_dgemv:
+      if (StubRoutines::_dgemvDgemv == NULL) {
+        break;
+      }
+      // 0 : ldr x0, [x20, #120]
+      // 1 : mov x1, #0x0  ==================>  ldr w1, [r0, <java_lang_String::offset_offset_in_bytes()>]
+      // 2 : orr x2, xzr, #0xc  =============>  orr x2, xzr, <java_lang_String::value_offset_in_bytes()>
+      if (java_lang_String::has_offset_field()) {
+        guarantee(Instruction_aarch64::extract(((unsigned*)entry)[1], 31, 23) == 0b110100101, "wrong insns in patch");
+        offset_offset = java_lang_String::offset_offset_in_bytes();
+        // ldr w1, [x0, <java_lang_String::value_offset_in_bytes()>]
+        address tmp = entry + 4 * 1;
+        Instruction_aarch64::patch(tmp, 31, 22, 0b1011100101);         // opc
+        Instruction_aarch64::patch(tmp, 21, 10, offset_offset >> 2);   // imm12
+        Instruction_aarch64::patch(tmp, 9, 5, 0);                      // Rn
+        Instruction_aarch64::patch(tmp, 4, 0, 1);                      // Rt
+      }
+      guarantee(Instruction_aarch64::extract(((unsigned*)entry)[2], 31, 23) == 0b101100100 &&
+             Instruction_aarch64::extract(((unsigned*)entry)[2], 9, 0) == 0b1111100010, "wrong insns in patch");
+      Instruction_aarch64::patch(entry + 4 * 2, 22, 10,
+                                 (uint64_t)encode_logical_immediate(false, (uint64_t)value_offset));   // imm16
+      ICache::invalidate_range(entry, 4 * 3);
+      break;
+    default:
+      break;
+    }
+  }
+
   protected:
 
   // Size of interpreter code.  Increase if too small.  Interpreter will
diff --git a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp
index 9e48a1d94..0007aa8be 100644
--- a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp
+++ b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp
@@ -31,20 +31,17 @@
 #ifdef CC_INTERP
 # define __ _masm->
 
-void CppInterpreter::initialize_stub() {
+void CppInterpreter::initialize() {
   if (_code != NULL) return;
-  int code_size = InterpreterCodeSize;
-  NOT_PRODUCT(code_size *= 4;)  // debug uses extra interpreter code space
-  _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,
-                        "Interpreter");
-}
-
-void CppInterpreter::initialize_code() {
   AbstractInterpreter::initialize();
 
   // generate interpreter
   { ResourceMark rm;
     TraceTime timer("Interpreter generation", TraceStartupTime);
+    int code_size = InterpreterCodeSize;
+    NOT_PRODUCT(code_size *= 4;)  // debug uses extra interpreter code space
+    _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,
+                          "Interpreter");
     InterpreterGenerator g(_code);
     if (PrintInterpreter) print();
   }
diff --git a/hotspot/src/share/vm/interpreter/cppInterpreter.hpp b/hotspot/src/share/vm/interpreter/cppInterpreter.hpp
index 58efcfaf2..6a6447503 100644
--- a/hotspot/src/share/vm/interpreter/cppInterpreter.hpp
+++ b/hotspot/src/share/vm/interpreter/cppInterpreter.hpp
@@ -54,8 +54,7 @@ class CppInterpreter: public AbstractInterpreter {
 
  public:
   // Initialization/debugging
-  static void       initialize_stub();
-  static void       initialize_code();
+  static void       initialize();
   // this only returns whether a pc is within generated code for the interpreter.
 
   // This is a moderately dubious interface for the c++ interpreter. Only
diff --git a/hotspot/src/share/vm/interpreter/interpreter.cpp b/hotspot/src/share/vm/interpreter/interpreter.cpp
index a313f2e63..bfcb1bea2 100644
--- a/hotspot/src/share/vm/interpreter/interpreter.cpp
+++ b/hotspot/src/share/vm/interpreter/interpreter.cpp
@@ -85,6 +85,7 @@ void InterpreterCodelet::print_on(outputStream* st) const {
 // Implementation of  platform independent aspects of Interpreter
 
 void AbstractInterpreter::initialize() {
+  if (_code != NULL) return;
   // make sure 'imported' classes are initialized
   if (CountBytecodes || TraceBytecodes || StopInterpreterAt) BytecodeCounter::reset();
   if (PrintBytecodeHistogram)                                BytecodeHistogram::reset();
@@ -112,22 +113,8 @@ void AbstractInterpreter::print() {
 }
 
 
-// The reason that interpreter initialization is split into two parts is that the first part
-// needs to run before methods are loaded (which with CDS implies linked also), and the other
-// part needs to run after. The reason is that when methods are loaded (with CDS) or linked
-// (without CDS), the i2c adapters are generated that assert we are currently in the interpreter.
-// Asserting that requires knowledge about where the interpreter is in memory. Therefore,
-// establishing the interpreter address must be done before methods are loaded. However,
-// we would like to actually generate the interpreter after methods are loaded. That allows
-// us to remove otherwise hardcoded offsets regarding fields that are needed in the interpreter
-// code. This leads to a split if 1. reserving the memory for the interpreter, 2. loading methods
-// and 3. generating the interpreter.
-void interpreter_init_stub() {
-  Interpreter::initialize_stub();
-}
-
-void interpreter_init_code() {
-  Interpreter::initialize_code();
+void interpreter_init() {
+  Interpreter::initialize();
 #ifndef PRODUCT
   if (TraceBytecodes) BytecodeTracer::set_closure(BytecodeTracer::std_closure());
 #endif // PRODUCT
diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp
index f38f05117..09298a7fc 100644
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp
@@ -32,20 +32,12 @@
 
 # define __ _masm->
 
-void TemplateInterpreter::initialize_stub() {
+void TemplateInterpreter::initialize() {
   if (_code != NULL) return;
   // assertions
   assert((int)Bytecodes::number_of_codes <= (int)DispatchTable::length,
          "dispatch table too small");
 
-  // allocate interpreter
-  int code_size = InterpreterCodeSize;
-  NOT_PRODUCT(code_size *= 4;)  // debug uses extra interpreter code space
-  _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,
-                        "Interpreter");
-}
-
-void TemplateInterpreter::initialize_code() {
   AbstractInterpreter::initialize();
 
   TemplateTable::initialize();
@@ -53,6 +45,10 @@ void TemplateInterpreter::initialize_code() {
   // generate interpreter
   { ResourceMark rm;
     TraceTime timer("Interpreter generation", TraceStartupTime);
+    int code_size = InterpreterCodeSize;
+    NOT_PRODUCT(code_size *= 4;)  // debug uses extra interpreter code space
+    _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,
+                          "Interpreter");
     InterpreterGenerator g(_code);
     if (PrintInterpreter) print();
   }
diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp
index 96da6353c..5f76dca8a 100644
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp
@@ -132,8 +132,7 @@ class TemplateInterpreter: public AbstractInterpreter {
 
  public:
   // Initialization/debugging
-  static void       initialize_stub();
-  static void       initialize_code();
+  static void       initialize();
   // this only returns whether a pc is within generated code for the interpreter.
   static bool       contains(address pc)                        { return _code != NULL && _code->contains(pc); }
 
diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp
index d9e670bee..1d05bcc73 100644
--- a/hotspot/src/share/vm/memory/universe.cpp
+++ b/hotspot/src/share/vm/memory/universe.cpp
@@ -425,6 +425,14 @@ void Universe::genesis(TRAPS) {
   // Initialize dependency array for null class loader
   ClassLoaderData::the_null_class_loader_data()->init_dependencies(CHECK);
 
+  // Patch the BLAS Interpreter intrinsics with java.lang.String
+  // offset after java.lang.String has been loaded.
+#if defined(TARGET_OS_ARCH_linux_aarch64) && !defined(CC_INTERP)
+  if (UseF2jBLASIntrinsics) {
+    Interpreter::patch_method(Interpreter::org_netlib_blas_Dgemm_dgemm);
+    Interpreter::patch_method(Interpreter::org_netlib_blas_Dgemv_dgemv);
+  }
+#endif
 }
 
 // CDS support for patching vtables in metadata in the shared archive.
diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp
index 4c133bd4e..d15e40d44 100644
--- a/hotspot/src/share/vm/runtime/init.cpp
+++ b/hotspot/src/share/vm/runtime/init.cpp
@@ -54,8 +54,7 @@ void VM_Version_init();
 void os_init_globals();        // depends on VM_Version_init, before universe_init
 void stubRoutines_init1();
 jint universe_init();          // depends on codeCache_init and stubRoutines_init
-void interpreter_init_stub();  // before any methods loaded
-void interpreter_init_code();  // after methods loaded, but before they are linked
+void interpreter_init();       // before any methods loaded
 void invocationCounter_init(); // before any methods loaded
 void marksweep_init();
 void accessFlags_init();
@@ -107,7 +106,7 @@ jint init_globals() {
   if (status != JNI_OK)
     return status;
 
-  interpreter_init_stub(); // before methods get loaded
+  interpreter_init(); // before any methods loaded
   invocationCounter_init();  // before any methods loaded
   marksweep_init();
   accessFlags_init();
@@ -115,7 +114,6 @@ jint init_globals() {
   InterfaceSupport_init();
   SharedRuntime::generate_stubs();
   universe2_init();  // dependent on codeCache_init and stubRoutines_init1
-  interpreter_init_code(); // after universe2_init and before any method gets linked
   referenceProcessor_init();
   jni_handles_init();
 #if INCLUDE_VM_STRUCTS
-- 
2.22.0

