From e464b779f1b12e17bd8aabfae98f7d0055b6d616 Mon Sep 17 00:00:00 2001 From: mdoerr Date: Tue, 28 Nov 2017 01:07:05 +0300 Subject: [PATCH] 8191907: PPC64 part of JDK-8174962: Better interface invocations Reviewed-by: goetz --- src/cpu/ppc/vm/macroAssembler_ppc.cpp | 46 ++++----- src/cpu/ppc/vm/macroAssembler_ppc.hpp | 7 +- src/cpu/ppc/vm/templateTable_ppc_64.cpp | 73 +++++++------- src/cpu/ppc/vm/vtableStubs_ppc_64.cpp | 120 ++++++++++-------------- 4 files changed, 117 insertions(+), 129 deletions(-) diff --git a/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/src/cpu/ppc/vm/macroAssembler_ppc.cpp index a96e31035..97d77d39b 100644 --- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -1,6 +1,6 @@ /* - * 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<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 diff --git a/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/src/cpu/ppc/vm/macroAssembler_ppc.hpp index c7e8de457..fc59b916d 100644 --- a/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -1,6 +1,6 @@ /* - * 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, diff --git a/src/cpu/ppc/vm/templateTable_ppc_64.cpp b/src/cpu/ppc/vm/templateTable_ppc_64.cpp index ee7b925bc..708d5b3f2 100644 --- a/src/cpu/ppc/vm/templateTable_ppc_64.cpp +++ b/src/cpu/ppc/vm/templateTable_ppc_64.cpp @@ -1,6 +1,6 @@ /* - * 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) { diff --git a/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp b/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp index 5931afd5c..17c91d08b 100644 --- a/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp +++ b/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp @@ -1,6 +1,6 @@ /* - * 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() { -- GitLab