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