mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8191907: PPC64 and s390 parts of JDK-8174962: Better interface invocations
Reviewed-by: goetz
This commit is contained in:
parent
7f2f3c08cb
commit
20439abed6
9 changed files with 195 additions and 256 deletions
|
@ -1788,11 +1788,10 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
|||
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 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
|||
add(scan_temp, recv_klass, scan_temp);
|
||||
|
||||
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
||||
if (return_method) {
|
||||
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);
|
||||
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();
|
||||
load_const_optimized(sethi_temp, (itable_offset<<logMEsize)+itentry_off); // static address, no relocation
|
||||
add(recv_klass, sethi_temp, recv_klass);
|
||||
// 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 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
|||
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 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
|||
|
||||
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 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
|||
bind(found_method);
|
||||
|
||||
// Got a hit.
|
||||
if (return_method) {
|
||||
int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
|
||||
lwz(scan_temp, ito_offset, scan_temp);
|
||||
ldx(method_result, scan_temp, recv_klass);
|
||||
ldx(method_result, scan_temp, method_result);
|
||||
}
|
||||
}
|
||||
|
||||
// virtual method calling
|
||||
|
|
|
@ -519,7 +519,8 @@ class MacroAssembler: public Assembler {
|
|||
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,
|
||||
|
|
|
@ -3486,11 +3486,11 @@ void TemplateTable::invokestatic(int byte_no) {
|
|||
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 @@ void TemplateTable::invokeinterface_object_method(Register Rrecv_klass,
|
|||
// 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 @@ void TemplateTable::invokeinterface(int byte_no) {
|
|||
|
||||
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 @@ void TemplateTable::invokeinterface(int byte_no) {
|
|||
// 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) {
|
||||
|
|
|
@ -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 @@ 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);
|
||||
|
||||
// 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 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
|||
__ 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 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
|||
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 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
|||
|
||||
#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 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
|||
// 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);
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
|||
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 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
|||
// 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 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
|||
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() {
|
||||
|
|
|
@ -2806,8 +2806,8 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
|||
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,7 +2842,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
|||
z_brne(search);
|
||||
|
||||
// Entry found and itable_entry_addr points to it, get offset of vtable for interface.
|
||||
|
||||
if (return_method) {
|
||||
const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() -
|
||||
itableOffsetEntry::interface_offset_in_bytes()) -
|
||||
itable_offset_search_inc;
|
||||
|
@ -2854,17 +2854,14 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
|||
// 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).
|
||||
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.
|
||||
itable_offset = itable_index.as_register();
|
||||
|
||||
z_sllg(itable_offset, itable_offset, exact_log2(itableMethodEntry::size() * wordSize));
|
||||
z_sllg(itable_offset, itable_index.as_register(), 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();
|
||||
|
||||
|
@ -2874,6 +2871,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
|||
|
||||
// Finally load the method's oop.
|
||||
z_lg(method_result, method_offset, itable_offset, recv_klass);
|
||||
}
|
||||
BLOCK_COMMENT("} lookup_interface_method");
|
||||
}
|
||||
|
||||
|
|
|
@ -671,8 +671,8 @@ class MacroAssembler: public Assembler {
|
|||
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,
|
||||
|
|
|
@ -498,7 +498,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
|
|||
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);
|
||||
|
||||
|
|
|
@ -3557,66 +3557,67 @@ void TemplateTable::invokeinterface(int byte_no) {
|
|||
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*/);
|
||||
__ profile_virtual_call(klass, Z_ARG1/*mdp*/, flags/*scratch*/);
|
||||
|
||||
NearLabel no_such_interface, no_such_method;
|
||||
Register method = Z_tmp_2;
|
||||
// Find entry point to call.
|
||||
|
||||
// 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,
|
||||
// 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 @@ void TemplateTable::invokeinterface(int byte_no) {
|
|||
// 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 @@ void TemplateTable::invokeinterface(int byte_no) {
|
|||
// 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();
|
||||
|
||||
|
|
|
@ -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 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
|||
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 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
|||
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 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
|||
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 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
|||
// 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 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
|||
__ 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()));
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
|||
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 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
|||
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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue