8191907: PPC64 and s390 parts of JDK-8174962: Better interface invocations
Reviewed-by: goetz
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Mon Nov 06 10:24:42 2017 -0800
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Tue Nov 28 01:08:26 2017 +0300
@@ -1788,11 +1788,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 = in_bytes(Klass::vtable_start_offset());
@@ -1810,15 +1809,17 @@
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
+ add_const_optimized(method_result, recv_klass, (itable_offset << logMEsize) + itentry_off, temp2);
+ }
}
// for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
@@ -1831,12 +1832,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);
@@ -1849,7 +1850,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);
}
@@ -1857,9 +1858,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/hotspot/cpu/ppc/macroAssembler_ppc.hpp Mon Nov 06 10:24:42 2017 -0800
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp Tue Nov 28 01:08:26 2017 +0300
@@ -519,7 +519,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/hotspot/cpu/ppc/templateTable_ppc_64.cpp Mon Nov 06 10:24:42 2017 -0800
+++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Tue Nov 28 01:08:26 2017 +0300
@@ -3486,11 +3486,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.
@@ -3502,14 +3502,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) {
@@ -3518,58 +3518,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:
@@ -3577,7 +3580,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/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp Mon Nov 06 10:24:42 2017 -0800
+++ b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp Tue Nov 28 01:08:26 2017 +0300
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2016 SAP SE. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 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
@@ -28,6 +28,7 @@
#include "code/vtableStubs.hpp"
#include "interp_masm_ppc.hpp"
#include "memory/resourceArea.hpp"
+#include "oops/compiledICHolder.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp"
#include "runtime/sharedRuntime.hpp"
@@ -55,17 +56,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 @@
__ ld(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,62 +161,28 @@
// 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
__ null_check(R3_ARG1, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL);
__ load_klass(rcvr_klass, R3_ARG1);
- BLOCK_COMMENT("Load start of itable entries into itable_entry.");
- __ lwz(vtable_len, in_bytes(Klass::vtable_length_offset()), rcvr_klass);
- __ slwi(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
- __ 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 = in_bytes(Klass::vtable_start_offset());
- __ 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) {
@@ -219,7 +198,7 @@
address ame_addr = __ pc(); // ame = abstract method error
// Must do an explicit check if implicit checks are disabled.
- __ null_check(R19_method, in_bytes(Method::from_compiled_offset()), &throw_icce);
+ __ null_check(R19_method, in_bytes(Method::from_compiled_offset()), &L_no_such_interface);
__ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
__ mtctr(R12_scratch2);
__ bctr();
@@ -229,8 +208,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();
@@ -245,14 +224,15 @@
int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
if (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() {
--- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp Mon Nov 06 10:24:42 2017 -0800
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp Tue Nov 28 01:08:26 2017 +0300
@@ -2806,8 +2806,8 @@
RegisterOrConstant itable_index,
Register method_result,
Register temp1_reg,
- Register temp2_reg,
- Label& no_such_interface) {
+ Label& no_such_interface,
+ bool return_method) {
const Register vtable_len = temp1_reg; // Used to compute itable_entry_addr.
const Register itable_entry_addr = Z_R1_scratch;
@@ -2842,38 +2842,36 @@
z_brne(search);
// Entry found and itable_entry_addr points to it, get offset of vtable for interface.
-
- const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() -
- itableOffsetEntry::interface_offset_in_bytes()) -
- itable_offset_search_inc;
-
- // Compute itableMethodEntry and get method and entry point
- // we use addressing with index and displacement, since the formula
- // for computing the entry's offset has a fixed and a dynamic part,
- // the latter depending on the matched interface entry and on the case,
- // that the itable index has been passed as a register, not a constant value.
- int method_offset = itableMethodEntry::method_offset_in_bytes();
- // Fixed part (displacement), common operand.
- Register itable_offset; // Dynamic part (index register).
-
- if (itable_index.is_register()) {
- // Compute the method's offset in that register, for the formula, see the
- // else-clause below.
- itable_offset = itable_index.as_register();
-
- z_sllg(itable_offset, itable_offset, exact_log2(itableMethodEntry::size() * wordSize));
- z_agf(itable_offset, vtable_offset_offset, itable_entry_addr);
- } else {
- itable_offset = Z_R1_scratch;
- // Displacement increases.
- method_offset += itableMethodEntry::size() * wordSize * itable_index.as_constant();
-
- // Load index from itable.
- z_llgf(itable_offset, vtable_offset_offset, itable_entry_addr);
- }
-
- // Finally load the method's oop.
- z_lg(method_result, method_offset, itable_offset, recv_klass);
+ if (return_method) {
+ const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() -
+ itableOffsetEntry::interface_offset_in_bytes()) -
+ itable_offset_search_inc;
+
+ // Compute itableMethodEntry and get method and entry point
+ // we use addressing with index and displacement, since the formula
+ // for computing the entry's offset has a fixed and a dynamic part,
+ // the latter depending on the matched interface entry and on the case,
+ // that the itable index has been passed as a register, not a constant value.
+ int method_offset = itableMethodEntry::method_offset_in_bytes();
+ // Fixed part (displacement), common operand.
+ Register itable_offset = method_result; // Dynamic part (index register).
+
+ if (itable_index.is_register()) {
+ // Compute the method's offset in that register, for the formula, see the
+ // else-clause below.
+ z_sllg(itable_offset, itable_index.as_register(), exact_log2(itableMethodEntry::size() * wordSize));
+ z_agf(itable_offset, vtable_offset_offset, itable_entry_addr);
+ } else {
+ // Displacement increases.
+ method_offset += itableMethodEntry::size() * wordSize * itable_index.as_constant();
+
+ // Load index from itable.
+ z_llgf(itable_offset, vtable_offset_offset, itable_entry_addr);
+ }
+
+ // Finally load the method's oop.
+ z_lg(method_result, method_offset, itable_offset, recv_klass);
+ }
BLOCK_COMMENT("} lookup_interface_method");
}
--- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp Mon Nov 06 10:24:42 2017 -0800
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp Tue Nov 28 01:08:26 2017 +0300
@@ -671,8 +671,8 @@
RegisterOrConstant itable_index,
Register method_result,
Register temp1_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/hotspot/cpu/s390/methodHandles_s390.cpp Mon Nov 06 10:24:42 2017 -0800
+++ b/src/hotspot/cpu/s390/methodHandles_s390.cpp Tue Nov 28 01:08:26 2017 +0300
@@ -498,7 +498,7 @@
Label L_no_such_interface;
__ lookup_interface_method(temp1_recv_klass, temp3_intf,
// Note: next two args must be the same:
- Z_index, Z_method, temp2, noreg,
+ Z_index, Z_method, temp2,
L_no_such_interface);
jump_from_method_handle(_masm, Z_method, temp2, Z_R0, for_compiler_entry);
--- a/src/hotspot/cpu/s390/templateTable_s390.cpp Mon Nov 06 10:24:42 2017 -0800
+++ b/src/hotspot/cpu/s390/templateTable_s390.cpp Tue Nov 28 01:08:26 2017 +0300
@@ -3557,66 +3557,67 @@
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
- Register interface = Z_tos;
- Register index = Z_ARG3;
- Register receiver = Z_tmp_1;
- Register flags = Z_ARG5;
+ Register klass = Z_ARG2,
+ method = Z_ARG3,
+ interface = Z_ARG4,
+ flags = Z_ARG5,
+ receiver = Z_tmp_1;
BLOCK_COMMENT("invokeinterface {");
- // Destroys Z_ARG1 and Z_ARG2, thus use Z_ARG4 and copy afterwards.
- prepare_invoke(byte_no, Z_ARG4, index, // Get f1 klassOop, f2 itable index.
+ prepare_invoke(byte_no, interface, method, // Get f1 klassOop, f2 itable index.
receiver, flags);
// Z_R14 (== Z_bytecode) : return entry
- __ z_lgr(interface, Z_ARG4);
-
// Special case of invokeinterface called for virtual method of
// java.lang.Object. See cpCacheOop.cpp for details.
// This code isn't produced by javac, but could be produced by
// another compliant java compiler.
- Label notMethod;
+ NearLabel notMethod, no_such_interface, no_such_method;
__ testbit(flags, ConstantPoolCacheEntry::is_forced_virtual_shift);
__ z_brz(notMethod);
- invokevirtual_helper(index, receiver, flags);
+ invokevirtual_helper(method, receiver, flags);
__ bind(notMethod);
// Get receiver klass into klass - also a null check.
- Register klass = flags;
-
__ restore_locals();
__ load_klass(klass, receiver);
+ __ lookup_interface_method(klass, interface, noreg, noreg, /*temp*/Z_ARG1,
+ no_such_interface, /*return_method=*/false);
+
// Profile this call.
- __ profile_virtual_call(klass, Z_ARG2/*mdp*/, Z_ARG4/*scratch*/);
-
- NearLabel no_such_interface, no_such_method;
- Register method = Z_tmp_2;
-
- // TK 2010-08-24: save the index to Z_ARG4. needed in case of an error
- // in throw_AbstractMethodErrorByTemplateTable
- __ z_lgr(Z_ARG4, index);
- // TK 2011-03-24: copy also klass because it could be changed in
- // lookup_interface_method
- __ z_lgr(Z_ARG2, klass);
- __ lookup_interface_method(// inputs: rec. class, interface, itable index
- klass, interface, index,
- // outputs: method, scan temp. reg
- method, Z_tmp_2, Z_R1_scratch,
- no_such_interface);
+ __ profile_virtual_call(klass, Z_ARG1/*mdp*/, flags/*scratch*/);
+
+ // Find entry point to call.
+
+ // Get declaring interface class from method
+ __ z_lg(interface, Address(method, Method::const_offset()));
+ __ z_lg(interface, Address(interface, ConstMethod::constants_offset()));
+ __ z_lg(interface, Address(interface, ConstantPool::pool_holder_offset_in_bytes()));
+
+ // Get itable index from method
+ Register index = receiver,
+ method2 = flags;
+ __ z_lgf(index, Address(method, Method::itable_index_offset()));
+ __ z_aghi(index, -Method::itable_index_max);
+ __ z_lcgr(index, index);
+
+ __ lookup_interface_method(klass, interface, index, method2, Z_tmp_2,
+ no_such_interface);
// Check for abstract method error.
// Note: This should be done more efficiently via a throw_abstract_method_error
// interpreter entry point and a conditional jump to it in case of a null
// method.
- __ compareU64_and_branch(method, (intptr_t) 0,
+ __ compareU64_and_branch(method2, (intptr_t) 0,
Assembler::bcondZero, no_such_method);
- __ profile_arguments_type(Z_ARG3, method, Z_ARG5, true);
+ __ profile_arguments_type(Z_tmp_1, method2, Z_tmp_2, true);
// Do the call.
- __ jump_from_interpreted(method, Z_ARG5);
+ __ jump_from_interpreted(method2, Z_tmp_2);
__ should_not_reach_here();
// exception handling code follows...
@@ -3628,12 +3629,8 @@
// Throw exception.
__ restore_bcp(); // Bcp must be correct for exception handler (was destroyed).
__ restore_locals(); // Make sure locals pointer is correct as well (was destroyed).
- // TK 2010-08-24: Call throw_AbstractMethodErrorByTemplateTable now with the
- // relevant information for generating a better error message
__ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_AbstractMethodError),
- Z_ARG2, interface, Z_ARG4);
+ CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
// The call_VM checks for exception, so we should never return here.
__ should_not_reach_here();
@@ -3642,12 +3639,8 @@
// Throw exception.
__ restore_bcp(); // Bcp must be correct for exception handler (was destroyed).
__ restore_locals(); // Make sure locals pointer is correct as well (was destroyed).
- // TK 2010-08-24: Call throw_IncompatibleClassChangeErrorByTemplateTable now with the
- // relevant information for generating a better error message
__ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_IncompatibleClassChangeError),
- Z_ARG2, interface);
+ CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
// The call_VM checks for exception, so we should never return here.
__ should_not_reach_here();
--- a/src/hotspot/cpu/s390/vtableStubs_s390.cpp Mon Nov 06 10:24:42 2017 -0800
+++ b/src/hotspot/cpu/s390/vtableStubs_s390.cpp Tue Nov 28 01:08:26 2017 +0300
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017 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
@@ -28,6 +28,7 @@
#include "code/vtableStubs.hpp"
#include "interp_masm_s390.hpp"
#include "memory/resourceArea.hpp"
+#include "oops/compiledICHolder.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp"
#include "runtime/sharedRuntime.hpp"
@@ -57,7 +58,6 @@
ResourceMark rm;
CodeBuffer cb(s->entry_point(), code_length);
MacroAssembler *masm = new MacroAssembler(&cb);
- address start_pc;
int padding_bytes = 0;
#if (!defined(PRODUCT) && defined(COMPILER2))
@@ -144,9 +144,9 @@
return s;
}
-VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
+VtableStub* VtableStubs::create_itable_stub(int itable_index) {
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);
if (s == NULL) { // Indicates OOM in the code cache.
return NULL;
}
@@ -154,7 +154,6 @@
ResourceMark rm;
CodeBuffer cb(s->entry_point(), code_length);
MacroAssembler *masm = new MacroAssembler(&cb);
- address start_pc;
int padding_bytes = 0;
#if (!defined(PRODUCT) && defined(COMPILER2))
@@ -174,11 +173,9 @@
// Entry arguments:
// Z_method: Interface
// Z_ARG1: Receiver
- const Register rcvr_klass = Z_tmp_1; // Used to compute itable_entry_addr.
- // Use extra reg to avoid re-load.
- const Register vtable_len = Z_tmp_2; // Used to compute itable_entry_addr.
- const Register itable_entry_addr = Z_R1_scratch;
- const Register itable_interface = Z_R0_scratch;
+ NearLabel no_such_interface;
+ const Register rcvr_klass = Z_tmp_1,
+ interface = Z_tmp_2;
// Get receiver klass.
// Must do an explicit check if implicit checks are disabled.
@@ -186,50 +183,15 @@
__ null_check(Z_ARG1, Z_R1_scratch, oopDesc::klass_offset_in_bytes());
__ load_klass(rcvr_klass, Z_ARG1);
- // Load start of itable entries into itable_entry.
- __ z_llgf(vtable_len, Address(rcvr_klass, Klass::vtable_length_offset()));
- __ z_sllg(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
-
- // Loop over all itable entries until desired interfaceOop(Rinterface) found.
- const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
- // Count unused bytes.
- start_pc = __ pc();
- __ add2reg_with_index(itable_entry_addr, vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes(), rcvr_klass, vtable_len);
- padding_bytes += 20 - (__ pc() - start_pc);
-
- const int itable_offset_search_inc = itableOffsetEntry::size() * wordSize;
- Label search;
- __ bind(search);
+ // Receiver subtype check against REFC.
+ __ z_lg(interface, Address(Z_method, CompiledICHolder::holder_klass_offset()));
+ __ lookup_interface_method(rcvr_klass, interface, noreg,
+ noreg, Z_R1, 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.
- NearLabel throw_icce;
- __ load_and_test_long(itable_interface, Address(itable_entry_addr));
- __ z_bre(throw_icce); // Throw the exception out-of-line.
- // Count unused bytes.
- start_pc = __ pc();
- __ add2reg(itable_entry_addr, itable_offset_search_inc);
- padding_bytes += 20 - (__ pc() - start_pc);
- __ z_cgr(itable_interface, Z_method);
- __ z_brne(search);
-
- // Entry found. Itable_entry_addr points to the subsequent entry (itable_offset_search_inc too far).
- // Get offset of vtable for interface.
-
- const Register vtable_offset = Z_R1_scratch;
- const Register itable_method = rcvr_klass; // Calculated before.
-
- const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() -
- itableOffsetEntry::interface_offset_in_bytes()) -
- itable_offset_search_inc;
- __ z_llgf(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();
-
- __ z_lg(Z_method, method_offset, vtable_offset, itable_method);
+ // Get Method* and entrypoint for compiler
+ __ z_lg(interface, Address(Z_method, CompiledICHolder::holder_metadata_offset()));
+ __ lookup_interface_method(rcvr_klass, interface, itable_index,
+ Z_method, Z_R1, no_such_interface, /*return_method=*/ true);
#ifndef PRODUCT
if (DebugVtables) {
@@ -244,13 +206,13 @@
address ame_addr = __ pc();
// Must do an explicit check if implicit checks are disabled.
if (!ImplicitNullChecks) {
- __ compare64_and_branch(Z_method, (intptr_t) 0, Assembler::bcondEqual, throw_icce);
+ __ compare64_and_branch(Z_method, (intptr_t) 0, Assembler::bcondEqual, no_such_interface);
}
__ z_lg(Z_R1_scratch, in_bytes(Method::from_compiled_offset()), Z_method);
__ z_br(Z_R1_scratch);
// Handle IncompatibleClassChangeError in itable stubs.
- __ bind(throw_icce);
+ __ bind(no_such_interface);
// Count unused bytes
// worst case actual size
// We force resolving of the call site by jumping to
@@ -273,13 +235,12 @@
if (CountCompiledCalls) {
size += 6 * 4;
}
- if (is_vtable_stub) {
- size += 52;
- } else {
- size += 104;
+ size += is_vtable_stub ? 36 : 140;
+ if (UseCompressedClassPointers) {
+ size += MacroAssembler::instr_size_for_decode_klass_not_null();
}
- if (Universe::narrow_klass_base() != NULL) {
- size += 16; // A guess.
+ if (!ImplicitNullChecks) {
+ size += 36;
}
return size;
}