aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroland <none@none>2013-10-22 09:51:47 +0200
committerroland <none@none>2013-10-22 09:51:47 +0200
commite1b04a791dcebf4477bb6830ffd11efcce4785f6 (patch)
tree5bb1c34522801d9bf57b1400ed7e357cf2ff42ec
parent6ec3e5836a130e96037f53c662f1b5c34a32ef9d (diff)
8026251: New type profiling points: parameters to methods
Summary: x86 interpreter and c1 type profiling for parameters on method entries Reviewed-by: kvn, twisti
-rw-r--r--src/cpu/x86/vm/bytecodeInterpreter_x86.cpp7
-rw-r--r--src/cpu/x86/vm/globals_x86.hpp2
-rw-r--r--src/cpu/x86/vm/interp_masm_x86.cpp229
-rw-r--r--src/cpu/x86/vm/interp_masm_x86.hpp60
-rw-r--r--src/cpu/x86/vm/interp_masm_x86_32.cpp155
-rw-r--r--src/cpu/x86/vm/interp_masm_x86_32.hpp21
-rw-r--r--src/cpu/x86/vm/interp_masm_x86_64.cpp156
-rw-r--r--src/cpu/x86/vm/interp_masm_x86_64.hpp20
-rw-r--r--src/cpu/x86/vm/register_definitions_x86.cpp7
-rw-r--r--src/cpu/x86/vm/templateInterpreter_x86_32.cpp1
-rw-r--r--src/cpu/x86/vm/templateInterpreter_x86_64.cpp1
-rw-r--r--src/cpu/x86/vm/vtableStubs_x86_32.cpp2
-rw-r--r--src/cpu/x86/vm/vtableStubs_x86_64.cpp2
-rw-r--r--src/share/vm/c1/c1_Compilation.hpp13
-rw-r--r--src/share/vm/c1/c1_GraphBuilder.cpp34
-rw-r--r--src/share/vm/c1/c1_GraphBuilder.hpp7
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.cpp109
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.hpp2
-rw-r--r--src/share/vm/ci/ciMethodData.cpp23
-rw-r--r--src/share/vm/ci/ciMethodData.hpp31
-rw-r--r--src/share/vm/interpreter/abstractInterpreter.hpp7
-rw-r--r--src/share/vm/interpreter/templateTable.hpp7
-rw-r--r--src/share/vm/oops/methodData.cpp121
-rw-r--r--src/share/vm/oops/methodData.hpp147
-rw-r--r--src/share/vm/runtime/globals.hpp11
-rw-r--r--src/share/vm/runtime/java.cpp5
26 files changed, 750 insertions, 430 deletions
diff --git a/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp b/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp
index 237c617ce..56129cc2d 100644
--- a/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp
+++ b/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp
@@ -40,11 +40,8 @@
#include "runtime/synchronizer.hpp"
#include "runtime/vframeArray.hpp"
#include "utilities/debug.hpp"
-#ifdef TARGET_ARCH_MODEL_x86_32
-# include "interp_masm_x86_32.hpp"
-#endif
-#ifdef TARGET_ARCH_MODEL_x86_64
-# include "interp_masm_x86_64.hpp"
+#ifdef TARGET_ARCH_x86
+# include "interp_masm_x86.hpp"
#endif
#ifdef CC_INTERP
diff --git a/src/cpu/x86/vm/globals_x86.hpp b/src/cpu/x86/vm/globals_x86.hpp
index a727e077b..b194ffbcf 100644
--- a/src/cpu/x86/vm/globals_x86.hpp
+++ b/src/cpu/x86/vm/globals_x86.hpp
@@ -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) \
\
diff --git a/src/cpu/x86/vm/interp_masm_x86.cpp b/src/cpu/x86/vm/interp_masm_x86.cpp
new file mode 100644
index 000000000..f47c0b1bb
--- /dev/null
+++ b/src/cpu/x86/vm/interp_masm_x86.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "interp_masm_x86.hpp"
+#include "interpreter/interpreter.hpp"
+#include "oops/methodData.hpp"
+
+#ifndef CC_INTERP
+void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
+ Label update, next, none;
+
+ verify_oop(obj);
+
+ testptr(obj, obj);
+ jccb(Assembler::notZero, update);
+ orptr(mdo_addr, TypeEntries::null_seen);
+ jmpb(next);
+
+ bind(update);
+ load_klass(obj, obj);
+
+ xorptr(obj, mdo_addr);
+ testptr(obj, TypeEntries::type_klass_mask);
+ jccb(Assembler::zero, next); // klass seen before, nothing to
+ // do. The unknown bit may have been
+ // set already but no need to check.
+
+ testptr(obj, TypeEntries::type_unknown);
+ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
+
+ cmpptr(mdo_addr, 0);
+ jccb(Assembler::equal, none);
+ cmpptr(mdo_addr, TypeEntries::null_seen);
+ jccb(Assembler::equal, none);
+ // There is a chance that the checks above (re-reading profiling
+ // data from memory) fail if another thread has just set the
+ // profiling to this obj's klass
+ xorptr(obj, mdo_addr);
+ testptr(obj, TypeEntries::type_klass_mask);
+ jccb(Assembler::zero, next);
+
+ // different than before. Cannot keep accurate profile.
+ orptr(mdo_addr, TypeEntries::type_unknown);
+ jmpb(next);
+
+ bind(none);
+ // first time here. Set profile type.
+ movptr(mdo_addr, obj);
+
+ bind(next);
+}
+
+void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) {
+ if (!ProfileInterpreter) {
+ return;
+ }
+
+ if (MethodData::profile_arguments() || MethodData::profile_return()) {
+ Label profile_continue;
+
+ test_method_data_pointer(mdp, profile_continue);
+
+ int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size());
+
+ cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag);
+ jcc(Assembler::notEqual, profile_continue);
+
+ if (MethodData::profile_arguments()) {
+ Label done;
+ int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset());
+ addptr(mdp, off_to_args);
+
+ for (int i = 0; i < TypeProfileArgsLimit; i++) {
+ if (i > 0 || MethodData::profile_return()) {
+ // If return value type is profiled we may have no argument to profile
+ movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
+ subl(tmp, i*TypeStackSlotEntries::per_arg_count());
+ cmpl(tmp, TypeStackSlotEntries::per_arg_count());
+ jcc(Assembler::less, done);
+ }
+ movptr(tmp, Address(callee, Method::const_offset()));
+ load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset()));
+ // stack offset o (zero based) from the start of the argument
+ // list, for n arguments translates into offset n - o - 1 from
+ // the end of the argument list
+ subptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args));
+ subl(tmp, 1);
+ Address arg_addr = argument_address(tmp);
+ movptr(tmp, arg_addr);
+
+ Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args);
+ profile_obj_type(tmp, mdo_arg_addr);
+
+ int to_add = in_bytes(TypeStackSlotEntries::per_arg_size());
+ addptr(mdp, to_add);
+ off_to_args += to_add;
+ }
+
+ if (MethodData::profile_return()) {
+ movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
+ subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count());
+ }
+
+ bind(done);
+
+ if (MethodData::profile_return()) {
+ // We're right after the type profile for the last
+ // argument. tmp is the number of cell left in the
+ // CallTypeData/VirtualCallTypeData to reach its end. Non null
+ // if there's a return to profile.
+ assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type");
+ shll(tmp, exact_log2(DataLayout::cell_size));
+ addptr(mdp, tmp);
+ }
+ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
+ } else {
+ assert(MethodData::profile_return(), "either profile call args or call ret");
+ update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size()));
+ }
+
+ // mdp points right after the end of the
+ // CallTypeData/VirtualCallTypeData, right after the cells for the
+ // return value type if there's one
+
+ bind(profile_continue);
+ }
+}
+
+void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) {
+ assert_different_registers(mdp, ret, tmp, _bcp_register);
+ if (ProfileInterpreter && MethodData::profile_return()) {
+ Label profile_continue, done;
+
+ test_method_data_pointer(mdp, profile_continue);
+
+ if (MethodData::profile_return_jsr292_only()) {
+ // If we don't profile all invoke bytecodes we must make sure
+ // it's a bytecode we indeed profile. We can't go back to the
+ // begining of the ProfileData we intend to update to check its
+ // type because we're right after it and we don't known its
+ // length
+ Label do_profile;
+ cmpb(Address(_bcp_register, 0), Bytecodes::_invokedynamic);
+ jcc(Assembler::equal, do_profile);
+ cmpb(Address(_bcp_register, 0), Bytecodes::_invokehandle);
+ jcc(Assembler::equal, do_profile);
+ get_method(tmp);
+ cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm);
+ jcc(Assembler::notEqual, profile_continue);
+
+ bind(do_profile);
+ }
+
+ Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size()));
+ mov(tmp, ret);
+ profile_obj_type(tmp, mdo_ret_addr);
+
+ bind(profile_continue);
+ }
+}
+
+void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register tmp1, Register tmp2) {
+ if (ProfileInterpreter && MethodData::profile_parameters()) {
+ Label profile_continue, done;
+
+ test_method_data_pointer(mdp, profile_continue);
+
+ // Load the offset of the area within the MDO used for
+ // parameters. If it's negative we're not profiling any parameters
+ movl(tmp1, Address(mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset())));
+ testl(tmp1, tmp1);
+ jcc(Assembler::negative, profile_continue);
+
+ // Compute a pointer to the area for parameters from the offset
+ // and move the pointer to the slot for the last
+ // parameters. Collect profiling from last parameter down.
+ // mdo start + parameters offset + array length - 1
+ addptr(mdp, tmp1);
+ movptr(tmp1, Address(mdp, in_bytes(ArrayData::array_len_offset())));
+ decrement(tmp1, TypeStackSlotEntries::per_arg_count());
+
+ Label loop;
+ bind(loop);
+
+ int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0));
+ int type_base = in_bytes(ParametersTypeData::type_offset(0));
+ Address::ScaleFactor per_arg_scale = Address::times(DataLayout::cell_size);
+ Address arg_off(mdp, tmp1, per_arg_scale, off_base);
+ Address arg_type(mdp, tmp1, per_arg_scale, type_base);
+
+ // load offset on the stack from the slot for this parameter
+ movptr(tmp2, arg_off);
+ negptr(tmp2);
+ // read the parameter from the local area
+ movptr(tmp2, Address(_locals_register, tmp2, Interpreter::stackElementScale()));
+
+ // profile the parameter
+ profile_obj_type(tmp2, arg_type);
+
+ // go to next parameter
+ decrement(tmp1, TypeStackSlotEntries::per_arg_count());
+ jcc(Assembler::positive, loop);
+
+ bind(profile_continue);
+ }
+}
+#endif
diff --git a/src/cpu/x86/vm/interp_masm_x86.hpp b/src/cpu/x86/vm/interp_masm_x86.hpp
new file mode 100644
index 000000000..2ac4d0266
--- /dev/null
+++ b/src/cpu/x86/vm/interp_masm_x86.hpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_X86_VM_INTERP_MASM_X86_HPP
+#define CPU_X86_VM_INTERP_MASM_X86_HPP
+
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "interpreter/invocationCounter.hpp"
+#include "runtime/frame.hpp"
+
+// This file specializes the assember with interpreter-specific macros
+
+
+class InterpreterMacroAssembler: public MacroAssembler {
+
+#ifdef TARGET_ARCH_MODEL_x86_32
+# include "interp_masm_x86_32.hpp"
+#endif
+#ifdef TARGET_ARCH_MODEL_x86_64
+# include "interp_masm_x86_64.hpp"
+#endif
+
+ private:
+
+ Register _locals_register; // register that contains the pointer to the locals
+ Register _bcp_register; // register that contains the bcp
+
+ public:
+#ifndef CC_INTERP
+ void profile_obj_type(Register obj, const Address& mdo_addr);
+ void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
+ void profile_return_type(Register mdp, Register ret, Register tmp);
+ void profile_parameters_type(Register mdp, Register tmp1, Register tmp2);
+#endif /* !CC_INTERP */
+
+};
+
+#endif // CPU_X86_VM_INTERP_MASM_X86_HPP
diff --git a/src/cpu/x86/vm/interp_masm_x86_32.cpp b/src/cpu/x86/vm/interp_masm_x86_32.cpp
index 183defa87..fcadd2ee9 100644
--- a/src/cpu/x86/vm/interp_masm_x86_32.cpp
+++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp
@@ -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;
diff --git a/src/cpu/x86/vm/interp_masm_x86_32.hpp b/src/cpu/x86/vm/interp_masm_x86_32.hpp
index 91f0aa1bc..19ff288bf 100644
--- a/src/cpu/x86/vm/interp_masm_x86_32.hpp
+++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp
@@ -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
diff --git a/src/cpu/x86/vm/interp_masm_x86_64.cpp b/src/cpu/x86/vm/interp_masm_x86_64.cpp
index 8495f0da1..7758d8fbc 100644
--- a/src/cpu/x86/vm/interp_masm_x86_64.cpp
+++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp
@@ -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;
diff --git a/src/cpu/x86/vm/interp_masm_x86_64.hpp b/src/cpu/x86/vm/interp_masm_x86_64.hpp
index fe7b76039..36bd779ef 100644
--- a/src/cpu/x86/vm/interp_masm_x86_64.hpp
+++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp
@@ -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
diff --git a/src/cpu/x86/vm/register_definitions_x86.cpp b/src/cpu/x86/vm/register_definitions_x86.cpp
index 7165872c2..f8a940793 100644
--- a/src/cpu/x86/vm/register_definitions_x86.cpp
+++ b/src/cpu/x86/vm/register_definitions_x86.cpp
@@ -26,11 +26,8 @@
#include "asm/assembler.hpp"
#include "asm/register.hpp"
#include "register_x86.hpp"
-#ifdef TARGET_ARCH_MODEL_x86_32
-# include "interp_masm_x86_32.hpp"
-#endif
-#ifdef TARGET_ARCH_MODEL_x86_64
-# include "interp_masm_x86_64.hpp"
+#ifdef TARGET_ARCH_x86
+# include "interp_masm_x86.hpp"
#endif
REGISTER_DEFINITION(Register, noreg);
diff --git a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
index 7d9af3e64..880b7732a 100644
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
@@ -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;
diff --git a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
index d7e0d7742..39c49cc43 100644
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
@@ -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;
diff --git a/src/cpu/x86/vm/vtableStubs_x86_32.cpp b/src/cpu/x86/vm/vtableStubs_x86_32.cpp
index 7c49d737f..3e7b42435 100644
--- a/src/cpu/x86/vm/vtableStubs_x86_32.cpp
+++ b/src/cpu/x86/vm/vtableStubs_x86_32.cpp
@@ -25,7 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "code/vtableStubs.hpp"
-#include "interp_masm_x86_32.hpp"
+#include "interp_masm_x86.hpp"
#include "memory/resourceArea.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp"
diff --git a/src/cpu/x86/vm/vtableStubs_x86_64.cpp b/src/cpu/x86/vm/vtableStubs_x86_64.cpp
index 911341736..4fc385f97 100644
--- a/src/cpu/x86/vm/vtableStubs_x86_64.cpp
+++ b/src/cpu/x86/vm/vtableStubs_x86_64.cpp
@@ -25,7 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "code/vtableStubs.hpp"
-#include "interp_masm_x86_64.hpp"
+#include "interp_masm_x86.hpp"
#include "memory/resourceArea.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp"
diff --git a/src/share/vm/c1/c1_Compilation.hpp b/src/share/vm/c1/c1_Compilation.hpp
index 7386dc414..679ff609a 100644
--- a/src/share/vm/c1/c1_Compilation.hpp
+++ b/src/share/vm/c1/c1_Compilation.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 {
diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp
index 23d800528..2ac2cceed 100644
--- a/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -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
diff --git a/src/share/vm/c1/c1_GraphBuilder.hpp b/src/share/vm/c1/c1_GraphBuilder.hpp
index 7945674fc..ce83cb73f 100644
--- a/src/share/vm/c1/c1_GraphBuilder.hpp
+++ b/src/share/vm/c1/c1_GraphBuilder.hpp
@@ -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();)
diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp
index 7b773b7a1..44ad61f64 100644
--- a/src/share/vm/c1/c1_LIRGenerator.cpp
+++ b/src/share/vm/c1/c1_LIRGenerator.cpp
@@ -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();
diff --git a/src/share/vm/c1/c1_LIRGenerator.hpp b/src/share/vm/c1/c1_LIRGenerator.hpp
index 05399e590..f0c640da9 100644
--- a/src/share/vm/c1/c1_LIRGenerator.hpp
+++ b/src/share/vm/c1/c1_LIRGenerator.hpp
@@ -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; }
diff --git a/src/share/vm/ci/ciMethodData.cpp b/src/share/vm/ci/ciMethodData.cpp
index aae7d92c2..e8b6ee6af 100644
--- a/src/share/vm/ci/ciMethodData.cpp
+++ b/src/share/vm/ci/ciMethodData.cpp
@@ -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
diff --git a/src/share/vm/ci/ciMethodData.hpp b/src/share/vm/ci/ciMethodData.hpp
index b57ab6dee..29a70c601 100644
--- a/src/share/vm/ci/ciMethodData.hpp
+++ b/src/share/vm/ci/ciMethodData.hpp
@@ -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)); }
diff --git a/src/share/vm/interpreter/abstractInterpreter.hpp b/src/share/vm/interpreter/abstractInterpreter.hpp
index 77471ad3d..4d7647ce0 100644
--- a/src/share/vm/interpreter/abstractInterpreter.hpp
+++ b/src/share/vm/interpreter/abstractInterpreter.hpp
@@ -30,11 +30,8 @@
#include "runtime/thread.inline.hpp"
#include "runtime/vmThread.hpp"
#include "utilities/top.hpp"
-#ifdef TARGET_ARCH_MODEL_x86_32
-# include "interp_masm_x86_32.hpp"
-#endif
-#ifdef TARGET_ARCH_MODEL_x86_64
-# include "interp_masm_x86_64.hpp"
+#ifdef TARGET_ARCH_x86
+# include "interp_masm_x86.hpp"
#endif
#ifdef TARGET_ARCH_MODEL_sparc
# include "interp_masm_sparc.hpp"
diff --git a/src/share/vm/interpreter/templateTable.hpp b/src/share/vm/interpreter/templateTable.hpp
index 40d05f49b..11c875ef3 100644
--- a/src/share/vm/interpreter/templateTable.hpp
+++ b/src/share/vm/interpreter/templateTable.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"
diff --git a/src/share/vm/oops/methodData.cpp b/src/share/vm/oops/methodData.cpp
index e50107f29..2cff5ee2c 100644
--- a/src/share/vm/oops/methodData.cpp
+++ b/src/share/vm/oops/methodData.cpp
@@ -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();
+}
diff --git a/src/share/vm/oops/methodData.hpp b/src/share/vm/oops/methodData.hpp
index 1dc6272c6..a007708bb 100644
--- a/src/share/vm/oops/methodData.hpp
+++ b/src/share/vm/oops/methodData.hpp
@@ -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),
@@ -1018,6 +1014,16 @@ public:
}
// An entry for a return value takes less space than an entry for an
+ // argument so if the number of cells exceeds the number of cells
+ // needed for an argument, this object contains type information for
+ // at least one argument.
+ bool has_arguments() const {
+ bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count();
+ assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments");
+ return res;
+ }
+
+ // An entry for a return value takes less space than an entry for an
// argument, so if the remainder of the number of cells divided by
// the number of cells for an argument is not null, a return value
// is profiled in this object.
@@ -1213,17 +1219,6 @@ 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();
};
diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
index 9e8216529..2fe5420be 100644
--- a/src/share/vm/runtime/globals.hpp
+++ b/src/share/vm/runtime/globals.hpp
@@ -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") \
diff --git a/src/share/vm/runtime/java.cpp b/src/share/vm/runtime/java.cpp
index e33e935fb..a356157e4 100644
--- a/src/share/vm/runtime/java.cpp
+++ b/src/share/vm/runtime/java.cpp
@@ -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();
}