# HG changeset patch # User roland # Date 1382428307 -7200 # Node ID 5ccbab1c69f3c3dbe1fac87258e4bbd725d2ba15 # Parent 4748b3308cda25ebf86bf3eb2d5f6e718de7d9af 8026251: New type profiling points: parameters to methods Summary: x86 interpreter and c1 type profiling for parameters on method entries Reviewed-by: kvn, twisti diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/bytecodeInterpreter_x86.cpp --- a/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -40,11 +40,8 @@ #include "runtime/synchronizer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 -# include "interp_masm_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 -# include "interp_masm_x86_64.hpp" +#ifdef TARGET_ARCH_x86 +# include "interp_masm_x86.hpp" #endif #ifdef CC_INTERP diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/globals_x86.hpp --- a/src/cpu/x86/vm/globals_x86.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/globals_x86.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -79,7 +79,7 @@ // GC Ergo Flags define_pd_global(uintx, CMSYoungGenPerWorker, 64*M); // default max size of CMS young gen, per GC worker thread -define_pd_global(uintx, TypeProfileLevel, 11); +define_pd_global(uintx, TypeProfileLevel, 111); #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ \ diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/interp_masm_x86.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/x86/vm/interp_masm_x86.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "interp_masm_x86.hpp" +#include "interpreter/interpreter.hpp" +#include "oops/methodData.hpp" + +#ifndef CC_INTERP +void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { + Label update, next, none; + + verify_oop(obj); + + testptr(obj, obj); + jccb(Assembler::notZero, update); + orptr(mdo_addr, TypeEntries::null_seen); + jmpb(next); + + bind(update); + load_klass(obj, obj); + + xorptr(obj, mdo_addr); + testptr(obj, TypeEntries::type_klass_mask); + jccb(Assembler::zero, next); // klass seen before, nothing to + // do. The unknown bit may have been + // set already but no need to check. + + testptr(obj, TypeEntries::type_unknown); + jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. + + cmpptr(mdo_addr, 0); + jccb(Assembler::equal, none); + cmpptr(mdo_addr, TypeEntries::null_seen); + jccb(Assembler::equal, none); + // There is a chance that the checks above (re-reading profiling + // data from memory) fail if another thread has just set the + // profiling to this obj's klass + xorptr(obj, mdo_addr); + testptr(obj, TypeEntries::type_klass_mask); + jccb(Assembler::zero, next); + + // different than before. Cannot keep accurate profile. + orptr(mdo_addr, TypeEntries::type_unknown); + jmpb(next); + + bind(none); + // first time here. Set profile type. + movptr(mdo_addr, obj); + + bind(next); +} + +void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) { + if (!ProfileInterpreter) { + return; + } + + if (MethodData::profile_arguments() || MethodData::profile_return()) { + Label profile_continue; + + test_method_data_pointer(mdp, profile_continue); + + int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); + + cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); + jcc(Assembler::notEqual, profile_continue); + + if (MethodData::profile_arguments()) { + Label done; + int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); + addptr(mdp, off_to_args); + + for (int i = 0; i < TypeProfileArgsLimit; i++) { + if (i > 0 || MethodData::profile_return()) { + // If return value type is profiled we may have no argument to profile + movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); + subl(tmp, i*TypeStackSlotEntries::per_arg_count()); + cmpl(tmp, TypeStackSlotEntries::per_arg_count()); + jcc(Assembler::less, done); + } + movptr(tmp, Address(callee, Method::const_offset())); + load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset())); + // stack offset o (zero based) from the start of the argument + // list, for n arguments translates into offset n - o - 1 from + // the end of the argument list + subptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args)); + subl(tmp, 1); + Address arg_addr = argument_address(tmp); + movptr(tmp, arg_addr); + + Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args); + profile_obj_type(tmp, mdo_arg_addr); + + int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); + addptr(mdp, to_add); + off_to_args += to_add; + } + + if (MethodData::profile_return()) { + movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); + subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count()); + } + + bind(done); + + if (MethodData::profile_return()) { + // We're right after the type profile for the last + // argument. tmp is the number of cell left in the + // CallTypeData/VirtualCallTypeData to reach its end. Non null + // if there's a return to profile. + assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); + shll(tmp, exact_log2(DataLayout::cell_size)); + addptr(mdp, tmp); + } + movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp); + } else { + assert(MethodData::profile_return(), "either profile call args or call ret"); + update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size())); + } + + // mdp points right after the end of the + // CallTypeData/VirtualCallTypeData, right after the cells for the + // return value type if there's one + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) { + assert_different_registers(mdp, ret, tmp, _bcp_register); + if (ProfileInterpreter && MethodData::profile_return()) { + Label profile_continue, done; + + test_method_data_pointer(mdp, profile_continue); + + if (MethodData::profile_return_jsr292_only()) { + // If we don't profile all invoke bytecodes we must make sure + // it's a bytecode we indeed profile. We can't go back to the + // begining of the ProfileData we intend to update to check its + // type because we're right after it and we don't known its + // length + Label do_profile; + cmpb(Address(_bcp_register, 0), Bytecodes::_invokedynamic); + jcc(Assembler::equal, do_profile); + cmpb(Address(_bcp_register, 0), Bytecodes::_invokehandle); + jcc(Assembler::equal, do_profile); + get_method(tmp); + cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm); + jcc(Assembler::notEqual, profile_continue); + + bind(do_profile); + } + + Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size())); + mov(tmp, ret); + profile_obj_type(tmp, mdo_ret_addr); + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register tmp1, Register tmp2) { + if (ProfileInterpreter && MethodData::profile_parameters()) { + Label profile_continue, done; + + test_method_data_pointer(mdp, profile_continue); + + // Load the offset of the area within the MDO used for + // parameters. If it's negative we're not profiling any parameters + movl(tmp1, Address(mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()))); + testl(tmp1, tmp1); + jcc(Assembler::negative, profile_continue); + + // Compute a pointer to the area for parameters from the offset + // and move the pointer to the slot for the last + // parameters. Collect profiling from last parameter down. + // mdo start + parameters offset + array length - 1 + addptr(mdp, tmp1); + movptr(tmp1, Address(mdp, in_bytes(ArrayData::array_len_offset()))); + decrement(tmp1, TypeStackSlotEntries::per_arg_count()); + + Label loop; + bind(loop); + + int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0)); + int type_base = in_bytes(ParametersTypeData::type_offset(0)); + Address::ScaleFactor per_arg_scale = Address::times(DataLayout::cell_size); + Address arg_off(mdp, tmp1, per_arg_scale, off_base); + Address arg_type(mdp, tmp1, per_arg_scale, type_base); + + // load offset on the stack from the slot for this parameter + movptr(tmp2, arg_off); + negptr(tmp2); + // read the parameter from the local area + movptr(tmp2, Address(_locals_register, tmp2, Interpreter::stackElementScale())); + + // profile the parameter + profile_obj_type(tmp2, arg_type); + + // go to next parameter + decrement(tmp1, TypeStackSlotEntries::per_arg_count()); + jcc(Assembler::positive, loop); + + bind(profile_continue); + } +} +#endif diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/interp_masm_x86.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/x86/vm/interp_masm_x86.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_X86_VM_INTERP_MASM_X86_HPP +#define CPU_X86_VM_INTERP_MASM_X86_HPP + +#include "asm/macroAssembler.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "interpreter/invocationCounter.hpp" +#include "runtime/frame.hpp" + +// This file specializes the assember with interpreter-specific macros + + +class InterpreterMacroAssembler: public MacroAssembler { + +#ifdef TARGET_ARCH_MODEL_x86_32 +# include "interp_masm_x86_32.hpp" +#endif +#ifdef TARGET_ARCH_MODEL_x86_64 +# include "interp_masm_x86_64.hpp" +#endif + + private: + + Register _locals_register; // register that contains the pointer to the locals + Register _bcp_register; // register that contains the bcp + + public: +#ifndef CC_INTERP + void profile_obj_type(Register obj, const Address& mdo_addr); + void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual); + void profile_return_type(Register mdp, Register ret, Register tmp); + void profile_parameters_type(Register mdp, Register tmp1, Register tmp2); +#endif /* !CC_INTERP */ + +}; + +#endif // CPU_X86_VM_INTERP_MASM_X86_HPP diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/interp_masm_x86_32.cpp --- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "interp_masm_x86_32.hpp" +#include "interp_masm_x86.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "oops/arrayOop.hpp" @@ -1046,159 +1046,6 @@ } } -void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { - Label update, next, none; - - verify_oop(obj); - - testptr(obj, obj); - jccb(Assembler::notZero, update); - orptr(mdo_addr, TypeEntries::null_seen); - jmpb(next); - - bind(update); - load_klass(obj, obj); - - xorptr(obj, mdo_addr); - testptr(obj, TypeEntries::type_klass_mask); - jccb(Assembler::zero, next); // klass seen before, nothing to - // do. The unknown bit may have been - // set already but no need to check. - - testptr(obj, TypeEntries::type_unknown); - jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. - - cmpptr(mdo_addr, 0); - jccb(Assembler::equal, none); - cmpptr(mdo_addr, TypeEntries::null_seen); - jccb(Assembler::equal, none); - // There is a chance that the checks above (re-reading profiling - // data from memory) fail if another thread has just set the - // profiling to this obj's klass - xorptr(obj, mdo_addr); - testptr(obj, TypeEntries::type_klass_mask); - jccb(Assembler::zero, next); - - // different than before. Cannot keep accurate profile. - orptr(mdo_addr, TypeEntries::type_unknown); - jmpb(next); - - bind(none); - // first time here. Set profile type. - movptr(mdo_addr, obj); - - bind(next); -} - -void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) { - if (!ProfileInterpreter) { - return; - } - - if (MethodData::profile_arguments() || MethodData::profile_return()) { - Label profile_continue; - - test_method_data_pointer(mdp, profile_continue); - - int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); - - cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); - jcc(Assembler::notEqual, profile_continue); - - if (MethodData::profile_arguments()) { - Label done; - int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); - addptr(mdp, off_to_args); - - for (int i = 0; i < TypeProfileArgsLimit; i++) { - if (i > 0 || MethodData::profile_return()) { - // If return value type is profiled we may have no argument to profile - movl(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); - subl(tmp, i*TypeStackSlotEntries::per_arg_count()); - cmpl(tmp, TypeStackSlotEntries::per_arg_count()); - jcc(Assembler::less, done); - } - movptr(tmp, Address(callee, Method::const_offset())); - load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset())); - // stack offset o (zero based) from the start of the argument - // list, for n arguments translates into offset n - o - 1 from - // the end of the argument list - subl(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args)); - subl(tmp, 1); - Address arg_addr = argument_address(tmp); - movptr(tmp, arg_addr); - - Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args); - profile_obj_type(tmp, mdo_arg_addr); - - int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); - addptr(mdp, to_add); - off_to_args += to_add; - } - - if (MethodData::profile_return()) { - movl(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); - subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count()); - } - - bind(done); - - if (MethodData::profile_return()) { - // We're right after the type profile for the last - // argument. tmp is the number of cell left in the - // CallTypeData/VirtualCallTypeData to reach its end. Non null - // if there's a return to profile. - assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); - shll(tmp, exact_log2(DataLayout::cell_size)); - addptr(mdp, tmp); - } - movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp); - } else { - assert(MethodData::profile_return(), "either profile call args or call ret"); - update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size())); - } - - // mdp points right after the end of the - // CallTypeData/VirtualCallTypeData, right after the cells for the - // return value type if there's one - - bind(profile_continue); - } -} - -void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) { - assert_different_registers(mdp, ret, tmp, rsi); - if (ProfileInterpreter && MethodData::profile_return()) { - Label profile_continue, done; - - test_method_data_pointer(mdp, profile_continue); - - if (MethodData::profile_return_jsr292_only()) { - // If we don't profile all invoke bytecodes we must make sure - // it's a bytecode we indeed profile. We can't go back to the - // begining of the ProfileData we intend to update to check its - // type because we're right after it and we don't known its - // length - Label do_profile; - cmpb(Address(rsi, 0), Bytecodes::_invokedynamic); - jcc(Assembler::equal, do_profile); - cmpb(Address(rsi, 0), Bytecodes::_invokehandle); - jcc(Assembler::equal, do_profile); - get_method(tmp); - cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm); - jcc(Assembler::notEqual, profile_continue); - - bind(do_profile); - } - - Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size())); - mov(tmp, ret); - profile_obj_type(tmp, mdo_ret_addr); - - bind(profile_continue); - } -} - void InterpreterMacroAssembler::profile_call(Register mdp) { if (ProfileInterpreter) { Label profile_continue; diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/interp_masm_x86_32.hpp --- a/src/cpu/x86/vm/interp_masm_x86_32.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -22,18 +22,6 @@ * */ -#ifndef CPU_X86_VM_INTERP_MASM_X86_32_HPP -#define CPU_X86_VM_INTERP_MASM_X86_32_HPP - -#include "asm/macroAssembler.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "interpreter/invocationCounter.hpp" -#include "runtime/frame.hpp" - -// This file specializes the assember with interpreter-specific macros - - -class InterpreterMacroAssembler: public MacroAssembler { #ifndef CC_INTERP protected: // Interpreter specific version of call_VM_base @@ -59,7 +47,7 @@ #endif /* CC_INTERP */ public: - InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {} + InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(rdi), _bcp_register(rsi) {} void load_earlyret_value(TosState state); @@ -215,9 +203,6 @@ void profile_taken_branch(Register mdp, Register bumped_count); void profile_not_taken_branch(Register mdp); - void profile_obj_type(Register obj, const Address& mdo_addr); - void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual); - void profile_return_type(Register mdp, Register ret, Register tmp); void profile_call(Register mdp); void profile_final_call(Register mdp); void profile_virtual_call(Register receiver, Register mdp, Register scratch2, @@ -236,7 +221,3 @@ // support for jvmti void notify_method_entry(); void notify_method_exit(TosState state, NotifyMethodExitMode mode); - -}; - -#endif // CPU_X86_VM_INTERP_MASM_X86_32_HPP diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "interp_masm_x86_64.hpp" +#include "interp_masm_x86.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "oops/arrayOop.hpp" @@ -1067,160 +1067,6 @@ } } -void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { - Label update, next, none; - - verify_oop(obj); - - testptr(obj, obj); - jccb(Assembler::notZero, update); - orptr(mdo_addr, TypeEntries::null_seen); - jmpb(next); - - bind(update); - load_klass(obj, obj); - - xorptr(obj, mdo_addr); - testptr(obj, TypeEntries::type_klass_mask); - jccb(Assembler::zero, next); // klass seen before, nothing to - // do. The unknown bit may have been - // set already but no need to check. - - testptr(obj, TypeEntries::type_unknown); - jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. - - // There is a chance that by the time we do these checks (re-reading - // profiling data from memory) another thread has set the profling - // to this obj's klass and we set the profiling as unknow - // erroneously - cmpptr(mdo_addr, 0); - jccb(Assembler::equal, none); - cmpptr(mdo_addr, TypeEntries::null_seen); - jccb(Assembler::equal, none); - // There is a chance that the checks above (re-reading profiling - // data from memory) fail if another thread has just set the - // profiling to this obj's klass - xorptr(obj, mdo_addr); - testptr(obj, TypeEntries::type_klass_mask); - jccb(Assembler::zero, next); - - // different than before. Cannot keep accurate profile. - orptr(mdo_addr, TypeEntries::type_unknown); - jmpb(next); - - bind(none); - // first time here. Set profile type. - movptr(mdo_addr, obj); - - bind(next); -} - -void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) { - if (!ProfileInterpreter) { - return; - } - - if (MethodData::profile_arguments() || MethodData::profile_return()) { - Label profile_continue; - - test_method_data_pointer(mdp, profile_continue); - - int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); - - cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); - jcc(Assembler::notEqual, profile_continue); - - if (MethodData::profile_arguments()) { - Label done; - int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); - addptr(mdp, off_to_args); - - for (int i = 0; i < TypeProfileArgsLimit; i++) { - if (i > 0 || MethodData::profile_return()) { - // If return value type is profiled we may have no argument to profile - movq(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); - subl(tmp, i*TypeStackSlotEntries::per_arg_count()); - cmpl(tmp, TypeStackSlotEntries::per_arg_count()); - jcc(Assembler::less, done); - } - movptr(tmp, Address(callee, Method::const_offset())); - load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset())); - subq(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args)); - subl(tmp, 1); - Address arg_addr = argument_address(tmp); - movptr(tmp, arg_addr); - - Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args); - profile_obj_type(tmp, mdo_arg_addr); - - int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); - addptr(mdp, to_add); - off_to_args += to_add; - } - - if (MethodData::profile_return()) { - movq(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); - subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count()); - } - - bind(done); - - if (MethodData::profile_return()) { - // We're right after the type profile for the last - // argument. tmp is the number of cell left in the - // CallTypeData/VirtualCallTypeData to reach its end. Non null - // if there's a return to profile. - assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); - shll(tmp, exact_log2(DataLayout::cell_size)); - addptr(mdp, tmp); - } - movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp); - } else { - assert(MethodData::profile_return(), "either profile call args or call ret"); - update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size())); - } - - // mdp points right after the end of the - // CallTypeData/VirtualCallTypeData, right after the cells for the - // return value type if there's one - - bind(profile_continue); - } -} - -void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) { - assert_different_registers(mdp, ret, tmp, r13); - if (ProfileInterpreter && MethodData::profile_return()) { - Label profile_continue, done; - - test_method_data_pointer(mdp, profile_continue); - - if (MethodData::profile_return_jsr292_only()) { - // If we don't profile all invoke bytecodes we must make sure - // it's a bytecode we indeed profile. We can't go back to the - // begining of the ProfileData we intend to update to check its - // type because we're right after it and we don't known its - // length - Label do_profile; - cmpb(Address(r13, 0), Bytecodes::_invokedynamic); - jcc(Assembler::equal, do_profile); - cmpb(Address(r13, 0), Bytecodes::_invokehandle); - jcc(Assembler::equal, do_profile); - get_method(tmp); - cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm); - jcc(Assembler::notEqual, profile_continue); - - bind(do_profile); - } - - Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size())); - mov(tmp, ret); - profile_obj_type(tmp, mdo_ret_addr); - - bind(profile_continue); - } -} - void InterpreterMacroAssembler::profile_call(Register mdp) { if (ProfileInterpreter) { Label profile_continue; diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/interp_masm_x86_64.hpp --- a/src/cpu/x86/vm/interp_masm_x86_64.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -22,18 +22,6 @@ * */ -#ifndef CPU_X86_VM_INTERP_MASM_X86_64_HPP -#define CPU_X86_VM_INTERP_MASM_X86_64_HPP - -#include "asm/macroAssembler.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "interpreter/invocationCounter.hpp" -#include "runtime/frame.hpp" - -// This file specializes the assember with interpreter-specific macros - - -class InterpreterMacroAssembler: public MacroAssembler { #ifndef CC_INTERP protected: // Interpreter specific version of call_VM_base @@ -55,7 +43,7 @@ #endif // CC_INTERP public: - InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {} + InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(r14), _bcp_register(r13) {} void load_earlyret_value(TosState state); @@ -224,9 +212,6 @@ void profile_taken_branch(Register mdp, Register bumped_count); void profile_not_taken_branch(Register mdp); - void profile_obj_type(Register obj, const Address& mdo_addr); - void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual); - void profile_return_type(Register mdp, Register ret, Register tmp); void profile_call(Register mdp); void profile_final_call(Register mdp); void profile_virtual_call(Register receiver, Register mdp, @@ -253,6 +238,3 @@ // support for jvmti/dtrace void notify_method_entry(); void notify_method_exit(TosState state, NotifyMethodExitMode mode); -}; - -#endif // CPU_X86_VM_INTERP_MASM_X86_64_HPP diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/register_definitions_x86.cpp --- a/src/cpu/x86/vm/register_definitions_x86.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/register_definitions_x86.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -26,11 +26,8 @@ #include "asm/assembler.hpp" #include "asm/register.hpp" #include "register_x86.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 -# include "interp_masm_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 -# include "interp_masm_x86_64.hpp" +#ifdef TARGET_ARCH_x86 +# include "interp_masm_x86.hpp" #endif REGISTER_DEFINITION(Register, noreg); diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -1490,6 +1490,7 @@ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); __ movbool(do_not_unlock_if_synchronized, true); + __ profile_parameters_type(rax, rcx, rdx); // increment invocation count & check for overflow Label invocation_counter_overflow; Label profile_method; diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -1497,6 +1497,7 @@ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); __ movbool(do_not_unlock_if_synchronized, true); + __ profile_parameters_type(rax, rcx, rdx); // increment invocation count & check for overflow Label invocation_counter_overflow; Label profile_method; diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/vtableStubs_x86_32.cpp --- a/src/cpu/x86/vm/vtableStubs_x86_32.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/vtableStubs_x86_32.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "code/vtableStubs.hpp" -#include "interp_masm_x86_32.hpp" +#include "interp_masm_x86.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" diff -r 4748b3308cda -r 5ccbab1c69f3 src/cpu/x86/vm/vtableStubs_x86_64.cpp --- a/src/cpu/x86/vm/vtableStubs_x86_64.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/cpu/x86/vm/vtableStubs_x86_64.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "code/vtableStubs.hpp" -#include "interp_masm_x86_64.hpp" +#include "interp_masm_x86.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/c1/c1_Compilation.hpp --- a/src/share/vm/c1/c1_Compilation.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/c1/c1_Compilation.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -238,7 +238,18 @@ return env()->comp_level() == CompLevel_full_profile && C1UpdateMethodData && C1ProfileCheckcasts; } - + bool profile_parameters() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && MethodData::profile_parameters(); + } + bool profile_arguments() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && MethodData::profile_arguments(); + } + bool profile_return() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && MethodData::profile_return(); + } // will compilation make optimistic assumptions that might lead to // deoptimization and that the runtime will account for? bool is_optimistic() const { diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -1470,7 +1470,7 @@ set_state(state()->caller_state()->copy_for_parsing()); if (x != NULL) { state()->push(x->type(), x); - if (profile_calls() && MethodData::profile_return() && x->type()->is_object_kind()) { + if (profile_return() && x->type()->is_object_kind()) { ciMethod* caller = state()->scope()->method(); ciMethodData* md = caller->method_data_or_null(); ciProfileData* data = md->bci_to_data(invoke_bci); @@ -1672,15 +1672,23 @@ } // How many arguments do we want to profile? -Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver) { +Values* GraphBuilder::args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver) { int n = 0; - assert(start == 0, "should be initialized"); - if (MethodData::profile_arguments()) { + bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci())); + start = has_receiver ? 1 : 0; + if (profile_arguments()) { ciProfileData* data = method()->method_data()->bci_to_data(bci()); if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { n = data->is_CallTypeData() ? data->as_CallTypeData()->number_of_arguments() : data->as_VirtualCallTypeData()->number_of_arguments(); - bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci())); - start = has_receiver ? 1 : 0; + } + } + // If we are inlining then we need to collect arguments to profile parameters for the target + if (profile_parameters() && target != NULL) { + if (target->method_data() != NULL && target->method_data()->parameters_type_data() != NULL) { + // The receiver is profiled on method entry so it's included in + // the number of parameters but here we're only interested in + // actual arguments. + n = MAX2(n, target->method_data()->parameters_type_data()->number_of_parameters() - start); } } if (n > 0) { @@ -1690,9 +1698,9 @@ } // Collect arguments that we want to profile in a list -Values* GraphBuilder::collect_args_for_profiling(Values* args, bool may_have_receiver) { +Values* GraphBuilder::collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver) { int start = 0; - Values* obj_args = args_list_for_profiling(start, may_have_receiver); + Values* obj_args = args_list_for_profiling(target, start, may_have_receiver); if (obj_args == NULL) { return NULL; } @@ -2006,7 +2014,7 @@ } else if (exact_target != NULL) { target_klass = exact_target->holder(); } - profile_call(target, recv, target_klass, collect_args_for_profiling(args, false), false); + profile_call(target, recv, target_klass, collect_args_for_profiling(args, NULL, false), false); } } @@ -2021,7 +2029,7 @@ push(result_type, result); } } - if (profile_calls() && MethodData::profile_return() && result_type->is_object_kind()) { + if (profile_return() && result_type->is_object_kind()) { profile_return_type(result, target); } } @@ -3561,7 +3569,7 @@ recv = args->at(0); null_check(recv); } - profile_call(callee, recv, NULL, collect_args_for_profiling(args, true), true); + profile_call(callee, recv, NULL, collect_args_for_profiling(args, callee, true), true); } } } @@ -3572,7 +3580,7 @@ Value value = append_split(result); if (result_type != voidType) push(result_type, value); - if (callee != method() && profile_calls() && MethodData::profile_return() && result_type->is_object_kind()) { + if (callee != method() && profile_return() && result_type->is_object_kind()) { profile_return_type(result, callee); } @@ -3820,7 +3828,7 @@ if (profile_calls()) { int start = 0; - Values* obj_args = args_list_for_profiling(start, has_receiver); + Values* obj_args = args_list_for_profiling(callee, start, has_receiver); if (obj_args != NULL) { int s = obj_args->size(); // if called through method handle invoke, some arguments may have been popped diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/c1/c1_GraphBuilder.hpp --- a/src/share/vm/c1/c1_GraphBuilder.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/c1/c1_GraphBuilder.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -386,9 +386,12 @@ bool profile_calls() { return _compilation->profile_calls(); } bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); } bool profile_checkcasts() { return _compilation->profile_checkcasts(); } + bool profile_parameters() { return _compilation->profile_parameters(); } + bool profile_arguments() { return _compilation->profile_arguments(); } + bool profile_return() { return _compilation->profile_return(); } - Values* args_list_for_profiling(int& start, bool may_have_receiver); - Values* collect_args_for_profiling(Values* args, bool may_have_receiver); + Values* args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver); + Values* collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver); public: NOT_PRODUCT(void print_stats();) diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -2647,6 +2647,39 @@ return result; } +// profile parameters on entry to the root of the compilation +void LIRGenerator::profile_parameters(Base* x) { + if (compilation()->profile_parameters()) { + CallingConvention* args = compilation()->frame_map()->incoming_arguments(); + ciMethodData* md = scope()->method()->method_data_or_null(); + assert(md != NULL, "Sanity"); + + if (md->parameters_type_data() != NULL) { + ciParametersTypeData* parameters_type_data = md->parameters_type_data(); + ciTypeStackSlotEntries* parameters = parameters_type_data->parameters(); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + for (int java_index = 0, i = 0, j = 0; j < parameters_type_data->number_of_parameters(); i++) { + LIR_Opr src = args->at(i); + assert(!src->is_illegal(), "check"); + BasicType t = src->type(); + if (t == T_OBJECT || t == T_ARRAY) { + intptr_t profiled_k = parameters->type(j); + Local* local = x->state()->local_at(java_index)->as_Local(); + ciKlass* exact = profile_arg_type(md, md->byte_offset_of_slot(parameters_type_data, ParametersTypeData::type_offset(0)), + in_bytes(ParametersTypeData::type_offset(j)) - in_bytes(ParametersTypeData::type_offset(0)), + profiled_k, local, mdp, false, local->declared_type()->as_klass()); + // If the profile is known statically set it once for all and do not emit any code + if (exact != NULL) { + md->set_parameter_type(j, exact); + } + j++; + } + java_index += type2size[t]; + } + } + } +} + void LIRGenerator::do_Base(Base* x) { __ std_entry(LIR_OprFact::illegalOpr); // Emit moves from physical registers / stack slots to virtual registers @@ -2722,6 +2755,7 @@ // increment invocation counters if needed if (!method()->is_accessor()) { // Accessors do not have MDOs, so no counting. + profile_parameters(x); CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, SynchronizationEntryBCI), NULL, false); increment_invocation_counter(info); } @@ -3081,11 +3115,12 @@ } void LIRGenerator::profile_arguments(ProfileCall* x) { - if (MethodData::profile_arguments()) { + if (compilation()->profile_arguments()) { int bci = x->bci_of_invoke(); ciMethodData* md = x->method()->method_data_or_null(); ciProfileData* data = md->bci_to_data(bci); - if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { + if ((data->is_CallTypeData() && data->as_CallTypeData()->has_arguments()) || + (data->is_VirtualCallTypeData() && data->as_VirtualCallTypeData()->has_arguments())) { ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset(); int base_offset = md->byte_offset_of_slot(data, extra); LIR_Opr mdp = LIR_OprFact::illegalOpr; @@ -3111,6 +3146,71 @@ md->set_argument_type(bci, i, exact); } } + } else { +#ifdef ASSERT + Bytecodes::Code code = x->method()->raw_code_at_bci(x->bci_of_invoke()); + int n = x->nb_profiled_args(); + assert(MethodData::profile_parameters() && x->inlined() && + ((code == Bytecodes::_invokedynamic && n <= 1) || (code == Bytecodes::_invokehandle && n <= 2)), + "only at JSR292 bytecodes"); +#endif + } + } +} + +// profile parameters on entry to an inlined method +void LIRGenerator::profile_parameters_at_call(ProfileCall* x) { + if (compilation()->profile_parameters() && x->inlined()) { + ciMethodData* md = x->callee()->method_data_or_null(); + if (md != NULL) { + ciParametersTypeData* parameters_type_data = md->parameters_type_data(); + if (parameters_type_data != NULL) { + ciTypeStackSlotEntries* parameters = parameters_type_data->parameters(); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + bool has_receiver = !x->callee()->is_static(); + ciSignature* sig = x->callee()->signature(); + ciSignatureStream sig_stream(sig, has_receiver ? x->callee()->holder() : NULL); + int i = 0; // to iterate on the Instructions + Value arg = x->recv(); + bool not_null = false; + int bci = x->bci_of_invoke(); + Bytecodes::Code bc = x->method()->java_code_at_bci(bci); + // The first parameter is the receiver so that's what we start + // with if it exists. On exception if method handle call to + // virtual method has receiver in the args list + if (arg == NULL || !Bytecodes::has_receiver(bc)) { + i = 1; + arg = x->profiled_arg_at(0); + not_null = !x->arg_needs_null_check(0); + } + int k = 0; // to iterate on the profile data + for (;;) { + intptr_t profiled_k = parameters->type(k); + ciKlass* exact = profile_arg_type(md, md->byte_offset_of_slot(parameters_type_data, ParametersTypeData::type_offset(0)), + in_bytes(ParametersTypeData::type_offset(k)) - in_bytes(ParametersTypeData::type_offset(0)), + profiled_k, arg, mdp, not_null, sig_stream.next_klass()); + // If the profile is known statically set it once for all and do not emit any code + if (exact != NULL) { + md->set_parameter_type(k, exact); + } + k++; + if (k >= parameters_type_data->number_of_parameters()) { +#ifdef ASSERT + int extra = 0; + if (MethodData::profile_arguments() && TypeProfileParmsLimit != -1 && + x->nb_profiled_args() >= TypeProfileParmsLimit && + x->recv() != NULL && Bytecodes::has_receiver(bc)) { + extra += 1; + } + assert(i == x->nb_profiled_args() - extra || (TypeProfileParmsLimit != -1 && TypeProfileArgsLimit > TypeProfileParmsLimit), "unused parameters?"); +#endif + break; + } + arg = x->profiled_arg_at(i); + not_null = !x->arg_needs_null_check(i); + i++; + } + } } } } @@ -3126,6 +3226,11 @@ profile_arguments(x); } + // profile parameters on inlined method entry including receiver + if (x->recv() != NULL || x->nb_profiled_args() > 0) { + profile_parameters_at_call(x); + } + if (x->recv() != NULL) { LIRItem value(x->recv(), this); value.load_item(); diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/c1/c1_LIRGenerator.hpp --- a/src/share/vm/c1/c1_LIRGenerator.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/c1/c1_LIRGenerator.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -436,6 +436,8 @@ #endif ciKlass* profile_arg_type(ciMethodData* md, int md_first_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k); void profile_arguments(ProfileCall* x); + void profile_parameters(Base* x); + void profile_parameters_at_call(ProfileCall* x); public: Compilation* compilation() const { return _compilation; } diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/ci/ciMethodData.cpp --- a/src/share/vm/ci/ciMethodData.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/ci/ciMethodData.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -53,6 +53,7 @@ _hint_di = first_di(); // Initialize the escape information (to "don't know."); _eflags = _arg_local = _arg_stack = _arg_returned = 0; + _parameters = NULL; } // ------------------------------------------------------------------ @@ -74,6 +75,7 @@ _hint_di = first_di(); // Initialize the escape information (to "don't know."); _eflags = _arg_local = _arg_stack = _arg_returned = 0; + _parameters = NULL; } void ciMethodData::load_data() { @@ -108,6 +110,12 @@ ci_data = next_data(ci_data); data = mdo->next_data(data); } + if (mdo->parameters_type_data() != NULL) { + _parameters = data_layout_at(mdo->parameters_type_data_di()); + ciParametersTypeData* parameters = new ciParametersTypeData(_parameters); + parameters->translate_from(mdo->parameters_type_data()); + } + // Note: Extra data are all BitData, and do not need translation. _current_mileage = MethodData::mileage_of(mdo->method()); _invocation_counter = mdo->invocation_count(); @@ -182,6 +190,8 @@ return new ciCallTypeData(data_layout); case DataLayout::virtual_call_type_data_tag: return new ciVirtualCallTypeData(data_layout); + case DataLayout::parameters_type_data_tag: + return new ciParametersTypeData(data_layout); }; } @@ -318,6 +328,14 @@ } } +void ciMethodData::set_parameter_type(int i, ciKlass* k) { + VM_ENTRY_MARK; + MethodData* mdo = get_MethodData(); + if (mdo != NULL) { + mdo->parameters_type_data()->set_type(i, k->get_Klass()); + } +} + void ciMethodData::set_return_type(int bci, ciKlass* k) { VM_ENTRY_MARK; MethodData* mdo = get_MethodData(); @@ -605,4 +623,9 @@ ret()->print_data_on(st); } } + +void ciParametersTypeData::print_data_on(outputStream* st) const { + st->print_cr("Parametertypes"); + parameters()->print_data_on(st); +} #endif diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/ci/ciMethodData.hpp --- a/src/share/vm/ci/ciMethodData.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/ci/ciMethodData.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -43,6 +43,7 @@ class ciArgInfoData; class ciCallTypeData; class ciVirtualCallTypeData; +class ciParametersTypeData; typedef ProfileData ciProfileData; @@ -124,7 +125,7 @@ ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)CallTypeData::args(); } ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)CallTypeData::ret(); } - void translate_type_data_from(const ProfileData* data) { + void translate_from(const ProfileData* data) { if (has_arguments()) { args()->translate_type_data_from(data->as_CallTypeData()->args()); } @@ -290,6 +291,25 @@ ciArgInfoData(DataLayout* layout) : ArgInfoData(layout) {}; }; +class ciParametersTypeData : public ParametersTypeData { +public: + ciParametersTypeData(DataLayout* layout) : ParametersTypeData(layout) {} + + virtual void translate_from(const ProfileData* data) { + parameters()->translate_type_data_from(data->as_ParametersTypeData()->parameters()); + } + + ciTypeStackSlotEntries* parameters() const { return (ciTypeStackSlotEntries*)ParametersTypeData::parameters(); } + + ciKlass* valid_parameter_type(int i) const { + return parameters()->valid_type(i); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + // ciMethodData // // This class represents a MethodData* in the HotSpot virtual @@ -335,6 +355,10 @@ // Coherent snapshot of original header. MethodData _orig; + // Dedicated area dedicated to parameters. Null if no parameter + // profiling for this method. + DataLayout* _parameters; + ciMethodData(MethodData* md); ciMethodData(); @@ -403,6 +427,7 @@ // If the compiler finds a profiled type that is known statically // for sure, set it in the MethodData void set_argument_type(int bci, int i, ciKlass* k); + void set_parameter_type(int i, ciKlass* k); void set_return_type(int bci, ciKlass* k); void load_data(); @@ -467,6 +492,10 @@ bool is_arg_returned(int i) const; uint arg_modified(int arg) const; + ciParametersTypeData* parameters_type_data() const { + return _parameters != NULL ? new ciParametersTypeData(_parameters) : NULL; + } + // Code generation helper ByteSize offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data); int byte_offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) { return in_bytes(offset_of_slot(data, slot_offset_in_data)); } diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/interpreter/abstractInterpreter.hpp --- a/src/share/vm/interpreter/abstractInterpreter.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/interpreter/abstractInterpreter.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -30,11 +30,8 @@ #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" #include "utilities/top.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 -# include "interp_masm_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 -# include "interp_masm_x86_64.hpp" +#ifdef TARGET_ARCH_x86 +# include "interp_masm_x86.hpp" #endif #ifdef TARGET_ARCH_MODEL_sparc # include "interp_masm_sparc.hpp" diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/interpreter/templateTable.hpp --- a/src/share/vm/interpreter/templateTable.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/interpreter/templateTable.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -28,11 +28,8 @@ #include "interpreter/bytecodes.hpp" #include "memory/allocation.hpp" #include "runtime/frame.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 -# include "interp_masm_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 -# include "interp_masm_x86_64.hpp" +#ifdef TARGET_ARCH_x86 +# include "interp_masm_x86.hpp" #endif #ifdef TARGET_ARCH_MODEL_sparc # include "interp_masm_sparc.hpp" diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/oops/methodData.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -41,7 +41,7 @@ // Some types of data layouts need a length field. bool DataLayout::needs_array_len(u1 tag) { - return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag); + return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag) || (tag == parameters_type_data_tag); } // Perform generic initialization of the data. More specific @@ -156,10 +156,13 @@ } #endif // !PRODUCT -int TypeStackSlotEntries::compute_cell_count(Symbol* signature, int max) { +int TypeStackSlotEntries::compute_cell_count(Symbol* signature, bool include_receiver, int max) { + // Parameter profiling include the receiver + int args_count = include_receiver ? 1 : 0; ResourceMark rm; SignatureStream ss(signature); - int args_count = MIN2(ss.reference_parameter_count(), max); + args_count += ss.reference_parameter_count(); + args_count = MIN2(args_count, max); return args_count * per_arg_cell_count; } @@ -169,7 +172,7 @@ Bytecode_invoke inv(stream->method(), stream->bci()); int args_cell = 0; if (arguments_profiling_enabled()) { - args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), TypeProfileArgsLimit); + args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), false, TypeProfileArgsLimit); } int ret_cell = 0; if (return_profiling_enabled() && (inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY)) { @@ -212,12 +215,19 @@ int off_at(int i) const { return _offsets.at(i); } }; -void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver) { +void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver, bool include_receiver) { ResourceMark rm; - ArgumentOffsetComputer aos(signature, _number_of_entries); + int start = 0; + // Parameter profiling include the receiver + if (include_receiver && has_receiver) { + set_stack_slot(0, 0); + set_type(0, type_none()); + start += 1; + } + ArgumentOffsetComputer aos(signature, _number_of_entries-start); aos.total(); - for (int i = 0; i < _number_of_entries; i++) { - set_stack_slot(i, aos.off_at(i) + (has_receiver ? 1 : 0)); + for (int i = start; i < _number_of_entries; i++) { + set_stack_slot(i, aos.off_at(i-start) + (has_receiver ? 1 : 0)); set_type(i, type_none()); } } @@ -234,7 +244,7 @@ assert(count > 0, "room for args type but none found?"); check_number_of_arguments(count); #endif - _args.post_initialize(inv.signature(), inv.has_receiver()); + _args.post_initialize(inv.signature(), inv.has_receiver(), false); } if (has_return()) { @@ -255,7 +265,7 @@ assert(count > 0, "room for args type but none found?"); check_number_of_arguments(count); #endif - _args.post_initialize(inv.signature(), inv.has_receiver()); + _args.post_initialize(inv.signature(), inv.has_receiver(), false); } if (has_return()) { @@ -579,6 +589,34 @@ } #endif + +int ParametersTypeData::compute_cell_count(Method* m) { + if (!MethodData::profile_parameters_for_method(m)) { + return 0; + } + int max = TypeProfileParmsLimit == -1 ? INT_MAX : TypeProfileParmsLimit; + int obj_args = TypeStackSlotEntries::compute_cell_count(m->signature(), !m->is_static(), max); + if (obj_args > 0) { + return obj_args + 1; // 1 cell for array len + } + return 0; +} + +void ParametersTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { + _parameters.post_initialize(mdo->method()->signature(), !mdo->method()->is_static(), true); +} + +bool ParametersTypeData::profiling_enabled() { + return MethodData::profile_parameters(); +} + +#ifndef PRODUCT +void ParametersTypeData::print_data_on(outputStream* st) const { + st->print("parameter types"); + _parameters.print_data_on(st); +} +#endif + // ================================================================== // MethodData* // @@ -741,6 +779,12 @@ int arg_size = method->size_of_parameters(); object_size += DataLayout::compute_size_in_bytes(arg_size+1); + // Reserve room for an area of the MDO dedicated to profiling of + // parameters + int args_cell = ParametersTypeData::compute_cell_count(method()); + if (args_cell > 0) { + object_size += DataLayout::compute_size_in_bytes(args_cell); + } return object_size; } @@ -915,6 +959,8 @@ return new CallTypeData(this); case DataLayout::virtual_call_type_data_tag: return new VirtualCallTypeData(this); + case DataLayout::parameters_type_data_tag: + return new ParametersTypeData(this); }; } @@ -936,6 +982,9 @@ stream->next(); data->post_initialize(stream, this); } + if (_parameters_type_data_di != -1) { + parameters_type_data()->post_initialize(NULL, this); + } } // Initialize the MethodData* corresponding to a given method. @@ -975,7 +1024,23 @@ int arg_size = method->size_of_parameters(); dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1); - object_size += extra_size + DataLayout::compute_size_in_bytes(arg_size+1); + int arg_data_size = DataLayout::compute_size_in_bytes(arg_size+1); + object_size += extra_size + arg_data_size; + + int args_cell = ParametersTypeData::compute_cell_count(method()); + // If we are profiling parameters, we reserver an area near the end + // of the MDO after the slots for bytecodes (because there's no bci + // for method entry so they don't fit with the framework for the + // profiling of bytecodes). We store the offset within the MDO of + // this area (or -1 if no parameter is profiled) + if (args_cell > 0) { + object_size += DataLayout::compute_size_in_bytes(args_cell); + _parameters_type_data_di = data_size + extra_size + arg_data_size; + DataLayout *dp = data_layout_at(data_size + extra_size + arg_data_size); + dp->initialize(DataLayout::parameters_type_data_tag, 0, args_cell); + } else { + _parameters_type_data_di = -1; + } // Set an initial hint. Don't use set_hint_di() because // first_di() may be out of bounds if data_size is 0. @@ -1134,6 +1199,9 @@ void MethodData::print_data_on(outputStream* st) const { ResourceMark rm; ProfileData* data = first_data(); + if (_parameters_type_data_di != -1) { + parameters_type_data()->print_data_on(st); + } for ( ; is_valid(data); data = next_data(data)) { st->print("%d", dp_to_di(data->dp())); st->fill_to(6); @@ -1222,7 +1290,7 @@ } int MethodData::profile_return_flag() { - return TypeProfileLevel / 10; + return (TypeProfileLevel % 100) / 10; } bool MethodData::profile_return() { @@ -1249,3 +1317,32 @@ assert(profile_return_jsr292_only(), "inconsistent"); return profile_jsr292(m, bci); } + +int MethodData::profile_parameters_flag() { + return TypeProfileLevel / 100; +} + +bool MethodData::profile_parameters() { + return profile_parameters_flag() > no_type_profile && profile_parameters_flag() <= type_profile_all; +} + +bool MethodData::profile_parameters_jsr292_only() { + return profile_parameters_flag() == type_profile_jsr292; +} + +bool MethodData::profile_all_parameters() { + return profile_parameters_flag() == type_profile_all; +} + +bool MethodData::profile_parameters_for_method(methodHandle m) { + if (!profile_parameters()) { + return false; + } + + if (profile_all_parameters()) { + return true; + } + + assert(profile_parameters_jsr292_only(), "inconsistent"); + return m->is_compiled_lambda_form(); +} diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/oops/methodData.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -119,7 +119,8 @@ multi_branch_data_tag, arg_info_data_tag, call_type_data_tag, - virtual_call_type_data_tag + virtual_call_type_data_tag, + parameters_type_data_tag }; enum { @@ -264,6 +265,7 @@ class ArrayData; class MultiBranchData; class ArgInfoData; +class ParametersTypeData; // ProfileData // @@ -397,6 +399,7 @@ virtual bool is_ArgInfoData() const { return false; } virtual bool is_CallTypeData() const { return false; } virtual bool is_VirtualCallTypeData()const { return false; } + virtual bool is_ParametersTypeData() const { return false; } BitData* as_BitData() const { @@ -447,6 +450,10 @@ assert(is_VirtualCallTypeData(), "wrong type"); return is_VirtualCallTypeData() ? (VirtualCallTypeData*)this : NULL; } + ParametersTypeData* as_ParametersTypeData() const { + assert(is_ParametersTypeData(), "wrong type"); + return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL; + } // Subclass specific initialization @@ -767,9 +774,9 @@ TypeStackSlotEntries(int base_off, int nb_entries) : TypeEntries(base_off), _number_of_entries(nb_entries) {} - static int compute_cell_count(Symbol* signature, int max); + static int compute_cell_count(Symbol* signature, bool include_receiver, int max); - void post_initialize(Symbol* signature, bool has_receiver); + void post_initialize(Symbol* signature, bool has_receiver, bool include_receiver); // offset of cell for stack slot for entry i within this block of cells for a TypeStackSlotEntries static int stack_slot_local_offset(int i) { @@ -946,17 +953,6 @@ assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); } -protected: - // An entry for a return value takes less space than an entry for an - // argument so if the number of cells exceeds the number of cells - // needed for an argument, this object contains type information for - // at least one argument. - bool has_arguments() const { - bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); - assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); - return res; - } - public: CallTypeData(DataLayout* layout) : CounterData(layout), @@ -1018,6 +1014,16 @@ } // An entry for a return value takes less space than an entry for an + // argument so if the number of cells exceeds the number of cells + // needed for an argument, this object contains type information for + // at least one argument. + bool has_arguments() const { + bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); + assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); + return res; + } + + // An entry for a return value takes less space than an entry for an // argument, so if the remainder of the number of cells divided by // the number of cells for an argument is not null, a return value // is profiled in this object. @@ -1213,17 +1219,6 @@ assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); } -protected: - // An entry for a return value takes less space than an entry for an - // argument so if the number of cells exceeds the number of cells - // needed for an argument, this object contains type information for - // at least one argument. - bool has_arguments() const { - bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); - assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); - return res; - } - public: VirtualCallTypeData(DataLayout* layout) : VirtualCallData(layout), @@ -1294,6 +1289,16 @@ return res; } + // An entry for a return value takes less space than an entry for an + // argument so if the number of cells exceeds the number of cells + // needed for an argument, this object contains type information for + // at least one argument. + bool has_arguments() const { + bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); + assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); + return res; + } + // Code generation support static ByteSize args_data_offset() { return cell_offset(VirtualCallData::static_cell_count()) + TypeEntriesAtCall::args_data_offset(); @@ -1662,6 +1667,75 @@ #endif }; +// ParametersTypeData +// +// A ParametersTypeData is used to access profiling information about +// types of parameters to a method +class ParametersTypeData : public ArrayData { + +private: + TypeStackSlotEntries _parameters; + + static int stack_slot_local_offset(int i) { + assert_profiling_enabled(); + return array_start_off_set + TypeStackSlotEntries::stack_slot_local_offset(i); + } + + static int type_local_offset(int i) { + assert_profiling_enabled(); + return array_start_off_set + TypeStackSlotEntries::type_local_offset(i); + } + + static bool profiling_enabled(); + static void assert_profiling_enabled() { + assert(profiling_enabled(), "method parameters profiling should be on"); + } + +public: + ParametersTypeData(DataLayout* layout) : ArrayData(layout), _parameters(1, number_of_parameters()) { + assert(layout->tag() == DataLayout::parameters_type_data_tag, "wrong type"); + // Some compilers (VC++) don't want this passed in member initialization list + _parameters.set_profile_data(this); + } + + static int compute_cell_count(Method* m); + + virtual bool is_ParametersTypeData() const { return true; } + + virtual void post_initialize(BytecodeStream* stream, MethodData* mdo); + + int number_of_parameters() const { + return array_len() / TypeStackSlotEntries::per_arg_count(); + } + + const TypeStackSlotEntries* parameters() const { return &_parameters; } + + uint stack_slot(int i) const { + return _parameters.stack_slot(i); + } + + void set_type(int i, Klass* k) { + intptr_t current = _parameters.type(i); + _parameters.set_type(i, TypeEntries::with_status((intptr_t)k, current)); + } + + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) { + _parameters.clean_weak_klass_links(is_alive_closure); + } + +#ifndef PRODUCT + virtual void print_data_on(outputStream* st) const; +#endif + + static ByteSize stack_slot_offset(int i) { + return cell_offset(stack_slot_local_offset(i)); + } + + static ByteSize type_offset(int i) { + return cell_offset(type_local_offset(i)); + } +}; + // MethodData* // // A MethodData* holds information which has been collected about @@ -1773,6 +1847,10 @@ // Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size; + // data index for the area dedicated to parameters. -1 if no + // parameter profiling. + int _parameters_type_data_di; + // Beginning of the data entries intptr_t _data[1]; @@ -1842,6 +1920,9 @@ static int profile_return_flag(); static bool profile_all_return(); static bool profile_return_for_invoke(methodHandle m, int bci); + static int profile_parameters_flag(); + static bool profile_parameters_jsr292_only(); + static bool profile_all_parameters(); public: static int header_size() { @@ -2048,6 +2129,16 @@ } } + // Return pointer to area dedicated to parameters in MDO + ParametersTypeData* parameters_type_data() const { + return _parameters_type_data_di != -1 ? data_layout_at(_parameters_type_data_di)->data_in()->as_ParametersTypeData() : NULL; + } + + int parameters_type_data_di() const { + assert(_parameters_type_data_di != -1, "no args type data"); + return _parameters_type_data_di; + } + // Support for code generation static ByteSize data_offset() { return byte_offset_of(MethodData, _data[0]); @@ -2060,6 +2151,10 @@ return byte_offset_of(MethodData, _backedge_counter); } + static ByteSize parameters_type_data_di_offset() { + return byte_offset_of(MethodData, _parameters_type_data_di); + } + // Deallocation support - no pointer fields to deallocate void deallocate_contents(ClassLoaderData* loader_data) {} @@ -2083,8 +2178,10 @@ void verify_on(outputStream* st); void verify_data_on(outputStream* st); + static bool profile_parameters_for_method(methodHandle m); static bool profile_arguments(); static bool profile_return(); + static bool profile_parameters(); static bool profile_return_jsr292_only(); }; diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/runtime/globals.hpp Tue Oct 22 09:51:47 2013 +0200 @@ -2671,13 +2671,18 @@ "Enable aggressive optimizations - see arguments.cpp") \ \ product_pd(uintx, TypeProfileLevel, \ - "=XY, with Y, Type profiling of arguments at call" \ - " X, Type profiling of return value at call" \ - "X and Y in 0->off ; 1->js292 only; 2->all methods") \ + "=XYZ, with Z: Type profiling of arguments at call; " \ + "Y: Type profiling of return value at call; " \ + "X: Type profiling of parameters to methods; " \ + "X, Y and Z in 0=off ; 1=jsr292 only; 2=all methods") \ \ product(intx, TypeProfileArgsLimit, 2, \ "max number of call arguments to consider for type profiling") \ \ + product(intx, TypeProfileParmsLimit, 2, \ + "max number of incoming parameters to consider for type profiling"\ + ", -1 for all") \ + \ /* statistics */ \ develop(bool, CountCompiledCalls, false, \ "Count method invocations") \ diff -r 4748b3308cda -r 5ccbab1c69f3 src/share/vm/runtime/java.cpp --- a/src/share/vm/runtime/java.cpp Mon Oct 21 17:34:27 2013 -0700 +++ b/src/share/vm/runtime/java.cpp Tue Oct 22 09:51:47 2013 +0200 @@ -193,6 +193,11 @@ m->print_invocation_count(); tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes()); tty->cr(); + // Dump data on parameters if any + if (m->method_data() != NULL && m->method_data()->parameters_type_data() != NULL) { + tty->fill_to(2); + m->method_data()->parameters_type_data()->print_data_on(tty); + } m->print_codes(); total_size += m->method_data()->size_in_bytes(); }