changeset 9814:b1606443958a jdk8u161-b11

8191907: PPC64 part of JDK-8174962: Better interface invocations Reviewed-by: goetz
author mdoerr
date Tue, 28 Nov 2017 01:07:05 +0300
parents 712de5fe954c
children 210f7ef62595 9f51d57ccc30
files src/cpu/ppc/vm/macroAssembler_ppc.cpp src/cpu/ppc/vm/macroAssembler_ppc.hpp src/cpu/ppc/vm/templateTable_ppc_64.cpp src/cpu/ppc/vm/vtableStubs_ppc_64.cpp
diffstat 4 files changed, 118 insertions(+), 130 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp	Tue Dec 05 13:24:09 2017 -0800
+++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp	Tue Nov 28 01:07:05 2017 +0300
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2014 SAP AG. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2017 SAP AG. 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,11 +1531,10 @@
                                              RegisterOrConstant itable_index,
                                              Register method_result,
                                              Register scan_temp,
-                                             Register sethi_temp,
-                                             Label& L_no_such_interface) {
+                                             Register temp2,
+                                             Label& L_no_such_interface,
+                                             bool return_method) {
   assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
-  assert(itable_index.is_constant() || itable_index.as_register() == method_result,
-         "caller must use same register for non-constant itable index as for method");
 
   // Compute start of first itableOffsetEntry (which is at the end of the vtable).
   int vtable_base = InstanceKlass::vtable_start_offset() * wordSize;
@@ -1553,15 +1552,18 @@
   add(scan_temp, recv_klass, scan_temp);
 
   // Adjust recv_klass by scaled itable_index, so we can free itable_index.
-  if (itable_index.is_register()) {
-    Register itable_offset = itable_index.as_register();
-    sldi(itable_offset, itable_offset, logMEsize);
-    if (itentry_off) addi(itable_offset, itable_offset, itentry_off);
-    add(recv_klass, itable_offset, recv_klass);
-  } else {
-    long itable_offset = (long)itable_index.as_constant();
-    load_const_optimized(sethi_temp, (itable_offset<<logMEsize)+itentry_off); // static address, no relocation
-    add(recv_klass, sethi_temp, recv_klass);
+  if (return_method) {
+    if (itable_index.is_register()) {
+      Register itable_offset = itable_index.as_register();
+      sldi(method_result, itable_offset, logMEsize);
+      if (itentry_off) { addi(method_result, method_result, itentry_off); }
+      add(method_result, method_result, recv_klass);
+    } else {
+      long itable_offset = (long)itable_index.as_constant();
+      // static address, no relocation
+      load_const_optimized(temp2, (itable_offset << logMEsize) + itentry_off); // static address, no relocation
+      add(method_result, temp2, recv_klass);
+    }
   }
 
   // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
@@ -1574,12 +1576,12 @@
   for (int peel = 1; peel >= 0; peel--) {
     // %%%% Could load both offset and interface in one ldx, if they were
     // in the opposite order. This would save a load.
-    ld(method_result, itableOffsetEntry::interface_offset_in_bytes(), scan_temp);
+    ld(temp2, itableOffsetEntry::interface_offset_in_bytes(), scan_temp);
 
     // Check that this entry is non-null. A null entry means that
     // the receiver class doesn't implement the interface, and wasn't the
     // same as when the caller was compiled.
-    cmpd(CCR0, method_result, intf_klass);
+    cmpd(CCR0, temp2, intf_klass);
 
     if (peel) {
       beq(CCR0, found_method);
@@ -1592,7 +1594,7 @@
 
     bind(search);
 
-    cmpdi(CCR0, method_result, 0);
+    cmpdi(CCR0, temp2, 0);
     beq(CCR0, L_no_such_interface);
     addi(scan_temp, scan_temp, scan_step);
   }
@@ -1600,9 +1602,11 @@
   bind(found_method);
 
   // Got a hit.
-  int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
-  lwz(scan_temp, ito_offset, scan_temp);
-  ldx(method_result, scan_temp, recv_klass);
+  if (return_method) {
+    int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
+    lwz(scan_temp, ito_offset, scan_temp);
+    ldx(method_result, scan_temp, method_result);
+  }
 }
 
 // virtual method calling
--- a/src/cpu/ppc/vm/macroAssembler_ppc.hpp	Tue Dec 05 13:24:09 2017 -0800
+++ b/src/cpu/ppc/vm/macroAssembler_ppc.hpp	Tue Nov 28 01:07:05 2017 +0300
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2014 SAP AG. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2017 SAP AG. 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
@@ -441,7 +441,8 @@
                                RegisterOrConstant itable_index,
                                Register method_result,
                                Register temp_reg, Register temp2_reg,
-                               Label& no_such_interface);
+                               Label& no_such_interface,
+                               bool return_method = true);
 
   // virtual method calling
   void lookup_virtual_method(Register recv_klass,
--- a/src/cpu/ppc/vm/templateTable_ppc_64.cpp	Tue Dec 05 13:24:09 2017 -0800
+++ b/src/cpu/ppc/vm/templateTable_ppc_64.cpp	Tue Nov 28 01:07:05 2017 +0300
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013, 2014 SAP AG. All rights reserved.
+ * Copyright (c) 2014, 2017 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, 2017 SAP AG. 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
@@ -3418,11 +3418,11 @@
 void TemplateTable::invokeinterface_object_method(Register Rrecv_klass,
                                                   Register Rret,
                                                   Register Rflags,
-                                                  Register Rindex,
+                                                  Register Rmethod,
                                                   Register Rtemp1,
                                                   Register Rtemp2) {
 
-  assert_different_registers(Rindex, Rret, Rrecv_klass, Rflags, Rtemp1, Rtemp2);
+  assert_different_registers(Rmethod, Rret, Rrecv_klass, Rflags, Rtemp1, Rtemp2);
   Label LnotFinal;
 
   // Check for vfinal.
@@ -3434,14 +3434,14 @@
   // Final call case.
   __ profile_final_call(Rtemp1, Rscratch);
   // Argument and return type profiling.
-  __ profile_arguments_type(Rindex, Rscratch, Rrecv_klass /* scratch */, true);
+  __ profile_arguments_type(Rmethod, Rscratch, Rrecv_klass /* scratch */, true);
   // Do the final call - the index (f2) contains the method.
-  __ call_from_interpreter(Rindex, Rret, Rscratch, Rrecv_klass /* scratch */);
+  __ call_from_interpreter(Rmethod, Rret, Rscratch, Rrecv_klass /* scratch */);
 
   // Non-final callc case.
   __ bind(LnotFinal);
   __ profile_virtual_call(Rrecv_klass, Rtemp1, Rscratch, false);
-  generate_vtable_call(Rrecv_klass, Rindex, Rret, Rscratch);
+  generate_vtable_call(Rrecv_klass, Rmethod, Rret, Rscratch);
 }
 
 void TemplateTable::invokeinterface(int byte_no) {
@@ -3450,58 +3450,61 @@
 
   const Register Rscratch1        = R11_scratch1,
                  Rscratch2        = R12_scratch2,
-                 Rscratch3        = R9_ARG7,
-                 Rscratch4        = R10_ARG8,
-                 Rtable_addr      = Rscratch2,
+                 Rmethod          = R6_ARG4,
+                 Rmethod2         = R9_ARG7,
                  Rinterface_klass = R5_ARG3,
-                 Rret_type        = R8_ARG6,
-                 Rret_addr        = Rret_type,
-                 Rindex           = R6_ARG4,
-                 Rreceiver        = R4_ARG2,
-                 Rrecv_klass      = Rreceiver,
+                 Rret_addr        = R8_ARG6,
+                 Rindex           = R10_ARG8,
+                 Rreceiver        = R3_ARG1,
+                 Rrecv_klass      = R4_ARG2,
                  Rflags           = R7_ARG5;
 
-  prepare_invoke(byte_no, Rinterface_klass, Rret_addr, Rindex, Rreceiver, Rflags, Rscratch1);
+  prepare_invoke(byte_no, Rinterface_klass, Rret_addr, Rmethod, Rreceiver, Rflags, Rscratch1);
 
   // Get receiver klass.
-  __ null_check_throw(Rreceiver, oopDesc::klass_offset_in_bytes(), Rscratch3);
+  __ null_check_throw(Rreceiver, oopDesc::klass_offset_in_bytes(), Rscratch2);
   __ load_klass(Rrecv_klass, Rreceiver);
 
   // Check corner case object method.
-  Label LobjectMethod;
-
+  Label LobjectMethod, L_no_such_interface, Lthrow_ame;
   __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_forced_virtual_shift);
   __ btrue(CCR0, LobjectMethod);
 
-  // Fallthrough: The normal invokeinterface case.
+  __ lookup_interface_method(Rrecv_klass, Rinterface_klass, noreg, noreg, Rscratch1, Rscratch2,
+                             L_no_such_interface, /*return_method=*/false);
+
   __ profile_virtual_call(Rrecv_klass, Rscratch1, Rscratch2, false);
 
   // Find entry point to call.
-  Label Lthrow_icc, Lthrow_ame;
-  // Result will be returned in Rindex.
-  __ mr(Rscratch4, Rrecv_klass);
-  __ mr(Rscratch3, Rindex);
-  __ lookup_interface_method(Rrecv_klass, Rinterface_klass, Rindex, Rindex, Rscratch1, Rscratch2, Lthrow_icc);
-
-  __ cmpdi(CCR0, Rindex, 0);
+
+  // Get declaring interface class from method
+  __ ld(Rinterface_klass, in_bytes(Method::const_offset()), Rmethod);
+  __ ld(Rinterface_klass, in_bytes(ConstMethod::constants_offset()), Rinterface_klass);
+  __ ld(Rinterface_klass, ConstantPool::pool_holder_offset_in_bytes(), Rinterface_klass);
+
+  // Get itable index from method
+  __ lwa(Rindex, in_bytes(Method::itable_index_offset()), Rmethod);
+  __ subfic(Rindex, Rindex, Method::itable_index_max);
+
+  __ lookup_interface_method(Rrecv_klass, Rinterface_klass, Rindex, Rmethod2, Rscratch1, Rscratch2,
+                             L_no_such_interface);
+
+  __ cmpdi(CCR0, Rmethod2, 0);
   __ beq(CCR0, Lthrow_ame);
   // Found entry. Jump off!
   // Argument and return type profiling.
-  __ profile_arguments_type(Rindex, Rscratch1, Rscratch2, true);
-  __ call_from_interpreter(Rindex, Rret_addr, Rscratch1, Rscratch2);
+  __ profile_arguments_type(Rmethod2, Rscratch1, Rscratch2, true);
+  //__ profile_called_method(Rindex, Rscratch1);
+  __ call_from_interpreter(Rmethod2, Rret_addr, Rscratch1, Rscratch2);
 
   // Vtable entry was NULL => Throw abstract method error.
   __ bind(Lthrow_ame);
-  __ mr(Rrecv_klass, Rscratch4);
-  __ mr(Rindex, Rscratch3);
   call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
 
   // Interface was not found => Throw incompatible class change error.
-  __ bind(Lthrow_icc);
-  __ mr(Rrecv_klass, Rscratch4);
+  __ bind(L_no_such_interface);
   call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
-
-  __ should_not_reach_here();
+  DEBUG_ONLY( __ should_not_reach_here(); )
 
   // Special case of invokeinterface called for virtual method of
   // java.lang.Object. See ConstantPoolCacheEntry::set_method() for details:
@@ -3509,7 +3512,7 @@
   // to handle this corner case. This code isn't produced by javac, but could
   // be produced by another compliant java compiler.
   __ bind(LobjectMethod);
-  invokeinterface_object_method(Rrecv_klass, Rret_addr, Rflags, Rindex, Rscratch1, Rscratch2);
+  invokeinterface_object_method(Rrecv_klass, Rret_addr, Rflags, Rmethod, Rscratch1, Rscratch2);
 }
 
 void TemplateTable::invokedynamic(int byte_no) {
--- a/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp	Tue Dec 05 13:24:09 2017 -0800
+++ b/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp	Tue Nov 28 01:07:05 2017 +0300
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2014 SAP AG. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2017 SAP AG. 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
@@ -29,6 +29,7 @@
 #include "code/vtableStubs.hpp"
 #include "interp_masm_ppc_64.hpp"
 #include "memory/resourceArea.hpp"
+#include "oops/compiledICHolder.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/klassVtable.hpp"
 #include "runtime/sharedRuntime.hpp"
@@ -56,17 +57,22 @@
   // PPC port: use fixed size.
   const int code_length = VtableStub::pd_code_size_limit(true);
   VtableStub* s = new (code_length) VtableStub(true, vtable_index);
+
+  // Can be NULL if there is no free space in the code cache.
+  if (s == NULL) {
+    return NULL;
+  }
+
   ResourceMark rm;
   CodeBuffer cb(s->entry_point(), code_length);
   MacroAssembler* masm = new MacroAssembler(&cb);
-  address start_pc;
 
 #ifndef PRODUCT
   if (CountCompiledCalls) {
-    __ load_const(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr());
-    __ lwz(R12_scratch2, 0, R11_scratch1);
+    int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true);
+    __ lwz(R12_scratch2, offs, R11_scratch1);
     __ addi(R12_scratch2, R12_scratch2, 1);
-    __ stw(R12_scratch2, 0, R11_scratch1);
+    __ stw(R12_scratch2, offs, R11_scratch1);
   }
 #endif
 
@@ -116,6 +122,7 @@
   __ load_with_trap_null_check(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
   __ mtctr(R12_scratch2);
   __ bctr();
+
   masm->flush();
 
   guarantee(__ pc() <= s->code_end(), "overflowed buffer");
@@ -125,10 +132,16 @@
   return s;
 }
 
-VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
+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, vtable_index);
+  VtableStub* s = new (code_length) VtableStub(false, itable_index);
+
+  // Can be NULL if there is no free space in the code cache.
+  if (s == NULL) {
+    return NULL;
+  }
+
   ResourceMark rm;
   CodeBuffer cb(s->entry_point(), code_length);
   MacroAssembler* masm = new MacroAssembler(&cb);
@@ -136,10 +149,10 @@
 
 #ifndef PRODUCT
   if (CountCompiledCalls) {
-    __ load_const(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr());
-    __ lwz(R12_scratch2, 0, R11_scratch1);
+    int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true);
+    __ lwz(R12_scratch2, offs, R11_scratch1);
     __ addi(R12_scratch2, R12_scratch2, 1);
-    __ stw(R12_scratch2, 0, R11_scratch1);
+    __ stw(R12_scratch2, offs, R11_scratch1);
   }
 #endif
 
@@ -148,61 +161,27 @@
   // Entry arguments:
   //  R19_method: Interface
   //  R3_ARG1:    Receiver
-  //
 
-  const Register rcvr_klass = R11_scratch1;
-  const Register vtable_len = R12_scratch2;
-  const Register itable_entry_addr = R21_tmp1;
-  const Register itable_interface = R22_tmp2;
+  Label L_no_such_interface;
+  const Register rcvr_klass = R11_scratch1,
+                 interface  = R12_scratch2,
+                 tmp1       = R21_tmp1,
+                 tmp2       = R22_tmp2;
 
-  // Get receiver klass.
-
-  // We might implicit NULL fault here.
   address npe_addr = __ pc(); // npe = null pointer exception
   __ load_klass_with_trap_null_check(rcvr_klass, R3_ARG1);
 
-  BLOCK_COMMENT("Load start of itable entries into itable_entry.");
-  __ lwz(vtable_len, InstanceKlass::vtable_length_offset() * wordSize, rcvr_klass);
-  __ slwi(vtable_len, vtable_len, exact_log2(vtableEntry::size() * wordSize));
-  __ add(itable_entry_addr, vtable_len, rcvr_klass);
-
-  // Loop over all itable entries until desired interfaceOop(Rinterface) found.
-  BLOCK_COMMENT("Increment itable_entry_addr in loop.");
-  const int vtable_base_offset = InstanceKlass::vtable_start_offset() * wordSize;
-  __ addi(itable_entry_addr, itable_entry_addr, vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes());
-
-  const int itable_offset_search_inc = itableOffsetEntry::size() * wordSize;
-  Label search;
-  __ bind(search);
-  __ ld(itable_interface, 0, itable_entry_addr);
+  // Receiver subtype check against REFC.
+  __ ld(interface, CompiledICHolder::holder_klass_offset(), R19_method);
+  __ lookup_interface_method(rcvr_klass, interface, noreg,
+                             R0, tmp1, tmp2,
+                             L_no_such_interface, /*return_method=*/ false);
 
-  // Handle IncompatibleClassChangeError in itable stubs.
-  // If the entry is NULL then we've reached the end of the table
-  // without finding the expected interface, so throw an exception.
-  BLOCK_COMMENT("Handle IncompatibleClassChangeError in itable stubs.");
-  Label throw_icce;
-  __ cmpdi(CCR1, itable_interface, 0);
-  __ cmpd(CCR0, itable_interface, R19_method);
-  __ addi(itable_entry_addr, itable_entry_addr, itable_offset_search_inc);
-  __ beq(CCR1, throw_icce);
-  __ bne(CCR0, search);
-
-  // Entry found and itable_entry_addr points to it, get offset of vtable for interface.
-
-  const Register vtable_offset = R12_scratch2;
-  const Register itable_method = R11_scratch1;
-
-  const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() -
-                                    itableOffsetEntry::interface_offset_in_bytes()) -
-                                   itable_offset_search_inc;
-  __ lwz(vtable_offset, vtable_offset_offset, itable_entry_addr);
-
-  // Compute itableMethodEntry and get method and entry point for compiler.
-  const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) +
-    itableMethodEntry::method_offset_in_bytes();
-
-  __ add(itable_method, rcvr_klass, vtable_offset);
-  __ ld(R19_method, method_offset, itable_method);
+  // Get Method* and entrypoint for compiler
+  __ ld(interface, CompiledICHolder::holder_metadata_offset(), R19_method);
+  __ lookup_interface_method(rcvr_klass, interface, itable_index,
+                             R19_method, tmp1, tmp2,
+                             L_no_such_interface, /*return_method=*/ true);
 
 #ifndef PRODUCT
   if (DebugVtables) {
@@ -224,7 +203,7 @@
       __ trap_null_check(R19_method);
     } else {
       __ cmpdi(CCR0, R19_method, 0);
-      __ beq(CCR0, throw_icce);
+      __ beq(CCR0, L_no_such_interface);
     }
   }
   __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
@@ -236,8 +215,8 @@
   // 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(throw_icce);
-  __ load_const(R11_scratch1, SharedRuntime::get_handle_wrong_method_stub());
+  __ bind(L_no_such_interface);
+  __ load_const_optimized(R11_scratch1, SharedRuntime::get_handle_wrong_method_stub(), R12_scratch2);
   __ mtctr(R11_scratch1);
   __ bctr();
 
@@ -252,14 +231,15 @@
 int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
   if (TraceJumps || DebugVtables || CountCompiledCalls || VerifyOops) {
     return 1000;
-  } else {
-    int decode_klass_size = MacroAssembler::instr_size_for_decode_klass_not_null();
-    if (is_vtable_stub) {
-      return 20 + decode_klass_size +  8 + 8;   // Plain + cOops + Traps + safety
-    } else {
-      return 96 + decode_klass_size + 12 + 8;   // Plain + cOops + Traps + safety
-    }
+  }
+  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() {