mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-18 06:15:16 +00:00
8026251: New type profiling points: parameters to methods
X86 interpreter and c1 type profiling for parameters on method entries Reviewed-by: kvn, twisti
This commit is contained in:
parent
4db165a8d7
commit
b94884a330
@ -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) \
|
||||
\
|
||||
|
||||
229
hotspot/src/cpu/x86/vm/interp_masm_x86.cpp
Normal file
229
hotspot/src/cpu/x86/vm/interp_masm_x86.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "interp_masm_x86.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "oops/methodData.hpp"
|
||||
|
||||
#ifndef CC_INTERP
|
||||
void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
|
||||
Label update, next, none;
|
||||
|
||||
verify_oop(obj);
|
||||
|
||||
testptr(obj, obj);
|
||||
jccb(Assembler::notZero, update);
|
||||
orptr(mdo_addr, TypeEntries::null_seen);
|
||||
jmpb(next);
|
||||
|
||||
bind(update);
|
||||
load_klass(obj, obj);
|
||||
|
||||
xorptr(obj, mdo_addr);
|
||||
testptr(obj, TypeEntries::type_klass_mask);
|
||||
jccb(Assembler::zero, next); // klass seen before, nothing to
|
||||
// do. The unknown bit may have been
|
||||
// set already but no need to check.
|
||||
|
||||
testptr(obj, TypeEntries::type_unknown);
|
||||
jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
|
||||
|
||||
cmpptr(mdo_addr, 0);
|
||||
jccb(Assembler::equal, none);
|
||||
cmpptr(mdo_addr, TypeEntries::null_seen);
|
||||
jccb(Assembler::equal, none);
|
||||
// There is a chance that the checks above (re-reading profiling
|
||||
// data from memory) fail if another thread has just set the
|
||||
// profiling to this obj's klass
|
||||
xorptr(obj, mdo_addr);
|
||||
testptr(obj, TypeEntries::type_klass_mask);
|
||||
jccb(Assembler::zero, next);
|
||||
|
||||
// different than before. Cannot keep accurate profile.
|
||||
orptr(mdo_addr, TypeEntries::type_unknown);
|
||||
jmpb(next);
|
||||
|
||||
bind(none);
|
||||
// first time here. Set profile type.
|
||||
movptr(mdo_addr, obj);
|
||||
|
||||
bind(next);
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) {
|
||||
if (!ProfileInterpreter) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MethodData::profile_arguments() || MethodData::profile_return()) {
|
||||
Label profile_continue;
|
||||
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size());
|
||||
|
||||
cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag);
|
||||
jcc(Assembler::notEqual, profile_continue);
|
||||
|
||||
if (MethodData::profile_arguments()) {
|
||||
Label done;
|
||||
int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset());
|
||||
addptr(mdp, off_to_args);
|
||||
|
||||
for (int i = 0; i < TypeProfileArgsLimit; i++) {
|
||||
if (i > 0 || MethodData::profile_return()) {
|
||||
// If return value type is profiled we may have no argument to profile
|
||||
movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
|
||||
subl(tmp, i*TypeStackSlotEntries::per_arg_count());
|
||||
cmpl(tmp, TypeStackSlotEntries::per_arg_count());
|
||||
jcc(Assembler::less, done);
|
||||
}
|
||||
movptr(tmp, Address(callee, Method::const_offset()));
|
||||
load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset()));
|
||||
// stack offset o (zero based) from the start of the argument
|
||||
// list, for n arguments translates into offset n - o - 1 from
|
||||
// the end of the argument list
|
||||
subptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args));
|
||||
subl(tmp, 1);
|
||||
Address arg_addr = argument_address(tmp);
|
||||
movptr(tmp, arg_addr);
|
||||
|
||||
Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args);
|
||||
profile_obj_type(tmp, mdo_arg_addr);
|
||||
|
||||
int to_add = in_bytes(TypeStackSlotEntries::per_arg_size());
|
||||
addptr(mdp, to_add);
|
||||
off_to_args += to_add;
|
||||
}
|
||||
|
||||
if (MethodData::profile_return()) {
|
||||
movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
|
||||
subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count());
|
||||
}
|
||||
|
||||
bind(done);
|
||||
|
||||
if (MethodData::profile_return()) {
|
||||
// We're right after the type profile for the last
|
||||
// argument. tmp is the number of cell left in the
|
||||
// CallTypeData/VirtualCallTypeData to reach its end. Non null
|
||||
// if there's a return to profile.
|
||||
assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type");
|
||||
shll(tmp, exact_log2(DataLayout::cell_size));
|
||||
addptr(mdp, tmp);
|
||||
}
|
||||
movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
|
||||
} else {
|
||||
assert(MethodData::profile_return(), "either profile call args or call ret");
|
||||
update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size()));
|
||||
}
|
||||
|
||||
// mdp points right after the end of the
|
||||
// CallTypeData/VirtualCallTypeData, right after the cells for the
|
||||
// return value type if there's one
|
||||
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) {
|
||||
assert_different_registers(mdp, ret, tmp, _bcp_register);
|
||||
if (ProfileInterpreter && MethodData::profile_return()) {
|
||||
Label profile_continue, done;
|
||||
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
if (MethodData::profile_return_jsr292_only()) {
|
||||
// If we don't profile all invoke bytecodes we must make sure
|
||||
// it's a bytecode we indeed profile. We can't go back to the
|
||||
// begining of the ProfileData we intend to update to check its
|
||||
// type because we're right after it and we don't known its
|
||||
// length
|
||||
Label do_profile;
|
||||
cmpb(Address(_bcp_register, 0), Bytecodes::_invokedynamic);
|
||||
jcc(Assembler::equal, do_profile);
|
||||
cmpb(Address(_bcp_register, 0), Bytecodes::_invokehandle);
|
||||
jcc(Assembler::equal, do_profile);
|
||||
get_method(tmp);
|
||||
cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm);
|
||||
jcc(Assembler::notEqual, profile_continue);
|
||||
|
||||
bind(do_profile);
|
||||
}
|
||||
|
||||
Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size()));
|
||||
mov(tmp, ret);
|
||||
profile_obj_type(tmp, mdo_ret_addr);
|
||||
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register tmp1, Register tmp2) {
|
||||
if (ProfileInterpreter && MethodData::profile_parameters()) {
|
||||
Label profile_continue, done;
|
||||
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
// Load the offset of the area within the MDO used for
|
||||
// parameters. If it's negative we're not profiling any parameters
|
||||
movl(tmp1, Address(mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset())));
|
||||
testl(tmp1, tmp1);
|
||||
jcc(Assembler::negative, profile_continue);
|
||||
|
||||
// Compute a pointer to the area for parameters from the offset
|
||||
// and move the pointer to the slot for the last
|
||||
// parameters. Collect profiling from last parameter down.
|
||||
// mdo start + parameters offset + array length - 1
|
||||
addptr(mdp, tmp1);
|
||||
movptr(tmp1, Address(mdp, in_bytes(ArrayData::array_len_offset())));
|
||||
decrement(tmp1, TypeStackSlotEntries::per_arg_count());
|
||||
|
||||
Label loop;
|
||||
bind(loop);
|
||||
|
||||
int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0));
|
||||
int type_base = in_bytes(ParametersTypeData::type_offset(0));
|
||||
Address::ScaleFactor per_arg_scale = Address::times(DataLayout::cell_size);
|
||||
Address arg_off(mdp, tmp1, per_arg_scale, off_base);
|
||||
Address arg_type(mdp, tmp1, per_arg_scale, type_base);
|
||||
|
||||
// load offset on the stack from the slot for this parameter
|
||||
movptr(tmp2, arg_off);
|
||||
negptr(tmp2);
|
||||
// read the parameter from the local area
|
||||
movptr(tmp2, Address(_locals_register, tmp2, Interpreter::stackElementScale()));
|
||||
|
||||
// profile the parameter
|
||||
profile_obj_type(tmp2, arg_type);
|
||||
|
||||
// go to next parameter
|
||||
decrement(tmp1, TypeStackSlotEntries::per_arg_count());
|
||||
jcc(Assembler::positive, loop);
|
||||
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
60
hotspot/src/cpu/x86/vm/interp_masm_x86.hpp
Normal file
60
hotspot/src/cpu/x86/vm/interp_masm_x86.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_X86_VM_INTERP_MASM_X86_HPP
|
||||
#define CPU_X86_VM_INTERP_MASM_X86_HPP
|
||||
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "interpreter/invocationCounter.hpp"
|
||||
#include "runtime/frame.hpp"
|
||||
|
||||
// This file specializes the assember with interpreter-specific macros
|
||||
|
||||
|
||||
class InterpreterMacroAssembler: public MacroAssembler {
|
||||
|
||||
#ifdef TARGET_ARCH_MODEL_x86_32
|
||||
# include "interp_masm_x86_32.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_x86_64
|
||||
# include "interp_masm_x86_64.hpp"
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
Register _locals_register; // register that contains the pointer to the locals
|
||||
Register _bcp_register; // register that contains the bcp
|
||||
|
||||
public:
|
||||
#ifndef CC_INTERP
|
||||
void profile_obj_type(Register obj, const Address& mdo_addr);
|
||||
void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
|
||||
void profile_return_type(Register mdp, Register ret, Register tmp);
|
||||
void profile_parameters_type(Register mdp, Register tmp1, Register tmp2);
|
||||
#endif /* !CC_INTERP */
|
||||
|
||||
};
|
||||
|
||||
#endif // CPU_X86_VM_INTERP_MASM_X86_HPP
|
||||
@ -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();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user