提交 ff67cad1 编写于 作者: M mdoerr

8191907: PPC64 part of JDK-8174962: Better interface invocations

Reviewed-by: goetz
上级 550a1609
/*
* 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 @@ 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 = InstanceKlass::vtable_start_offset() * wordSize;
......@@ -1553,15 +1552,18 @@ 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 (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 @@ 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);
......@@ -1592,7 +1594,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);
}
......@@ -1600,9 +1602,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
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
......
/*
* 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 @@ 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,
......
/*
* 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::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.
......@@ -3434,14 +3434,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) {
......@@ -3450,58 +3450,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:
......@@ -3509,7 +3512,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) {
......
/*
* 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 @@ 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) {
__ 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 @@ 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,61 +161,27 @@ 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;
// Get receiver klass.
Label L_no_such_interface;
const Register rcvr_klass = R11_scratch1,
interface = R12_scratch2,
tmp1 = R21_tmp1,
tmp2 = R22_tmp2;
// 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());
// 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);
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) {
......@@ -224,7 +203,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
__ 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 @@ 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();
......@@ -252,14 +231,15 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
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() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册