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