changeset 8561:1cd346521065 jdk8u161-b13-aarch32-180220

8174962: [aarch32] Better interface invocations Reviewed-by: duke Contributed-by: Anton Kozlov <akozlov@azul.com>
author snazarki
date Tue, 20 Feb 2018 13:39:15 +0300
parents 0f0a20929b1a
children 70a3ac350241
files src/cpu/aarch32/vm/macroAssembler_aarch32.cpp src/cpu/aarch32/vm/macroAssembler_aarch32.hpp src/cpu/aarch32/vm/sharedRuntime_aarch32.cpp src/cpu/aarch32/vm/templateTable_aarch32.cpp src/cpu/aarch32/vm/vtableStubs_aarch32.cpp
diffstat 5 files changed, 83 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/aarch32/vm/macroAssembler_aarch32.cpp	Tue Feb 20 12:56:36 2018 +0300
+++ b/src/cpu/aarch32/vm/macroAssembler_aarch32.cpp	Tue Feb 20 13:39:15 2018 +0300
@@ -793,10 +793,12 @@
                                              RegisterOrConstant itable_index,
                                              Register method_result,
                                              Register scan_temp,
-                                             Label& L_no_such_interface) {
-  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");
+                                             Label& L_no_such_interface,
+                                             bool return_method) {
+  assert_different_registers(recv_klass, intf_klass, scan_temp);
+  assert_different_registers(method_result, intf_klass, scan_temp);
+  assert(recv_klass != method_result || !return_method,
+         "recv_klass can be destroyed when method isn't needed");
 
   // Compute start of first itableOffsetEntry (which is at the end of the vtable)
   int vtable_base = InstanceKlass::vtable_start_offset() * wordSize;
@@ -817,14 +819,16 @@
     round_to(scan_temp, BytesPerLong);
   }
 
-  // Adjust recv_klass by scaled itable_index, so we can free itable_index.
-  assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
-  // lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
-  lea(recv_klass, itable_index.is_register() ?
-          Address(recv_klass, itable_index, lsl(2)) :
-          Address(recv_klass, itable_index.as_constant() << 2));
-  if (itentry_off)
-    add(recv_klass, recv_klass, itentry_off);
+  if (return_method) {
+    // Adjust recv_klass by scaled itable_index, so we can free itable_index.
+    assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
+    // lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
+    lea(recv_klass, itable_index.is_register() ?
+            Address(recv_klass, itable_index, lsl(2)) :
+            Address(recv_klass, itable_index.as_constant() << 2));
+    if (itentry_off)
+      add(recv_klass, recv_klass, itentry_off);
+  }
 
   // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
   //   if (scan->interface() == intf) {
@@ -857,9 +861,11 @@
 
   bind(found_method);
 
-  // Got a hit.
-  ldr(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
-  ldr(method_result, Address(recv_klass, scan_temp));
+  if (return_method) {
+    // Got a hit.
+    ldr(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
+    ldr(method_result, Address(recv_klass, scan_temp));
+  }
 }
 
 // virtual method calling
--- a/src/cpu/aarch32/vm/macroAssembler_aarch32.hpp	Tue Feb 20 12:56:36 2018 +0300
+++ b/src/cpu/aarch32/vm/macroAssembler_aarch32.hpp	Tue Feb 20 13:39:15 2018 +0300
@@ -506,7 +506,8 @@
                                RegisterOrConstant itable_index,
                                Register method_result,
                                Register scan_temp,
-                               Label& no_such_interface);
+                               Label& no_such_interface,
+                               bool return_method = true);
 
   // virtual method calling
   // n.b. x86 allows RegisterOrConstant for vtable_index
--- a/src/cpu/aarch32/vm/sharedRuntime_aarch32.cpp	Tue Feb 20 12:56:36 2018 +0300
+++ b/src/cpu/aarch32/vm/sharedRuntime_aarch32.cpp	Tue Feb 20 13:39:15 2018 +0300
@@ -726,7 +726,7 @@
     __ load_klass(rscratch1, receiver);
     __ ldr(tmp, Address(holder, CompiledICHolder::holder_klass_offset()));
     __ cmp(rscratch1, tmp);
-    __ ldr(rmethod, Address(holder, CompiledICHolder::holder_method_offset()));
+    __ ldr(rmethod, Address(holder, CompiledICHolder::holder_metadata_offset()));
     __ b(ok, Assembler::EQ);
     __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
 
--- a/src/cpu/aarch32/vm/templateTable_aarch32.cpp	Tue Feb 20 12:56:36 2018 +0300
+++ b/src/cpu/aarch32/vm/templateTable_aarch32.cpp	Tue Feb 20 13:39:15 2018 +0300
@@ -3668,11 +3668,11 @@
   assert(byte_no == f1_byte, "use this argument");
 
   Register temp = rdispatch; //free at this point and reloaded later
-  prepare_invoke(byte_no, r0, rmethod,  // get f1 Klass*, f2 itable index
+  prepare_invoke(byte_no, r0, rmethod,  // get f1 Klass*, f2 Method*
                  r2, r3); // recv, flags
 
   // r0: interface klass (from f1)
-  // rmethod: itable index (from f2)
+  // rmethod: method (from f2)
   // r2: receiver
   // r3: flags
 
@@ -3693,10 +3693,30 @@
   __ null_check(r2, oopDesc::klass_offset_in_bytes());
   __ load_klass(r3, r2);
 
+  Label no_such_interface, no_such_method;
+
+  // Receiver subtype check against REFC.
+  // Superklass in r0. Subklass in r3.
+  __ lookup_interface_method(// inputs: rec. class, interface, itable index
+                             r3, r0, noreg,
+                             // outputs: scan temp. reg, scan temp. reg
+                             rbcp, temp,
+                             no_such_interface,
+                             /*return_method=*/false);
+
+
   // profile this call
+  __ restore_bcp(); // rbcp was destroyed by receiver type check
   __ profile_virtual_call(r3, temp, r1);
 
-  Label no_such_interface, no_such_method;
+  // Get declaring interface class from method, and itable index
+  __ ldr(r0, Address(rmethod, Method::const_offset()));
+  __ ldr(r0, Address(r0, ConstMethod::constants_offset()));
+  __ ldr(r0, Address(r0, ConstantPool::pool_holder_offset_in_bytes()));
+  __ ldr(rmethod, Address(rmethod, Method::itable_index_offset()));
+  assert(Method::itable_index_max <= 0, "incorrect below");
+  __ add(temp, rmethod, -Method::itable_index_max);
+  __ neg(rmethod, temp);
 
   __ lookup_interface_method(// inputs: rec. class, interface, itable index
                              r3, r0, rmethod,
--- a/src/cpu/aarch32/vm/vtableStubs_aarch32.cpp	Tue Feb 20 12:56:36 2018 +0300
+++ b/src/cpu/aarch32/vm/vtableStubs_aarch32.cpp	Tue Feb 20 13:39:15 2018 +0300
@@ -30,6 +30,7 @@
 #include "code/vtableStubs.hpp"
 #include "interp_masm_aarch32.hpp"
 #include "memory/resourceArea.hpp"
+#include "oops/compiledICHolder.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/klassVtable.hpp"
 #include "runtime/sharedRuntime.hpp"
@@ -136,53 +137,65 @@
 #endif
 
   // Entry arguments:
-  //  rscratch2: Interface
+  //  rscratch2: CompiledICHolder
   //  j_rarg0: Receiver
 
   // Free registers (non-args) are r0 (interface), rmethod
 
-  // get receiver (need to skip return address on top of stack)
-
-  assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
-  // get receiver klass (also an implicit null-check)
-  address npe_addr = __ pc();
-
   // Most registers are in use; we'll use r0, rmethod, rscratch1, r4
   // IMPORTANT: r4 is used as a temp register, if it's changed callee-save
   // the code should be fixed
   // TODO: put an assert here to ensure r4 is caller-save
-  __ load_klass(rscratch1, j_rarg0);
+  const Register recv_klass_reg     = rscratch1;
+  const Register holder_klass_reg   = rscratch2; // declaring interface klass (DECC)
+  const Register resolved_klass_reg = rmethod; // resolved interface klass (REFC)
+  const Register temp_reg           = r4;
 
-  Label throw_icce;
+  __ ldr(resolved_klass_reg, Address(rscratch2, CompiledICHolder::holder_klass_offset()));
+  __ ldr(holder_klass_reg,   Address(rscratch2, CompiledICHolder::holder_metadata_offset()));
 
-  // Get Method* and entrypoint for compiler
+  Label L_no_such_interface;
+
+  // get receiver klass (also an implicit null-check)
+  address npe_addr = __ pc();
+  assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
+  __ load_klass(recv_klass_reg, j_rarg0);
+
+  // Receiver subtype check against REFC.
+  // Destroys recv_klass_reg value.
+  __ lookup_interface_method(// inputs: rec. class, interface
+                             recv_klass_reg, resolved_klass_reg, noreg,
+                             // outputs:  scan temp. reg1, scan temp. reg2
+                             recv_klass_reg, temp_reg,
+                             L_no_such_interface,
+                             /*return_method=*/false);
+
+  // Get selected method from declaring class and itable index
+  __ load_klass(recv_klass_reg, j_rarg0); // restore recv_klass_reg
   __ lookup_interface_method(// inputs: rec. class, interface, itable index
-                             rscratch1, rscratch2, itable_index,
+                             recv_klass_reg, holder_klass_reg, itable_index,
                              // outputs: method, scan temp. reg
-                             rmethod, r4,
-                             throw_icce);
-
-  // method (rmethod): Method*
+                             rmethod, temp_reg,
+                             L_no_such_interface);
+  // rmethod: Method*
   // j_rarg0: receiver
 
 #ifdef ASSERT
   if (DebugVtables) {
     Label L2;
     __ cbz(rmethod, L2);
-    __ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset()));
-    __ cbnz(rscratch1, L2);
+    __ ldr(recv_klass_reg, Address(rmethod, Method::from_compiled_offset()));
+    __ cbnz(recv_klass_reg, L2);
     __ stop("compiler entrypoint is null");
     __ bind(L2);
   }
 #endif // ASSERT
 
-  // rmethod: Method*
-  // j_rarg0: receiver
   address ame_addr = __ pc();
-  __ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset()));
-  __ b(rscratch1);
+  __ ldr(recv_klass_reg, Address(rmethod, Method::from_compiled_offset()));
+  __ b(recv_klass_reg);
 
-  __ bind(throw_icce);
+  __ bind(L_no_such_interface);
   __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
 
   __ flush();
@@ -207,7 +220,7 @@
   if (is_vtable_stub)
     size += 26;
   else
-    size += 92;
+    size += 160;
   return size;
 
   // In order to tune these parameters, run the JVM with VM options