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,
|
RegisterOrConstant itable_index,
|
||||||
Register method_result,
|
Register method_result,
|
||||||
Register scan_temp,
|
Register scan_temp,
|
||||||
Register sethi_temp,
|
Register temp2,
|
||||||
Label& L_no_such_interface) {
|
Label& L_no_such_interface,
|
||||||
|
bool return_method) {
|
||||||
assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
|
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).
|
// Compute start of first itableOffsetEntry (which is at the end of the vtable).
|
||||||
int vtable_base = in_bytes(Klass::vtable_start_offset());
|
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);
|
add(scan_temp, recv_klass, scan_temp);
|
||||||
|
|
||||||
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
||||||
if (itable_index.is_register()) {
|
if (return_method) {
|
||||||
Register itable_offset = itable_index.as_register();
|
if (itable_index.is_register()) {
|
||||||
sldi(itable_offset, itable_offset, logMEsize);
|
Register itable_offset = itable_index.as_register();
|
||||||
if (itentry_off) addi(itable_offset, itable_offset, itentry_off);
|
sldi(method_result, itable_offset, logMEsize);
|
||||||
add(recv_klass, itable_offset, recv_klass);
|
if (itentry_off) { addi(method_result, method_result, itentry_off); }
|
||||||
} else {
|
add(method_result, method_result, recv_klass);
|
||||||
long itable_offset = (long)itable_index.as_constant();
|
} else {
|
||||||
load_const_optimized(sethi_temp, (itable_offset<<logMEsize)+itentry_off); // static address, no relocation
|
long itable_offset = (long)itable_index.as_constant();
|
||||||
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) {
|
// 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--) {
|
for (int peel = 1; peel >= 0; peel--) {
|
||||||
// %%%% Could load both offset and interface in one ldx, if they were
|
// %%%% Could load both offset and interface in one ldx, if they were
|
||||||
// in the opposite order. This would save a load.
|
// 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
|
// Check that this entry is non-null. A null entry means that
|
||||||
// the receiver class doesn't implement the interface, and wasn't the
|
// the receiver class doesn't implement the interface, and wasn't the
|
||||||
// same as when the caller was compiled.
|
// same as when the caller was compiled.
|
||||||
cmpd(CCR0, method_result, intf_klass);
|
cmpd(CCR0, temp2, intf_klass);
|
||||||
|
|
||||||
if (peel) {
|
if (peel) {
|
||||||
beq(CCR0, found_method);
|
beq(CCR0, found_method);
|
||||||
|
@ -1849,7 +1850,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||||
|
|
||||||
bind(search);
|
bind(search);
|
||||||
|
|
||||||
cmpdi(CCR0, method_result, 0);
|
cmpdi(CCR0, temp2, 0);
|
||||||
beq(CCR0, L_no_such_interface);
|
beq(CCR0, L_no_such_interface);
|
||||||
addi(scan_temp, scan_temp, scan_step);
|
addi(scan_temp, scan_temp, scan_step);
|
||||||
}
|
}
|
||||||
|
@ -1857,9 +1858,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||||
bind(found_method);
|
bind(found_method);
|
||||||
|
|
||||||
// Got a hit.
|
// Got a hit.
|
||||||
int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
|
if (return_method) {
|
||||||
lwz(scan_temp, ito_offset, scan_temp);
|
int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
|
||||||
ldx(method_result, scan_temp, recv_klass);
|
lwz(scan_temp, ito_offset, scan_temp);
|
||||||
|
ldx(method_result, scan_temp, method_result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual method calling
|
// virtual method calling
|
||||||
|
|
|
@ -519,7 +519,8 @@ class MacroAssembler: public Assembler {
|
||||||
RegisterOrConstant itable_index,
|
RegisterOrConstant itable_index,
|
||||||
Register method_result,
|
Register method_result,
|
||||||
Register temp_reg, Register temp2_reg,
|
Register temp_reg, Register temp2_reg,
|
||||||
Label& no_such_interface);
|
Label& no_such_interface,
|
||||||
|
bool return_method = true);
|
||||||
|
|
||||||
// virtual method calling
|
// virtual method calling
|
||||||
void lookup_virtual_method(Register recv_klass,
|
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,
|
void TemplateTable::invokeinterface_object_method(Register Rrecv_klass,
|
||||||
Register Rret,
|
Register Rret,
|
||||||
Register Rflags,
|
Register Rflags,
|
||||||
Register Rindex,
|
Register Rmethod,
|
||||||
Register Rtemp1,
|
Register Rtemp1,
|
||||||
Register Rtemp2) {
|
Register Rtemp2) {
|
||||||
|
|
||||||
assert_different_registers(Rindex, Rret, Rrecv_klass, Rflags, Rtemp1, Rtemp2);
|
assert_different_registers(Rmethod, Rret, Rrecv_klass, Rflags, Rtemp1, Rtemp2);
|
||||||
Label LnotFinal;
|
Label LnotFinal;
|
||||||
|
|
||||||
// Check for vfinal.
|
// Check for vfinal.
|
||||||
|
@ -3502,14 +3502,14 @@ void TemplateTable::invokeinterface_object_method(Register Rrecv_klass,
|
||||||
// Final call case.
|
// Final call case.
|
||||||
__ profile_final_call(Rtemp1, Rscratch);
|
__ profile_final_call(Rtemp1, Rscratch);
|
||||||
// Argument and return type profiling.
|
// 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.
|
// 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.
|
// Non-final callc case.
|
||||||
__ bind(LnotFinal);
|
__ bind(LnotFinal);
|
||||||
__ profile_virtual_call(Rrecv_klass, Rtemp1, Rscratch, false);
|
__ 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) {
|
void TemplateTable::invokeinterface(int byte_no) {
|
||||||
|
@ -3518,58 +3518,61 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||||
|
|
||||||
const Register Rscratch1 = R11_scratch1,
|
const Register Rscratch1 = R11_scratch1,
|
||||||
Rscratch2 = R12_scratch2,
|
Rscratch2 = R12_scratch2,
|
||||||
Rscratch3 = R9_ARG7,
|
Rmethod = R6_ARG4,
|
||||||
Rscratch4 = R10_ARG8,
|
Rmethod2 = R9_ARG7,
|
||||||
Rtable_addr = Rscratch2,
|
|
||||||
Rinterface_klass = R5_ARG3,
|
Rinterface_klass = R5_ARG3,
|
||||||
Rret_type = R8_ARG6,
|
Rret_addr = R8_ARG6,
|
||||||
Rret_addr = Rret_type,
|
Rindex = R10_ARG8,
|
||||||
Rindex = R6_ARG4,
|
Rreceiver = R3_ARG1,
|
||||||
Rreceiver = R4_ARG2,
|
Rrecv_klass = R4_ARG2,
|
||||||
Rrecv_klass = Rreceiver,
|
|
||||||
Rflags = R7_ARG5;
|
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.
|
// 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);
|
__ load_klass(Rrecv_klass, Rreceiver);
|
||||||
|
|
||||||
// Check corner case object method.
|
// Check corner case object method.
|
||||||
Label LobjectMethod;
|
Label LobjectMethod, L_no_such_interface, Lthrow_ame;
|
||||||
|
|
||||||
__ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_forced_virtual_shift);
|
__ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_forced_virtual_shift);
|
||||||
__ btrue(CCR0, LobjectMethod);
|
__ 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);
|
__ profile_virtual_call(Rrecv_klass, Rscratch1, Rscratch2, false);
|
||||||
|
|
||||||
// Find entry point to call.
|
// 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);
|
__ beq(CCR0, Lthrow_ame);
|
||||||
// Found entry. Jump off!
|
// Found entry. Jump off!
|
||||||
// Argument and return type profiling.
|
// Argument and return type profiling.
|
||||||
__ profile_arguments_type(Rindex, Rscratch1, Rscratch2, true);
|
__ profile_arguments_type(Rmethod2, Rscratch1, Rscratch2, true);
|
||||||
__ call_from_interpreter(Rindex, Rret_addr, Rscratch1, Rscratch2);
|
//__ profile_called_method(Rindex, Rscratch1);
|
||||||
|
__ call_from_interpreter(Rmethod2, Rret_addr, Rscratch1, Rscratch2);
|
||||||
|
|
||||||
// Vtable entry was NULL => Throw abstract method error.
|
// Vtable entry was NULL => Throw abstract method error.
|
||||||
__ bind(Lthrow_ame);
|
__ bind(Lthrow_ame);
|
||||||
__ mr(Rrecv_klass, Rscratch4);
|
|
||||||
__ mr(Rindex, Rscratch3);
|
|
||||||
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
|
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
|
||||||
|
|
||||||
// Interface was not found => Throw incompatible class change error.
|
// Interface was not found => Throw incompatible class change error.
|
||||||
__ bind(Lthrow_icc);
|
__ bind(L_no_such_interface);
|
||||||
__ mr(Rrecv_klass, Rscratch4);
|
|
||||||
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
|
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
|
||||||
|
DEBUG_ONLY( __ should_not_reach_here(); )
|
||||||
__ should_not_reach_here();
|
|
||||||
|
|
||||||
// Special case of invokeinterface called for virtual method of
|
// Special case of invokeinterface called for virtual method of
|
||||||
// java.lang.Object. See ConstantPoolCacheEntry::set_method() for details:
|
// 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
|
// to handle this corner case. This code isn't produced by javac, but could
|
||||||
// be produced by another compliant java compiler.
|
// be produced by another compliant java compiler.
|
||||||
__ bind(LobjectMethod);
|
__ 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) {
|
void TemplateTable::invokedynamic(int byte_no) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
* Copyright (c) 2012, 2017 SAP SE. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
#include "code/vtableStubs.hpp"
|
#include "code/vtableStubs.hpp"
|
||||||
#include "interp_masm_ppc.hpp"
|
#include "interp_masm_ppc.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
#include "oops/compiledICHolder.hpp"
|
||||||
#include "oops/instanceKlass.hpp"
|
#include "oops/instanceKlass.hpp"
|
||||||
#include "oops/klassVtable.hpp"
|
#include "oops/klassVtable.hpp"
|
||||||
#include "runtime/sharedRuntime.hpp"
|
#include "runtime/sharedRuntime.hpp"
|
||||||
|
@ -55,17 +56,22 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||||
// PPC port: use fixed size.
|
// PPC port: use fixed size.
|
||||||
const int code_length = VtableStub::pd_code_size_limit(true);
|
const int code_length = VtableStub::pd_code_size_limit(true);
|
||||||
VtableStub* s = new (code_length) VtableStub(true, vtable_index);
|
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;
|
ResourceMark rm;
|
||||||
CodeBuffer cb(s->entry_point(), code_length);
|
CodeBuffer cb(s->entry_point(), code_length);
|
||||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||||
address start_pc;
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (CountCompiledCalls) {
|
if (CountCompiledCalls) {
|
||||||
__ load_const(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr());
|
int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true);
|
||||||
__ lwz(R12_scratch2, 0, R11_scratch1);
|
__ lwz(R12_scratch2, offs, R11_scratch1);
|
||||||
__ addi(R12_scratch2, R12_scratch2, 1);
|
__ addi(R12_scratch2, R12_scratch2, 1);
|
||||||
__ stw(R12_scratch2, 0, R11_scratch1);
|
__ stw(R12_scratch2, offs, R11_scratch1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -116,6 +122,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||||
__ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
|
__ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
|
||||||
__ mtctr(R12_scratch2);
|
__ mtctr(R12_scratch2);
|
||||||
__ bctr();
|
__ bctr();
|
||||||
|
|
||||||
masm->flush();
|
masm->flush();
|
||||||
|
|
||||||
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
|
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
|
||||||
|
@ -125,10 +132,16 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||||
// PPC port: use fixed size.
|
// PPC port: use fixed size.
|
||||||
const int code_length = VtableStub::pd_code_size_limit(false);
|
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;
|
ResourceMark rm;
|
||||||
CodeBuffer cb(s->entry_point(), code_length);
|
CodeBuffer cb(s->entry_point(), code_length);
|
||||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||||
|
@ -136,10 +149,10 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (CountCompiledCalls) {
|
if (CountCompiledCalls) {
|
||||||
__ load_const(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr());
|
int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true);
|
||||||
__ lwz(R12_scratch2, 0, R11_scratch1);
|
__ lwz(R12_scratch2, offs, R11_scratch1);
|
||||||
__ addi(R12_scratch2, R12_scratch2, 1);
|
__ addi(R12_scratch2, R12_scratch2, 1);
|
||||||
__ stw(R12_scratch2, 0, R11_scratch1);
|
__ stw(R12_scratch2, offs, R11_scratch1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -148,62 +161,28 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||||
// Entry arguments:
|
// Entry arguments:
|
||||||
// R19_method: Interface
|
// R19_method: Interface
|
||||||
// R3_ARG1: Receiver
|
// R3_ARG1: Receiver
|
||||||
//
|
|
||||||
|
|
||||||
const Register rcvr_klass = R11_scratch1;
|
Label L_no_such_interface;
|
||||||
const Register vtable_len = R12_scratch2;
|
const Register rcvr_klass = R11_scratch1,
|
||||||
const Register itable_entry_addr = R21_tmp1;
|
interface = R12_scratch2,
|
||||||
const Register itable_interface = R22_tmp2;
|
tmp1 = R21_tmp1,
|
||||||
|
tmp2 = R22_tmp2;
|
||||||
|
|
||||||
// Get receiver klass.
|
|
||||||
|
|
||||||
// We might implicit NULL fault here.
|
|
||||||
address npe_addr = __ pc(); // npe = null pointer exception
|
address npe_addr = __ pc(); // npe = null pointer exception
|
||||||
__ null_check(R3_ARG1, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL);
|
__ null_check(R3_ARG1, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL);
|
||||||
__ load_klass(rcvr_klass, R3_ARG1);
|
__ load_klass(rcvr_klass, R3_ARG1);
|
||||||
|
|
||||||
BLOCK_COMMENT("Load start of itable entries into itable_entry.");
|
// Receiver subtype check against REFC.
|
||||||
__ lwz(vtable_len, in_bytes(Klass::vtable_length_offset()), rcvr_klass);
|
__ ld(interface, CompiledICHolder::holder_klass_offset(), R19_method);
|
||||||
__ slwi(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
|
__ lookup_interface_method(rcvr_klass, interface, noreg,
|
||||||
__ add(itable_entry_addr, vtable_len, rcvr_klass);
|
R0, tmp1, tmp2,
|
||||||
|
L_no_such_interface, /*return_method=*/ false);
|
||||||
|
|
||||||
// Loop over all itable entries until desired interfaceOop(Rinterface) found.
|
// Get Method* and entrypoint for compiler
|
||||||
BLOCK_COMMENT("Increment itable_entry_addr in loop.");
|
__ ld(interface, CompiledICHolder::holder_metadata_offset(), R19_method);
|
||||||
const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
|
__ lookup_interface_method(rcvr_klass, interface, itable_index,
|
||||||
__ addi(itable_entry_addr, itable_entry_addr, vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes());
|
R19_method, tmp1, tmp2,
|
||||||
|
L_no_such_interface, /*return_method=*/ true);
|
||||||
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);
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (DebugVtables) {
|
if (DebugVtables) {
|
||||||
|
@ -219,7 +198,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||||
address ame_addr = __ pc(); // ame = abstract method error
|
address ame_addr = __ pc(); // ame = abstract method error
|
||||||
|
|
||||||
// Must do an explicit check if implicit checks are disabled.
|
// 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);
|
__ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
|
||||||
__ mtctr(R12_scratch2);
|
__ mtctr(R12_scratch2);
|
||||||
__ bctr();
|
__ 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
|
// We force resolving of the call site by jumping to the "handle
|
||||||
// wrong method" stub, and so let the interpreter runtime do all the
|
// wrong method" stub, and so let the interpreter runtime do all the
|
||||||
// dirty work.
|
// dirty work.
|
||||||
__ bind(throw_icce);
|
__ bind(L_no_such_interface);
|
||||||
__ load_const(R11_scratch1, SharedRuntime::get_handle_wrong_method_stub());
|
__ load_const_optimized(R11_scratch1, SharedRuntime::get_handle_wrong_method_stub(), R12_scratch2);
|
||||||
__ mtctr(R11_scratch1);
|
__ mtctr(R11_scratch1);
|
||||||
__ bctr();
|
__ bctr();
|
||||||
|
|
||||||
|
@ -245,14 +224,15 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||||
int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
|
||||||
if (DebugVtables || CountCompiledCalls || VerifyOops) {
|
if (DebugVtables || CountCompiledCalls || VerifyOops) {
|
||||||
return 1000;
|
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() {
|
int VtableStub::pd_code_alignment() {
|
||||||
|
|
|
@ -2806,8 +2806,8 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||||
RegisterOrConstant itable_index,
|
RegisterOrConstant itable_index,
|
||||||
Register method_result,
|
Register method_result,
|
||||||
Register temp1_reg,
|
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 vtable_len = temp1_reg; // Used to compute itable_entry_addr.
|
||||||
const Register itable_entry_addr = Z_R1_scratch;
|
const Register itable_entry_addr = Z_R1_scratch;
|
||||||
|
@ -2842,38 +2842,36 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||||
z_brne(search);
|
z_brne(search);
|
||||||
|
|
||||||
// Entry found and itable_entry_addr points to it, get offset of vtable for interface.
|
// 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;
|
||||||
|
|
||||||
const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() -
|
// Compute itableMethodEntry and get method and entry point
|
||||||
itableOffsetEntry::interface_offset_in_bytes()) -
|
// we use addressing with index and displacement, since the formula
|
||||||
itable_offset_search_inc;
|
// 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).
|
||||||
|
|
||||||
// Compute itableMethodEntry and get method and entry point
|
if (itable_index.is_register()) {
|
||||||
// we use addressing with index and displacement, since the formula
|
// Compute the method's offset in that register, for the formula, see the
|
||||||
// for computing the entry's offset has a fixed and a dynamic part,
|
// else-clause below.
|
||||||
// the latter depending on the matched interface entry and on the case,
|
z_sllg(itable_offset, itable_index.as_register(), exact_log2(itableMethodEntry::size() * wordSize));
|
||||||
// that the itable index has been passed as a register, not a constant value.
|
z_agf(itable_offset, vtable_offset_offset, itable_entry_addr);
|
||||||
int method_offset = itableMethodEntry::method_offset_in_bytes();
|
} else {
|
||||||
// Fixed part (displacement), common operand.
|
// Displacement increases.
|
||||||
Register itable_offset; // Dynamic part (index register).
|
method_offset += itableMethodEntry::size() * wordSize * itable_index.as_constant();
|
||||||
|
|
||||||
if (itable_index.is_register()) {
|
// Load index from itable.
|
||||||
// Compute the method's offset in that register, for the formula, see the
|
z_llgf(itable_offset, vtable_offset_offset, itable_entry_addr);
|
||||||
// else-clause below.
|
}
|
||||||
itable_offset = itable_index.as_register();
|
|
||||||
|
|
||||||
z_sllg(itable_offset, itable_offset, exact_log2(itableMethodEntry::size() * wordSize));
|
// Finally load the method's oop.
|
||||||
z_agf(itable_offset, vtable_offset_offset, itable_entry_addr);
|
z_lg(method_result, method_offset, itable_offset, recv_klass);
|
||||||
} 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);
|
|
||||||
BLOCK_COMMENT("} lookup_interface_method");
|
BLOCK_COMMENT("} lookup_interface_method");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -671,8 +671,8 @@ class MacroAssembler: public Assembler {
|
||||||
RegisterOrConstant itable_index,
|
RegisterOrConstant itable_index,
|
||||||
Register method_result,
|
Register method_result,
|
||||||
Register temp1_reg,
|
Register temp1_reg,
|
||||||
Register temp2_reg,
|
Label& no_such_interface,
|
||||||
Label& no_such_interface);
|
bool return_method = true);
|
||||||
|
|
||||||
// virtual method calling
|
// virtual method calling
|
||||||
void lookup_virtual_method(Register recv_klass,
|
void lookup_virtual_method(Register recv_klass,
|
||||||
|
|
|
@ -498,7 +498,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
|
||||||
Label L_no_such_interface;
|
Label L_no_such_interface;
|
||||||
__ lookup_interface_method(temp1_recv_klass, temp3_intf,
|
__ lookup_interface_method(temp1_recv_klass, temp3_intf,
|
||||||
// Note: next two args must be the same:
|
// Note: next two args must be the same:
|
||||||
Z_index, Z_method, temp2, noreg,
|
Z_index, Z_method, temp2,
|
||||||
L_no_such_interface);
|
L_no_such_interface);
|
||||||
jump_from_method_handle(_masm, Z_method, temp2, Z_R0, for_compiler_entry);
|
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);
|
transition(vtos, vtos);
|
||||||
|
|
||||||
assert(byte_no == f1_byte, "use this argument");
|
assert(byte_no == f1_byte, "use this argument");
|
||||||
Register interface = Z_tos;
|
Register klass = Z_ARG2,
|
||||||
Register index = Z_ARG3;
|
method = Z_ARG3,
|
||||||
Register receiver = Z_tmp_1;
|
interface = Z_ARG4,
|
||||||
Register flags = Z_ARG5;
|
flags = Z_ARG5,
|
||||||
|
receiver = Z_tmp_1;
|
||||||
|
|
||||||
BLOCK_COMMENT("invokeinterface {");
|
BLOCK_COMMENT("invokeinterface {");
|
||||||
|
|
||||||
// Destroys Z_ARG1 and Z_ARG2, thus use Z_ARG4 and copy afterwards.
|
prepare_invoke(byte_no, interface, method, // Get f1 klassOop, f2 itable index.
|
||||||
prepare_invoke(byte_no, Z_ARG4, index, // Get f1 klassOop, f2 itable index.
|
|
||||||
receiver, flags);
|
receiver, flags);
|
||||||
|
|
||||||
// Z_R14 (== Z_bytecode) : return entry
|
// Z_R14 (== Z_bytecode) : return entry
|
||||||
|
|
||||||
__ z_lgr(interface, Z_ARG4);
|
|
||||||
|
|
||||||
// Special case of invokeinterface called for virtual method of
|
// Special case of invokeinterface called for virtual method of
|
||||||
// java.lang.Object. See cpCacheOop.cpp for details.
|
// java.lang.Object. See cpCacheOop.cpp for details.
|
||||||
// This code isn't produced by javac, but could be produced by
|
// This code isn't produced by javac, but could be produced by
|
||||||
// another compliant java compiler.
|
// another compliant java compiler.
|
||||||
Label notMethod;
|
NearLabel notMethod, no_such_interface, no_such_method;
|
||||||
__ testbit(flags, ConstantPoolCacheEntry::is_forced_virtual_shift);
|
__ testbit(flags, ConstantPoolCacheEntry::is_forced_virtual_shift);
|
||||||
__ z_brz(notMethod);
|
__ z_brz(notMethod);
|
||||||
invokevirtual_helper(index, receiver, flags);
|
invokevirtual_helper(method, receiver, flags);
|
||||||
__ bind(notMethod);
|
__ bind(notMethod);
|
||||||
|
|
||||||
// Get receiver klass into klass - also a null check.
|
// Get receiver klass into klass - also a null check.
|
||||||
Register klass = flags;
|
|
||||||
|
|
||||||
__ restore_locals();
|
__ restore_locals();
|
||||||
__ load_klass(klass, receiver);
|
__ load_klass(klass, receiver);
|
||||||
|
|
||||||
|
__ lookup_interface_method(klass, interface, noreg, noreg, /*temp*/Z_ARG1,
|
||||||
|
no_such_interface, /*return_method=*/false);
|
||||||
|
|
||||||
// Profile this call.
|
// 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;
|
// Find entry point to call.
|
||||||
Register method = Z_tmp_2;
|
|
||||||
|
|
||||||
// TK 2010-08-24: save the index to Z_ARG4. needed in case of an error
|
// Get declaring interface class from method
|
||||||
// in throw_AbstractMethodErrorByTemplateTable
|
__ z_lg(interface, Address(method, Method::const_offset()));
|
||||||
__ z_lgr(Z_ARG4, index);
|
__ z_lg(interface, Address(interface, ConstMethod::constants_offset()));
|
||||||
// TK 2011-03-24: copy also klass because it could be changed in
|
__ z_lg(interface, Address(interface, ConstantPool::pool_holder_offset_in_bytes()));
|
||||||
// lookup_interface_method
|
|
||||||
__ z_lgr(Z_ARG2, klass);
|
// Get itable index from method
|
||||||
__ lookup_interface_method(// inputs: rec. class, interface, itable index
|
Register index = receiver,
|
||||||
klass, interface, index,
|
method2 = flags;
|
||||||
// outputs: method, scan temp. reg
|
__ z_lgf(index, Address(method, Method::itable_index_offset()));
|
||||||
method, Z_tmp_2, Z_R1_scratch,
|
__ z_aghi(index, -Method::itable_index_max);
|
||||||
no_such_interface);
|
__ z_lcgr(index, index);
|
||||||
|
|
||||||
|
__ lookup_interface_method(klass, interface, index, method2, Z_tmp_2,
|
||||||
|
no_such_interface);
|
||||||
|
|
||||||
// Check for abstract method error.
|
// Check for abstract method error.
|
||||||
// Note: This should be done more efficiently via a throw_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
|
// interpreter entry point and a conditional jump to it in case of a null
|
||||||
// method.
|
// method.
|
||||||
__ compareU64_and_branch(method, (intptr_t) 0,
|
__ compareU64_and_branch(method2, (intptr_t) 0,
|
||||||
Assembler::bcondZero, no_such_method);
|
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.
|
// Do the call.
|
||||||
__ jump_from_interpreted(method, Z_ARG5);
|
__ jump_from_interpreted(method2, Z_tmp_2);
|
||||||
__ should_not_reach_here();
|
__ should_not_reach_here();
|
||||||
|
|
||||||
// exception handling code follows...
|
// exception handling code follows...
|
||||||
|
@ -3628,12 +3629,8 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||||
// Throw exception.
|
// Throw exception.
|
||||||
__ restore_bcp(); // Bcp must be correct for exception handler (was destroyed).
|
__ restore_bcp(); // Bcp must be correct for exception handler (was destroyed).
|
||||||
__ restore_locals(); // Make sure locals pointer is correct as well (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,
|
__ call_VM(noreg,
|
||||||
CAST_FROM_FN_PTR(address,
|
CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
|
||||||
InterpreterRuntime::throw_AbstractMethodError),
|
|
||||||
Z_ARG2, interface, Z_ARG4);
|
|
||||||
// The call_VM checks for exception, so we should never return here.
|
// The call_VM checks for exception, so we should never return here.
|
||||||
__ should_not_reach_here();
|
__ should_not_reach_here();
|
||||||
|
|
||||||
|
@ -3642,12 +3639,8 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||||
// Throw exception.
|
// Throw exception.
|
||||||
__ restore_bcp(); // Bcp must be correct for exception handler (was destroyed).
|
__ restore_bcp(); // Bcp must be correct for exception handler (was destroyed).
|
||||||
__ restore_locals(); // Make sure locals pointer is correct as well (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,
|
__ call_VM(noreg,
|
||||||
CAST_FROM_FN_PTR(address,
|
CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
|
||||||
InterpreterRuntime::throw_IncompatibleClassChangeError),
|
|
||||||
Z_ARG2, interface);
|
|
||||||
// The call_VM checks for exception, so we should never return here.
|
// The call_VM checks for exception, so we should never return here.
|
||||||
__ should_not_reach_here();
|
__ should_not_reach_here();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
#include "code/vtableStubs.hpp"
|
#include "code/vtableStubs.hpp"
|
||||||
#include "interp_masm_s390.hpp"
|
#include "interp_masm_s390.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
#include "oops/compiledICHolder.hpp"
|
||||||
#include "oops/instanceKlass.hpp"
|
#include "oops/instanceKlass.hpp"
|
||||||
#include "oops/klassVtable.hpp"
|
#include "oops/klassVtable.hpp"
|
||||||
#include "runtime/sharedRuntime.hpp"
|
#include "runtime/sharedRuntime.hpp"
|
||||||
|
@ -57,7 +58,6 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
CodeBuffer cb(s->entry_point(), code_length);
|
CodeBuffer cb(s->entry_point(), code_length);
|
||||||
MacroAssembler *masm = new MacroAssembler(&cb);
|
MacroAssembler *masm = new MacroAssembler(&cb);
|
||||||
address start_pc;
|
|
||||||
int padding_bytes = 0;
|
int padding_bytes = 0;
|
||||||
|
|
||||||
#if (!defined(PRODUCT) && defined(COMPILER2))
|
#if (!defined(PRODUCT) && defined(COMPILER2))
|
||||||
|
@ -144,9 +144,9 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||||
return s;
|
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);
|
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.
|
if (s == NULL) { // Indicates OOM in the code cache.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,6 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
CodeBuffer cb(s->entry_point(), code_length);
|
CodeBuffer cb(s->entry_point(), code_length);
|
||||||
MacroAssembler *masm = new MacroAssembler(&cb);
|
MacroAssembler *masm = new MacroAssembler(&cb);
|
||||||
address start_pc;
|
|
||||||
int padding_bytes = 0;
|
int padding_bytes = 0;
|
||||||
|
|
||||||
#if (!defined(PRODUCT) && defined(COMPILER2))
|
#if (!defined(PRODUCT) && defined(COMPILER2))
|
||||||
|
@ -174,11 +173,9 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||||
// Entry arguments:
|
// Entry arguments:
|
||||||
// Z_method: Interface
|
// Z_method: Interface
|
||||||
// Z_ARG1: Receiver
|
// Z_ARG1: Receiver
|
||||||
const Register rcvr_klass = Z_tmp_1; // Used to compute itable_entry_addr.
|
NearLabel no_such_interface;
|
||||||
// Use extra reg to avoid re-load.
|
const Register rcvr_klass = Z_tmp_1,
|
||||||
const Register vtable_len = Z_tmp_2; // Used to compute itable_entry_addr.
|
interface = Z_tmp_2;
|
||||||
const Register itable_entry_addr = Z_R1_scratch;
|
|
||||||
const Register itable_interface = Z_R0_scratch;
|
|
||||||
|
|
||||||
// Get receiver klass.
|
// Get receiver klass.
|
||||||
// Must do an explicit check if implicit checks are disabled.
|
// 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());
|
__ null_check(Z_ARG1, Z_R1_scratch, oopDesc::klass_offset_in_bytes());
|
||||||
__ load_klass(rcvr_klass, Z_ARG1);
|
__ load_klass(rcvr_klass, Z_ARG1);
|
||||||
|
|
||||||
// Load start of itable entries into itable_entry.
|
// Receiver subtype check against REFC.
|
||||||
__ z_llgf(vtable_len, Address(rcvr_klass, Klass::vtable_length_offset()));
|
__ z_lg(interface, Address(Z_method, CompiledICHolder::holder_klass_offset()));
|
||||||
__ z_sllg(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
|
__ 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.
|
// Get Method* and entrypoint for compiler
|
||||||
const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
|
__ z_lg(interface, Address(Z_method, CompiledICHolder::holder_metadata_offset()));
|
||||||
// Count unused bytes.
|
__ lookup_interface_method(rcvr_klass, interface, itable_index,
|
||||||
start_pc = __ pc();
|
Z_method, Z_R1, no_such_interface, /*return_method=*/ true);
|
||||||
__ 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);
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (DebugVtables) {
|
if (DebugVtables) {
|
||||||
|
@ -244,13 +206,13 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||||
address ame_addr = __ pc();
|
address ame_addr = __ pc();
|
||||||
// Must do an explicit check if implicit checks are disabled.
|
// Must do an explicit check if implicit checks are disabled.
|
||||||
if (!ImplicitNullChecks) {
|
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_lg(Z_R1_scratch, in_bytes(Method::from_compiled_offset()), Z_method);
|
||||||
__ z_br(Z_R1_scratch);
|
__ z_br(Z_R1_scratch);
|
||||||
|
|
||||||
// Handle IncompatibleClassChangeError in itable stubs.
|
// Handle IncompatibleClassChangeError in itable stubs.
|
||||||
__ bind(throw_icce);
|
__ bind(no_such_interface);
|
||||||
// Count unused bytes
|
// Count unused bytes
|
||||||
// worst case actual size
|
// worst case actual size
|
||||||
// We force resolving of the call site by jumping to
|
// 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) {
|
if (CountCompiledCalls) {
|
||||||
size += 6 * 4;
|
size += 6 * 4;
|
||||||
}
|
}
|
||||||
if (is_vtable_stub) {
|
size += is_vtable_stub ? 36 : 140;
|
||||||
size += 52;
|
if (UseCompressedClassPointers) {
|
||||||
} else {
|
size += MacroAssembler::instr_size_for_decode_klass_not_null();
|
||||||
size += 104;
|
|
||||||
}
|
}
|
||||||
if (Universe::narrow_klass_base() != NULL) {
|
if (!ImplicitNullChecks) {
|
||||||
size += 16; // A guess.
|
size += 36;
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue