< prev index next >

src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp

Print this page
rev 51490 : 8207343: Automate vtable/itable stub size calculation
Reviewed-by: kvn

@@ -37,59 +37,58 @@
 #include "opto/runtime.hpp"
 #endif
 
 #define __ masm->
 
-#ifdef PRODUCT
-#define BLOCK_COMMENT(str) // nothing
-#else
-#define BLOCK_COMMENT(str) __ block_comment(str)
-#endif
-#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
-
 #ifndef PRODUCT
 extern "C" void bad_compiled_vtable_index(JavaThread* thread, oopDesc* receiver, int index);
 #endif
 
-// Used by compiler only; may use only caller saved, non-argument
-// registers.
+// Used by compiler only; may use only caller saved, non-argument registers.
 VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
-  // PPC port: use fixed size.
-  const int code_length = VtableStub::pd_code_size_limit(true);
-  VtableStub* s = new (code_length) VtableStub(true, vtable_index);
-
+  // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing.
+  const int stub_code_length = code_size_limit(true);
+  VtableStub* s = new(stub_code_length) VtableStub(true, vtable_index);
   // Can be NULL if there is no free space in the code cache.
   if (s == NULL) {
     return NULL;
   }
 
+  // Count unused bytes in instruction sequences of variable size.
+  // We add them to the computed buffer size in order to avoid
+  // overflow in subsequently generated stubs.
+  address   start_pc;
+  int       slop_bytes = 8; // just a two-instruction safety net
+  int       slop_delta = 0;
+
   ResourceMark rm;
-  CodeBuffer cb(s->entry_point(), code_length);
+  CodeBuffer      cb(s->entry_point(), stub_code_length);
   MacroAssembler* masm = new MacroAssembler(&cb);
 
-#ifndef PRODUCT
+#if (!defined(PRODUCT) && defined(COMPILER2))
   if (CountCompiledCalls) {
+    start_pc = __ pc();
+    int load_const_maxLen = 5*BytesPerInstWord;  // load_const generates 5 instructions. Assume that as max size for laod_const_optimized
     int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true);
+    slop_delta  = load_const_maxLen - (__ pc() - start_pc);
+    slop_bytes += slop_delta;
+    assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta);
     __ lwz(R12_scratch2, offs, R11_scratch1);
     __ addi(R12_scratch2, R12_scratch2, 1);
     __ stw(R12_scratch2, offs, R11_scratch1);
   }
 #endif
 
   assert(VtableStub::receiver_location() == R3_ARG1->as_VMReg(), "receiver expected in R3_ARG1");
 
-  // Get receiver klass.
   const Register rcvr_klass = R11_scratch1;
-
-  // We might implicit NULL fault here.
   address npe_addr = __ pc(); // npe = null pointer exception
+  // check if we must do an explicit check (implicit checks disabled, offset too large).
   __ null_check(R3, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL);
+  // Get receiver klass.
   __ load_klass(rcvr_klass, R3);
 
- // Set method (in case of interpreted method), and destination address.
-  int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index*vtableEntry::size_in_bytes();
-
 #ifndef PRODUCT
   if (DebugVtables) {
     Label L;
     // Check offset vs vtable length.
     const Register vtable_len = R12_scratch2;

@@ -100,10 +99,12 @@
     __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), R3_ARG1, R12_scratch2, false);
     __ bind(L);
   }
 #endif
 
+  int entry_offset = in_bytes(Klass::vtable_start_offset()) +
+                     vtable_index*vtableEntry::size_in_bytes();
   int v_off = entry_offset + vtableEntry::method_offset_in_bytes();
 
   __ ld(R19_method, (RegisterOrConstant)v_off, rcvr_klass);
 
 #ifndef PRODUCT

@@ -114,44 +115,52 @@
     __ stop("Vtable entry is ZERO", 102);
     __ bind(L);
   }
 #endif
 
-  // If the vtable entry is null, the method is abstract.
   address ame_addr = __ pc(); // ame = abstract method error
+                              // if the vtable entry is null, the method is abstract
+                              // NOTE: for vtable dispatches, the vtable entry will never be null.
+
   __ null_check(R19_method, in_bytes(Method::from_compiled_offset()), /*implicit only*/NULL);
   __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
   __ mtctr(R12_scratch2);
   __ bctr();
 
   masm->flush();
-
-  guarantee(__ pc() <= s->code_end(), "overflowed buffer");
-
-  s->set_exception_points(npe_addr, ame_addr);
+  bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, 0);
 
   return s;
 }
 
 VtableStub* VtableStubs::create_itable_stub(int itable_index) {
-  // PPC port: use fixed size.
-  const int code_length = VtableStub::pd_code_size_limit(false);
-  VtableStub* s = new (code_length) VtableStub(false, itable_index);
-
+  // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing.
+  const int stub_code_length = code_size_limit(false);
+  VtableStub* s = new(stub_code_length) VtableStub(false, itable_index);
   // Can be NULL if there is no free space in the code cache.
   if (s == NULL) {
     return NULL;
   }
+  // Count unused bytes in instruction sequences of variable size.
+  // We add them to the computed buffer size in order to avoid
+  // overflow in subsequently generated stubs.
+  address   start_pc;
+  int       slop_bytes = 8; // just a two-instruction safety net
+  int       slop_delta = 0;
 
   ResourceMark rm;
-  CodeBuffer cb(s->entry_point(), code_length);
+  CodeBuffer      cb(s->entry_point(), stub_code_length);
   MacroAssembler* masm = new MacroAssembler(&cb);
-  address start_pc;
+  int             load_const_maxLen = 5*BytesPerInstWord;  // load_const generates 5 instructions. Assume that as max size for laod_const_optimized
 
-#ifndef PRODUCT
+#if (!defined(PRODUCT) && defined(COMPILER2))
   if (CountCompiledCalls) {
+    start_pc = __ pc();
     int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true);
+    slop_delta  = load_const_maxLen - (__ pc() - start_pc);
+    slop_bytes += slop_delta;
+    assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta);
     __ lwz(R12_scratch2, offs, R11_scratch1);
     __ addi(R12_scratch2, R12_scratch2, 1);
     __ stw(R12_scratch2, offs, R11_scratch1);
   }
 #endif

@@ -207,35 +216,24 @@
   // More detailed error message.
   // We force resolving of the call site by jumping to the "handle
   // wrong method" stub, and so let the interpreter runtime do all the
   // dirty work.
   __ bind(L_no_such_interface);
+  start_pc = __ pc();
   __ load_const_optimized(R11_scratch1, SharedRuntime::get_handle_wrong_method_stub(), R12_scratch2);
+  slop_delta  = load_const_maxLen - (__ pc() - start_pc);
+  slop_bytes += slop_delta;
+  assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta);
   __ mtctr(R11_scratch1);
   __ bctr();
 
   masm->flush();
+  bookkeeping(masm, tty, s, npe_addr, ame_addr, false, itable_index, slop_bytes, 0);
 
-  guarantee(__ pc() <= s->code_end(), "overflowed buffer");
-
-  s->set_exception_points(npe_addr, ame_addr);
   return s;
 }
 
-int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
-  if (DebugVtables || CountCompiledCalls || VerifyOops) {
-    return 1000;
-  }
-  int size = is_vtable_stub ? 20 + 8 : 164 + 20; // Plain + safety
-  if (UseCompressedClassPointers) {
-    size += MacroAssembler::instr_size_for_decode_klass_not_null();
-  }
-  if (!ImplicitNullChecks || !os::zero_page_read_protected()) {
-    size += is_vtable_stub ? 8 : 12;
-  }
-  return size;
-}
-
 int VtableStub::pd_code_alignment() {
+  // Power cache line size is 128 bytes, but we want to limit alignment loss.
   const unsigned int icache_line_size = 32;
   return icache_line_size;
 }
< prev index next >