提交 3a7d7165 编写于 作者: R roland

8026251: New type profiling points: parameters to methods

Summary: x86 interpreter and c1 type profiling for parameters on method entries
Reviewed-by: kvn, twisti
上级 1da24bc7
...@@ -40,11 +40,8 @@ ...@@ -40,11 +40,8 @@
#include "runtime/synchronizer.hpp" #include "runtime/synchronizer.hpp"
#include "runtime/vframeArray.hpp" #include "runtime/vframeArray.hpp"
#include "utilities/debug.hpp" #include "utilities/debug.hpp"
#ifdef TARGET_ARCH_MODEL_x86_32 #ifdef TARGET_ARCH_x86
# include "interp_masm_x86_32.hpp" # include "interp_masm_x86.hpp"
#endif
#ifdef TARGET_ARCH_MODEL_x86_64
# include "interp_masm_x86_64.hpp"
#endif #endif
#ifdef CC_INTERP #ifdef CC_INTERP
......
...@@ -79,7 +79,7 @@ define_pd_global(bool, UseMembar, false); ...@@ -79,7 +79,7 @@ define_pd_global(bool, UseMembar, false);
// GC Ergo Flags // 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, 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) \ #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
\ \
......
/*
* 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
/*
* 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
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "interp_masm_x86_32.hpp" #include "interp_masm_x86.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp" #include "interpreter/interpreterRuntime.hpp"
#include "oops/arrayOop.hpp" #include "oops/arrayOop.hpp"
...@@ -1046,159 +1046,6 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { ...@@ -1046,159 +1046,6 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) {
} }
} }
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) { void InterpreterMacroAssembler::profile_call(Register mdp) {
if (ProfileInterpreter) { if (ProfileInterpreter) {
Label profile_continue; Label profile_continue;
......
...@@ -22,18 +22,6 @@ ...@@ -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 #ifndef CC_INTERP
protected: protected:
// Interpreter specific version of call_VM_base // Interpreter specific version of call_VM_base
...@@ -59,7 +47,7 @@ class InterpreterMacroAssembler: public MacroAssembler { ...@@ -59,7 +47,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
#endif /* CC_INTERP */ #endif /* CC_INTERP */
public: public:
InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {} InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(rdi), _bcp_register(rsi) {}
void load_earlyret_value(TosState state); void load_earlyret_value(TosState state);
...@@ -215,9 +203,6 @@ class InterpreterMacroAssembler: public MacroAssembler { ...@@ -215,9 +203,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
void profile_taken_branch(Register mdp, Register bumped_count); void profile_taken_branch(Register mdp, Register bumped_count);
void profile_not_taken_branch(Register mdp); 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_call(Register mdp);
void profile_final_call(Register mdp); void profile_final_call(Register mdp);
void profile_virtual_call(Register receiver, Register mdp, Register scratch2, void profile_virtual_call(Register receiver, Register mdp, Register scratch2,
...@@ -236,7 +221,3 @@ class InterpreterMacroAssembler: public MacroAssembler { ...@@ -236,7 +221,3 @@ class InterpreterMacroAssembler: public MacroAssembler {
// support for jvmti // support for jvmti
void notify_method_entry(); void notify_method_entry();
void notify_method_exit(TosState state, NotifyMethodExitMode mode); void notify_method_exit(TosState state, NotifyMethodExitMode mode);
};
#endif // CPU_X86_VM_INTERP_MASM_X86_32_HPP
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "interp_masm_x86_64.hpp" #include "interp_masm_x86.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp" #include "interpreter/interpreterRuntime.hpp"
#include "oops/arrayOop.hpp" #include "oops/arrayOop.hpp"
...@@ -1067,160 +1067,6 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { ...@@ -1067,160 +1067,6 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) {
} }
} }
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) { void InterpreterMacroAssembler::profile_call(Register mdp) {
if (ProfileInterpreter) { if (ProfileInterpreter) {
Label profile_continue; Label profile_continue;
......
...@@ -22,18 +22,6 @@ ...@@ -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 #ifndef CC_INTERP
protected: protected:
// Interpreter specific version of call_VM_base // Interpreter specific version of call_VM_base
...@@ -55,7 +43,7 @@ class InterpreterMacroAssembler: public MacroAssembler { ...@@ -55,7 +43,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
#endif // CC_INTERP #endif // CC_INTERP
public: public:
InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {} InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(r14), _bcp_register(r13) {}
void load_earlyret_value(TosState state); void load_earlyret_value(TosState state);
...@@ -224,9 +212,6 @@ class InterpreterMacroAssembler: public MacroAssembler { ...@@ -224,9 +212,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
void profile_taken_branch(Register mdp, Register bumped_count); void profile_taken_branch(Register mdp, Register bumped_count);
void profile_not_taken_branch(Register mdp); 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_call(Register mdp);
void profile_final_call(Register mdp); void profile_final_call(Register mdp);
void profile_virtual_call(Register receiver, Register mdp, void profile_virtual_call(Register receiver, Register mdp,
...@@ -253,6 +238,3 @@ class InterpreterMacroAssembler: public MacroAssembler { ...@@ -253,6 +238,3 @@ class InterpreterMacroAssembler: public MacroAssembler {
// support for jvmti/dtrace // support for jvmti/dtrace
void notify_method_entry(); void notify_method_entry();
void notify_method_exit(TosState state, NotifyMethodExitMode mode); void notify_method_exit(TosState state, NotifyMethodExitMode mode);
};
#endif // CPU_X86_VM_INTERP_MASM_X86_64_HPP
...@@ -26,11 +26,8 @@ ...@@ -26,11 +26,8 @@
#include "asm/assembler.hpp" #include "asm/assembler.hpp"
#include "asm/register.hpp" #include "asm/register.hpp"
#include "register_x86.hpp" #include "register_x86.hpp"
#ifdef TARGET_ARCH_MODEL_x86_32 #ifdef TARGET_ARCH_x86
# include "interp_masm_x86_32.hpp" # include "interp_masm_x86.hpp"
#endif
#ifdef TARGET_ARCH_MODEL_x86_64
# include "interp_masm_x86_64.hpp"
#endif #endif
REGISTER_DEFINITION(Register, noreg); REGISTER_DEFINITION(Register, noreg);
......
...@@ -1490,6 +1490,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { ...@@ -1490,6 +1490,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
__ movbool(do_not_unlock_if_synchronized, true); __ movbool(do_not_unlock_if_synchronized, true);
__ profile_parameters_type(rax, rcx, rdx);
// increment invocation count & check for overflow // increment invocation count & check for overflow
Label invocation_counter_overflow; Label invocation_counter_overflow;
Label profile_method; Label profile_method;
......
...@@ -1497,6 +1497,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { ...@@ -1497,6 +1497,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
__ movbool(do_not_unlock_if_synchronized, true); __ movbool(do_not_unlock_if_synchronized, true);
__ profile_parameters_type(rax, rcx, rdx);
// increment invocation count & check for overflow // increment invocation count & check for overflow
Label invocation_counter_overflow; Label invocation_counter_overflow;
Label profile_method; Label profile_method;
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.hpp"
#include "code/vtableStubs.hpp" #include "code/vtableStubs.hpp"
#include "interp_masm_x86_32.hpp" #include "interp_masm_x86.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp" #include "oops/klassVtable.hpp"
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.hpp"
#include "code/vtableStubs.hpp" #include "code/vtableStubs.hpp"
#include "interp_masm_x86_64.hpp" #include "interp_masm_x86.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp" #include "oops/klassVtable.hpp"
......
...@@ -238,7 +238,18 @@ class Compilation: public StackObj { ...@@ -238,7 +238,18 @@ class Compilation: public StackObj {
return env()->comp_level() == CompLevel_full_profile && return env()->comp_level() == CompLevel_full_profile &&
C1UpdateMethodData && C1ProfileCheckcasts; 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 // will compilation make optimistic assumptions that might lead to
// deoptimization and that the runtime will account for? // deoptimization and that the runtime will account for?
bool is_optimistic() const { bool is_optimistic() const {
......
...@@ -1470,7 +1470,7 @@ void GraphBuilder::method_return(Value x) { ...@@ -1470,7 +1470,7 @@ void GraphBuilder::method_return(Value x) {
set_state(state()->caller_state()->copy_for_parsing()); set_state(state()->caller_state()->copy_for_parsing());
if (x != NULL) { if (x != NULL) {
state()->push(x->type(), x); 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(); ciMethod* caller = state()->scope()->method();
ciMethodData* md = caller->method_data_or_null(); ciMethodData* md = caller->method_data_or_null();
ciProfileData* data = md->bci_to_data(invoke_bci); ciProfileData* data = md->bci_to_data(invoke_bci);
...@@ -1672,15 +1672,23 @@ Dependencies* GraphBuilder::dependency_recorder() const { ...@@ -1672,15 +1672,23 @@ Dependencies* GraphBuilder::dependency_recorder() const {
} }
// How many arguments do we want to profile? // 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; int n = 0;
assert(start == 0, "should be initialized"); bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci()));
if (MethodData::profile_arguments()) { start = has_receiver ? 1 : 0;
if (profile_arguments()) {
ciProfileData* data = method()->method_data()->bci_to_data(bci()); ciProfileData* data = method()->method_data()->bci_to_data(bci());
if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
n = data->is_CallTypeData() ? data->as_CallTypeData()->number_of_arguments() : data->as_VirtualCallTypeData()->number_of_arguments(); 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) { if (n > 0) {
...@@ -1690,9 +1698,9 @@ Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver ...@@ -1690,9 +1698,9 @@ Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver
} }
// Collect arguments that we want to profile in a list // 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; 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) { if (obj_args == NULL) {
return NULL; return NULL;
} }
...@@ -2006,7 +2014,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) { ...@@ -2006,7 +2014,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
} else if (exact_target != NULL) { } else if (exact_target != NULL) {
target_klass = exact_target->holder(); 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 @@ void GraphBuilder::invoke(Bytecodes::Code code) { ...@@ -2021,7 +2029,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
push(result_type, result); 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); profile_return_type(result, target);
} }
} }
...@@ -3561,7 +3569,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { ...@@ -3561,7 +3569,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
recv = args->at(0); recv = args->at(0);
null_check(recv); 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 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { ...@@ -3572,7 +3580,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
Value value = append_split(result); Value value = append_split(result);
if (result_type != voidType) push(result_type, value); 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); profile_return_type(result, callee);
} }
...@@ -3820,7 +3828,7 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode ...@@ -3820,7 +3828,7 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
if (profile_calls()) { if (profile_calls()) {
int start = 0; 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) { if (obj_args != NULL) {
int s = obj_args->size(); int s = obj_args->size();
// if called through method handle invoke, some arguments may have been popped // if called through method handle invoke, some arguments may have been popped
......
...@@ -386,9 +386,12 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC { ...@@ -386,9 +386,12 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
bool profile_calls() { return _compilation->profile_calls(); } bool profile_calls() { return _compilation->profile_calls(); }
bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); } bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); }
bool profile_checkcasts() { return _compilation->profile_checkcasts(); } 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* args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver);
Values* collect_args_for_profiling(Values* args, bool may_have_receiver); Values* collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver);
public: public:
NOT_PRODUCT(void print_stats();) NOT_PRODUCT(void print_stats();)
......
...@@ -2647,6 +2647,39 @@ ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, in ...@@ -2647,6 +2647,39 @@ ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, in
return result; 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) { void LIRGenerator::do_Base(Base* x) {
__ std_entry(LIR_OprFact::illegalOpr); __ std_entry(LIR_OprFact::illegalOpr);
// Emit moves from physical registers / stack slots to virtual registers // Emit moves from physical registers / stack slots to virtual registers
...@@ -2722,6 +2755,7 @@ void LIRGenerator::do_Base(Base* x) { ...@@ -2722,6 +2755,7 @@ void LIRGenerator::do_Base(Base* x) {
// increment invocation counters if needed // increment invocation counters if needed
if (!method()->is_accessor()) { // Accessors do not have MDOs, so no counting. 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); CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, SynchronizationEntryBCI), NULL, false);
increment_invocation_counter(info); increment_invocation_counter(info);
} }
...@@ -3081,11 +3115,12 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { ...@@ -3081,11 +3115,12 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
} }
void LIRGenerator::profile_arguments(ProfileCall* x) { void LIRGenerator::profile_arguments(ProfileCall* x) {
if (MethodData::profile_arguments()) { if (compilation()->profile_arguments()) {
int bci = x->bci_of_invoke(); int bci = x->bci_of_invoke();
ciMethodData* md = x->method()->method_data_or_null(); ciMethodData* md = x->method()->method_data_or_null();
ciProfileData* data = md->bci_to_data(bci); 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(); ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset();
int base_offset = md->byte_offset_of_slot(data, extra); int base_offset = md->byte_offset_of_slot(data, extra);
LIR_Opr mdp = LIR_OprFact::illegalOpr; LIR_Opr mdp = LIR_OprFact::illegalOpr;
...@@ -3111,6 +3146,71 @@ void LIRGenerator::profile_arguments(ProfileCall* x) { ...@@ -3111,6 +3146,71 @@ void LIRGenerator::profile_arguments(ProfileCall* x) {
md->set_argument_type(bci, i, exact); 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 @@ void LIRGenerator::do_ProfileCall(ProfileCall* x) { ...@@ -3126,6 +3226,11 @@ void LIRGenerator::do_ProfileCall(ProfileCall* x) {
profile_arguments(x); 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) { if (x->recv() != NULL) {
LIRItem value(x->recv(), this); LIRItem value(x->recv(), this);
value.load_item(); value.load_item();
......
...@@ -436,6 +436,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { ...@@ -436,6 +436,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
#endif #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); 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_arguments(ProfileCall* x);
void profile_parameters(Base* x);
void profile_parameters_at_call(ProfileCall* x);
public: public:
Compilation* compilation() const { return _compilation; } Compilation* compilation() const { return _compilation; }
......
...@@ -53,6 +53,7 @@ ciMethodData::ciMethodData(MethodData* md) : ciMetadata(md) { ...@@ -53,6 +53,7 @@ ciMethodData::ciMethodData(MethodData* md) : ciMetadata(md) {
_hint_di = first_di(); _hint_di = first_di();
// Initialize the escape information (to "don't know."); // Initialize the escape information (to "don't know.");
_eflags = _arg_local = _arg_stack = _arg_returned = 0; _eflags = _arg_local = _arg_stack = _arg_returned = 0;
_parameters = NULL;
} }
// ------------------------------------------------------------------ // ------------------------------------------------------------------
...@@ -74,6 +75,7 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) { ...@@ -74,6 +75,7 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) {
_hint_di = first_di(); _hint_di = first_di();
// Initialize the escape information (to "don't know."); // Initialize the escape information (to "don't know.");
_eflags = _arg_local = _arg_stack = _arg_returned = 0; _eflags = _arg_local = _arg_stack = _arg_returned = 0;
_parameters = NULL;
} }
void ciMethodData::load_data() { void ciMethodData::load_data() {
...@@ -108,6 +110,12 @@ void ciMethodData::load_data() { ...@@ -108,6 +110,12 @@ void ciMethodData::load_data() {
ci_data = next_data(ci_data); ci_data = next_data(ci_data);
data = mdo->next_data(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. // Note: Extra data are all BitData, and do not need translation.
_current_mileage = MethodData::mileage_of(mdo->method()); _current_mileage = MethodData::mileage_of(mdo->method());
_invocation_counter = mdo->invocation_count(); _invocation_counter = mdo->invocation_count();
...@@ -182,6 +190,8 @@ ciProfileData* ciMethodData::data_at(int data_index) { ...@@ -182,6 +190,8 @@ ciProfileData* ciMethodData::data_at(int data_index) {
return new ciCallTypeData(data_layout); return new ciCallTypeData(data_layout);
case DataLayout::virtual_call_type_data_tag: case DataLayout::virtual_call_type_data_tag:
return new ciVirtualCallTypeData(data_layout); return new ciVirtualCallTypeData(data_layout);
case DataLayout::parameters_type_data_tag:
return new ciParametersTypeData(data_layout);
}; };
} }
...@@ -318,6 +328,14 @@ void ciMethodData::set_argument_type(int bci, int i, ciKlass* k) { ...@@ -318,6 +328,14 @@ void ciMethodData::set_argument_type(int bci, int i, ciKlass* k) {
} }
} }
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) { void ciMethodData::set_return_type(int bci, ciKlass* k) {
VM_ENTRY_MARK; VM_ENTRY_MARK;
MethodData* mdo = get_MethodData(); MethodData* mdo = get_MethodData();
...@@ -605,4 +623,9 @@ void ciVirtualCallTypeData::print_data_on(outputStream* st) const { ...@@ -605,4 +623,9 @@ void ciVirtualCallTypeData::print_data_on(outputStream* st) const {
ret()->print_data_on(st); ret()->print_data_on(st);
} }
} }
void ciParametersTypeData::print_data_on(outputStream* st) const {
st->print_cr("Parametertypes");
parameters()->print_data_on(st);
}
#endif #endif
...@@ -43,6 +43,7 @@ class ciMultiBranchData; ...@@ -43,6 +43,7 @@ class ciMultiBranchData;
class ciArgInfoData; class ciArgInfoData;
class ciCallTypeData; class ciCallTypeData;
class ciVirtualCallTypeData; class ciVirtualCallTypeData;
class ciParametersTypeData;
typedef ProfileData ciProfileData; typedef ProfileData ciProfileData;
...@@ -124,7 +125,7 @@ public: ...@@ -124,7 +125,7 @@ public:
ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)CallTypeData::args(); } ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)CallTypeData::args(); }
ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)CallTypeData::ret(); } ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)CallTypeData::ret(); }
void translate_type_data_from(const ProfileData* data) { void translate_from(const ProfileData* data) {
if (has_arguments()) { if (has_arguments()) {
args()->translate_type_data_from(data->as_CallTypeData()->args()); args()->translate_type_data_from(data->as_CallTypeData()->args());
} }
...@@ -290,6 +291,25 @@ public: ...@@ -290,6 +291,25 @@ public:
ciArgInfoData(DataLayout* layout) : ArgInfoData(layout) {}; 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 // ciMethodData
// //
// This class represents a MethodData* in the HotSpot virtual // This class represents a MethodData* in the HotSpot virtual
...@@ -335,6 +355,10 @@ private: ...@@ -335,6 +355,10 @@ private:
// Coherent snapshot of original header. // Coherent snapshot of original header.
MethodData _orig; MethodData _orig;
// Dedicated area dedicated to parameters. Null if no parameter
// profiling for this method.
DataLayout* _parameters;
ciMethodData(MethodData* md); ciMethodData(MethodData* md);
ciMethodData(); ciMethodData();
...@@ -403,6 +427,7 @@ public: ...@@ -403,6 +427,7 @@ public:
// If the compiler finds a profiled type that is known statically // If the compiler finds a profiled type that is known statically
// for sure, set it in the MethodData // for sure, set it in the MethodData
void set_argument_type(int bci, int i, ciKlass* k); 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 set_return_type(int bci, ciKlass* k);
void load_data(); void load_data();
...@@ -467,6 +492,10 @@ public: ...@@ -467,6 +492,10 @@ public:
bool is_arg_returned(int i) const; bool is_arg_returned(int i) const;
uint arg_modified(int arg) const; uint arg_modified(int arg) const;
ciParametersTypeData* parameters_type_data() const {
return _parameters != NULL ? new ciParametersTypeData(_parameters) : NULL;
}
// Code generation helper // Code generation helper
ByteSize offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data); 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)); } int byte_offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) { return in_bytes(offset_of_slot(data, slot_offset_in_data)); }
......
...@@ -30,11 +30,8 @@ ...@@ -30,11 +30,8 @@
#include "runtime/thread.inline.hpp" #include "runtime/thread.inline.hpp"
#include "runtime/vmThread.hpp" #include "runtime/vmThread.hpp"
#include "utilities/top.hpp" #include "utilities/top.hpp"
#ifdef TARGET_ARCH_MODEL_x86_32 #ifdef TARGET_ARCH_x86
# include "interp_masm_x86_32.hpp" # include "interp_masm_x86.hpp"
#endif
#ifdef TARGET_ARCH_MODEL_x86_64
# include "interp_masm_x86_64.hpp"
#endif #endif
#ifdef TARGET_ARCH_MODEL_sparc #ifdef TARGET_ARCH_MODEL_sparc
# include "interp_masm_sparc.hpp" # include "interp_masm_sparc.hpp"
......
...@@ -28,11 +28,8 @@ ...@@ -28,11 +28,8 @@
#include "interpreter/bytecodes.hpp" #include "interpreter/bytecodes.hpp"
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
#include "runtime/frame.hpp" #include "runtime/frame.hpp"
#ifdef TARGET_ARCH_MODEL_x86_32 #ifdef TARGET_ARCH_x86
# include "interp_masm_x86_32.hpp" # include "interp_masm_x86.hpp"
#endif
#ifdef TARGET_ARCH_MODEL_x86_64
# include "interp_masm_x86_64.hpp"
#endif #endif
#ifdef TARGET_ARCH_MODEL_sparc #ifdef TARGET_ARCH_MODEL_sparc
# include "interp_masm_sparc.hpp" # include "interp_masm_sparc.hpp"
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
// Some types of data layouts need a length field. // Some types of data layouts need a length field.
bool DataLayout::needs_array_len(u1 tag) { 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 // Perform generic initialization of the data. More specific
...@@ -156,10 +156,13 @@ void JumpData::print_data_on(outputStream* st) const { ...@@ -156,10 +156,13 @@ void JumpData::print_data_on(outputStream* st) const {
} }
#endif // !PRODUCT #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; ResourceMark rm;
SignatureStream ss(signature); 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; return args_count * per_arg_cell_count;
} }
...@@ -169,7 +172,7 @@ int TypeEntriesAtCall::compute_cell_count(BytecodeStream* stream) { ...@@ -169,7 +172,7 @@ int TypeEntriesAtCall::compute_cell_count(BytecodeStream* stream) {
Bytecode_invoke inv(stream->method(), stream->bci()); Bytecode_invoke inv(stream->method(), stream->bci());
int args_cell = 0; int args_cell = 0;
if (arguments_profiling_enabled()) { 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; int ret_cell = 0;
if (return_profiling_enabled() && (inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY)) { if (return_profiling_enabled() && (inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY)) {
...@@ -212,12 +215,19 @@ public: ...@@ -212,12 +215,19 @@ public:
int off_at(int i) const { return _offsets.at(i); } 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; 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(); aos.total();
for (int i = 0; i < _number_of_entries; i++) { for (int i = start; i < _number_of_entries; i++) {
set_stack_slot(i, aos.off_at(i) + (has_receiver ? 1 : 0)); set_stack_slot(i, aos.off_at(i-start) + (has_receiver ? 1 : 0));
set_type(i, type_none()); set_type(i, type_none());
} }
} }
...@@ -234,7 +244,7 @@ void CallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { ...@@ -234,7 +244,7 @@ void CallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
assert(count > 0, "room for args type but none found?"); assert(count > 0, "room for args type but none found?");
check_number_of_arguments(count); check_number_of_arguments(count);
#endif #endif
_args.post_initialize(inv.signature(), inv.has_receiver()); _args.post_initialize(inv.signature(), inv.has_receiver(), false);
} }
if (has_return()) { if (has_return()) {
...@@ -255,7 +265,7 @@ void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* md ...@@ -255,7 +265,7 @@ void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* md
assert(count > 0, "room for args type but none found?"); assert(count > 0, "room for args type but none found?");
check_number_of_arguments(count); check_number_of_arguments(count);
#endif #endif
_args.post_initialize(inv.signature(), inv.has_receiver()); _args.post_initialize(inv.signature(), inv.has_receiver(), false);
} }
if (has_return()) { if (has_return()) {
...@@ -579,6 +589,34 @@ void ArgInfoData::print_data_on(outputStream* st) const { ...@@ -579,6 +589,34 @@ void ArgInfoData::print_data_on(outputStream* st) const {
} }
#endif #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* // MethodData*
// //
...@@ -741,6 +779,12 @@ int MethodData::compute_allocation_size_in_bytes(methodHandle method) { ...@@ -741,6 +779,12 @@ int MethodData::compute_allocation_size_in_bytes(methodHandle method) {
int arg_size = method->size_of_parameters(); int arg_size = method->size_of_parameters();
object_size += DataLayout::compute_size_in_bytes(arg_size+1); 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; return object_size;
} }
...@@ -915,6 +959,8 @@ ProfileData* DataLayout::data_in() { ...@@ -915,6 +959,8 @@ ProfileData* DataLayout::data_in() {
return new CallTypeData(this); return new CallTypeData(this);
case DataLayout::virtual_call_type_data_tag: case DataLayout::virtual_call_type_data_tag:
return new VirtualCallTypeData(this); return new VirtualCallTypeData(this);
case DataLayout::parameters_type_data_tag:
return new ParametersTypeData(this);
}; };
} }
...@@ -936,6 +982,9 @@ void MethodData::post_initialize(BytecodeStream* stream) { ...@@ -936,6 +982,9 @@ void MethodData::post_initialize(BytecodeStream* stream) {
stream->next(); stream->next();
data->post_initialize(stream, this); 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. // Initialize the MethodData* corresponding to a given method.
...@@ -975,7 +1024,23 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) { ...@@ -975,7 +1024,23 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) {
int arg_size = method->size_of_parameters(); int arg_size = method->size_of_parameters();
dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1); 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 // Set an initial hint. Don't use set_hint_di() because
// first_di() may be out of bounds if data_size is 0. // first_di() may be out of bounds if data_size is 0.
...@@ -1134,6 +1199,9 @@ void MethodData::print_value_on(outputStream* st) const { ...@@ -1134,6 +1199,9 @@ void MethodData::print_value_on(outputStream* st) const {
void MethodData::print_data_on(outputStream* st) const { void MethodData::print_data_on(outputStream* st) const {
ResourceMark rm; ResourceMark rm;
ProfileData* data = first_data(); 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)) { for ( ; is_valid(data); data = next_data(data)) {
st->print("%d", dp_to_di(data->dp())); st->print("%d", dp_to_di(data->dp()));
st->fill_to(6); st->fill_to(6);
...@@ -1222,7 +1290,7 @@ bool MethodData::profile_arguments_for_invoke(methodHandle m, int bci) { ...@@ -1222,7 +1290,7 @@ bool MethodData::profile_arguments_for_invoke(methodHandle m, int bci) {
} }
int MethodData::profile_return_flag() { int MethodData::profile_return_flag() {
return TypeProfileLevel / 10; return (TypeProfileLevel % 100) / 10;
} }
bool MethodData::profile_return() { bool MethodData::profile_return() {
...@@ -1249,3 +1317,32 @@ bool MethodData::profile_return_for_invoke(methodHandle m, int bci) { ...@@ -1249,3 +1317,32 @@ bool MethodData::profile_return_for_invoke(methodHandle m, int bci) {
assert(profile_return_jsr292_only(), "inconsistent"); assert(profile_return_jsr292_only(), "inconsistent");
return profile_jsr292(m, bci); 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();
}
...@@ -119,7 +119,8 @@ public: ...@@ -119,7 +119,8 @@ public:
multi_branch_data_tag, multi_branch_data_tag,
arg_info_data_tag, arg_info_data_tag,
call_type_data_tag, call_type_data_tag,
virtual_call_type_data_tag virtual_call_type_data_tag,
parameters_type_data_tag
}; };
enum { enum {
...@@ -264,6 +265,7 @@ class BranchData; ...@@ -264,6 +265,7 @@ class BranchData;
class ArrayData; class ArrayData;
class MultiBranchData; class MultiBranchData;
class ArgInfoData; class ArgInfoData;
class ParametersTypeData;
// ProfileData // ProfileData
// //
...@@ -397,6 +399,7 @@ public: ...@@ -397,6 +399,7 @@ public:
virtual bool is_ArgInfoData() const { return false; } virtual bool is_ArgInfoData() const { return false; }
virtual bool is_CallTypeData() const { return false; } virtual bool is_CallTypeData() const { return false; }
virtual bool is_VirtualCallTypeData()const { return false; } virtual bool is_VirtualCallTypeData()const { return false; }
virtual bool is_ParametersTypeData() const { return false; }
BitData* as_BitData() const { BitData* as_BitData() const {
...@@ -447,6 +450,10 @@ public: ...@@ -447,6 +450,10 @@ public:
assert(is_VirtualCallTypeData(), "wrong type"); assert(is_VirtualCallTypeData(), "wrong type");
return is_VirtualCallTypeData() ? (VirtualCallTypeData*)this : NULL; return is_VirtualCallTypeData() ? (VirtualCallTypeData*)this : NULL;
} }
ParametersTypeData* as_ParametersTypeData() const {
assert(is_ParametersTypeData(), "wrong type");
return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL;
}
// Subclass specific initialization // Subclass specific initialization
...@@ -767,9 +774,9 @@ public: ...@@ -767,9 +774,9 @@ public:
TypeStackSlotEntries(int base_off, int nb_entries) TypeStackSlotEntries(int base_off, int nb_entries)
: TypeEntries(base_off), _number_of_entries(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 // 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) { static int stack_slot_local_offset(int i) {
...@@ -946,17 +953,6 @@ private: ...@@ -946,17 +953,6 @@ private:
assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); 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: public:
CallTypeData(DataLayout* layout) : CallTypeData(DataLayout* layout) :
CounterData(layout), CounterData(layout),
...@@ -1017,6 +1013,16 @@ public: ...@@ -1017,6 +1013,16 @@ public:
_ret.set_type(TypeEntries::with_status(k, current)); _ret.set_type(TypeEntries::with_status(k, current));
} }
// 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 // 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 // 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 // the number of cells for an argument is not null, a return value
...@@ -1213,17 +1219,6 @@ private: ...@@ -1213,17 +1219,6 @@ private:
assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); 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: public:
VirtualCallTypeData(DataLayout* layout) : VirtualCallTypeData(DataLayout* layout) :
VirtualCallData(layout), VirtualCallData(layout),
...@@ -1294,6 +1289,16 @@ public: ...@@ -1294,6 +1289,16 @@ public:
return res; 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 // Code generation support
static ByteSize args_data_offset() { static ByteSize args_data_offset() {
return cell_offset(VirtualCallData::static_cell_count()) + TypeEntriesAtCall::args_data_offset(); return cell_offset(VirtualCallData::static_cell_count()) + TypeEntriesAtCall::args_data_offset();
...@@ -1662,6 +1667,75 @@ public: ...@@ -1662,6 +1667,75 @@ public:
#endif #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* // MethodData*
// //
// A MethodData* holds information which has been collected about // A MethodData* holds information which has been collected about
...@@ -1773,6 +1847,10 @@ private: ...@@ -1773,6 +1847,10 @@ private:
// Size of _data array in bytes. (Excludes header and extra_data fields.) // Size of _data array in bytes. (Excludes header and extra_data fields.)
int _data_size; 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 // Beginning of the data entries
intptr_t _data[1]; intptr_t _data[1];
...@@ -1842,6 +1920,9 @@ private: ...@@ -1842,6 +1920,9 @@ private:
static int profile_return_flag(); static int profile_return_flag();
static bool profile_all_return(); static bool profile_all_return();
static bool profile_return_for_invoke(methodHandle m, int bci); 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: public:
static int header_size() { static int header_size() {
...@@ -2048,6 +2129,16 @@ public: ...@@ -2048,6 +2129,16 @@ public:
} }
} }
// 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 // Support for code generation
static ByteSize data_offset() { static ByteSize data_offset() {
return byte_offset_of(MethodData, _data[0]); return byte_offset_of(MethodData, _data[0]);
...@@ -2060,6 +2151,10 @@ public: ...@@ -2060,6 +2151,10 @@ public:
return byte_offset_of(MethodData, _backedge_counter); 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 // Deallocation support - no pointer fields to deallocate
void deallocate_contents(ClassLoaderData* loader_data) {} void deallocate_contents(ClassLoaderData* loader_data) {}
...@@ -2083,8 +2178,10 @@ public: ...@@ -2083,8 +2178,10 @@ public:
void verify_on(outputStream* st); void verify_on(outputStream* st);
void verify_data_on(outputStream* st); void verify_data_on(outputStream* st);
static bool profile_parameters_for_method(methodHandle m);
static bool profile_arguments(); static bool profile_arguments();
static bool profile_return(); static bool profile_return();
static bool profile_parameters();
static bool profile_return_jsr292_only(); static bool profile_return_jsr292_only();
}; };
......
...@@ -2671,13 +2671,18 @@ class CommandLineFlags { ...@@ -2671,13 +2671,18 @@ class CommandLineFlags {
"Enable aggressive optimizations - see arguments.cpp") \ "Enable aggressive optimizations - see arguments.cpp") \
\ \
product_pd(uintx, TypeProfileLevel, \ product_pd(uintx, TypeProfileLevel, \
"=XY, with Y, Type profiling of arguments at call" \ "=XYZ, with Z: Type profiling of arguments at call; " \
" X, Type profiling of return value at call" \ "Y: Type profiling of return value at call; " \
"X and Y in 0->off ; 1->js292 only; 2->all methods") \ "X: Type profiling of parameters to methods; " \
"X, Y and Z in 0=off ; 1=jsr292 only; 2=all methods") \
\ \
product(intx, TypeProfileArgsLimit, 2, \ product(intx, TypeProfileArgsLimit, 2, \
"max number of call arguments to consider for type profiling") \ "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 */ \ /* statistics */ \
develop(bool, CountCompiledCalls, false, \ develop(bool, CountCompiledCalls, false, \
"Count method invocations") \ "Count method invocations") \
......
...@@ -193,6 +193,11 @@ void print_method_profiling_data() { ...@@ -193,6 +193,11 @@ void print_method_profiling_data() {
m->print_invocation_count(); m->print_invocation_count();
tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes()); tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes());
tty->cr(); 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(); m->print_codes();
total_size += m->method_data()->size_in_bytes(); total_size += m->method_data()->size_in_bytes();
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册