aoqi@1: /* aoqi@1: * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@1: * Copyright (c) 2015, 2016, Loongson Technology. All rights reserved. aoqi@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@1: * aoqi@1: * This code is free software; you can redistribute it and/or modify it aoqi@1: * under the terms of the GNU General Public License version 2 only, as aoqi@1: * published by the Free Software Foundation. aoqi@1: * aoqi@1: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@1: * version 2 for more details (a copy is included in the LICENSE file that aoqi@1: * accompanied this code). aoqi@1: * aoqi@1: * You should have received a copy of the GNU General Public License version aoqi@1: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@1: * aoqi@1: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@1: * or visit www.oracle.com if you need additional information or have any aoqi@1: * questions. aoqi@1: * aoqi@1: */ aoqi@1: aoqi@1: // This file specializes the assember with interpreter-specific macros aoqi@1: aoqi@1: #ifndef CPU_MIPS_VM_INTERP_MASM_MIPS_64_HPP aoqi@1: #define CPU_MIPS_VM_INTERP_MASM_MIPS_64_HPP aoqi@1: aoqi@1: #include "asm/macroAssembler.hpp" aoqi@1: #include "asm/macroAssembler.inline.hpp" aoqi@1: #include "interpreter/invocationCounter.hpp" aoqi@1: #include "runtime/frame.hpp" aoqi@1: aoqi@1: aoqi@1: class InterpreterMacroAssembler: public MacroAssembler { aoqi@1: #ifndef CC_INTERP aoqi@1: private: aoqi@1: Register _locals_register; // register that contains the pointer to the locals aoqi@1: Register _bcp_register; // register that contains the bcp aoqi@1: aoqi@1: protected: aoqi@1: // Interpreter specific version of call_VM_base aoqi@1: virtual void call_VM_leaf_base(address entry_point, aoqi@1: int number_of_arguments); aoqi@1: aoqi@1: virtual void call_VM_base(Register oop_result, aoqi@1: Register java_thread, aoqi@1: Register last_java_sp, aoqi@1: address entry_point, aoqi@1: int number_of_arguments, aoqi@1: bool check_exceptions); aoqi@1: aoqi@1: virtual void check_and_handle_popframe(Register java_thread); aoqi@1: virtual void check_and_handle_earlyret(Register java_thread); aoqi@1: aoqi@1: // base routine for all dispatches aoqi@1: void dispatch_base(TosState state, address* table, bool verifyoop = true); aoqi@1: #endif // CC_INTERP aoqi@1: aoqi@1: public: aoqi@1: InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(LVP), _bcp_register(BCP) {} aoqi@1: aoqi@16: void get_2_byte_integer_at_bcp(Register reg, Register tmp, int offset); aoqi@16: void get_4_byte_integer_at_bcp(Register reg, Register tmp, int offset); aoqi@16: aoqi@1: void load_earlyret_value(TosState state); aoqi@1: aoqi@1: #ifdef CC_INTERP aoqi@1: void save_bcp() { /* not needed in c++ interpreter and harmless */ } aoqi@1: void restore_bcp() { /* not needed in c++ interpreter and harmless */ } aoqi@1: aoqi@1: // Helpers for runtime call arguments/results aoqi@1: void get_method(Register reg); aoqi@1: aoqi@1: #else aoqi@1: aoqi@1: // Interpreter-specific registers aoqi@1: void save_bcp() { aoqi@1: sd(BCP, FP, frame::interpreter_frame_bcx_offset * wordSize); aoqi@1: } aoqi@1: aoqi@1: void restore_bcp() { aoqi@1: ld(BCP, FP, frame::interpreter_frame_bcx_offset * wordSize); aoqi@1: } aoqi@1: aoqi@1: void restore_locals() { aoqi@1: ld(LVP, FP, frame::interpreter_frame_locals_offset * wordSize); aoqi@1: } aoqi@1: aoqi@1: // Helpers for runtime call arguments/results aoqi@1: void get_method(Register reg) { aoqi@1: ld(reg, FP, frame::interpreter_frame_method_offset * wordSize); aoqi@1: } aoqi@1: aoqi@1: void get_const(Register reg){ aoqi@1: get_method(reg); aoqi@1: ld(reg, reg, in_bytes(Method::const_offset())); aoqi@1: } aoqi@1: aoqi@1: void get_constant_pool(Register reg) { aoqi@1: get_const(reg); aoqi@1: ld(reg, reg, in_bytes(ConstMethod::constants_offset())); aoqi@1: } aoqi@1: aoqi@1: void get_constant_pool_cache(Register reg) { aoqi@1: get_constant_pool(reg); aoqi@1: ld(reg, reg, ConstantPool::cache_offset_in_bytes()); aoqi@1: } aoqi@1: aoqi@1: void get_cpool_and_tags(Register cpool, Register tags) { aoqi@1: get_constant_pool(cpool); aoqi@1: ld(tags, cpool, ConstantPool::tags_offset_in_bytes()); aoqi@1: } aoqi@1: aoqi@1: void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset); aoqi@1: void get_cache_and_index_at_bcp(Register cache, Register index, aoqi@1: int bcp_offset, size_t index_size = sizeof (u2)); aoqi@1: void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, aoqi@1: Register bytecode, int byte_no, aoqi@1: int bcp_offset, size_t index_size = sizeof(u2)); aoqi@1: void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, aoqi@1: int bcp_offset, size_t index_size = sizeof(u2)); aoqi@1: void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2)); aoqi@1: void get_method_counters(Register method, Register mcs, Label& skip); aoqi@1: // load cpool->resolved_references(index); aoqi@1: void load_resolved_reference_at_index(Register result, Register index); aoqi@1: aoqi@1: void pop_ptr(Register r = V0); aoqi@1: void pop_i(Register r = V0); aoqi@1: //void pop_l(Register r = V0); aoqi@1: void pop_l(Register lo = V0, Register hi = V1); aoqi@1: //void pop_f(XMMRegister r = xmm0); aoqi@1: //void pop_d(XMMRegister r = xmm0); aoqi@1: void pop_f(); aoqi@1: void pop_d(); aoqi@1: void push_ptr(Register r = V0); aoqi@1: void push_i(Register r = V0); aoqi@1: //void push_l(Register r = V0); aoqi@1: void push_l(Register lo = V0, Register hi = V1); aoqi@1: //void push_f(XMMRegister r = xmm0); aoqi@1: //void push_d(XMMRegister r = xmm0); aoqi@1: void push_f(); aoqi@1: void push_d(FloatRegister r = F0); aoqi@1: aoqi@1: void pop(Register r ) { ((MacroAssembler*)this)->pop(r); } aoqi@1: aoqi@1: void push(Register r ) { ((MacroAssembler*)this)->push(r); } aoqi@1: //void push(int32_t imm ) { ((MacroAssembler*)this)->push(imm); } aoqi@1: aoqi@1: void pop_dtos_to_esp(); aoqi@1: void pop_ftos_to_esp(); aoqi@1: aoqi@1: void pop(TosState state); // transition vtos -> state aoqi@1: void push(TosState state); // transition state -> vtos aoqi@1: /* aoqi@1: // Tagged stack support, pop and push both tag and value. aoqi@1: void pop_ptr(Register r, Register tag); aoqi@1: void push_ptr(Register r, Register tag); aoqi@1: #endif // CC_INTERP aoqi@1: aoqi@1: DEBUG_ONLY(void verify_stack_tag(frame::Tag t);) aoqi@1: aoqi@1: #ifndef CC_INTERP aoqi@1: aoqi@1: // Tagged stack helpers for swap and dup aoqi@1: void load_ptr_and_tag(int n, Register val, Register tag); aoqi@1: void store_ptr_and_tag(int n, Register val, Register tag); aoqi@1: aoqi@1: // Tagged Local support aoqi@1: void tag_local(frame::Tag tag, int n); aoqi@1: void tag_local(Register tag, int n); aoqi@1: void tag_local(frame::Tag tag, Register idx); aoqi@1: void tag_local(Register tag, Register idx); aoqi@1: aoqi@1: #ifdef ASSERT aoqi@1: void verify_local_tag(frame::Tag tag, int n); aoqi@1: void verify_local_tag(frame::Tag tag, Register idx); aoqi@1: #endif // ASSERT aoqi@1: aoqi@1: */ aoqi@1: void empty_expression_stack() aoqi@1: { aoqi@1: ld(SP, FP, frame::interpreter_frame_monitor_block_top_offset * wordSize); aoqi@1: // NULL last_sp until next java call aoqi@1: sd(R0, FP, frame::interpreter_frame_last_sp_offset * wordSize); aoqi@1: } aoqi@1: aoqi@1: // Super call_VM calls - correspond to MacroAssembler::call_VM(_leaf) calls aoqi@1: /*void super_call_VM_leaf(address entry_point); aoqi@1: void super_call_VM_leaf(address entry_point, Register arg_1); aoqi@1: void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2); aoqi@1: void super_call_VM_leaf(address entry_point, aoqi@1: Register arg_1, Register arg_2, Register arg_3);*/ aoqi@1: void load_ptr(int n, Register val); aoqi@1: void store_ptr(int n, Register val); aoqi@1: aoqi@1: // Generate a subtype check: branch to ok_is_subtype if sub_klass is aoqi@1: // a subtype of super_klass. aoqi@1: //void gen_subtype_check( Register sub_klass, Label &ok_is_subtype ); aoqi@1: void gen_subtype_check( Register Rsup_klass, Register sub_klass, Label &ok_is_subtype ); aoqi@1: aoqi@1: // Dispatching aoqi@1: void dispatch_prolog(TosState state, int step = 0); aoqi@1: void dispatch_epilog(TosState state, int step = 0); aoqi@1: // dispatch via ebx (assume ebx is loaded already) aoqi@1: void dispatch_only(TosState state); aoqi@1: // dispatch normal table via ebx (assume ebx is loaded already) aoqi@1: void dispatch_only_normal(TosState state); aoqi@1: void dispatch_only_noverify(TosState state); aoqi@1: // load ebx from [esi + step] and dispatch via ebx aoqi@1: void dispatch_next(TosState state, int step = 0); aoqi@1: // load ebx from [esi] and dispatch via ebx and table aoqi@1: void dispatch_via (TosState state, address* table); aoqi@1: aoqi@1: // jump to an invoked target aoqi@1: void prepare_to_jump_from_interpreted(); aoqi@1: void jump_from_interpreted(Register method, Register temp); aoqi@1: aoqi@1: aoqi@1: // Returning from interpreted functions aoqi@1: // aoqi@1: // Removes the current activation (incl. unlocking of monitors) aoqi@1: // and sets up the return address. This code is also used for aoqi@1: // exception unwindwing. In that case, we do not want to throw aoqi@1: // IllegalMonitorStateExceptions, since that might get us into an aoqi@1: // infinite rethrow exception loop. aoqi@1: // Additionally this code is used for popFrame and earlyReturn. aoqi@1: // In popFrame case we want to skip throwing an exception, aoqi@1: // installing an exception, and notifying jvmdi. aoqi@1: // In earlyReturn case we only want to skip throwing an exception aoqi@1: // and installing an exception. aoqi@1: void remove_activation(TosState state, Register ret_addr, aoqi@1: bool throw_monitor_exception = true, aoqi@1: bool install_monitor_exception = true, aoqi@1: bool notify_jvmdi = true); aoqi@1: #endif // CC_INTERP aoqi@1: aoqi@1: // Object locking aoqi@1: void lock_object (Register lock_reg); aoqi@1: void unlock_object(Register lock_reg); aoqi@1: aoqi@1: #ifndef CC_INTERP aoqi@1: aoqi@1: // Interpreter profiling operations aoqi@1: void set_method_data_pointer_for_bcp(); aoqi@1: void test_method_data_pointer(Register mdp, Label& zero_continue); aoqi@1: void verify_method_data_pointer(); aoqi@1: aoqi@1: void set_mdp_data_at(Register mdp_in, int constant, Register value); aoqi@1: void increment_mdp_data_at(Address data, bool decrement = false); aoqi@1: void increment_mdp_data_at(Register mdp_in, int constant, aoqi@1: bool decrement = false); aoqi@1: void increment_mdp_data_at(Register mdp_in, Register reg, int constant, aoqi@1: bool decrement = false); aoqi@1: /* void increment_mask_and_jump(Address counter_addr, aoqi@1: int increment, int mask, aoqi@1: Register scratch, bool preloaded, aoqi@1: Condition cond, Label* where); */ aoqi@1: void set_mdp_flag_at(Register mdp_in, int flag_constant); aoqi@1: void test_mdp_data_at(Register mdp_in, int offset, Register value, aoqi@1: Register test_value_out, aoqi@1: Label& not_equal_continue); aoqi@1: aoqi@1: void record_klass_in_profile(Register receiver, Register mdp, aoqi@1: Register reg2, bool is_virtual_call); aoqi@1: void record_klass_in_profile_helper(Register receiver, Register mdp, aoqi@1: Register reg2, int start_row, aoqi@1: Label& done, bool is_virtual_call); aoqi@1: aoqi@1: void update_mdp_by_offset(Register mdp_in, int offset_of_offset); aoqi@1: void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); aoqi@1: void update_mdp_by_constant(Register mdp_in, int constant); aoqi@1: void update_mdp_for_ret(Register return_bci); aoqi@1: aoqi@1: void profile_taken_branch(Register mdp, Register bumped_count); aoqi@1: void profile_not_taken_branch(Register mdp); aoqi@1: void profile_call(Register mdp); aoqi@1: void profile_final_call(Register mdp); aoqi@1: void profile_virtual_call(Register receiver, Register mdp, aoqi@1: Register scratch2, aoqi@1: bool receiver_can_be_null = false); aoqi@1: void profile_ret(Register return_bci, Register mdp); aoqi@1: void profile_checkcast(bool is_null , Register mdp); aoqi@1: void profile_null_seen(Register mdp); aoqi@1: void profile_typecheck(Register mdp, Register klass, Register scratch); aoqi@1: void profile_typecheck_failed(Register mdp); aoqi@1: void profile_switch_default(Register mdp); aoqi@1: void profile_switch_case(Register index_in_scratch, Register mdp, aoqi@1: Register scratch2); aoqi@1: aoqi@1: // Debugging aoqi@1: // only if +VerifyOops && state == atos aoqi@1: void verify_oop(Register reg, TosState state = atos); aoqi@1: // only if +VerifyFPU && (state == ftos || state == dtos) aoqi@1: void verify_FPU(int stack_depth, TosState state = ftos); aoqi@1: aoqi@1: void profile_obj_type(Register obj, const Address& mdo_addr); aoqi@1: void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual); aoqi@1: void profile_return_type(Register mdp, Register ret, Register tmp); aoqi@1: void profile_parameters_type(Register mdp, Register tmp1, Register tmp2); aoqi@1: #endif // !CC_INTERP aoqi@1: aoqi@1: typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; aoqi@1: aoqi@1: // support for jvmti/dtrace aoqi@1: void notify_method_entry(); aoqi@1: void notify_method_exit(bool is_native_method, TosState state, NotifyMethodExitMode mode); aoqi@1: void save_return_value(TosState state, bool is_native_call); aoqi@1: void restore_return_value(TosState state, bool is_native_call); aoqi@1: }; aoqi@1: aoqi@1: #endif // CPU_MIPS_VM_INTERP_MASM_MIPS_64_HPP