提交 1e08da20 编写于 作者: 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
上级 45cd1688
......@@ -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
......
......@@ -79,7 +79,7 @@ define_pd_global(bool, UseMembar, false);
// 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) \
\
......
/*
* 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 @@
*/
#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_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) {
if (ProfileInterpreter) {
Label profile_continue;
......
......@@ -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 @@ class InterpreterMacroAssembler: public MacroAssembler {
#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 @@ class InterpreterMacroAssembler: public MacroAssembler {
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 @@ class InterpreterMacroAssembler: public MacroAssembler {
// support for jvmti
void notify_method_entry();
void notify_method_exit(TosState state, NotifyMethodExitMode mode);
};
#endif // CPU_X86_VM_INTERP_MASM_X86_32_HPP
......@@ -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_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) {
if (ProfileInterpreter) {
Label profile_continue;
......
......@@ -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 @@ class InterpreterMacroAssembler: public MacroAssembler {
#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 @@ class InterpreterMacroAssembler: public MacroAssembler {
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 @@ class InterpreterMacroAssembler: public MacroAssembler {
// 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
......@@ -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);
......
......@@ -1490,6 +1490,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
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;
......
......@@ -1497,6 +1497,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
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;
......
......@@ -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"
......
......@@ -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"
......
......@@ -238,7 +238,18 @@ class Compilation: public StackObj {
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 {
......
......@@ -1470,7 +1470,7 @@ void GraphBuilder::method_return(Value x) {
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 @@ Dependencies* GraphBuilder::dependency_recorder() const {
}
// 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 @@ Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver
}
// 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 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
} 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 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
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 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
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 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
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 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
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
......
......@@ -386,9 +386,12 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
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();)
......
......@@ -2647,6 +2647,39 @@ ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, in
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 @@ void LIRGenerator::do_Base(Base* x) {
// 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::do_Intrinsic(Intrinsic* x) {
}
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 @@ void LIRGenerator::profile_arguments(ProfileCall* x) {
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) {
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();
......
......@@ -436,6 +436,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
#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; }
......
......@@ -53,6 +53,7 @@ ciMethodData::ciMethodData(MethodData* md) : ciMetadata(md) {
_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 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) {
_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 @@ void ciMethodData::load_data() {
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 @@ ciProfileData* ciMethodData::data_at(int data_index) {
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_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) {
VM_ENTRY_MARK;
MethodData* mdo = get_MethodData();
......@@ -605,4 +623,9 @@ void ciVirtualCallTypeData::print_data_on(outputStream* st) const {
ret()->print_data_on(st);
}
}
void ciParametersTypeData::print_data_on(outputStream* st) const {
st->print_cr("Parametertypes");
parameters()->print_data_on(st);
}
#endif
......@@ -43,6 +43,7 @@ class ciMultiBranchData;
class ciArgInfoData;
class ciCallTypeData;
class ciVirtualCallTypeData;
class ciParametersTypeData;
typedef ProfileData ciProfileData;
......@@ -124,7 +125,7 @@ public:
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 @@ public:
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 @@ private:
// 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 @@ public:
// 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 @@ public:
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)); }
......
......@@ -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"
......
......@@ -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"
......
......@@ -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 @@ void JumpData::print_data_on(outputStream* st) const {
}
#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 @@ int TypeEntriesAtCall::compute_cell_count(BytecodeStream* stream) {
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 @@ public:
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 @@ void CallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
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 @@ void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* md
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 @@ void ArgInfoData::print_data_on(outputStream* st) const {
}
#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 MethodData::compute_allocation_size_in_bytes(methodHandle method) {
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 @@ ProfileData* DataLayout::data_in() {
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 @@ void MethodData::post_initialize(BytecodeStream* stream) {
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 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) {
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_value_on(outputStream* st) const {
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 @@ bool MethodData::profile_arguments_for_invoke(methodHandle m, int bci) {
}
int MethodData::profile_return_flag() {
return TypeProfileLevel / 10;
return (TypeProfileLevel % 100) / 10;
}
bool MethodData::profile_return() {
......@@ -1249,3 +1317,32 @@ bool MethodData::profile_return_for_invoke(methodHandle m, int bci) {
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();
}
......@@ -119,7 +119,8 @@ public:
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 BranchData;
class ArrayData;
class MultiBranchData;
class ArgInfoData;
class ParametersTypeData;
// ProfileData
//
......@@ -397,6 +399,7 @@ public:
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 @@ public:
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 @@ public:
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 @@ private:
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),
......@@ -1017,6 +1013,16 @@ public:
_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
// 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
......@@ -1213,17 +1219,6 @@ private:
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 @@ public:
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 @@ public:
#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 @@ private:
// 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 @@ private:
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 @@ 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
static ByteSize data_offset() {
return byte_offset_of(MethodData, _data[0]);
......@@ -2060,6 +2151,10 @@ public:
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 @@ public:
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();
};
......
......@@ -2671,13 +2671,18 @@ class CommandLineFlags {
"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") \
......
......@@ -193,6 +193,11 @@ void print_method_profiling_data() {
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();
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册