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: #include "precompiled.hpp" aoqi@1: #include "asm/macroAssembler.hpp" aoqi@1: #include "interpreter/interpreter.hpp" aoqi@1: #include "interpreter/interpreterRuntime.hpp" aoqi@1: #include "interpreter/templateTable.hpp" aoqi@1: #include "memory/universe.inline.hpp" aoqi@1: #include "oops/methodData.hpp" aoqi@1: #include "oops/objArrayKlass.hpp" aoqi@1: #include "oops/oop.inline.hpp" aoqi@1: #include "prims/methodHandles.hpp" aoqi@1: #include "runtime/sharedRuntime.hpp" aoqi@1: #include "runtime/stubRoutines.hpp" aoqi@1: #include "runtime/synchronizer.hpp" aoqi@1: aoqi@1: aoqi@1: #ifndef CC_INTERP aoqi@1: aoqi@1: #define __ _masm-> aoqi@1: aoqi@1: // Platform-dependent initialization aoqi@1: aoqi@1: void TemplateTable::pd_initialize() { aoqi@1: // No mips specific initialization aoqi@1: } aoqi@1: aoqi@1: // Address computation: local variables aoqi@6880: aoqi@1: static inline Address iaddress(int n) { aoqi@1: return Address(LVP, Interpreter::local_offset_in_bytes(n)); aoqi@1: } aoqi@1: aoqi@1: static inline Address laddress(int n) { aoqi@1: return iaddress(n + 1); aoqi@1: } aoqi@1: aoqi@1: static inline Address faddress(int n) { aoqi@1: return iaddress(n); aoqi@1: } aoqi@1: aoqi@1: static inline Address daddress(int n) { aoqi@1: return laddress(n); aoqi@1: } aoqi@1: aoqi@1: static inline Address aaddress(int n) { aoqi@1: return iaddress(n); aoqi@1: } aoqi@1: static inline Address haddress(int n) { return iaddress(n + 0); } aoqi@1: aoqi@6880: aoqi@6880: static inline Address at_sp() { return Address(SP, 0); } aoqi@1: static inline Address at_sp_p1() { return Address(SP, 1 * wordSize); } aoqi@1: static inline Address at_sp_p2() { return Address(SP, 2 * wordSize); } aoqi@1: aoqi@1: // At top of Java expression stack which may be different than esp(). It aoqi@1: // isn't for category 1 objects. aoqi@1: static inline Address at_tos () { aoqi@1: Address tos = Address(SP, Interpreter::expr_offset_in_bytes(0)); aoqi@1: return tos; aoqi@1: } aoqi@1: aoqi@1: static inline Address at_tos_p1() { aoqi@1: return Address(SP, Interpreter::expr_offset_in_bytes(1)); aoqi@1: } aoqi@1: aoqi@1: static inline Address at_tos_p2() { aoqi@1: return Address(SP, Interpreter::expr_offset_in_bytes(2)); aoqi@1: } aoqi@1: aoqi@1: static inline Address at_tos_p3() { aoqi@1: return Address(SP, Interpreter::expr_offset_in_bytes(3)); aoqi@1: } aoqi@1: aoqi@6880: // we use S0 as bcp, be sure you have bcp in S0 before you call any of the Template generator aoqi@1: Address TemplateTable::at_bcp(int offset) { aoqi@1: assert(_desc->uses_bcp(), "inconsistent uses_bcp information"); aoqi@1: return Address(BCP, offset); aoqi@1: } aoqi@1: aoqi@1: // bytecode folding aoqi@1: void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg, aoqi@6880: Register tmp_reg, bool load_bc_into_bc_reg/*=true*/, aoqi@1: int byte_no) { aoqi@6880: if (!RewriteBytecodes) return; aoqi@1: Label L_patch_done; aoqi@6880: aoqi@1: switch (bc) { aoqi@1: case Bytecodes::_fast_aputfield: aoqi@1: case Bytecodes::_fast_bputfield: aoqi@1: case Bytecodes::_fast_cputfield: aoqi@1: case Bytecodes::_fast_dputfield: aoqi@1: case Bytecodes::_fast_fputfield: aoqi@1: case Bytecodes::_fast_iputfield: aoqi@1: case Bytecodes::_fast_lputfield: aoqi@1: case Bytecodes::_fast_sputfield: aoqi@1: { aoqi@6880: // We skip bytecode quickening for putfield instructions when aoqi@6880: // the put_code written to the constant pool cache is zero. aoqi@6880: // This is required so that every execution of this instruction aoqi@6880: // calls out to InterpreterRuntime::resolve_get_put to do aoqi@6880: // additional, required work. aoqi@6880: assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); aoqi@6880: assert(load_bc_into_bc_reg, "we use bc_reg as temp"); aoqi@6880: __ get_cache_and_index_and_bytecode_at_bcp(tmp_reg, bc_reg, tmp_reg, byte_no, 1); aoqi@6880: __ daddi(bc_reg, R0, bc); aoqi@6880: __ beq(tmp_reg, R0, L_patch_done); aoqi@6880: __ delayed()->nop(); aoqi@1: } aoqi@1: break; aoqi@1: default: aoqi@1: assert(byte_no == -1, "sanity"); aoqi@6880: // the pair bytecodes have already done the load. aoqi@6880: if (load_bc_into_bc_reg) { aoqi@6880: __ move(bc_reg, bc); aoqi@6880: } aoqi@1: } aoqi@1: aoqi@1: if (JvmtiExport::can_post_breakpoint()) { aoqi@1: Label L_fast_patch; aoqi@1: // if a breakpoint is present we can't rewrite the stream directly aoqi@1: __ lbu(tmp_reg, at_bcp(0)); aoqi@1: __ move(AT, Bytecodes::_breakpoint); aoqi@1: __ bne(tmp_reg, AT, L_fast_patch); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ get_method(tmp_reg); aoqi@6880: // Let breakpoint table handling rewrite to quicker bytecode aoqi@6880: __ call_VM(NOREG, CAST_FROM_FN_PTR(address, aoqi@6880: InterpreterRuntime::set_original_bytecode_at), tmp_reg, BCP, bc_reg); aoqi@1: aoqi@1: __ b(L_patch_done); aoqi@1: __ delayed()->nop(); aoqi@1: __ bind(L_fast_patch); aoqi@1: } aoqi@1: aoqi@1: #ifdef ASSERT aoqi@1: Label L_okay; aoqi@1: __ lbu(tmp_reg, at_bcp(0)); aoqi@1: __ move(AT, (int)Bytecodes::java_code(bc)); aoqi@1: __ beq(tmp_reg, AT, L_okay); aoqi@1: __ delayed()->nop(); aoqi@1: __ beq(tmp_reg, bc_reg, L_patch_done); aoqi@1: __ delayed()->nop(); aoqi@1: __ stop("patching the wrong bytecode"); aoqi@1: __ bind(L_okay); aoqi@1: #endif aoqi@1: aoqi@1: // patch bytecode aoqi@1: __ sb(bc_reg, at_bcp(0)); aoqi@1: __ bind(L_patch_done); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: // Individual instructions aoqi@1: aoqi@1: void TemplateTable::nop() { aoqi@1: transition(vtos, vtos); aoqi@1: // nothing to do aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::shouldnotreachhere() { aoqi@1: transition(vtos, vtos); aoqi@1: __ stop("shouldnotreachhere bytecode"); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::aconst_null() { aoqi@1: transition(vtos, atos); aoqi@1: __ move(FSR, R0); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::iconst(int value) { aoqi@1: transition(vtos, itos); aoqi@1: if (value == 0) { aoqi@1: __ move(FSR, R0); aoqi@1: } else { aoqi@1: __ move(FSR, value); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::lconst(int value) { aoqi@1: transition(vtos, ltos); aoqi@1: if (value == 0) { aoqi@1: __ move(FSR, R0); aoqi@1: } else { aoqi@1: __ move(FSR, value); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::fconst(int value) { aoqi@1: transition(vtos, ftos); aoqi@1: switch( value ) { fujie@6888: case 0: __ mtc1(R0, FSF); return; fujie@6888: case 1: __ addiu(AT, R0, 1); break; fujie@6888: case 2: __ addiu(AT, R0, 2); break; aoqi@1: default: ShouldNotReachHere(); aoqi@1: } fujie@6888: __ mtc1(AT, FSF); fujie@6888: __ cvt_s_w(FSF, FSF); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::dconst(int value) { aoqi@1: transition(vtos, dtos); aoqi@1: switch( value ) { aoqi@7997: case 0: __ dmtc1(R0, FSF); fujie@6888: return; fujie@6888: case 1: __ daddiu(AT, R0, 1); fujie@6888: __ dmtc1(AT, FSF); fujie@6888: __ cvt_d_w(FSF, FSF); fujie@6888: break; aoqi@1: default: ShouldNotReachHere(); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::bipush() { aoqi@1: transition(vtos, itos); aoqi@1: __ lb(FSR, at_bcp(1)); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::sipush() { aoqi@6880: transition(vtos, itos); fujie@6888: __ lb(FSR, BCP, 1); fujie@6888: __ lbu(AT, BCP, 2); aoqi@7997: __ dsll(FSR, FSR, 8); fujie@6888: __ orr(FSR, FSR, AT); aoqi@1: } aoqi@1: aoqi@1: // T1 : tags aoqi@1: // T2 : index aoqi@1: // T3 : cpool aoqi@1: // T8 : tag aoqi@1: void TemplateTable::ldc(bool wide) { aoqi@1: transition(vtos, vtos); aoqi@1: Label call_ldc, notFloat, notClass, Done; aoqi@1: // get index in cpool aoqi@1: if (wide) { fujie@6885: __ get_unsigned_2_byte_index_at_bcp(T2, 1); aoqi@1: } else { aoqi@1: __ lbu(T2, at_bcp(1)); aoqi@1: } aoqi@1: aoqi@1: __ get_cpool_and_tags(T3, T1); aoqi@1: aoqi@1: const int base_offset = ConstantPool::header_size() * wordSize; aoqi@1: const int tags_offset = Array::base_offset_in_bytes(); aoqi@1: aoqi@1: // get type fujie@6885: if (UseLoongsonISA && Assembler::is_simm(sizeof(tags_offset), 8)) { fujie@6885: __ gslbx(T1, T1, T2, tags_offset); fujie@6885: } else { fujie@6885: __ dadd(AT, T1, T2); fujie@6885: __ lb(T1, AT, tags_offset); fujie@6885: } aoqi@1: //now T1 is the tag aoqi@1: aoqi@1: // unresolved class - get the resolved class aoqi@1: __ daddiu(AT, T1, - JVM_CONSTANT_UnresolvedClass); aoqi@1: __ beq(AT, R0, call_ldc); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // unresolved class in error (resolution failed) - call into runtime aoqi@1: // so that the same error from first resolution attempt is thrown. aoqi@6880: __ daddiu(AT, T1, -JVM_CONSTANT_UnresolvedClassInError); aoqi@1: __ beq(AT, R0, call_ldc); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // resolved class - need to call vm to get java mirror of the class aoqi@1: __ daddiu(AT, T1, - JVM_CONSTANT_Class); aoqi@1: __ bne(AT, R0, notClass); aoqi@1: __ delayed()->dsll(T2, T2, Address::times_8); aoqi@1: aoqi@1: __ bind(call_ldc); aoqi@1: __ move(A1, wide); aoqi@1: call_VM(FSR, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), A1); fujie@6885: //__ push(atos); fujie@6885: __ sd(FSR, SP, - Interpreter::stackElementSize); aoqi@1: __ b(Done); fujie@6885: __ delayed()->daddiu(SP, SP, - Interpreter::stackElementSize); fujie@6885: __ nop(); // added for performance issue fujie@6885: aoqi@1: __ bind(notClass); aoqi@1: __ daddiu(AT, T1, -JVM_CONSTANT_Float); aoqi@1: __ bne(AT, R0, notFloat); aoqi@1: __ delayed()->nop(); aoqi@1: // ftos fujie@6885: if (UseLoongsonISA && Assembler::is_simm(sizeof(base_offset), 8)) { fujie@6885: __ gslwxc1(FSF, T3, T2, base_offset); fujie@6885: } else { fujie@6885: __ dadd(AT, T3, T2); fujie@6885: __ lwc1(FSF, AT, base_offset); fujie@6885: } fujie@6885: //__ push_f(); fujie@6885: __ swc1(FSF, SP, - Interpreter::stackElementSize); aoqi@1: __ b(Done); fujie@6885: __ delayed()->daddiu(SP, SP, - Interpreter::stackElementSize); aoqi@1: aoqi@1: __ bind(notFloat); aoqi@1: #ifdef ASSERT aoqi@6880: { aoqi@1: Label L; aoqi@1: __ daddiu(AT, T1, -JVM_CONSTANT_Integer); aoqi@1: __ beq(AT, R0, L); aoqi@1: __ delayed()->nop(); aoqi@1: __ stop("unexpected tag type in ldc"); aoqi@1: __ bind(L); aoqi@1: } aoqi@1: #endif fujie@6885: // itos JVM_CONSTANT_Integer only fujie@6885: if (UseLoongsonISA && Assembler::is_simm(sizeof(base_offset), 8)) { fujie@6885: __ gslwx(FSR, T3, T2, base_offset); fujie@6885: } else { fujie@6885: __ dadd(T0, T3, T2); fujie@6885: __ lw(FSR, T0, base_offset); fujie@6885: } aoqi@1: __ push(itos); aoqi@1: __ bind(Done); aoqi@1: } aoqi@1: aoqi@1: // Fast path for caching oop constants. aoqi@1: void TemplateTable::fast_aldc(bool wide) { aoqi@1: transition(vtos, atos); aoqi@1: aoqi@1: Register result = FSR; aoqi@1: Register tmp = SSR; aoqi@1: int index_size = wide ? sizeof(u2) : sizeof(u1); aoqi@1: aoqi@1: Label resolved; aoqi@6880: aoqi@6880: // We are resolved if the resolved reference cache entry contains a aoqi@6880: // non-null object (String, MethodType, etc.) aoqi@1: assert_different_registers(result, tmp); aoqi@1: __ get_cache_index_at_bcp(tmp, 1, index_size); aoqi@1: __ load_resolved_reference_at_index(result, tmp); aoqi@1: __ bne(result, R0, resolved); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); aoqi@1: // first time invocation - must resolve first aoqi@1: int i = (int)bytecode(); aoqi@1: __ move(tmp, i); aoqi@1: __ call_VM(result, entry, tmp); aoqi@1: aoqi@1: __ bind(resolved); aoqi@1: aoqi@1: if (VerifyOops) { aoqi@1: __ verify_oop(result); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: // used register: T2, T3, T1 aoqi@1: // T2 : index aoqi@1: // T3 : cpool aoqi@1: // T1 : tag aoqi@1: void TemplateTable::ldc2_w() { aoqi@1: transition(vtos, vtos); aoqi@1: Label Long, Done; aoqi@1: aoqi@1: // get index in cpool fujie@6889: __ get_unsigned_2_byte_index_at_bcp(T2, 1); aoqi@1: aoqi@1: __ get_cpool_and_tags(T3, T1); aoqi@1: aoqi@1: const int base_offset = ConstantPool::header_size() * wordSize; aoqi@1: const int tags_offset = Array::base_offset_in_bytes(); aoqi@1: aoqi@1: // get type in T1 fujie@6889: if (UseLoongsonISA && Assembler::is_simm(tags_offset, 8)) { fujie@6889: __ gslbx(T1, T1, T2, tags_offset); fujie@6889: } else { fujie@6889: __ dadd(AT, T1, T2); fujie@6889: __ lb(T1, AT, tags_offset); fujie@6889: } aoqi@1: aoqi@1: __ daddiu(AT, T1, - JVM_CONSTANT_Double); aoqi@1: __ bne(AT, R0, Long); aoqi@1: __ delayed()->dsll(T2, T2, Address::times_8); fujie@6889: aoqi@6880: // dtos fujie@6889: if (UseLoongsonISA && Assembler::is_simm(base_offset, 8)) { fujie@6889: __ gsldxc1(FSF, T3, T2, base_offset); fujie@6889: } else { fujie@6889: __ daddu(AT, T3, T2); fujie@6889: __ ldc1(FSF, AT, base_offset); fujie@6889: } aoqi@1: __ sdc1(FSF, SP, - 2 * wordSize); aoqi@1: __ b(Done); aoqi@1: __ delayed()->daddi(SP, SP, - 2 * wordSize); aoqi@1: aoqi@1: // ltos aoqi@1: __ bind(Long); fujie@6889: if (UseLoongsonISA && Assembler::is_simm(base_offset, 8)) { fujie@6889: __ gsldx(FSR, T3, T2, base_offset); fujie@6889: } else { fujie@6889: __ dadd(AT, T3, T2); fujie@6889: __ ld(FSR, AT, base_offset); fujie@6889: } aoqi@1: __ push(ltos); aoqi@1: aoqi@1: __ bind(Done); aoqi@1: } aoqi@1: aoqi@1: // we compute the actual local variable address here aoqi@1: // the x86 dont do so for it has scaled index memory access model, we dont have, so do here aoqi@1: void TemplateTable::locals_index(Register reg, int offset) { aoqi@1: __ lbu(reg, at_bcp(offset)); aoqi@1: __ dsll(reg, reg, Address::times_8); aoqi@1: __ dsub(reg, LVP, reg); aoqi@1: } aoqi@1: aoqi@1: // this method will do bytecode folding of the two form: aoqi@6880: // iload iload iload caload aoqi@1: // used register : T2, T3 aoqi@1: // T2 : bytecode aoqi@1: // T3 : folded code aoqi@1: void TemplateTable::iload() { aoqi@1: transition(vtos, itos); aoqi@6880: if (RewriteFrequentPairs) { aoqi@1: Label rewrite, done; aoqi@1: // get the next bytecode in T2 aoqi@1: __ lbu(T2, at_bcp(Bytecodes::length_for(Bytecodes::_iload))); aoqi@1: // if _iload, wait to rewrite to iload2. We only want to rewrite the aoqi@1: // last two iloads in a pair. Comparing against fast_iload means that aoqi@1: // the next bytecode is neither an iload or a caload, and therefore aoqi@1: // an iload pair. aoqi@1: __ move(AT, Bytecodes::_iload); aoqi@1: __ beq(AT, T2, done); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ move(T3, Bytecodes::_fast_iload2); aoqi@1: __ move(AT, Bytecodes::_fast_iload); aoqi@1: __ beq(AT, T2, rewrite); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // if _caload, rewrite to fast_icaload aoqi@1: __ move(T3, Bytecodes::_fast_icaload); aoqi@1: __ move(AT, Bytecodes::_caload); aoqi@1: __ beq(AT, T2, rewrite); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // rewrite so iload doesn't check again. aoqi@1: __ move(T3, Bytecodes::_fast_iload); aoqi@1: aoqi@1: // rewrite aoqi@1: // T3 : fast bytecode aoqi@1: __ bind(rewrite); aoqi@1: patch_bytecode(Bytecodes::_iload, T3, T2, false); aoqi@1: __ bind(done); aoqi@1: } aoqi@1: aoqi@1: // Get the local value into tos aoqi@1: locals_index(T2); aoqi@1: __ lw(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::fast_iload2() { aoqi@6880: transition(vtos, itos); aoqi@6880: locals_index(T2); aoqi@6880: __ lw(FSR, T2, 0); aoqi@6880: __ push(itos); aoqi@6880: locals_index(T2, 3); aoqi@6880: __ lw(FSR, T2, 0); aoqi@1: } aoqi@6880: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::fast_iload() { aoqi@1: transition(vtos, itos); aoqi@1: locals_index(T2); aoqi@1: __ lw(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::lload() { aoqi@1: transition(vtos, ltos); aoqi@1: locals_index(T2); aoqi@1: __ ld(FSR, T2, -wordSize); aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::fload() { aoqi@1: transition(vtos, ftos); aoqi@1: locals_index(T2); aoqi@1: __ lwc1(FSF, T2, 0); aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::dload() { aoqi@1: transition(vtos, dtos); aoqi@1: locals_index(T2); aoqi@6880: __ ldc1(FSF, T2, -wordSize); aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@6880: void TemplateTable::aload() { aoqi@1: transition(vtos, atos); aoqi@1: locals_index(T2); aoqi@1: __ ld(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::locals_index_wide(Register reg) { fujie@6890: __ get_unsigned_2_byte_index_at_bcp(reg, 2); aoqi@1: __ dsll(reg, reg, Address::times_8); aoqi@1: __ dsub(reg, LVP, reg); aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::wide_iload() { aoqi@6880: transition(vtos, itos); aoqi@6880: locals_index_wide(T2); aoqi@6880: __ ld(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::wide_lload() { aoqi@6880: transition(vtos, ltos); aoqi@6880: locals_index_wide(T2); wangxue@6881: __ ld(FSR, T2, -wordSize); aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::wide_fload() { aoqi@6880: transition(vtos, ftos); aoqi@6880: locals_index_wide(T2); aoqi@6880: __ lwc1(FSF, T2, 0); aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::wide_dload() { aoqi@6880: transition(vtos, dtos); aoqi@6880: locals_index_wide(T2); wangxue@6881: __ ldc1(FSF, T2, -wordSize); aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::wide_aload() { aoqi@6880: transition(vtos, atos); aoqi@6880: locals_index_wide(T2); aoqi@6880: __ ld(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: // we use A2 as the regiser for index, BE CAREFUL! aoqi@1: // we dont use our tge 29 now, for later optimization aoqi@1: void TemplateTable::index_check(Register array, Register index) { aoqi@1: // Pop ptr into array aoqi@1: __ pop_ptr(array); aoqi@1: index_check_without_pop(array, index); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::index_check_without_pop(Register array, Register index) { aoqi@1: // destroys ebx aoqi@1: // check array aoqi@1: __ null_check(array, arrayOopDesc::length_offset_in_bytes()); aoqi@1: fujie@108: #ifdef _LP64 fujie@108: // sign extend since tos (index) might contain garbage in upper bits fujie@108: __ sll(index, index, 0); fujie@108: #endif // _LP64 fujie@108: aoqi@1: // check index aoqi@1: Label ok; aoqi@1: __ lw(AT, array, arrayOopDesc::length_offset_in_bytes()); aoqi@1: #ifndef OPT_RANGECHECK aoqi@1: __ sltu(AT, index, AT); aoqi@1: __ bne(AT, R0, ok); aoqi@6880: __ delayed()->nop(); aoqi@1: aoqi@1: //throw_ArrayIndexOutOfBoundsException assume abberrant index in A2 aoqi@6880: if (A2 != index) __ move(A2, index); aoqi@1: __ jmp(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); aoqi@1: __ delayed()->nop(); aoqi@1: __ bind(ok); aoqi@1: #else aoqi@1: __ lw(AT, array, arrayOopDesc::length_offset_in_bytes()); aoqi@1: __ move(A2, index); aoqi@1: __ tgeu(A2, AT, 29); aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::iaload() { aoqi@1: transition(itos, itos); aoqi@6880: if(UseBoundCheckInstruction) { jiangshaofeng@362: __ pop(SSR); //SSR:array FSR: index jiangshaofeng@362: __ dsll(FSR, FSR, 2); jiangshaofeng@362: __ dadd(FSR, SSR, FSR); jiangshaofeng@362: __ addi(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_INT)); aoqi@6880: jiangshaofeng@362: __ lw(AT, SSR, arrayOopDesc::length_offset_in_bytes()); //bound jiangshaofeng@362: __ dsll(AT, AT, 2); jiangshaofeng@362: __ dadd(AT, SSR, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_INT)); aoqi@6880: jiangshaofeng@362: __ gslwle(FSR, FSR, AT); jiangshaofeng@362: } else { jiangshaofeng@362: index_check(SSR, FSR); jiangshaofeng@362: __ dsll(FSR, FSR, 2); fujie@6890: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_INT), 8)) { fujie@6890: __ gslwx(FSR, FSR, SSR, arrayOopDesc::base_offset_in_bytes(T_INT)); fujie@6890: } else { fujie@6890: __ dadd(FSR, SSR, FSR); fujie@6890: __ lw(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_INT)); fujie@6890: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::laload() { aoqi@1: transition(itos, ltos); jiangshaofeng@362: if(UseBoundCheckInstruction) { jiangshaofeng@362: __ pop(SSR); //SSR:array FSR: index jiangshaofeng@362: __ dsll(FSR, FSR, Address::times_8); jiangshaofeng@362: __ dadd(FSR, SSR, FSR); jiangshaofeng@362: __ addi(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_LONG) + 0 * wordSize); aoqi@6880: jiangshaofeng@362: __ lw(AT, SSR, arrayOopDesc::length_offset_in_bytes()); //bound jiangshaofeng@362: __ dsll(AT, AT, Address::times_8); jiangshaofeng@362: __ dadd(AT, SSR, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_LONG) + 0 * wordSize); aoqi@6880: aoqi@6880: __ gsldle(FSR, FSR, AT); jiangshaofeng@362: } else { jiangshaofeng@362: index_check(SSR, FSR); jiangshaofeng@362: __ dsll(AT, FSR, Address::times_8); fujie@6890: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_LONG), 8)) { fujie@6890: __ gsldx(FSR, SSR, AT, arrayOopDesc::base_offset_in_bytes(T_LONG)); fujie@6890: } else { fujie@6890: __ dadd(AT, SSR, AT); fujie@6890: __ ld(FSR, AT, arrayOopDesc::base_offset_in_bytes(T_LONG)); fujie@6890: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::faload() { jiangshaofeng@362: transition(itos, ftos); jiangshaofeng@362: if(UseBoundCheckInstruction) { jiangshaofeng@362: __ pop(SSR); //SSR:array FSR: index jiangshaofeng@362: __ shl(FSR, 2); jiangshaofeng@362: __ dadd(FSR, SSR, FSR); jiangshaofeng@362: __ addi(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_FLOAT)); aoqi@6880: jiangshaofeng@362: __ lw(AT, SSR, arrayOopDesc::length_offset_in_bytes()); //bound jiangshaofeng@362: __ shl(AT, 2); jiangshaofeng@362: __ dadd(AT, SSR, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_FLOAT)); aoqi@6880: jiangshaofeng@362: __ gslwlec1(FSF, FSR, AT); jiangshaofeng@362: } else { aoqi@6880: index_check(SSR, FSR); jiangshaofeng@362: __ shl(FSR, 2); fujie@6890: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_FLOAT), 8)) { fujie@6890: __ gslwxc1(FSF, SSR, FSR, arrayOopDesc::base_offset_in_bytes(T_FLOAT)); fujie@6890: } else { fujie@6890: __ dadd(FSR, SSR, FSR); fujie@6890: __ lwc1(FSF, FSR, arrayOopDesc::base_offset_in_bytes(T_FLOAT)); fujie@6890: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::daload() { jiangshaofeng@362: transition(itos, dtos); jiangshaofeng@362: if(UseBoundCheckInstruction) { jiangshaofeng@362: __ pop(SSR); //SSR:array FSR: index jiangshaofeng@362: __ dsll(FSR, FSR, 3); jiangshaofeng@362: __ dadd(FSR, SSR, FSR); jiangshaofeng@362: __ addi(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_DOUBLE) + 0 * wordSize); aoqi@6880: jiangshaofeng@362: __ lw(AT, SSR, arrayOopDesc::length_offset_in_bytes()); //bound jiangshaofeng@362: __ dsll(AT, AT, 3); jiangshaofeng@362: __ dadd(AT, SSR, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_DOUBLE) + 0 * wordSize); aoqi@6880: jiangshaofeng@362: __ gsldlec1(FSF, FSR, AT); jiangshaofeng@362: } else { aoqi@6880: index_check(SSR, FSR); jiangshaofeng@362: __ dsll(AT, FSR, 3); fujie@6890: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_DOUBLE), 8)) { fujie@6890: __ gsldxc1(FSF, SSR, AT, arrayOopDesc::base_offset_in_bytes(T_DOUBLE)); fujie@6890: } else { fujie@6890: __ dadd(AT, SSR, AT); fujie@6890: __ ldc1(FSF, AT, arrayOopDesc::base_offset_in_bytes(T_DOUBLE)); fujie@6890: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::aaload() { aoqi@1: transition(itos, atos); aoqi@1: index_check(SSR, FSR); aoqi@1: __ dsll(FSR, FSR, UseCompressedOops ? Address::times_4 : Address::times_8); aoqi@1: __ dadd(FSR, SSR, FSR); aoqi@1: //add for compressedoops aoqi@1: __ load_heap_oop(FSR, Address(FSR, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::baload() { aoqi@1: transition(itos, itos); jiangshaofeng@362: if(UseBoundCheckInstruction) { jiangshaofeng@362: __ pop(SSR); //SSR:array FSR:index jiangshaofeng@362: __ dadd(FSR, SSR, FSR); jiangshaofeng@362: __ addi(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_BYTE)); //base jiangshaofeng@362: aoqi@6880: __ lw(AT, SSR, arrayOopDesc::length_offset_in_bytes()); jiangshaofeng@362: __ dadd(AT, SSR, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_BYTE)); //bound jiangshaofeng@362: jiangshaofeng@362: __ gslble(FSR, FSR, AT); jiangshaofeng@362: } else { aoqi@6880: index_check(SSR, FSR); fujie@6890: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_BYTE), 8)) { fujie@6890: __ gslbx(FSR, SSR, FSR, arrayOopDesc::base_offset_in_bytes(T_BYTE)); fujie@6890: } else { fujie@6890: __ dadd(FSR, SSR, FSR); fujie@6890: __ lb(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_BYTE)); fujie@6890: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::caload() { aoqi@1: transition(itos, itos); aoqi@1: index_check(SSR, FSR); aoqi@1: __ dsll(FSR, FSR, Address::times_2); aoqi@1: __ dadd(FSR, SSR, FSR); aoqi@1: __ lhu(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_CHAR)); aoqi@1: } aoqi@1: aoqi@1: // iload followed by caload frequent pair aoqi@1: // used register : T2 aoqi@1: // T2 : index aoqi@1: void TemplateTable::fast_icaload() { aoqi@1: transition(vtos, itos); aoqi@1: // load index out of locals aoqi@1: locals_index(T2); aoqi@1: __ lw(FSR, T2, 0); aoqi@1: index_check(SSR, FSR); aoqi@1: __ dsll(FSR, FSR, 1); aoqi@1: __ dadd(FSR, SSR, FSR); aoqi@1: __ lhu(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_CHAR)); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::saload() { aoqi@1: transition(itos, itos); jiangshaofeng@362: if(UseBoundCheckInstruction) { jiangshaofeng@362: __ pop(SSR); //SSR:array FSR: index jiangshaofeng@362: __ dsll(FSR, FSR, Address::times_2); jiangshaofeng@362: __ dadd(FSR, SSR, FSR); jiangshaofeng@362: __ addi(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_SHORT)); aoqi@6880: jiangshaofeng@362: __ lw(AT, SSR, arrayOopDesc::length_offset_in_bytes()); //bound jiangshaofeng@362: __ dsll(AT, AT, Address::times_2); jiangshaofeng@362: __ dadd(AT, SSR, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_SHORT)); aoqi@6880: aoqi@6880: __ gslhle(FSR, FSR, AT); jiangshaofeng@362: } else { aoqi@6880: index_check(SSR, FSR); jiangshaofeng@362: __ dsll(FSR, FSR, Address::times_2); fujie@6890: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_SHORT), 8)) { fujie@6890: __ gslhx(FSR, SSR, FSR, arrayOopDesc::base_offset_in_bytes(T_SHORT)); fujie@6890: } else { fujie@6890: __ dadd(FSR, SSR, FSR); fujie@6890: __ lh(FSR, FSR, arrayOopDesc::base_offset_in_bytes(T_SHORT)); fujie@6890: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::iload(int n) { aoqi@6880: transition(vtos, itos); aoqi@6880: __ lw(FSR, iaddress(n)); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::lload(int n) { aoqi@6880: transition(vtos, ltos); aoqi@6880: __ ld(FSR, laddress(n)); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::fload(int n) { aoqi@1: transition(vtos, ftos); aoqi@1: __ lwc1(FSF, faddress(n)); aoqi@1: } aoqi@6880: aoqi@1: void TemplateTable::dload(int n) { aoqi@6880: transition(vtos, dtos); aoqi@6880: __ ldc1(FSF, laddress(n)); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::aload(int n) { aoqi@1: transition(vtos, atos); aoqi@1: __ ld(FSR, aaddress(n)); aoqi@1: } aoqi@1: aoqi@1: // used register : T2, T3 aoqi@1: // T2 : bytecode aoqi@1: // T3 : folded code aoqi@1: void TemplateTable::aload_0() { aoqi@6880: transition(vtos, atos); aoqi@6880: // According to bytecode histograms, the pairs: aoqi@6880: // aoqi@6880: // _aload_0, _fast_igetfield aoqi@6880: // _aload_0, _fast_agetfield aoqi@6880: // _aload_0, _fast_fgetfield aoqi@6880: // aoqi@6880: // occur frequently. If RewriteFrequentPairs is set, the (slow) aoqi@6880: // _aload_0 bytecode checks if the next bytecode is either aoqi@6880: // _fast_igetfield, _fast_agetfield or _fast_fgetfield and then aoqi@6880: // rewrites the current bytecode into a pair bytecode; otherwise it aoqi@6880: // rewrites the current bytecode into _fast_aload_0 that doesn't do aoqi@6880: // the pair check anymore. aoqi@6880: // aoqi@6880: // Note: If the next bytecode is _getfield, the rewrite must be aoqi@6880: // delayed, otherwise we may miss an opportunity for a pair. aoqi@6880: // aoqi@6880: // Also rewrite frequent pairs aoqi@6880: // aload_0, aload_1 aoqi@6880: // aload_0, iload_1 aoqi@6880: // These bytecodes with a small amount of code are most profitable aoqi@6880: // to rewrite aoqi@6880: if (RewriteFrequentPairs) { aoqi@6880: Label rewrite, done; aoqi@6880: // get the next bytecode in T2 aoqi@6880: __ lbu(T2, at_bcp(Bytecodes::length_for(Bytecodes::_aload_0))); aoqi@6880: aoqi@6880: // do actual aload_0 aoqi@6880: aload(0); aoqi@6880: aoqi@6880: // if _getfield then wait with rewrite aoqi@6880: __ move(AT, Bytecodes::_getfield); aoqi@6880: __ beq(AT, T2, done); aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6880: // if _igetfield then reqrite to _fast_iaccess_0 aoqi@6880: assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) == aoqi@6880: Bytecodes::_aload_0, aoqi@6880: "fix bytecode definition"); aoqi@6880: __ move(T3, Bytecodes::_fast_iaccess_0); aoqi@6880: __ move(AT, Bytecodes::_fast_igetfield); aoqi@6880: __ beq(AT, T2, rewrite); aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6880: // if _agetfield then reqrite to _fast_aaccess_0 aoqi@6880: assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) == aoqi@6880: Bytecodes::_aload_0, aoqi@6880: "fix bytecode definition"); aoqi@6880: __ move(T3, Bytecodes::_fast_aaccess_0); aoqi@6880: __ move(AT, Bytecodes::_fast_agetfield); aoqi@6880: __ beq(AT, T2, rewrite); aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6880: // if _fgetfield then reqrite to _fast_faccess_0 aoqi@6880: assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) == aoqi@6880: Bytecodes::_aload_0, aoqi@6880: "fix bytecode definition"); aoqi@6880: __ move(T3, Bytecodes::_fast_faccess_0); aoqi@6880: __ move(AT, Bytecodes::_fast_fgetfield); aoqi@6880: __ beq(AT, T2, rewrite); aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6880: // else rewrite to _fast_aload0 aoqi@6880: assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) == aoqi@6880: Bytecodes::_aload_0, aoqi@6880: "fix bytecode definition"); aoqi@6880: __ move(T3, Bytecodes::_fast_aload_0); aoqi@6880: aoqi@6880: // rewrite aoqi@6880: __ bind(rewrite); aoqi@6880: patch_bytecode(Bytecodes::_aload_0, T3, T2, false); aoqi@6880: aoqi@6880: __ bind(done); aoqi@6880: } else { aoqi@6880: aload(0); aoqi@6880: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::istore() { aoqi@6880: transition(itos, vtos); aoqi@6880: locals_index(T2); aoqi@6880: __ sw(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::lstore() { aoqi@1: transition(ltos, vtos); aoqi@1: locals_index(T2); aoqi@1: __ sd(FSR, T2, -wordSize); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::fstore() { aoqi@6880: transition(ftos, vtos); aoqi@6880: locals_index(T2); aoqi@6880: __ swc1(FSF, T2, 0); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::dstore() { aoqi@1: transition(dtos, vtos); aoqi@1: locals_index(T2); aoqi@1: __ sdc1(FSF, T2, -wordSize); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::astore() { aoqi@1: transition(vtos, vtos); aoqi@1: __ pop_ptr(FSR); aoqi@1: locals_index(T2); aoqi@1: __ sd(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::wide_istore() { aoqi@6880: transition(vtos, vtos); aoqi@6880: __ pop_i(FSR); aoqi@6880: locals_index_wide(T2); aoqi@6880: __ sd(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::wide_lstore() { aoqi@6880: transition(vtos, vtos); aoqi@6880: __ pop_l(FSR); aoqi@6880: locals_index_wide(T2); wangxue@6881: __ sd(FSR, T2, -wordSize); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::wide_fstore() { aoqi@6880: wide_istore(); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::wide_dstore() { aoqi@6880: wide_lstore(); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::wide_astore() { aoqi@6880: transition(vtos, vtos); aoqi@6880: __ pop_ptr(FSR); aoqi@6880: locals_index_wide(T2); aoqi@6880: __ sd(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: // used register : T2 aoqi@1: void TemplateTable::iastore() { aoqi@1: transition(itos, vtos); jiangshaofeng@362: __ pop_i(SSR); // T2: array SSR: index jiangshaofeng@362: if(UseBoundCheckInstruction) { aoqi@6880: __ pop_ptr(T2); jiangshaofeng@362: __ dsll(SSR, SSR, Address::times_4); jiangshaofeng@362: __ dadd(SSR, T2, SSR); jiangshaofeng@362: __ addi(SSR, SSR, arrayOopDesc::base_offset_in_bytes(T_INT)); // base aoqi@6880: aoqi@6880: __ lw(AT, T2, arrayOopDesc::length_offset_in_bytes()); jiangshaofeng@362: __ dsll(AT, AT, Address::times_4); jiangshaofeng@362: __ dadd(AT, T2, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_INT)); //bound aoqi@6880: jiangshaofeng@362: __ gsswle(FSR, SSR, AT); jiangshaofeng@362: } else { jiangshaofeng@362: index_check(T2, SSR); // prefer index in ebx jiangshaofeng@362: __ dsll(SSR, SSR, Address::times_4); fujie@6891: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_INT), 8)) { fujie@6891: __ gsswx(FSR, T2, SSR, arrayOopDesc::base_offset_in_bytes(T_INT)); fujie@6891: } else { fujie@6891: __ dadd(T2, T2, SSR); fujie@6891: __ sw(FSR, T2, arrayOopDesc::base_offset_in_bytes(T_INT)); fujie@6891: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: aoqi@1: // used register T2, T3 aoqi@1: void TemplateTable::lastore() { aoqi@1: transition(ltos, vtos); aoqi@1: __ pop_i (T2); jiangshaofeng@362: if(UseBoundCheckInstruction) { aoqi@6880: __ pop_ptr(T3); jiangshaofeng@362: __ dsll(T2, T2, Address::times_8); jiangshaofeng@362: __ dadd(T2, T3, T2); jiangshaofeng@362: __ addi(T2, T2, arrayOopDesc::base_offset_in_bytes(T_LONG) + 0 * wordSize); // base aoqi@6880: aoqi@6880: __ lw(AT, T3, arrayOopDesc::length_offset_in_bytes()); jiangshaofeng@362: __ dsll(AT, AT, Address::times_8); jiangshaofeng@362: __ dadd(AT, T3, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_LONG) + 0 * wordSize); //bound aoqi@6880: jiangshaofeng@362: __ gssdle(FSR, T2, AT); jiangshaofeng@362: } else { jiangshaofeng@362: index_check(T3, T2); jiangshaofeng@362: __ dsll(T2, T2, Address::times_8); fujie@6891: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_LONG), 8)) { fujie@6891: __ gssdx(FSR, T3, T2, arrayOopDesc::base_offset_in_bytes(T_LONG)); fujie@6891: } else { fujie@6891: __ dadd(T3, T3, T2); fujie@6891: __ sd(FSR, T3, arrayOopDesc::base_offset_in_bytes(T_LONG)); fujie@6891: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: // used register T2 aoqi@1: void TemplateTable::fastore() { aoqi@1: transition(ftos, vtos); aoqi@6880: __ pop_i(SSR); jiangshaofeng@362: if(UseBoundCheckInstruction) { aoqi@6880: __ pop_ptr(T2); jiangshaofeng@362: __ dsll(SSR, SSR, Address::times_4); jiangshaofeng@362: __ dadd(SSR, T2, SSR); jiangshaofeng@362: __ addi(SSR, SSR, arrayOopDesc::base_offset_in_bytes(T_FLOAT)); // base aoqi@6880: aoqi@6880: __ lw(AT, T2, arrayOopDesc::length_offset_in_bytes()); jiangshaofeng@362: __ dsll(AT, AT, Address::times_4); jiangshaofeng@362: __ dadd(AT, T2, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_FLOAT)); //bound aoqi@6880: jiangshaofeng@362: __ gsswlec1(FSF, SSR, AT); jiangshaofeng@362: } else { aoqi@6880: index_check(T2, SSR); jiangshaofeng@362: __ dsll(SSR, SSR, Address::times_4); fujie@6891: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_FLOAT), 8)) { fujie@6891: __ gsswxc1(FSF, T2, SSR, arrayOopDesc::base_offset_in_bytes(T_FLOAT)); fujie@6891: } else { fujie@6891: __ dadd(T2, T2, SSR); fujie@6891: __ swc1(FSF, T2, arrayOopDesc::base_offset_in_bytes(T_FLOAT)); fujie@6891: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: // used register T2, T3 aoqi@1: void TemplateTable::dastore() { aoqi@1: transition(dtos, vtos); aoqi@6880: __ pop_i (T2); jiangshaofeng@362: if(UseBoundCheckInstruction) { aoqi@6880: __ pop_ptr(T3); jiangshaofeng@362: __ dsll(T2, T2, Address::times_8); jiangshaofeng@362: __ dadd(T2, T3, T2); jiangshaofeng@362: __ addi(T2, T2, arrayOopDesc::base_offset_in_bytes(T_DOUBLE) + 0 * wordSize); // base aoqi@6880: aoqi@6880: __ lw(AT, T3, arrayOopDesc::length_offset_in_bytes()); jiangshaofeng@362: __ dsll(AT, AT, Address::times_8); jiangshaofeng@362: __ dadd(AT, T3, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_DOUBLE) + 0 * wordSize); //bound aoqi@6880: jiangshaofeng@362: __ gssdlec1(FSF, T2, AT); jiangshaofeng@362: } else { aoqi@6880: index_check(T3, T2); jiangshaofeng@362: __ dsll(T2, T2, Address::times_8); fujie@6891: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_DOUBLE), 8)) { fujie@6891: __ gssdxc1(FSF, T3, T2, arrayOopDesc::base_offset_in_bytes(T_DOUBLE)); fujie@6891: } else { fujie@6891: __ daddu(T3, T3, T2); fujie@6891: __ sdc1(FSF, T3, arrayOopDesc::base_offset_in_bytes(T_DOUBLE)); fujie@6891: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: // used register : T2, T3, T8 aoqi@1: // T2 : array aoqi@1: // T3 : subklass aoqi@1: // T8 : supklass aoqi@1: void TemplateTable::aastore() { aoqi@1: Label is_null, ok_is_subtype, done; aoqi@1: transition(vtos, vtos); aoqi@1: // stack: ..., array, index, value aoqi@1: __ ld(FSR, at_tos()); // Value aoqi@1: __ lw(SSR, at_tos_p1()); // Index aoqi@1: __ ld(T2, at_tos_p2()); // Array aoqi@1: aoqi@1: // index_check(T2, SSR); aoqi@1: index_check_without_pop(T2, SSR); aoqi@1: // do array store check - check for NULL value first aoqi@1: __ beq(FSR, R0, is_null); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // Move subklass into T3 aoqi@1: //add for compressedoops aoqi@1: __ load_klass(T3, FSR); aoqi@1: // Move superklass into T8 aoqi@1: //add for compressedoops aoqi@1: __ load_klass(T8, T2); aoqi@1: __ ld(T8, Address(T8, ObjArrayKlass::element_klass_offset())); aoqi@1: // Compress array+index*4+12 into a single register. T2 aoqi@1: __ dsll(AT, SSR, UseCompressedOops? Address::times_4 : Address::times_8); aoqi@1: __ dadd(T2, T2, AT); aoqi@1: __ daddi(T2, T2, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); aoqi@1: aoqi@1: // Generate subtype check. aoqi@1: // Superklass in T8. Subklass in T3. aoqi@6880: __ gen_subtype_check(T8, T3, ok_is_subtype); // <-- Jin aoqi@1: // Come here on failure aoqi@1: // object is at FSR aoqi@1: __ jmp(Interpreter::_throw_ArrayStoreException_entry); // <-- Jin aoqi@1: __ delayed()->nop(); aoqi@1: // Come here on success aoqi@1: __ bind(ok_is_subtype); aoqi@1: //replace with do_oop_store->store_heap_oop aoqi@6880: __ store_heap_oop(Address(T2, 0), FSR); // <-- Jin aoqi@1: __ store_check(T2); aoqi@1: __ b(done); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // Have a NULL in FSR, EDX=T2, SSR=index. Store NULL at ary[idx] aoqi@1: __ bind(is_null); aoqi@1: __ profile_null_seen(T9); aoqi@1: __ dsll(AT, SSR, UseCompressedOops? Address::times_4 : Address::times_8); aoqi@1: __ dadd(T2, T2, AT); aoqi@6880: __ store_heap_oop(Address(T2, arrayOopDesc::base_offset_in_bytes(T_OBJECT)), FSR); /* FSR is null here */ aoqi@1: aoqi@1: __ bind(done); aoqi@1: __ daddi(SP, SP, 3 * Interpreter::stackElementSize); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::bastore() { aoqi@1: transition(itos, vtos); aoqi@6880: __ pop_i(SSR); jiangshaofeng@362: if(UseBoundCheckInstruction) { aoqi@6880: __ pop_ptr(T2); jiangshaofeng@362: __ dadd(SSR, T2, SSR); jiangshaofeng@362: __ addi(SSR, SSR, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // base aoqi@6880: aoqi@6880: __ lw(AT, T2, arrayOopDesc::length_offset_in_bytes()); jiangshaofeng@362: __ dadd(AT, T2, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_BYTE)); //bound aoqi@6880: jiangshaofeng@362: __ gssble(FSR, SSR, AT); jiangshaofeng@362: } else { jiangshaofeng@362: index_check(T2, SSR); fujie@6891: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_BYTE), 8)) { fujie@6891: __ gssbx(FSR, T2, SSR, arrayOopDesc::base_offset_in_bytes(T_BYTE)); fujie@6891: } else { fujie@6891: __ dadd(SSR, T2, SSR); fujie@6891: __ sb(FSR, SSR, arrayOopDesc::base_offset_in_bytes(T_BYTE)); fujie@6891: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::castore() { aoqi@1: transition(itos, vtos); aoqi@6880: __ pop_i(SSR); jiangshaofeng@362: if(UseBoundCheckInstruction) { aoqi@6880: __ pop_ptr(T2); jiangshaofeng@362: __ dsll(SSR, SSR, Address::times_2); jiangshaofeng@362: __ dadd(SSR, T2, SSR); jiangshaofeng@362: __ addi(SSR, SSR, arrayOopDesc::base_offset_in_bytes(T_CHAR)); // base aoqi@6880: aoqi@6880: __ lw(AT, T2, arrayOopDesc::length_offset_in_bytes()); jiangshaofeng@362: __ dsll(AT, AT, Address::times_2); jiangshaofeng@362: __ dadd(AT, T2, AT); jiangshaofeng@362: __ addi(AT, AT, arrayOopDesc::base_offset_in_bytes(T_CHAR)); //bound aoqi@6880: jiangshaofeng@362: __ gsshle(FSR, SSR, AT); jiangshaofeng@362: } else { aoqi@6880: index_check(T2, SSR); jiangshaofeng@362: __ dsll(SSR, SSR, Address::times_2); fujie@6891: if (UseLoongsonISA && Assembler::is_simm(arrayOopDesc::base_offset_in_bytes(T_CHAR), 8)) { fujie@6891: __ gsshx(FSR, T2, SSR, arrayOopDesc::base_offset_in_bytes(T_CHAR)); fujie@6891: } else { fujie@6891: __ dadd(SSR, T2, SSR); fujie@6891: __ sh(FSR, SSR, arrayOopDesc::base_offset_in_bytes(T_CHAR)); fujie@6891: } jiangshaofeng@362: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::sastore() { aoqi@1: castore(); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::istore(int n) { aoqi@1: transition(itos, vtos); aoqi@1: __ sw(FSR, iaddress(n)); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::lstore(int n) { aoqi@1: transition(ltos, vtos); aoqi@1: __ sd(FSR, laddress(n)); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::fstore(int n) { aoqi@1: transition(ftos, vtos); aoqi@1: __ swc1(FSF, faddress(n)); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::dstore(int n) { aoqi@1: transition(dtos, vtos); aoqi@1: __ sdc1(FSF, laddress(n)); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::astore(int n) { aoqi@1: transition(vtos, vtos); aoqi@1: __ pop_ptr(FSR); aoqi@1: __ sd(FSR, aaddress(n)); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::pop() { aoqi@1: transition(vtos, vtos); aoqi@1: __ daddi(SP, SP, Interpreter::stackElementSize); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::pop2() { aoqi@1: transition(vtos, vtos); aoqi@1: __ daddi(SP, SP, 2 * Interpreter::stackElementSize); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::dup() { aoqi@1: transition(vtos, vtos); aoqi@1: // stack: ..., a aoqi@1: __ load_ptr(0, FSR); aoqi@1: __ push_ptr(FSR); aoqi@1: // stack: ..., a, a aoqi@1: } aoqi@1: aoqi@1: // blows FSR aoqi@1: void TemplateTable::dup_x1() { aoqi@6880: transition(vtos, vtos); aoqi@6880: // stack: ..., a, b aoqi@6880: __ load_ptr(0, FSR); // load b aoqi@6880: __ load_ptr(1, A5); // load a aoqi@6880: __ store_ptr(1, FSR); // store b aoqi@6880: __ store_ptr(0, A5); // store a aoqi@6880: __ push_ptr(FSR); // push b aoqi@6880: // stack: ..., b, a, b aoqi@1: } aoqi@1: aoqi@1: // blows FSR aoqi@1: void TemplateTable::dup_x2() { aoqi@6880: transition(vtos, vtos); aoqi@6880: // stack: ..., a, b, c aoqi@6880: __ load_ptr(0, FSR); // load c aoqi@6880: __ load_ptr(2, A5); // load a aoqi@6880: __ store_ptr(2, FSR); // store c in a aoqi@6880: __ push_ptr(FSR); // push c aoqi@6880: // stack: ..., c, b, c, c aoqi@6880: __ load_ptr(2, FSR); // load b aoqi@6880: __ store_ptr(2, A5); // store a in b aoqi@6880: // stack: ..., c, a, c, c aoqi@6880: __ store_ptr(1, FSR); // store b in c aoqi@6880: // stack: ..., c, a, b, c aoqi@1: } aoqi@1: aoqi@1: // blows FSR aoqi@1: void TemplateTable::dup2() { aoqi@6880: transition(vtos, vtos); aoqi@6880: // stack: ..., a, b aoqi@6880: __ load_ptr(1, FSR); // load a aoqi@6880: __ push_ptr(FSR); // push a aoqi@6880: __ load_ptr(1, FSR); // load b aoqi@6880: __ push_ptr(FSR); // push b aoqi@6880: // stack: ..., a, b, a, b aoqi@1: } aoqi@1: aoqi@1: // blows FSR aoqi@1: void TemplateTable::dup2_x1() { aoqi@6880: transition(vtos, vtos); aoqi@6880: // stack: ..., a, b, c aoqi@6880: __ load_ptr(0, T2); // load c aoqi@6880: __ load_ptr(1, FSR); // load b aoqi@6880: __ push_ptr(FSR); // push b aoqi@6880: __ push_ptr(T2); // push c aoqi@6880: // stack: ..., a, b, c, b, c aoqi@6880: __ store_ptr(3, T2); // store c in b aoqi@6880: // stack: ..., a, c, c, b, c aoqi@6880: __ load_ptr(4, T2); // load a aoqi@6880: __ store_ptr(2, T2); // store a in 2nd c aoqi@6880: // stack: ..., a, c, a, b, c aoqi@6880: __ store_ptr(4, FSR); // store b in a aoqi@6880: // stack: ..., b, c, a, b, c aoqi@6880: aoqi@6880: // stack: ..., b, c, a, b, c aoqi@1: } aoqi@1: aoqi@1: // blows FSR, SSR aoqi@1: void TemplateTable::dup2_x2() { aoqi@6880: transition(vtos, vtos); aoqi@6880: // stack: ..., a, b, c, d aoqi@6880: // stack: ..., a, b, c, d aoqi@6880: __ load_ptr(0, T2); // load d aoqi@6880: __ load_ptr(1, FSR); // load c aoqi@6880: __ push_ptr(FSR); // push c aoqi@6880: __ push_ptr(T2); // push d aoqi@6880: // stack: ..., a, b, c, d, c, d aoqi@6880: __ load_ptr(4, FSR); // load b aoqi@6880: __ store_ptr(2, FSR); // store b in d aoqi@6880: __ store_ptr(4, T2); // store d in b aoqi@6880: // stack: ..., a, d, c, b, c, d aoqi@6880: __ load_ptr(5, T2); // load a aoqi@6880: __ load_ptr(3, FSR); // load c aoqi@6880: __ store_ptr(3, T2); // store a in c aoqi@6880: __ store_ptr(5, FSR); // store c in a aoqi@6880: // stack: ..., c, d, a, b, c, d aoqi@6880: aoqi@6880: // stack: ..., c, d, a, b, c, d aoqi@1: } aoqi@1: aoqi@1: // blows FSR aoqi@1: void TemplateTable::swap() { aoqi@6880: transition(vtos, vtos); aoqi@6880: // stack: ..., a, b aoqi@6880: aoqi@6880: __ load_ptr(1, A5); // load a aoqi@6880: __ load_ptr(0, FSR); // load b aoqi@6880: __ store_ptr(0, A5); // store a in b aoqi@6880: __ store_ptr(1, FSR); // store b in a aoqi@6880: aoqi@6880: // stack: ..., b, a aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::iop2(Operation op) { aoqi@6880: transition(itos, itos); fujie@6887: fujie@6887: __ pop_i(SSR); aoqi@6880: switch (op) { fujie@6887: case add : __ addu32(FSR, SSR, FSR); break; fujie@6887: case sub : __ subu32(FSR, SSR, FSR); break; fujie@6887: case mul : __ mul(FSR, SSR, FSR); break; fujie@6887: case _and : __ andr(FSR, SSR, FSR); break; fujie@6887: case _or : __ orr(FSR, SSR, FSR); break; fujie@6887: case _xor : __ xorr(FSR, SSR, FSR); break; fujie@6887: case shl : __ sllv(FSR, SSR, FSR); break; // implicit masking of lower 5 bits by Intel shift instr. mips also fujie@6887: case shr : __ srav(FSR, SSR, FSR); break; // implicit masking of lower 5 bits by Intel shift instr. mips also fujie@6887: case ushr : __ srlv(FSR, SSR, FSR); break; // implicit masking of lower 5 bits by Intel shift instr. mips also aoqi@6880: default : ShouldNotReachHere(); aoqi@6880: } aoqi@1: } aoqi@1: aoqi@1: // the result stored in FSR, SSR, aoqi@1: // used registers : T2, T3 aoqi@1: void TemplateTable::lop2(Operation op) { aoqi@1: transition(ltos, ltos); fujie@6893: __ pop_l(T2); fujie@6893: aoqi@1: switch (op) { fujie@6887: case add : __ daddu(FSR, T2, FSR); break; fujie@6887: case sub : __ dsubu(FSR, T2, FSR); break; fujie@6887: case _and: __ andr(FSR, T2, FSR); break; fujie@6887: case _or : __ orr(FSR, T2, FSR); break; fujie@6887: case _xor: __ xorr(FSR, T2, FSR); break; aoqi@1: default : ShouldNotReachHere(); aoqi@1: } aoqi@1: } aoqi@1: aoqi@6880: // java require this bytecode could handle 0x80000000/-1, dont cause a overflow exception, aoqi@1: // the result is 0x80000000 aoqi@1: // the godson2 cpu do the same, so we need not handle this specially like x86 aoqi@1: void TemplateTable::idiv() { aoqi@6880: transition(itos, itos); aoqi@6880: Label not_zero; aoqi@6880: aoqi@6880: __ bne(FSR, R0, not_zero); aoqi@6880: __ delayed()->nop(); aoqi@6880: __ jmp(Interpreter::_throw_ArithmeticException_entry); aoqi@6880: __ delayed()->nop(); aoqi@6880: __ bind(not_zero); aoqi@6880: aoqi@6880: __ pop_i(SSR); aoqi@6880: if (UseLoongsonISA) { aoqi@6880: __ gsdiv(FSR, SSR, FSR); aoqi@6880: } else { aoqi@6880: __ div(SSR, FSR); aoqi@6880: __ mflo(FSR); aoqi@6880: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::irem() { aoqi@6880: transition(itos, itos); aoqi@6880: Label not_zero; aoqi@6880: __ pop_i(SSR); aoqi@6880: __ div(SSR, FSR); aoqi@6880: aoqi@6880: __ bne(FSR, R0, not_zero); aoqi@6880: __ delayed()->nop(); aoqi@6880: //__ brk(7); aoqi@6880: __ jmp(Interpreter::_throw_ArithmeticException_entry); aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6880: __ bind(not_zero); aoqi@6880: __ mfhi(FSR); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::lmul() { aoqi@1: transition(ltos, ltos); jiangshaofeng@89: __ pop_l(T2); jiangshaofeng@89: if(UseLoongsonISA){ jiangshaofeng@89: __ gsdmult(FSR, T2, FSR); jiangshaofeng@89: } else { aoqi@6880: __ dmult(T2, FSR); aoqi@6880: __ mflo(FSR); aoqi@6880: } aoqi@6880: } aoqi@1: aoqi@1: // NOTE: i DONT use the Interpreter::_throw_ArithmeticException_entry aoqi@1: void TemplateTable::ldiv() { aoqi@1: transition(ltos, ltos); aoqi@1: Label normal; aoqi@1: aoqi@1: __ bne(FSR, R0, normal); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@6880: //__ brk(7); //generate FPE aoqi@1: __ jmp(Interpreter::_throw_ArithmeticException_entry); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ bind(normal); fujie@6893: __ pop_l(A2); chenhaoxuan@87: if (UseLoongsonISA) { aoqi@6880: __ gsddiv(FSR, A2, FSR); chenhaoxuan@87: } else { chenhaoxuan@87: __ ddiv(A2, FSR); chenhaoxuan@87: __ mflo(FSR); chenhaoxuan@87: } aoqi@1: } aoqi@1: aoqi@1: // NOTE: i DONT use the Interpreter::_throw_ArithmeticException_entry aoqi@1: void TemplateTable::lrem() { aoqi@1: transition(ltos, ltos); aoqi@1: Label normal; aoqi@1: aoqi@1: __ bne(FSR, R0, normal); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ jmp(Interpreter::_throw_ArithmeticException_entry); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ bind(normal); fujie@6893: __ pop_l (A2); lifangyuan@88: lifangyuan@88: if(UseLoongsonISA){ lifangyuan@88: __ gsdmod(FSR, A2, FSR); aoqi@6880: } else { lifangyuan@88: __ ddiv(A2, FSR); lifangyuan@88: __ mfhi(FSR); lifangyuan@88: } aoqi@1: } aoqi@1: aoqi@1: // result in FSR aoqi@1: // used registers : T0 aoqi@1: void TemplateTable::lshl() { aoqi@1: transition(itos, ltos); fujie@6893: __ pop_l(T0); aoqi@1: __ dsllv(FSR, T0, FSR); aoqi@1: } aoqi@1: aoqi@1: // used registers : T0 aoqi@1: void TemplateTable::lshr() { aoqi@1: transition(itos, ltos); fujie@6893: __ pop_l(T0); aoqi@1: __ dsrav(FSR, T0, FSR); aoqi@1: } aoqi@1: aoqi@1: // used registers : T0 aoqi@1: void TemplateTable::lushr() { aoqi@1: transition(itos, ltos); fujie@6893: __ pop_l(T0); aoqi@1: __ dsrlv(FSR, T0, FSR); aoqi@1: } aoqi@1: aoqi@1: // result in FSF aoqi@1: void TemplateTable::fop2(Operation op) { aoqi@6880: transition(ftos, ftos); aoqi@6880: switch (op) { aoqi@6880: case add: aoqi@6880: __ lwc1(FTF, at_sp()); aoqi@6880: __ add_s(FSF, FTF, FSF); aoqi@6880: break; aoqi@6880: case sub: aoqi@6880: __ lwc1(FTF, at_sp()); aoqi@6880: __ sub_s(FSF, FTF, FSF); aoqi@6880: break; aoqi@6880: case mul: aoqi@6880: __ lwc1(FTF, at_sp()); aoqi@6880: __ mul_s(FSF, FTF, FSF); aoqi@6880: break; aoqi@6880: case div: aoqi@6880: __ lwc1(FTF, at_sp()); aoqi@6880: __ div_s(FSF, FTF, FSF); aoqi@6880: break; aoqi@6880: case rem: aoqi@6880: __ mov_s(F13, FSF); aoqi@6880: __ lwc1(F12, at_sp()); aoqi@6880: __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem), 2); aoqi@6880: break; aoqi@6880: default : ShouldNotReachHere(); aoqi@6880: } aoqi@6880: aoqi@6880: __ daddi(SP, SP, 1 * wordSize); aoqi@1: } aoqi@1: aoqi@1: // result in SSF||FSF aoqi@1: // i dont handle the strict flags aoqi@1: void TemplateTable::dop2(Operation op) { aoqi@6880: transition(dtos, dtos); aoqi@6880: switch (op) { aoqi@6880: case add: aoqi@6880: __ ldc1(FTF, at_sp()); aoqi@6880: __ add_d(FSF, FTF, FSF); aoqi@6880: break; aoqi@6880: case sub: aoqi@6880: __ ldc1(FTF, at_sp()); aoqi@6880: __ sub_d(FSF, FTF, FSF); aoqi@6880: break; aoqi@6880: case mul: aoqi@6880: __ ldc1(FTF, at_sp()); aoqi@6880: __ mul_d(FSF, FTF, FSF); aoqi@6880: break; aoqi@6880: case div: aoqi@6880: __ ldc1(FTF, at_sp()); aoqi@6880: __ div_d(FSF, FTF, FSF); aoqi@6880: break; aoqi@6880: case rem: aoqi@6880: __ mov_d(F13, FSF); aoqi@6880: __ ldc1(F12, at_sp()); aoqi@6880: __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem), 2); aoqi@6880: break; aoqi@6880: default : ShouldNotReachHere(); aoqi@6880: } aoqi@6880: aoqi@6880: __ daddi(SP, SP, 2 * wordSize); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::ineg() { aoqi@6880: transition(itos, itos); aoqi@6880: __ neg(FSR); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::lneg() { aoqi@6880: transition(ltos, ltos); aoqi@6880: __ dsubu(FSR, R0, FSR); aoqi@1: } aoqi@6880: aoqi@6880: void TemplateTable::fneg() { aoqi@6880: transition(ftos, ftos); aoqi@6880: __ neg_s(FSF, FSF); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::dneg() { aoqi@6880: transition(dtos, dtos); aoqi@6880: __ neg_d(FSF, FSF); aoqi@1: } aoqi@1: aoqi@1: // used registers : T2 aoqi@1: void TemplateTable::iinc() { aoqi@6880: transition(vtos, vtos); aoqi@6880: locals_index(T2); aoqi@6880: __ lw(FSR, T2, 0); aoqi@6880: __ lb(AT, at_bcp(2)); // get constant aoqi@6880: __ daddu(FSR, FSR, AT); aoqi@6880: __ sw(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: // used register : T2 aoqi@1: void TemplateTable::wide_iinc() { aoqi@6880: transition(vtos, vtos); aoqi@6880: locals_index_wide(T2); aoqi@6880: __ get_2_byte_integer_at_bcp(FSR, AT, 4); aoqi@6880: __ hswap(FSR); aoqi@6880: __ lw(AT, T2, 0); aoqi@6880: __ daddu(FSR, AT, FSR); aoqi@6880: __ sw(FSR, T2, 0); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::convert() { aoqi@1: // Checking aoqi@1: #ifdef ASSERT aoqi@6880: { aoqi@6880: TosState tos_in = ilgl; aoqi@1: TosState tos_out = ilgl; aoqi@1: switch (bytecode()) { aoqi@1: case Bytecodes::_i2l: // fall through aoqi@1: case Bytecodes::_i2f: // fall through aoqi@1: case Bytecodes::_i2d: // fall through aoqi@1: case Bytecodes::_i2b: // fall through aoqi@1: case Bytecodes::_i2c: // fall through aoqi@1: case Bytecodes::_i2s: tos_in = itos; break; aoqi@1: case Bytecodes::_l2i: // fall through aoqi@1: case Bytecodes::_l2f: // fall through aoqi@1: case Bytecodes::_l2d: tos_in = ltos; break; aoqi@1: case Bytecodes::_f2i: // fall through aoqi@1: case Bytecodes::_f2l: // fall through aoqi@1: case Bytecodes::_f2d: tos_in = ftos; break; aoqi@1: case Bytecodes::_d2i: // fall through aoqi@1: case Bytecodes::_d2l: // fall through aoqi@1: case Bytecodes::_d2f: tos_in = dtos; break; aoqi@1: default : ShouldNotReachHere(); aoqi@1: } aoqi@1: switch (bytecode()) { aoqi@1: case Bytecodes::_l2i: // fall through aoqi@1: case Bytecodes::_f2i: // fall through aoqi@1: case Bytecodes::_d2i: // fall through aoqi@1: case Bytecodes::_i2b: // fall through aoqi@1: case Bytecodes::_i2c: // fall through aoqi@1: case Bytecodes::_i2s: tos_out = itos; break; aoqi@1: case Bytecodes::_i2l: // fall through aoqi@1: case Bytecodes::_f2l: // fall through aoqi@1: case Bytecodes::_d2l: tos_out = ltos; break; aoqi@1: case Bytecodes::_i2f: // fall through aoqi@1: case Bytecodes::_l2f: // fall through aoqi@1: case Bytecodes::_d2f: tos_out = ftos; break; aoqi@1: case Bytecodes::_i2d: // fall through aoqi@1: case Bytecodes::_l2d: // fall through aoqi@1: case Bytecodes::_f2d: tos_out = dtos; break; aoqi@1: default : ShouldNotReachHere(); aoqi@1: } aoqi@1: transition(tos_in, tos_out); aoqi@1: } aoqi@1: #endif // ASSERT aoqi@1: aoqi@1: // Conversion aoqi@1: // (Note: use pushl(ecx)/popl(ecx) for 1/2-word stack-ptr manipulation) aoqi@1: switch (bytecode()) { aoqi@1: case Bytecodes::_i2l: aoqi@1: __ sll(FSR, FSR, 0); aoqi@1: break; aoqi@1: case Bytecodes::_i2f: aoqi@1: __ mtc1(FSR, FSF); aoqi@1: __ cvt_s_w(FSF, FSF); aoqi@1: break; aoqi@1: case Bytecodes::_i2d: aoqi@1: __ mtc1(FSR, FSF); aoqi@1: __ cvt_d_w(FSF, FSF); aoqi@1: break; aoqi@1: case Bytecodes::_i2b: fujie@256: __ seb(FSR, FSR); aoqi@1: break; aoqi@1: case Bytecodes::_i2c: aoqi@1: __ andi(FSR, FSR, 0xFFFF); // truncate upper 56 bits aoqi@1: break; aoqi@1: case Bytecodes::_i2s: fujie@256: __ seh(FSR, FSR); aoqi@1: break; aoqi@1: case Bytecodes::_l2i: fujie@257: __ sll(FSR, FSR, 0); aoqi@1: break; aoqi@1: case Bytecodes::_l2f: aoqi@1: __ dmtc1(FSR, FSF); aoqi@1: __ cvt_s_l(FSF, FSF); aoqi@1: break; aoqi@1: case Bytecodes::_l2d: aoqi@1: __ dmtc1(FSR, FSF); aoqi@1: __ cvt_d_l(FSF, FSF); aoqi@1: break; aoqi@1: case Bytecodes::_f2i: aoqi@6880: { aoqi@6880: Label L; aoqi@6880: aoqi@6880: __ trunc_w_s(F12, FSF); aoqi@6880: __ move(AT, 0x7fffffff); aoqi@6880: __ mfc1(FSR, F12); aoqi@6880: __ c_un_s(FSF, FSF); //NaN? aoqi@6880: __ movt(FSR, R0); aoqi@6880: aoqi@6880: __ bne(AT, FSR, L); aoqi@6880: __ delayed()->lui(T9, 0x8000); aoqi@6880: aoqi@6880: __ mfc1(AT, FSF); aoqi@6880: __ andr(AT, AT, T9); aoqi@6880: aoqi@6880: __ movn(FSR, T9, AT); aoqi@6880: aoqi@6880: __ bind(L); aoqi@6880: } aoqi@1: break; aoqi@1: case Bytecodes::_f2l: aoqi@6880: { aoqi@6880: Label L; aoqi@6880: aoqi@6880: __ trunc_l_s(F12, FSF); aoqi@6880: __ daddiu(AT, R0, -1); aoqi@6880: __ dsrl(AT, AT, 1); aoqi@6880: __ dmfc1(FSR, F12); aoqi@6880: __ c_un_s(FSF, FSF); //NaN? aoqi@6880: __ movt(FSR, R0); aoqi@6880: aoqi@6880: __ bne(AT, FSR, L); aoqi@6880: __ delayed()->lui(T9, 0x8000); aoqi@6880: aoqi@6880: __ mfc1(AT, FSF); aoqi@6880: __ andr(AT, AT, T9); aoqi@6880: aoqi@6880: __ dsll32(T9, T9, 0); aoqi@6880: __ movn(FSR, T9, AT); aoqi@6880: aoqi@6880: __ bind(L); aoqi@6880: } aoqi@1: break; aoqi@1: case Bytecodes::_f2d: aoqi@1: __ cvt_d_s(FSF, FSF); aoqi@1: break; aoqi@1: case Bytecodes::_d2i: aoqi@6880: { aoqi@6880: Label L; aoqi@6880: aoqi@6880: __ trunc_w_d(F12, FSF); aoqi@6880: __ move(AT, 0x7fffffff); aoqi@6880: __ mfc1(FSR, F12); aoqi@6880: aoqi@6880: __ bne(FSR, AT, L); aoqi@6880: __ delayed()->mtc1(R0, F12); aoqi@6880: aoqi@6880: __ cvt_d_w(F12, F12); aoqi@6880: __ c_ult_d(FSF, F12); aoqi@6880: __ bc1f(L); aoqi@6880: __ delayed()->addiu(T9, R0, -1); aoqi@6880: aoqi@6880: __ c_un_d(FSF, FSF); //NaN? aoqi@6880: __ subu32(FSR, T9, AT); aoqi@6880: __ movt(FSR, R0); aoqi@6880: aoqi@6880: __ bind(L); aoqi@6880: } aoqi@1: break; aoqi@1: case Bytecodes::_d2l: aoqi@6880: { aoqi@6880: Label L; aoqi@6880: aoqi@6880: __ trunc_l_d(F12, FSF); aoqi@6880: __ daddiu(AT, R0, -1); aoqi@6880: __ dsrl(AT, AT, 1); aoqi@6880: __ dmfc1(FSR, F12); aoqi@6880: aoqi@6880: __ bne(FSR, AT, L); aoqi@6880: __ delayed()->mtc1(R0, F12); aoqi@6880: aoqi@6880: __ cvt_d_w(F12, F12); aoqi@6880: __ c_ult_d(FSF, F12); aoqi@6880: __ bc1f(L); aoqi@6880: __ delayed()->daddiu(T9, R0, -1); aoqi@6880: aoqi@6880: __ c_un_d(FSF, FSF); //NaN? aoqi@6880: __ subu(FSR, T9, AT); aoqi@6880: __ movt(FSR, R0); aoqi@6880: aoqi@6880: __ bind(L); aoqi@6880: } aoqi@1: break; aoqi@1: case Bytecodes::_d2f: aoqi@1: __ cvt_s_d(FSF, FSF); aoqi@1: break; aoqi@1: default : aoqi@1: ShouldNotReachHere(); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::lcmp() { aoqi@1: transition(ltos, itos); aoqi@1: aoqi@1: Label low, high, done; aoqi@1: __ pop(T0); aoqi@1: __ pop(R0); aoqi@1: __ slt(AT, T0, FSR); aoqi@1: __ bne(AT, R0, low); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ bne(T0, FSR, high); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ li(FSR, (long)0); aoqi@1: __ b(done); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ bind(low); aoqi@1: __ li(FSR, (long)-1); aoqi@1: __ b(done); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ bind(high); aoqi@1: __ li(FSR, (long)1); aoqi@1: __ b(done); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ bind(done); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::float_cmp(bool is_float, int unordered_result) { aoqi@6880: Label less, done; aoqi@6880: aoqi@6880: __ move(FSR, R0); aoqi@6880: aoqi@6880: if (is_float) { aoqi@6880: __ lwc1(FTF, at_sp()); aoqi@6880: __ c_eq_s(FTF, FSF); aoqi@6880: __ bc1t(done); aoqi@6880: __ delayed()->daddi(SP, SP, 1 * wordSize); aoqi@6880: aoqi@6880: if (unordered_result<0) aoqi@6880: __ c_ult_s(FTF, FSF); aoqi@6880: else aoqi@6880: __ c_olt_s(FTF, FSF); aoqi@6880: } else { aoqi@6880: __ ldc1(FTF, at_sp()); aoqi@6880: __ c_eq_d(FTF, FSF); aoqi@6880: __ bc1t(done); aoqi@6880: __ delayed()->daddi(SP, SP, 2 * wordSize); aoqi@6880: aoqi@6880: if (unordered_result<0) aoqi@6880: __ c_ult_d(FTF, FSF); aoqi@6880: else aoqi@6880: __ c_olt_d(FTF, FSF); aoqi@6880: } aoqi@6880: __ bc1t(less); aoqi@6880: __ delayed()->nop(); aoqi@6880: __ move(FSR, 1); aoqi@6880: __ b(done); aoqi@6880: __ delayed()->nop(); aoqi@6880: __ bind(less); aoqi@6880: __ move(FSR, -1); aoqi@6880: __ bind(done); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: // used registers : T3, A7, Rnext aoqi@1: // FSR : return bci, this is defined by the vm specification aoqi@1: // T2 : MDO taken count aoqi@1: // T3 : method aoqi@1: // A7 : offset aoqi@1: // Rnext : next bytecode, this is required by dispatch_base aoqi@1: void TemplateTable::branch(bool is_jsr, bool is_wide) { aoqi@1: __ get_method(T3); aoqi@6880: __ profile_taken_branch(A7, T2); // only C2 meaningful aoqi@1: aoqi@1: #ifndef CORE aoqi@6880: const ByteSize be_offset = MethodCounters::backedge_counter_offset() + aoqi@6880: InvocationCounter::counter_offset(); aoqi@6880: const ByteSize inv_offset = MethodCounters::invocation_counter_offset() + aoqi@6880: InvocationCounter::counter_offset(); aoqi@1: #endif // CORE aoqi@1: aoqi@1: // Load up T4 with the branch displacement aoqi@1: if (!is_wide) { fujie@6895: __ lb(A7, BCP, 1); fujie@6895: __ lbu(AT, BCP, 2); aoqi@7997: __ dsll(A7, A7, 8); fujie@6895: __ orr(A7, A7, AT); aoqi@1: } else { aoqi@15: __ get_4_byte_integer_at_bcp(A7, AT, 1); aoqi@1: __ swap(A7); aoqi@1: } aoqi@1: aoqi@1: // Handle all the JSR stuff here, then exit. aoqi@6880: // It's much shorter and cleaner than intermingling with the non-JSR aoqi@6880: // normal-branch stuff occuring below. aoqi@1: if (is_jsr) { aoqi@1: // Pre-load the next target bytecode into Rnext aoqi@1: __ dadd(AT, BCP, A7); aoqi@1: __ lbu(Rnext, AT, 0); aoqi@1: aoqi@1: // compute return address as bci in FSR aoqi@1: __ daddi(FSR, BCP, (is_wide?5:3) - in_bytes(ConstMethod::codes_offset())); aoqi@1: __ ld(AT, T3, in_bytes(Method::const_offset())); aoqi@1: __ dsub(FSR, FSR, AT); aoqi@1: // Adjust the bcp in BCP by the displacement in A7 aoqi@1: __ dadd(BCP, BCP, A7); aoqi@1: // jsr returns atos that is not an oop aoqi@1: // Push return address aoqi@1: __ push_i(FSR); aoqi@1: // jsr returns vtos aoqi@1: __ dispatch_only_noverify(vtos); aoqi@1: aoqi@1: return; aoqi@1: } aoqi@1: aoqi@1: // Normal (non-jsr) branch handling aoqi@1: aoqi@1: // Adjust the bcp in S0 by the displacement in T4 aoqi@1: __ dadd(BCP, BCP, A7); aoqi@1: aoqi@1: #ifdef CORE aoqi@1: // Pre-load the next target bytecode into EBX aoqi@1: __ lbu(Rnext, BCP, 0); aoqi@1: // continue with the bytecode @ target aoqi@1: __ dispatch_only(vtos); aoqi@1: #else aoqi@1: assert(UseLoopCounter || !UseOnStackReplacement, "on-stack-replacement requires loop counters"); aoqi@1: Label backedge_counter_overflow; aoqi@1: Label profile_method; aoqi@1: Label dispatch; aoqi@1: if (UseLoopCounter) { aoqi@1: // increment backedge counter for backward branches aoqi@1: // eax: MDO aoqi@1: // ebx: MDO bumped taken-count aoqi@1: // T3: method aoqi@1: // T4: target offset aoqi@1: // BCP: target bcp aoqi@1: // LVP: locals pointer aoqi@6880: __ bgtz(A7, dispatch); // check if forward or backward branch aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // check if MethodCounters exists aoqi@1: Label has_counters; aoqi@6880: __ ld(AT, T3, in_bytes(Method::method_counters_offset())); // use AT as MDO, TEMP aoqi@1: __ bne(AT, R0, has_counters); aoqi@1: __ nop(); aoqi@418: __ push(T3); aoqi@1: //__ push(A7); aoqi@1: __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters), aoqi@1: T3); aoqi@1: //__ pop(A7); aoqi@418: __ pop(T3); aoqi@1: __ ld(AT, T3, in_bytes(Method::method_counters_offset())); // use AT as MDO, TEMP aoqi@1: __ beq(AT, R0, dispatch); aoqi@1: __ nop(); aoqi@1: __ bind(has_counters); aoqi@1: aoqi@6880: // increment back edge counter aoqi@1: __ ld(T1, T3, in_bytes(Method::method_counters_offset())); aoqi@1: __ lw(T0, T1, in_bytes(be_offset)); aoqi@1: __ increment(T0, InvocationCounter::count_increment); aoqi@1: __ sw(T0, T1, in_bytes(be_offset)); aoqi@1: aoqi@1: // load invocation counter aoqi@1: __ lw(T1, T1, in_bytes(inv_offset)); aoqi@1: // buffer bit added, mask no needed aoqi@1: aoqi@1: // dadd backedge counter & invocation counter aoqi@1: __ dadd(T1, T1, T0); aoqi@1: aoqi@1: if (ProfileInterpreter) { aoqi@1: // Test to see if we should create a method data oop aoqi@1: // T1 : backedge counter & invocation counter fujie@6895: if (Assembler::is_simm16(InvocationCounter::InterpreterProfileLimit)) { fujie@6895: __ slti(AT, T1, InvocationCounter::InterpreterProfileLimit); fujie@6895: } else { fujie@6895: __ li(AT, (long)&InvocationCounter::InterpreterProfileLimit); fujie@6895: __ lw(AT, AT, 0); fujie@6895: __ slt(AT, T1, AT); fujie@6895: } fujie@6895: aoqi@1: __ bne(AT, R0, dispatch); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // if no method data exists, go to profile method aoqi@1: __ test_method_data_pointer(T1, profile_method); aoqi@1: aoqi@1: if (UseOnStackReplacement) { fujie@6895: if (Assembler::is_simm16(InvocationCounter::InterpreterBackwardBranchLimit)) { fujie@6895: __ slti(AT, T2, InvocationCounter::InterpreterBackwardBranchLimit); fujie@6895: } else { fujie@6895: __ li(AT, (long)&InvocationCounter::InterpreterBackwardBranchLimit); fujie@6895: __ lw(AT, AT, 0); fujie@6895: __ slt(AT, T2, AT); fujie@6895: } fujie@6895: aoqi@6880: __ bne(AT, R0, dispatch); aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6880: // When ProfileInterpreter is on, the backedge_count comes aoqi@6880: // from the methodDataOop, which value does not get reset on aoqi@6880: // the call to frequency_counter_overflow(). aoqi@6880: // To avoid excessive calls to the overflow routine while aoqi@6880: // the method is being compiled, dadd a second test to make aoqi@6880: // sure the overflow function is called only once every aoqi@6880: // overflow_frequency. aoqi@6880: const int overflow_frequency = 1024; aoqi@6880: __ andi(AT, T2, overflow_frequency-1); aoqi@6880: __ beq(AT, R0, backedge_counter_overflow); aoqi@6880: __ delayed()->nop(); aoqi@1: } aoqi@1: } else { aoqi@1: if (UseOnStackReplacement) { aoqi@6880: // check for overflow against eax, which is the sum of the counters aoqi@6880: __ li(AT, (long)&InvocationCounter::InterpreterBackwardBranchLimit); aoqi@6880: __ lw(AT, AT, 0); aoqi@6880: __ slt(AT, T1, AT); aoqi@6880: __ beq(AT, R0, backedge_counter_overflow); aoqi@6880: __ delayed()->nop(); aoqi@1: } aoqi@1: } aoqi@1: __ bind(dispatch); aoqi@1: } aoqi@1: aoqi@1: // Pre-load the next target bytecode into Rnext aoqi@1: __ lbu(Rnext, BCP, 0); aoqi@1: aoqi@1: // continue with the bytecode @ target aoqi@1: // FSR: return bci for jsr's, unused otherwise aoqi@1: // Rnext: target bytecode aoqi@1: // BCP: target bcp aoqi@1: __ dispatch_only(vtos); aoqi@1: aoqi@1: if (UseLoopCounter) { aoqi@1: if (ProfileInterpreter) { aoqi@1: // Out-of-line code to allocate method data oop. aoqi@1: __ bind(profile_method); aoqi@1: __ call_VM(NOREG, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); aoqi@1: __ lbu(Rnext, BCP, 0); aoqi@1: __ set_method_data_pointer_for_bcp(); aoqi@1: __ b(dispatch); aoqi@1: __ delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: if (UseOnStackReplacement) { aoqi@1: // invocation counter overflow aoqi@1: __ bind(backedge_counter_overflow); aoqi@6880: __ sub(A7, BCP, A7); // branch bcp aoqi@6880: call_VM(NOREG, CAST_FROM_FN_PTR(address, aoqi@6880: InterpreterRuntime::frequency_counter_overflow), A7); aoqi@1: __ lbu(Rnext, BCP, 0); aoqi@1: aoqi@1: // V0: osr nmethod (osr ok) or NULL (osr not possible) aoqi@1: // V1: osr adapter frame return address aoqi@1: // Rnext: target bytecode aoqi@1: // LVP: locals pointer aoqi@1: // BCP: bcp aoqi@1: __ beq(V0, R0, dispatch); aoqi@1: __ delayed()->nop(); aoqi@1: // nmethod may have been invalidated (VM may block upon call_VM return) aoqi@1: __ lw(T3, V0, nmethod::entry_bci_offset()); aoqi@1: __ move(AT, InvalidOSREntryBci); aoqi@1: __ beq(AT, T3, dispatch); aoqi@1: __ delayed()->nop(); aoqi@1: // We need to prepare to execute the OSR method. First we must aoqi@1: // migrate the locals and monitors off of the stack. aoqi@1: //eax V0: osr nmethod (osr ok) or NULL (osr not possible) aoqi@1: //ebx V1: osr adapter frame return address aoqi@1: //edx Rnext: target bytecode aoqi@1: //edi LVP: locals pointer aoqi@1: //esi BCP: bcp aoqi@6880: __ move(BCP, V0); aoqi@1: // const Register thread = ecx; aoqi@1: const Register thread = TREG; aoqi@1: #ifndef OPT_THREAD aoqi@1: __ get_thread(thread); aoqi@1: #endif aoqi@6880: call_VM(noreg, CAST_FROM_FN_PTR(address, aoqi@6880: SharedRuntime::OSR_migration_begin)); aoqi@1: // eax is OSR buffer, move it to expected parameter location aoqi@6880: //refer to osrBufferPointer in c1_LIRAssembler_mips.cpp aoqi@1: __ move(T0, V0); aoqi@1: aoqi@1: // pop the interpreter frame aoqi@6880: __ ld(A7, Address(FP, frame::interpreter_frame_sender_sp_offset * wordSize)); aoqi@6880: //FIXME, shall we keep the return address on the stack? aoqi@1: __ leave(); // remove frame anchor aoqi@6880: __ move(LVP, RA); aoqi@1: __ move(SP, A7); aoqi@1: aoqi@6880: __ move(AT, -(StackAlignmentInBytes)); aoqi@6880: __ andr(SP , SP , AT); aoqi@6880: aoqi@6880: // push the (possibly adjusted) return address aoqi@6880: //refer to osr_entry in c1_LIRAssembler_mips.cpp aoqi@6880: __ ld(AT, BCP, nmethod::osr_entry_point_offset()); aoqi@6880: __ jr(AT); aoqi@1: __ delayed()->nop(); aoqi@1: } aoqi@1: } aoqi@1: #endif // not CORE aoqi@1: } aoqi@1: aoqi@6880: aoqi@1: void TemplateTable::if_0cmp(Condition cc) { aoqi@1: transition(itos, vtos); aoqi@1: // assume branch is more often taken than not (loops use backward branches) aoqi@1: Label not_taken; aoqi@1: switch(cc) { aoqi@1: case not_equal: aoqi@1: __ beq(FSR, R0, not_taken); aoqi@1: break; aoqi@1: case equal: aoqi@1: __ bne(FSR, R0, not_taken); aoqi@1: break; aoqi@1: case less: aoqi@1: __ bgez(FSR, not_taken); aoqi@1: break; aoqi@1: case less_equal: aoqi@1: __ bgtz(FSR, not_taken); aoqi@1: break; aoqi@1: case greater: aoqi@1: __ blez(FSR, not_taken); aoqi@1: break; aoqi@1: case greater_equal: aoqi@1: __ bltz(FSR, not_taken); aoqi@1: break; aoqi@1: } aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: branch(false, false); aoqi@1: aoqi@1: __ bind(not_taken); aoqi@1: __ profile_not_taken_branch(FSR); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::if_icmp(Condition cc) { aoqi@1: transition(itos, vtos); aoqi@1: // assume branch is more often taken than not (loops use backward branches) aoqi@1: Label not_taken; aoqi@1: aoqi@6880: __ pop_i(SSR); aoqi@1: switch(cc) { aoqi@1: case not_equal: aoqi@1: __ beq(SSR, FSR, not_taken); aoqi@1: break; aoqi@1: case equal: aoqi@1: __ bne(SSR, FSR, not_taken); aoqi@1: break; aoqi@1: case less: aoqi@1: __ slt(AT, SSR, FSR); aoqi@1: __ beq(AT, R0, not_taken); aoqi@1: break; aoqi@1: case less_equal: aoqi@1: __ slt(AT, FSR, SSR); aoqi@1: __ bne(AT, R0, not_taken); aoqi@1: break; aoqi@1: case greater: aoqi@1: __ slt(AT, FSR, SSR); aoqi@1: __ beq(AT, R0, not_taken); aoqi@1: break; aoqi@1: case greater_equal: aoqi@1: __ slt(AT, SSR, FSR); aoqi@1: __ bne(AT, R0, not_taken); aoqi@1: break; aoqi@1: } aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: branch(false, false); aoqi@1: __ bind(not_taken); aoqi@1: __ profile_not_taken_branch(FSR); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::if_nullcmp(Condition cc) { aoqi@1: transition(atos, vtos); aoqi@1: // assume branch is more often taken than not (loops use backward branches) aoqi@1: Label not_taken; aoqi@1: switch(cc) { aoqi@1: case not_equal: aoqi@1: __ beq(FSR, R0, not_taken); aoqi@1: break; aoqi@1: case equal: aoqi@1: __ bne(FSR, R0, not_taken); aoqi@1: break; aoqi@1: default: aoqi@1: ShouldNotReachHere(); aoqi@1: } aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: branch(false, false); aoqi@1: __ bind(not_taken); aoqi@1: __ profile_not_taken_branch(FSR); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void TemplateTable::if_acmp(Condition cc) { aoqi@6880: transition(atos, vtos); aoqi@6880: // assume branch is more often taken than not (loops use backward branches) aoqi@6880: Label not_taken; aoqi@6880: // __ lw(SSR, SP, 0); aoqi@6880: __ pop_ptr(SSR); aoqi@6880: switch(cc) { aoqi@6880: case not_equal: aoqi@6880: __ beq(SSR, FSR, not_taken); aoqi@6880: break; aoqi@6880: case equal: aoqi@6880: __ bne(SSR, FSR, not_taken); aoqi@6880: break; aoqi@6880: default: aoqi@6880: ShouldNotReachHere(); aoqi@6880: } aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6880: branch(false, false); aoqi@6880: aoqi@6880: __ bind(not_taken); aoqi@6880: __ profile_not_taken_branch(FSR); aoqi@1: } aoqi@1: aoqi@1: // used registers : T1, T2, T3 aoqi@1: // T1 : method aoqi@1: // T2 : returb bci aoqi@1: void TemplateTable::ret() { aoqi@6880: transition(vtos, vtos); aoqi@6880: aoqi@6880: locals_index(T2); aoqi@6880: __ ld(T2, T2, 0); aoqi@6880: __ profile_ret(T2, T3); aoqi@6880: aoqi@6880: __ get_method(T1); aoqi@6880: __ ld(BCP, T1, in_bytes(Method::const_offset())); aoqi@6880: __ dadd(BCP, BCP, T2); aoqi@6880: __ daddi(BCP, BCP, in_bytes(ConstMethod::codes_offset())); aoqi@6880: aoqi@6880: __ dispatch_next(vtos); aoqi@1: } aoqi@1: aoqi@1: // used registers : T1, T2, T3 aoqi@1: // T1 : method aoqi@1: // T2 : returb bci aoqi@1: void TemplateTable::wide_ret() { aoqi@6880: transition(vtos, vtos); aoqi@6880: aoqi@6880: locals_index_wide(T2); aoqi@6880: __ ld(T2, T2, 0); // get return bci, compute return bcp aoqi@6880: __ profile_ret(T2, T3); aoqi@6880: aoqi@6880: __ get_method(T1); aoqi@6880: __ ld(BCP, T1, in_bytes(Method::const_offset())); aoqi@6880: __ dadd(BCP, BCP, T2); aoqi@6880: __ daddi(BCP, BCP, in_bytes(ConstMethod::codes_offset())); aoqi@6880: aoqi@6880: __ dispatch_next(vtos); aoqi@1: } aoqi@1: aoqi@1: // used register T2, T3, A7, Rnext aoqi@1: // T2 : bytecode pointer aoqi@1: // T3 : low aoqi@1: // A7 : high aoqi@1: // Rnext : dest bytecode, required by dispatch_base aoqi@1: void TemplateTable::tableswitch() { aoqi@6880: Label default_case, continue_execution; aoqi@6880: transition(itos, vtos); aoqi@6880: aoqi@6880: // align BCP aoqi@6880: __ daddi(T2, BCP, BytesPerInt); aoqi@6880: __ li(AT, -BytesPerInt); aoqi@6880: __ andr(T2, T2, AT); aoqi@6880: aoqi@6880: // load lo & hi aoqi@6880: __ lw(T3, T2, 1 * BytesPerInt); aoqi@6880: __ swap(T3); aoqi@6880: __ lw(A7, T2, 2 * BytesPerInt); aoqi@6880: __ swap(A7); aoqi@6880: aoqi@6880: // check against lo & hi aoqi@6880: __ slt(AT, FSR, T3); aoqi@6880: __ bne(AT, R0, default_case); aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6880: __ slt(AT, A7, FSR); aoqi@6880: __ bne(AT, R0, default_case); aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6880: // lookup dispatch offset, in A7 big endian aoqi@6880: __ dsub(FSR, FSR, T3); aoqi@6880: __ dsll(AT, FSR, Address::times_4); aoqi@6880: __ dadd(AT, T2, AT); aoqi@6880: __ lw(A7, AT, 3 * BytesPerInt); aoqi@6880: __ profile_switch_case(FSR, T9, T3); aoqi@6880: aoqi@6880: __ bind(continue_execution); aoqi@6880: __ swap(A7); aoqi@6880: __ dadd(BCP, BCP, A7); aoqi@6880: __ lbu(Rnext, BCP, 0); aoqi@6880: __ dispatch_only(vtos); aoqi@6880: aoqi@6880: // handle default aoqi@6880: __ bind(default_case); aoqi@6880: __ profile_switch_default(FSR); aoqi@6880: __ lw(A7, T2, 0); aoqi@6880: __ b(continue_execution); aoqi@6880: __ delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::lookupswitch() { aoqi@6880: transition(itos, itos); aoqi@6880: __ stop("lookupswitch bytecode should have been rewritten"); aoqi@1: } aoqi@1: aoqi@1: // used registers : T2, T3, A7, Rnext aoqi@1: // T2 : bytecode pointer aoqi@1: // T3 : pair index aoqi@1: // A7 : offset aoqi@1: // Rnext : dest bytecode aoqi@1: // the data after the opcode is the same as lookupswitch aoqi@1: // see Rewriter::rewrite_method for more information aoqi@1: void TemplateTable::fast_linearswitch() { aoqi@1: transition(itos, vtos); aoqi@6880: Label loop_entry, loop, found, continue_execution; aoqi@1: aoqi@1: // swap eax so we can avoid swapping the table entries aoqi@1: __ swap(FSR); aoqi@1: aoqi@1: // align BCP aoqi@1: __ daddi(T2, BCP, BytesPerInt); aoqi@1: __ li(AT, -BytesPerInt); aoqi@1: __ andr(T2, T2, AT); aoqi@1: aoqi@1: // set counter aoqi@1: __ lw(T3, T2, BytesPerInt); aoqi@1: __ swap(T3); aoqi@1: __ b(loop_entry); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // table search aoqi@1: __ bind(loop); aoqi@1: // get the entry value aoqi@1: __ dsll(AT, T3, Address::times_8); aoqi@1: __ dadd(AT, T2, AT); aoqi@1: __ lw(AT, AT, 2 * BytesPerInt); aoqi@1: aoqi@1: // found? aoqi@1: __ beq(FSR, AT, found); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ bind(loop_entry); aoqi@1: __ bgtz(T3, loop); aoqi@1: __ delayed()->daddiu(T3, T3, -1); aoqi@1: aoqi@1: // default case aoqi@1: __ profile_switch_default(FSR); aoqi@1: __ lw(A7, T2, 0); aoqi@1: __ b(continue_execution); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // entry found -> get offset aoqi@1: __ bind(found); aoqi@1: __ dsll(AT, T3, Address::times_8); aoqi@1: __ dadd(AT, T2, AT); aoqi@1: __ lw(A7, AT, 3 * BytesPerInt); aoqi@1: __ profile_switch_case(T3, FSR, T2); aoqi@1: aoqi@1: // continue execution aoqi@6880: __ bind(continue_execution); aoqi@1: __ swap(A7); aoqi@1: __ dadd(BCP, BCP, A7); aoqi@1: __ lbu(Rnext, BCP, 0); aoqi@1: __ dispatch_only(vtos); aoqi@1: } aoqi@1: aoqi@1: // used registers : T0, T1, T2, T3, A7, Rnext aoqi@1: // T2 : pairs address(array) aoqi@1: // Rnext : dest bytecode aoqi@1: // the data after the opcode is the same as lookupswitch aoqi@1: // see Rewriter::rewrite_method for more information aoqi@1: void TemplateTable::fast_binaryswitch() { aoqi@1: transition(itos, vtos); aoqi@1: // Implementation using the following core algorithm: aoqi@1: // aoqi@1: // int binary_search(int key, LookupswitchPair* array, int n) { aoqi@1: // // Binary search according to "Methodik des Programmierens" by aoqi@1: // // Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985. aoqi@1: // int i = 0; aoqi@1: // int j = n; aoqi@1: // while (i+1 < j) { aoqi@1: // // invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q) aoqi@1: // // with Q: for all i: 0 <= i < n: key < a[i] aoqi@1: // // where a stands for the array and assuming that the (inexisting) aoqi@1: // // element a[n] is infinitely big. aoqi@1: // int h = (i + j) >> 1; aoqi@1: // // i < h < j aoqi@1: // if (key < array[h].fast_match()) { aoqi@1: // j = h; aoqi@1: // } else { aoqi@1: // i = h; aoqi@1: // } aoqi@1: // } aoqi@1: // // R: a[i] <= key < a[i+1] or Q aoqi@1: // // (i.e., if key is within array, i is the correct index) aoqi@1: // return i; aoqi@1: // } aoqi@1: aoqi@1: // register allocation aoqi@1: const Register array = T2; aoqi@1: const Register i = T3, j = A7; aoqi@1: const Register h = T1; aoqi@1: const Register temp = T0; aoqi@1: const Register key = FSR; aoqi@1: aoqi@1: // setup array aoqi@1: __ daddi(array, BCP, 3*BytesPerInt); aoqi@1: __ li(AT, -BytesPerInt); aoqi@1: __ andr(array, array, AT); aoqi@1: aoqi@1: // initialize i & j aoqi@1: __ move(i, R0); aoqi@1: __ lw(j, array, - 1 * BytesPerInt); aoqi@6880: // Convert j into native byteordering aoqi@1: __ swap(j); aoqi@1: aoqi@1: // and start aoqi@1: Label entry; aoqi@1: __ b(entry); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // binary search loop aoqi@6880: { aoqi@1: Label loop; aoqi@1: __ bind(loop); aoqi@1: // int h = (i + j) >> 1; aoqi@1: __ dadd(h, i, j); aoqi@1: __ dsrl(h, h, 1); aoqi@1: // if (key < array[h].fast_match()) { aoqi@1: // j = h; aoqi@1: // } else { aoqi@1: // i = h; aoqi@1: // } aoqi@1: // Convert array[h].match to native byte-ordering before compare aoqi@1: __ dsll(AT, h, Address::times_8); aoqi@1: __ dadd(AT, array, AT); aoqi@1: __ lw(temp, AT, 0 * BytesPerInt); aoqi@1: __ swap(temp); aoqi@1: aoqi@1: { aoqi@1: Label set_i, end_of_if; aoqi@1: __ slt(AT, key, temp); aoqi@1: __ beq(AT, R0, set_i); aoqi@6880: __ delayed()->nop(); aoqi@1: aoqi@1: __ b(end_of_if); aoqi@1: __ delayed(); __ move(j, h); aoqi@1: aoqi@1: __ bind(set_i); aoqi@1: __ move(i, h); aoqi@1: aoqi@1: __ bind(end_of_if); aoqi@1: } aoqi@1: // while (i+1 < j) aoqi@1: __ bind(entry); aoqi@1: __ daddi(h, i, 1); aoqi@1: __ slt(AT, h, j); aoqi@1: __ bne(AT, R0, loop); aoqi@1: __ delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: // end of binary search, result index is i (must check again!) aoqi@1: Label default_case; aoqi@1: // Convert array[i].match to native byte-ordering before compare aoqi@1: __ dsll(AT, i, Address::times_8); aoqi@1: __ dadd(AT, array, AT); aoqi@1: __ lw(temp, AT, 0 * BytesPerInt); aoqi@1: __ swap(temp); aoqi@1: __ bne(key, temp, default_case); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // entry found -> j = offset aoqi@1: __ dsll(AT, i, Address::times_8); aoqi@1: __ dadd(AT, array, AT); aoqi@1: __ lw(j, AT, 1 * BytesPerInt); aoqi@1: __ profile_switch_case(i, key, array); aoqi@1: __ swap(j); aoqi@1: aoqi@1: __ dadd(BCP, BCP, j); aoqi@1: __ lbu(Rnext, BCP, 0); aoqi@1: __ dispatch_only(vtos); aoqi@1: aoqi@1: // default case -> j = default offset aoqi@1: __ bind(default_case); aoqi@1: __ profile_switch_default(i); aoqi@1: __ lw(j, array, - 2 * BytesPerInt); aoqi@1: __ swap(j); aoqi@1: __ dadd(BCP, BCP, j); aoqi@1: __ lbu(Rnext, BCP, 0); aoqi@1: __ dispatch_only(vtos); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::_return(TosState state) { aoqi@1: transition(state, state); aoqi@6880: assert(_desc->calls_vm(), aoqi@6880: "inconsistent calls_vm information"); // call in remove_activation aoqi@6880: aoqi@1: if (_desc->bytecode() == Bytecodes::_return_register_finalizer) { aoqi@1: assert(state == vtos, "only valid state"); aoqi@1: __ ld(T1, aaddress(0)); aoqi@1: __ load_klass(LVP, T1); aoqi@1: __ lw(LVP, LVP, in_bytes(Klass::access_flags_offset())); aoqi@6880: __ move(AT, JVM_ACC_HAS_FINALIZER); aoqi@1: __ andr(AT, AT, LVP);//by_css aoqi@1: Label skip_register_finalizer; aoqi@1: __ beq(AT, R0, skip_register_finalizer); aoqi@6880: __ delayed()->nop(); aoqi@6880: __ call_VM(noreg, CAST_FROM_FN_PTR(address, aoqi@6880: InterpreterRuntime::register_finalizer), T1); aoqi@1: __ bind(skip_register_finalizer); aoqi@1: } aoqi@1: __ remove_activation(state, T9); fujie@32: __ sync(); aoqi@1: aoqi@1: __ jr(T9); aoqi@1: __ delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: // ---------------------------------------------------------------------------- aoqi@1: // Volatile variables demand their effects be made known to all CPU's aoqi@1: // in order. Store buffers on most chips allow reads & writes to aoqi@1: // reorder; the JMM's ReadAfterWrite.java test fails in -Xint mode aoqi@1: // without some kind of memory barrier (i.e., it's not sufficient that aoqi@1: // the interpreter does not reorder volatile references, the hardware aoqi@1: // also must not reorder them). aoqi@1: // aoqi@1: // According to the new Java Memory Model (JMM): aoqi@1: // (1) All volatiles are serialized wrt to each other. ALSO reads & aoqi@1: // writes act as aquire & release, so: aoqi@1: // (2) A read cannot let unrelated NON-volatile memory refs that aoqi@1: // happen after the read float up to before the read. It's OK for aoqi@1: // non-volatile memory refs that happen before the volatile read to aoqi@1: // float down below it. aoqi@1: // (3) Similar a volatile write cannot let unrelated NON-volatile aoqi@1: // memory refs that happen BEFORE the write float down to after the aoqi@1: // write. It's OK for non-volatile memory refs that happen after the aoqi@1: // volatile write to float up before it. aoqi@1: // aoqi@1: // We only put in barriers around volatile refs (they are expensive), aoqi@1: // not _between_ memory refs (that would require us to track the aoqi@1: // flavor of the previous memory refs). Requirements (2) and (3) aoqi@1: // require some barriers before volatile stores and after volatile aoqi@1: // loads. These nearly cover requirement (1) but miss the aoqi@1: // volatile-store-volatile-load case. This final case is placed after aoqi@1: // volatile-stores although it could just as well go before aoqi@1: // volatile-loads. aoqi@1: //void TemplateTable::volatile_barrier(Assembler::Membar_mask_bits aoqi@1: // order_constraint) { aoqi@1: void TemplateTable::volatile_barrier( ) { aoqi@1: // Helper function to insert a is-volatile test and memory barrier aoqi@1: //if (os::is_MP()) { // Not needed on single CPU aoqi@1: // __ membar(order_constraint); aoqi@1: //} aoqi@6880: if( !os::is_MP() ) return; // Not needed on single CPU aoqi@6880: __ sync(); aoqi@1: } aoqi@1: aoqi@1: // we dont shift left 2 bits in get_cache_and_index_at_bcp aoqi@6880: // for we always need shift the index we use it. the ConstantPoolCacheEntry aoqi@6880: // is 16-byte long, index is the index in aoqi@6880: // ConstantPoolCache, so cache + base_offset() + index * 16 is aoqi@1: // the corresponding ConstantPoolCacheEntry aoqi@1: // used registers : T2 aoqi@1: // NOTE : the returned index need also shift left 4 to get the address! aoqi@1: void TemplateTable::resolve_cache_and_index(int byte_no, aoqi@1: Register Rcache, aoqi@6880: Register index, aoqi@1: size_t index_size) { aoqi@1: assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); aoqi@1: const Register temp = A1; aoqi@1: assert_different_registers(Rcache, index); aoqi@6880: aoqi@1: Label resolved; aoqi@1: __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size); aoqi@1: // is resolved? aoqi@1: int i = (int)bytecode(); aoqi@1: __ addi(temp, temp, -i); aoqi@1: __ beq(temp, R0, resolved); aoqi@1: __ delayed()->nop(); aoqi@1: // resolve first time through aoqi@1: address entry; aoqi@1: switch (bytecode()) { aoqi@1: case Bytecodes::_getstatic : // fall through aoqi@1: case Bytecodes::_putstatic : // fall through aoqi@1: case Bytecodes::_getfield : // fall through aoqi@6880: case Bytecodes::_putfield : aoqi@6880: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); aoqi@1: break; aoqi@1: case Bytecodes::_invokevirtual : // fall through aoqi@1: case Bytecodes::_invokespecial : // fall through aoqi@1: case Bytecodes::_invokestatic : // fall through aoqi@6880: case Bytecodes::_invokeinterface: aoqi@6880: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); aoqi@1: break; aoqi@1: case Bytecodes::_invokehandle: aoqi@1: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokehandle); aoqi@1: break; aoqi@1: case Bytecodes::_invokedynamic: aoqi@1: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); aoqi@1: break; aoqi@6880: default : aoqi@1: fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(bytecode()))); aoqi@6880: break; aoqi@1: } aoqi@1: aoqi@1: __ move(temp, i); aoqi@1: __ call_VM(NOREG, entry, temp); aoqi@1: aoqi@1: // Update registers with resolved info aoqi@1: __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size); aoqi@1: __ bind(resolved); aoqi@1: } aoqi@1: aoqi@1: // The Rcache and index registers must be set before call aoqi@1: void TemplateTable::load_field_cp_cache_entry(Register obj, aoqi@1: Register cache, aoqi@1: Register index, aoqi@1: Register off, aoqi@1: Register flags, aoqi@1: bool is_static = false) { aoqi@1: assert_different_registers(cache, index, flags, off); aoqi@6880: aoqi@1: ByteSize cp_base_offset = ConstantPoolCache::base_offset(); aoqi@1: // Field offset aoqi@1: __ dsll(AT, index, Address::times_ptr); aoqi@1: __ dadd(AT, cache, AT); aoqi@1: __ ld(off, AT, in_bytes(cp_base_offset + ConstantPoolCacheEntry::f2_offset())); aoqi@6880: // Flags aoqi@1: __ ld(flags, AT, in_bytes(cp_base_offset + ConstantPoolCacheEntry::flags_offset())); aoqi@1: aoqi@6880: // klass overwrite register aoqi@1: if (is_static) { aoqi@6880: __ ld(obj, AT, in_bytes(cp_base_offset + ConstantPoolCacheEntry::f1_offset())); aoqi@1: const int mirror_offset = in_bytes(Klass::java_mirror_offset()); aoqi@1: __ ld(obj, Address(obj, mirror_offset)); aoqi@1: aoqi@6880: __ verify_oop(obj); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: // get the method, itable_index and flags of the current invoke aoqi@1: void TemplateTable::load_invoke_cp_cache_entry(int byte_no, aoqi@1: Register method, aoqi@1: Register itable_index, aoqi@1: Register flags, aoqi@1: bool is_invokevirtual, aoqi@1: bool is_invokevfinal, /*unused*/ aoqi@1: bool is_invokedynamic) { aoqi@1: // setup registers aoqi@1: const Register cache = T3; aoqi@1: const Register index = T1; aoqi@1: assert_different_registers(method, flags); aoqi@1: assert_different_registers(method, cache, index); aoqi@1: assert_different_registers(itable_index, flags); aoqi@1: assert_different_registers(itable_index, cache, index); aoqi@1: assert(is_invokevirtual == (byte_no == f2_byte), "is invokevirtual flag redundant"); aoqi@1: // determine constant pool cache field offsets aoqi@1: const int method_offset = in_bytes( aoqi@6880: ConstantPoolCache::base_offset() + aoqi@1: ((byte_no == f2_byte) aoqi@1: ? ConstantPoolCacheEntry::f2_offset() aoqi@6880: : ConstantPoolCacheEntry::f1_offset())); aoqi@1: const int flags_offset = in_bytes(ConstantPoolCache::base_offset() + aoqi@6880: ConstantPoolCacheEntry::flags_offset()); aoqi@1: // access constant pool cache fields aoqi@1: const int index_offset = in_bytes(ConstantPoolCache::base_offset() + aoqi@6880: ConstantPoolCacheEntry::f2_offset()); aoqi@6880: aoqi@1: size_t index_size = (is_invokedynamic ? sizeof(u4): sizeof(u2)); aoqi@1: resolve_cache_and_index(byte_no, cache, index, index_size); aoqi@1: aoqi@1: //assert(wordSize == 8, "adjust code below"); aoqi@6880: // note we shift 4 not 2, for we get is the true inde aoqi@1: // of ConstantPoolCacheEntry, not the shifted 2-bit index as x86 version aoqi@1: __ dsll(AT, index, Address::times_ptr); aoqi@1: __ dadd(AT, cache, AT); aoqi@1: __ ld(method, AT, method_offset); aoqi@1: aoqi@1: if (itable_index != NOREG) { aoqi@1: __ ld(itable_index, AT, index_offset); aoqi@1: } aoqi@1: __ ld(flags, AT, flags_offset); aoqi@1: } aoqi@1: aoqi@1: // The registers cache and index expected to be set before call. aoqi@1: // Correct values of the cache and index registers are preserved. aoqi@1: void TemplateTable::jvmti_post_field_access(Register cache, Register index, aoqi@1: bool is_static, bool has_tos) { aoqi@1: // do the JVMTI work here to avoid disturbing the register state below aoqi@1: // We use c_rarg registers here because we want to use the register used in aoqi@1: // the call to the VM aoqi@6880: if (JvmtiExport::can_post_field_access()) { aoqi@6880: // Check to see if a field access watch has been set before we aoqi@6880: // take the time to call into the VM. aoqi@6880: Label L1; aoqi@6883: // kill FSR aoqi@6883: Register tmp1 = T2; aoqi@6883: Register tmp2 = T1; aoqi@6883: Register tmp3 = T3; aoqi@6883: assert_different_registers(cache, index, AT); aoqi@6880: __ li(AT, (intptr_t)JvmtiExport::get_field_access_count_addr()); aoqi@6883: __ lw(AT, AT, 0); aoqi@6883: __ beq(AT, R0, L1); aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6883: __ get_cache_and_index_at_bcp(tmp2, tmp3, 1); aoqi@6883: aoqi@6880: // cache entry pointer aoqi@6883: __ daddi(tmp2, tmp2, in_bytes(ConstantPoolCache::base_offset())); aoqi@6883: __ shl(tmp3, LogBytesPerWord); aoqi@6883: __ dadd(tmp2, tmp2, tmp3); aoqi@6880: if (is_static) { aoqi@6883: __ move(tmp1, R0); aoqi@6880: } else { aoqi@6883: __ ld(tmp1, SP, 0); aoqi@6883: __ verify_oop(tmp1); aoqi@6880: } aoqi@6883: // tmp1: object pointer or NULL aoqi@6883: // tmp2: cache entry pointer aoqi@6883: // tmp3: jvalue object on the stack aoqi@6880: __ call_VM(NOREG, CAST_FROM_FN_PTR(address, aoqi@6883: InterpreterRuntime::post_field_access), aoqi@6883: tmp1, tmp2, tmp3); aoqi@6880: __ get_cache_and_index_at_bcp(cache, index, 1); aoqi@6880: __ bind(L1); aoqi@6880: } aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::pop_and_check_object(Register r) { aoqi@1: __ pop_ptr(r); aoqi@1: __ null_check(r); // for field access must check obj. aoqi@1: __ verify_oop(r); aoqi@1: } aoqi@1: aoqi@1: // used registers : T1, T2, T3, T1 aoqi@1: // T1 : flags aoqi@1: // T2 : off aoqi@1: // T3 : obj aoqi@1: // T1 : field address aoqi@1: // The flags 31, 30, 29, 28 together build a 4 bit number 0 to 8 with the aoqi@1: // following mapping to the TosState states: aoqi@1: // btos: 0 aoqi@1: // ctos: 1 aoqi@1: // stos: 2 aoqi@1: // itos: 3 aoqi@1: // ltos: 4 aoqi@1: // ftos: 5 aoqi@1: // dtos: 6 aoqi@1: // atos: 7 aoqi@1: // vtos: 8 aoqi@1: // see ConstantPoolCacheEntry::set_field for more info aoqi@1: void TemplateTable::getfield_or_static(int byte_no, bool is_static) { aoqi@1: transition(vtos, vtos); aoqi@1: aoqi@1: const Register cache = T3; aoqi@1: const Register index = T0; aoqi@1: aoqi@1: const Register obj = T3; aoqi@1: const Register off = T2; aoqi@1: const Register flags = T1; aoqi@1: resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); aoqi@6883: jvmti_post_field_access(cache, index, is_static, false); aoqi@1: load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); aoqi@1: aoqi@1: if (!is_static) pop_and_check_object(obj); aoqi@1: __ dadd(index, obj, off); aoqi@1: aoqi@1: aoqi@6880: Label Done, notByte, notInt, notShort, notChar, aoqi@6880: notLong, notFloat, notObj, notDouble; aoqi@1: aoqi@1: assert(btos == 0, "change code, btos != 0"); aoqi@1: __ dsrl(flags, flags, ConstantPoolCacheEntry::tos_state_shift); aoqi@1: __ andi(flags, flags, 0xf); aoqi@1: __ bne(flags, R0, notByte); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // btos aoqi@6880: __ lb(FSR, index, 0); aoqi@1: __ sd(FSR, SP, - wordSize); aoqi@1: aoqi@1: // Rewrite bytecode to be faster aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_bgetfield, T3, T2); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->daddi(SP, SP, - wordSize); aoqi@1: aoqi@1: __ bind(notByte); aoqi@1: __ move(AT, itos); aoqi@1: __ bne(flags, AT, notInt); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // itos aoqi@1: __ lw(FSR, index, 0); aoqi@1: __ sd(FSR, SP, - wordSize); aoqi@1: aoqi@1: // Rewrite bytecode to be faster aoqi@1: if (!is_static) { aoqi@1: // patch_bytecode(Bytecodes::_fast_igetfield, T3, T2); aoqi@1: patch_bytecode(Bytecodes::_fast_igetfield, T3, T2); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->daddi(SP, SP, - wordSize); aoqi@1: aoqi@1: __ bind(notInt); aoqi@1: __ move(AT, atos); aoqi@1: __ bne(flags, AT, notObj); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // atos aoqi@1: //add for compressedoops aoqi@1: __ load_heap_oop(FSR, Address(index, 0)); aoqi@1: __ sd(FSR, SP, - wordSize); aoqi@1: aoqi@1: if (!is_static) { aoqi@1: //patch_bytecode(Bytecodes::_fast_agetfield, T3, T2); aoqi@1: patch_bytecode(Bytecodes::_fast_agetfield, T3, T2); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->daddi(SP, SP, - wordSize); aoqi@1: aoqi@1: __ bind(notObj); aoqi@1: __ move(AT, ctos); aoqi@1: __ bne(flags, AT, notChar); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // ctos aoqi@1: __ lhu(FSR, index, 0); aoqi@1: __ sd(FSR, SP, - wordSize); aoqi@1: aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_cgetfield, T3, T2); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->daddi(SP, SP, - wordSize); aoqi@1: aoqi@1: __ bind(notChar); aoqi@1: __ move(AT, stos); aoqi@1: __ bne(flags, AT, notShort); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // stos aoqi@1: __ lh(FSR, index, 0); aoqi@1: __ sd(FSR, SP, - wordSize); aoqi@1: aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_sgetfield, T3, T2); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->daddi(SP, SP, - wordSize); aoqi@1: aoqi@1: __ bind(notShort); aoqi@1: __ move(AT, ltos); aoqi@1: __ bne(flags, AT, notLong); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // FIXME : the load/store should be atomic, we have no simple method to do this in mips32 aoqi@1: // ltos aoqi@1: __ ld(FSR, index, 0 * wordSize); aoqi@1: __ sd(FSR, SP, -2 * wordSize); aoqi@1: __ sd(R0, SP, -1 * wordSize); aoqi@1: aoqi@1: // Don't rewrite to _fast_lgetfield for potential volatile case. aoqi@1: __ b(Done); aoqi@1: __ delayed()->daddi(SP, SP, - 2 * wordSize); aoqi@1: aoqi@1: __ bind(notLong); aoqi@1: __ move(AT, ftos); aoqi@1: __ bne(flags, AT, notFloat); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // ftos aoqi@1: __ lwc1(FSF, index, 0); aoqi@1: __ sdc1(FSF, SP, - wordSize); aoqi@1: aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_fgetfield, T3, T2); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->daddi(SP, SP, - wordSize); aoqi@1: aoqi@1: __ bind(notFloat); aoqi@1: __ move(AT, dtos); aoqi@1: __ bne(flags, AT, notDouble); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // dtos aoqi@1: __ ldc1(FSF, index, 0 * wordSize); aoqi@1: __ sdc1(FSF, SP, - 2 * wordSize); aoqi@1: __ sd(R0, SP, - 1 * wordSize); aoqi@1: aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_dgetfield, T3, T2); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->daddi(SP, SP, - 2 * wordSize); aoqi@1: aoqi@1: __ bind(notDouble); aoqi@1: aoqi@1: __ stop("Bad state"); aoqi@1: aoqi@1: __ bind(Done); aoqi@1: } aoqi@1: aoqi@6880: aoqi@1: void TemplateTable::getfield(int byte_no) { aoqi@1: getfield_or_static(byte_no, false); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::getstatic(int byte_no) { aoqi@1: getfield_or_static(byte_no, true); aoqi@1: } aoqi@1: aoqi@1: // The registers cache and index expected to be set before call. aoqi@1: // The function may destroy various registers, just not the cache and index registers. aoqi@1: void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is_static) { aoqi@6883: transition(vtos, vtos); aoqi@6883: aoqi@6880: ByteSize cp_base_offset = ConstantPoolCache::base_offset(); aoqi@6880: aoqi@6880: if (JvmtiExport::can_post_field_modification()) { aoqi@6883: // Check to see if a field modification watch has been set before aoqi@6883: // we take the time to call into the VM. aoqi@6880: Label L1; aoqi@6883: //kill AT, T1, T2, T3, T9 aoqi@6883: Register tmp1 = T2; aoqi@6883: Register tmp2 = T1; aoqi@6883: Register tmp3 = T3; aoqi@6883: Register tmp4 = T9; aoqi@6883: assert_different_registers(cache, index, tmp4); aoqi@6880: aoqi@6880: __ li(AT, JvmtiExport::get_field_modification_count_addr()); aoqi@6883: __ lw(AT, AT, 0); aoqi@6883: __ beq(AT, R0, L1); aoqi@6880: __ delayed()->nop(); aoqi@6880: aoqi@6883: __ get_cache_and_index_at_bcp(tmp2, tmp4, 1); aoqi@6880: aoqi@6880: if (is_static) { aoqi@6883: __ move(tmp1, R0); aoqi@6880: } else { aoqi@6883: // Life is harder. The stack holds the value on top, followed by aoqi@6883: // the object. We don't know the size of the value, though; it aoqi@6883: // could be one or two words depending on its type. As a result, aoqi@6883: // we must find the type to determine where the object is. aoqi@6880: Label two_word, valsize_known; aoqi@6883: __ dsll(AT, tmp4, Address::times_8); aoqi@6883: __ dadd(AT, tmp2, AT); aoqi@6883: __ ld(tmp3, AT, in_bytes(cp_base_offset + aoqi@6883: ConstantPoolCacheEntry::flags_offset())); aoqi@6883: __ shr(tmp3, ConstantPoolCacheEntry::tos_state_shift); aoqi@6880: aoqi@6880: // Make sure we don't need to mask ecx for tos_state_shift aoqi@6880: // after the above shift aoqi@6880: ConstantPoolCacheEntry::verify_tos_state_shift(); aoqi@6883: __ move(tmp1, SP); aoqi@6880: __ move(AT, ltos); aoqi@6883: __ beq(tmp3, AT, two_word); aoqi@6880: __ delayed()->nop(); aoqi@6880: __ move(AT, dtos); aoqi@6883: __ beq(tmp3, AT, two_word); aoqi@6880: __ delayed()->nop(); aoqi@6880: __ b(valsize_known); aoqi@6883: __ delayed()->daddi(tmp1, tmp1, Interpreter::expr_offset_in_bytes(1) ); aoqi@6880: aoqi@6880: __ bind(two_word); aoqi@6883: __ daddi(tmp1, tmp1, Interpreter::expr_offset_in_bytes(2)); aoqi@6880: aoqi@6880: __ bind(valsize_known); aoqi@6880: // setup object pointer aoqi@6883: __ ld(tmp1, tmp1, 0*wordSize); aoqi@6880: } aoqi@6880: // cache entry pointer aoqi@6883: __ daddi(tmp2, tmp2, in_bytes(cp_base_offset)); aoqi@6883: __ shl(tmp4, LogBytesPerWord); aoqi@6883: __ daddu(tmp2, tmp2, tmp4); aoqi@6880: // object (tos) aoqi@6883: __ move(tmp3, SP); aoqi@6883: // tmp1: object pointer set up above (NULL if static) aoqi@6883: // tmp2: cache entry pointer aoqi@6883: // tmp3: jvalue object on the stack aoqi@6883: __ call_VM(NOREG, aoqi@6883: CAST_FROM_FN_PTR(address, aoqi@6883: InterpreterRuntime::post_field_modification), aoqi@6883: tmp1, tmp2, tmp3); aoqi@6880: __ get_cache_and_index_at_bcp(cache, index, 1); aoqi@6880: __ bind(L1); aoqi@6880: } aoqi@1: } aoqi@1: aoqi@1: // used registers : T0, T1, T2, T3, T8 aoqi@1: // T1 : flags aoqi@1: // T2 : off aoqi@1: // T3 : obj aoqi@1: // T8 : volatile bit aoqi@1: // see ConstantPoolCacheEntry::set_field for more info aoqi@1: void TemplateTable::putfield_or_static(int byte_no, bool is_static) { aoqi@1: transition(vtos, vtos); aoqi@1: aoqi@1: const Register cache = T3; aoqi@1: const Register index = T0; aoqi@1: const Register obj = T3; aoqi@1: const Register off = T2; aoqi@1: const Register flags = T1; aoqi@1: const Register bc = T3; aoqi@1: aoqi@1: resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); aoqi@6883: jvmti_post_field_mod(cache, index, is_static); aoqi@1: load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); aoqi@1: aoqi@1: Label notVolatile, Done; aoqi@1: __ move(AT, 1<nop(); aoqi@1: aoqi@1: __ pop(btos); aoqi@1: if (!is_static) { aoqi@6880: pop_and_check_object(obj); aoqi@1: } aoqi@1: __ dadd(AT, obj, off); aoqi@1: __ sb(FSR, AT, 0); aoqi@1: aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_bputfield, bc, off, true, byte_no); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ bind(notByte); aoqi@1: // itos aoqi@1: __ move(AT, itos); aoqi@1: __ bne(flags, AT, notInt); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ pop(itos); aoqi@1: if (!is_static) { aoqi@6880: pop_and_check_object(obj); aoqi@1: } aoqi@1: __ dadd(AT, obj, off); aoqi@1: __ sw(FSR, AT, 0); aoqi@1: aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_iputfield, bc, off, true, byte_no); aoqi@1: } aoqi@1: __ b(Done); aoqi@6880: __ delayed()->nop(); aoqi@1: __ bind(notInt); aoqi@1: // atos aoqi@1: __ move(AT, atos); aoqi@1: __ bne(flags, AT, notObj); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ pop(atos); aoqi@1: if (!is_static) { aoqi@6880: pop_and_check_object(obj); aoqi@1: } aoqi@1: aoqi@1: __ dadd(AT, obj, off); aoqi@1: __ store_heap_oop(Address(AT, 0), FSR); aoqi@1: __ store_check(obj); aoqi@1: aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_aputfield, bc, off, true, byte_no); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->nop(); aoqi@1: __ bind(notObj); aoqi@1: // ctos aoqi@1: __ move(AT, ctos); aoqi@1: __ bne(flags, AT, notChar); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ pop(ctos); aoqi@1: if (!is_static) { aoqi@6880: pop_and_check_object(obj); aoqi@1: } aoqi@1: __ dadd(AT, obj, off); aoqi@1: __ sh(FSR, AT, 0); aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_cputfield, bc, off, true, byte_no); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->nop(); aoqi@1: __ bind(notChar); aoqi@1: // stos aoqi@1: __ move(AT, stos); aoqi@1: __ bne(flags, AT, notShort); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ pop(stos); aoqi@1: if (!is_static) { aoqi@6880: pop_and_check_object(obj); aoqi@1: } aoqi@1: __ dadd(AT, obj, off); aoqi@1: __ sh(FSR, AT, 0); aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_sputfield, bc, off, true, byte_no); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->nop(); aoqi@1: __ bind(notShort); aoqi@1: // ltos aoqi@1: __ move(AT, ltos); aoqi@1: __ bne(flags, AT, notLong); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // FIXME: there is no simple method to load/store 64-bit data in a atomic operation aoqi@1: // we just ignore the volatile flag. aoqi@1: //Label notVolatileLong; aoqi@1: //__ beq(T1, R0, notVolatileLong); aoqi@1: //__ delayed()->nop(); aoqi@1: aoqi@1: //addent = 2 * wordSize; aoqi@1: // no need aoqi@1: //__ lw(FSR, SP, 0); aoqi@1: //__ lw(SSR, SP, 1 * wordSize); aoqi@1: //if (!is_static) { aoqi@6880: // __ lw(T3, SP, addent); aoqi@6880: // addent += 1 * wordSize; aoqi@6880: // __ verify_oop(T3); aoqi@1: //} aoqi@1: aoqi@1: //__ daddu(AT, T3, T2); aoqi@1: aoqi@1: // Replace with real volatile test aoqi@1: // NOTE : we assume that sdc1&ldc1 operate in 32-bit, this is true for Godson2 even in 64-bit kernel aoqi@1: // last modified by yjl 7/12/2005 aoqi@6880: //__ ldc1(FSF, SP, 0); aoqi@1: //__ sdc1(FSF, AT, 0); aoqi@1: //volatile_barrier(); aoqi@1: aoqi@1: // Don't rewrite volatile version aoqi@1: //__ b(notVolatile); aoqi@1: //__ delayed()->addiu(SP, SP, addent); aoqi@1: aoqi@1: //__ bind(notVolatileLong); aoqi@1: aoqi@1: //__ pop(ltos); // overwrites edx aoqi@6880: // __ lw(FSR, SP, 0 * wordSize); aoqi@6880: // __ lw(SSR, SP, 1 * wordSize); aoqi@6880: // __ daddi(SP, SP, 2*wordSize); aoqi@1: __ pop(ltos); aoqi@1: if (!is_static) { aoqi@6880: pop_and_check_object(obj); aoqi@1: } aoqi@1: __ dadd(AT, obj, off); aoqi@1: __ sd(FSR, AT, 0); aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_lputfield, bc, off, true, byte_no); aoqi@1: } aoqi@1: __ b(notVolatile); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ bind(notLong); aoqi@1: // ftos aoqi@1: __ move(AT, ftos); aoqi@1: __ bne(flags, AT, notFloat); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ pop(ftos); aoqi@1: if (!is_static) { aoqi@6880: pop_and_check_object(obj); aoqi@1: } aoqi@1: __ dadd(AT, obj, off); aoqi@1: __ swc1(FSF, AT, 0); aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_fputfield, bc, off, true, byte_no); aoqi@1: } aoqi@1: __ b(Done); aoqi@1: __ delayed()->nop(); aoqi@1: __ bind(notFloat); aoqi@1: // dtos aoqi@1: __ move(AT, dtos); aoqi@1: __ bne(flags, AT, notDouble); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ pop(dtos); aoqi@1: if (!is_static) { aoqi@6880: pop_and_check_object(obj); aoqi@1: } aoqi@1: __ dadd(AT, obj, off); aoqi@1: __ sdc1(FSF, AT, 0); aoqi@1: if (!is_static) { aoqi@1: patch_bytecode(Bytecodes::_fast_dputfield, bc, off, true, byte_no); aoqi@1: } aoqi@6880: aoqi@6880: #ifdef ASSERT aoqi@1: __ b(Done); aoqi@1: __ delayed()->nop(); aoqi@6880: aoqi@1: __ bind(notDouble); aoqi@1: __ stop("Bad state"); aoqi@6880: #endif aoqi@1: aoqi@1: __ bind(Done); aoqi@1: aoqi@1: // Check for volatile store aoqi@1: __ beq(T8, R0, notVolatile); aoqi@1: __ delayed()->nop(); aoqi@1: volatile_barrier( ); aoqi@1: __ bind(notVolatile); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::putfield(int byte_no) { aoqi@1: putfield_or_static(byte_no, false); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::putstatic(int byte_no) { aoqi@1: putfield_or_static(byte_no, true); aoqi@1: } aoqi@1: aoqi@1: // used registers : T1, T2, T3 aoqi@1: // T1 : cp_entry aoqi@1: // T2 : obj aoqi@1: // T3 : value pointer aoqi@1: void TemplateTable::jvmti_post_fast_field_mod() { aoqi@6880: if (JvmtiExport::can_post_field_modification()) { aoqi@6880: // Check to see if a field modification watch has been set before aoqi@6880: // we take the time to call into the VM. aoqi@6880: Label L2; aoqi@6883: //kill AT, T1, T2, T3, T9 aoqi@6883: Register tmp1 = T2; aoqi@6883: Register tmp2 = T1; aoqi@6883: Register tmp3 = T3; aoqi@6883: Register tmp4 = T9; aoqi@6880: __ li(AT, JvmtiExport::get_field_modification_count_addr()); aoqi@6883: __ lw(tmp3, AT, 0); aoqi@6883: __ beq(tmp3, R0, L2); aoqi@6880: __ delayed()->nop(); aoqi@6883: __ pop_ptr(tmp1); aoqi@6883: __ verify_oop(tmp1); aoqi@6883: __ push_ptr(tmp1); aoqi@6880: switch (bytecode()) { // load values into the jvalue object aoqi@6883: case Bytecodes::_fast_aputfield: __ push_ptr(FSR); break; aoqi@6883: case Bytecodes::_fast_bputfield: // fall through aoqi@6883: case Bytecodes::_fast_sputfield: // fall through aoqi@6883: case Bytecodes::_fast_cputfield: // fall through aoqi@6883: case Bytecodes::_fast_iputfield: __ push_i(FSR); break; aoqi@6883: case Bytecodes::_fast_dputfield: __ push_d(FSF); break; aoqi@6883: case Bytecodes::_fast_fputfield: __ push_f(); break; aoqi@6883: case Bytecodes::_fast_lputfield: __ push_l(FSR); break; aoqi@6880: default: ShouldNotReachHere(); aoqi@6880: } aoqi@6883: __ move(tmp3, SP); aoqi@6880: // access constant pool cache entry aoqi@6883: __ get_cache_entry_pointer_at_bcp(tmp2, FSR, 1); aoqi@6883: __ verify_oop(tmp1); aoqi@6883: // tmp1: object pointer copied above aoqi@6883: // tmp2: cache entry pointer aoqi@6883: // tmp3: jvalue object on the stack aoqi@6883: __ call_VM(NOREG, aoqi@6883: CAST_FROM_FN_PTR(address, aoqi@6883: InterpreterRuntime::post_field_modification), aoqi@6883: tmp1, tmp2, tmp3); aoqi@6883: aoqi@6883: switch (bytecode()) { // restore tos values aoqi@6883: case Bytecodes::_fast_aputfield: __ pop_ptr(FSR); break; aoqi@6883: case Bytecodes::_fast_bputfield: // fall through aoqi@6883: case Bytecodes::_fast_sputfield: // fall through aoqi@6883: case Bytecodes::_fast_cputfield: // fall through aoqi@6883: case Bytecodes::_fast_iputfield: __ pop_i(FSR); break; aoqi@6883: case Bytecodes::_fast_dputfield: __ pop_d(); break; aoqi@6883: case Bytecodes::_fast_fputfield: __ pop_f(); break; aoqi@6883: case Bytecodes::_fast_lputfield: __ pop_l(FSR); break; aoqi@6883: } aoqi@6880: __ bind(L2); aoqi@6880: } aoqi@1: } aoqi@1: aoqi@1: // used registers : T2, T3, T1 aoqi@1: // T2 : index & off & field address aoqi@1: // T3 : cache & obj aoqi@1: // T1 : flags aoqi@1: void TemplateTable::fast_storefield(TosState state) { aoqi@1: transition(state, vtos); aoqi@1: aoqi@1: ByteSize base = ConstantPoolCache::base_offset(); aoqi@1: aoqi@1: jvmti_post_fast_field_mod(); aoqi@1: aoqi@1: // access constant pool cache aoqi@1: __ get_cache_and_index_at_bcp(T3, T2, 1); aoqi@1: aoqi@1: // test for volatile with edx but edx is tos register for lputfield. aoqi@6880: __ dsll(AT, T2, Address::times_8); aoqi@1: __ dadd(AT, T3, AT); aoqi@1: __ ld(T1, AT, in_bytes(base + ConstantPoolCacheEntry::flags_offset())); aoqi@1: aoqi@1: // replace index with field offset from cache entry aoqi@1: __ ld(T2, AT, in_bytes(base + ConstantPoolCacheEntry::f2_offset())); aoqi@1: aoqi@1: // Doug Lea believes this is not needed with current Sparcs (TSO) and Intel (PSO). aoqi@1: // volatile_barrier( ); aoqi@1: aoqi@1: Label notVolatile, Done; aoqi@1: // Check for volatile store aoqi@1: __ move(AT, 1<nop(); aoqi@1: aoqi@1: aoqi@1: // Get object from stack aoqi@1: pop_and_check_object(T3); aoqi@6880: aoqi@6880: // field address aoqi@1: __ dadd(T2, T3, T2); aoqi@1: aoqi@1: // access field aoqi@1: switch (bytecode()) { aoqi@6880: case Bytecodes::_fast_bputfield: aoqi@1: __ sb(FSR, T2, 0); aoqi@1: break; aoqi@1: case Bytecodes::_fast_sputfield: // fall through aoqi@6880: case Bytecodes::_fast_cputfield: aoqi@1: __ sh(FSR, T2, 0); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_iputfield: aoqi@1: __ sw(FSR, T2, 0); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_lputfield: aoqi@1: __ sd(FSR, T2, 0 * wordSize); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_fputfield: aoqi@1: __ swc1(FSF, T2, 0); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_dputfield: aoqi@1: __ sdc1(FSF, T2, 0 * wordSize); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_aputfield: aoqi@1: __ store_heap_oop(Address(T2, 0), FSR); aoqi@1: __ store_check(T3); aoqi@1: break; aoqi@1: default: aoqi@1: ShouldNotReachHere(); aoqi@1: } aoqi@1: aoqi@1: Label done; aoqi@1: volatile_barrier( ); aoqi@1: __ b(done); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // Same code as above, but don't need edx to test for volatile. aoqi@1: __ bind(notVolatile); aoqi@1: pop_and_check_object(T3); aoqi@1: //get the field address aoqi@1: __ dadd(T2, T3, T2); aoqi@1: aoqi@1: // access field aoqi@1: switch (bytecode()) { aoqi@6880: case Bytecodes::_fast_bputfield: aoqi@6880: __ sb(FSR, T2, 0); aoqi@1: break; aoqi@1: case Bytecodes::_fast_sputfield: // fall through aoqi@6880: case Bytecodes::_fast_cputfield: aoqi@1: __ sh(FSR, T2, 0); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_iputfield: aoqi@1: __ sw(FSR, T2, 0); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_lputfield: aoqi@1: __ sd(FSR, T2, 0 * wordSize); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_fputfield: aoqi@1: __ swc1(FSF, T2, 0); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_dputfield: aoqi@1: __ sdc1(FSF, T2, 0 * wordSize); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_aputfield: aoqi@1: //add for compressedoops aoqi@1: __ store_heap_oop(Address(T2, 0), FSR); aoqi@1: __ store_check(T3); aoqi@1: break; aoqi@1: default: aoqi@1: ShouldNotReachHere(); aoqi@1: } aoqi@1: __ bind(done); aoqi@1: } aoqi@1: aoqi@1: // used registers : T2, T3, T1 aoqi@1: // T3 : cp_entry & cache aoqi@1: // T2 : index & offset aoqi@1: void TemplateTable::fast_accessfield(TosState state) { aoqi@1: transition(atos, state); aoqi@1: aoqi@1: // do the JVMTI work here to avoid disturbing the register state below aoqi@1: if (JvmtiExport::can_post_field_access()) { aoqi@1: // Check to see if a field access watch has been set before we take aoqi@1: // the time to call into the VM. aoqi@1: Label L1; aoqi@1: __ li(AT, (intptr_t)JvmtiExport::get_field_access_count_addr()); aoqi@1: __ lw(T3, AT, 0); aoqi@1: __ beq(T3, R0, L1); aoqi@1: __ delayed()->nop(); aoqi@1: // access constant pool cache entry aoqi@1: __ get_cache_entry_pointer_at_bcp(T3, T1, 1); aoqi@1: __ move(TSR, FSR); aoqi@1: __ verify_oop(FSR); aoqi@1: // FSR: object pointer copied above aoqi@1: // T3: cache entry pointer aoqi@6880: __ call_VM(NOREG, aoqi@6880: CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), aoqi@6880: FSR, T3); aoqi@1: __ move(FSR, TSR); aoqi@1: __ bind(L1); aoqi@1: } aoqi@1: aoqi@1: // access constant pool cache aoqi@1: __ get_cache_and_index_at_bcp(T3, T2, 1); aoqi@1: // replace index with field offset from cache entry aoqi@1: __ dsll(AT, T2, Address::times_8); aoqi@1: __ dadd(AT, T3, AT); aoqi@6880: __ ld(T2, AT, in_bytes(ConstantPoolCache::base_offset() aoqi@6880: + ConstantPoolCacheEntry::f2_offset())); aoqi@1: aoqi@1: // eax: object aoqi@1: __ verify_oop(FSR); aoqi@1: __ null_check(FSR); aoqi@1: // field addresses aoqi@1: __ dadd(FSR, FSR, T2); aoqi@1: aoqi@1: // access field aoqi@1: switch (bytecode()) { aoqi@6880: case Bytecodes::_fast_bgetfield: aoqi@1: __ lb(FSR, FSR, 0); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_sgetfield: aoqi@1: __ lh(FSR, FSR, 0); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_cgetfield: aoqi@1: __ lhu(FSR, FSR, 0); aoqi@1: break; aoqi@1: case Bytecodes::_fast_igetfield: aoqi@1: __ lw(FSR, FSR, 0); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_lgetfield: aoqi@6880: __ stop("should not be rewritten"); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_fgetfield: aoqi@1: __ lwc1(FSF, FSR, 0); aoqi@1: break; aoqi@6880: case Bytecodes::_fast_dgetfield: aoqi@1: __ ldc1(FSF, FSR, 0); aoqi@1: break; aoqi@1: case Bytecodes::_fast_agetfield: aoqi@1: //add for compressedoops aoqi@1: __ load_heap_oop(FSR, Address(FSR, 0)); aoqi@1: __ verify_oop(FSR); aoqi@1: break; aoqi@1: default: aoqi@1: ShouldNotReachHere(); aoqi@1: } aoqi@1: aoqi@1: // Doug Lea believes this is not needed with current Sparcs(TSO) and Intel(PSO) aoqi@1: // volatile_barrier( ); aoqi@1: } aoqi@1: aoqi@1: // generator for _fast_iaccess_0, _fast_aaccess_0, _fast_faccess_0 aoqi@1: // used registers : T1, T2, T3, T1 aoqi@1: // T1 : obj & field address aoqi@1: // T2 : off aoqi@1: // T3 : cache aoqi@1: // T1 : index aoqi@1: void TemplateTable::fast_xaccess(TosState state) { aoqi@1: transition(vtos, state); aoqi@6880: aoqi@1: // get receiver aoqi@1: __ ld(T1, aaddress(0)); aoqi@1: // access constant pool cache aoqi@1: __ get_cache_and_index_at_bcp(T3, T2, 2); aoqi@1: __ dsll(AT, T2, Address::times_8); aoqi@1: __ dadd(AT, T3, AT); aoqi@6880: __ ld(T2, AT, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset())); aoqi@6880: aoqi@6880: // make sure exception is reported in correct bcp range (getfield is aoqi@6880: // next instruction) aoqi@1: __ daddi(BCP, BCP, 1); aoqi@1: __ null_check(T1); aoqi@1: __ dadd(T1, T1, T2); aoqi@1: aoqi@1: if (state == itos) { aoqi@1: __ lw(FSR, T1, 0); aoqi@1: } else if (state == atos) { aoqi@1: __ load_heap_oop(FSR, Address(T1, 0)); aoqi@1: __ verify_oop(FSR); aoqi@1: } else if (state == ftos) { aoqi@1: __ lwc1(FSF, T1, 0); aoqi@1: } else { aoqi@1: ShouldNotReachHere(); aoqi@1: } aoqi@1: __ daddi(BCP, BCP, -1); aoqi@1: } aoqi@1: aoqi@6880: aoqi@6880: aoqi@6880: //----------------------------------------------------------------------------- aoqi@1: // Calls aoqi@1: aoqi@6880: void TemplateTable::count_calls(Register method, Register temp) { aoqi@6880: // implemented elsewhere aoqi@6880: ShouldNotReachHere(); aoqi@1: } aoqi@1: aoqi@1: // method, index, recv, flags: T1, T2, T3, T1 aoqi@1: // byte_no = 2 for _invokevirtual, 1 else aoqi@1: // T0 : return address aoqi@6880: // get the method & index of the invoke, and push the return address of aoqi@1: // the invoke(first word in the frame) aoqi@1: // this address is where the return code jmp to. aoqi@1: // NOTE : this method will set T3&T1 as recv&flags aoqi@1: void TemplateTable::prepare_invoke(int byte_no, aoqi@6880: Register method, // linked method (or i-klass) aoqi@6880: Register index, // itable index, MethodType, etc. aoqi@6880: Register recv, // if caller wants to see it aoqi@6880: Register flags // if caller wants to test it aoqi@6880: ) { aoqi@1: // determine flags aoqi@1: const Bytecodes::Code code = bytecode(); aoqi@1: const bool is_invokeinterface = code == Bytecodes::_invokeinterface; aoqi@1: const bool is_invokedynamic = code == Bytecodes::_invokedynamic; aoqi@1: const bool is_invokehandle = code == Bytecodes::_invokehandle; aoqi@1: const bool is_invokevirtual = code == Bytecodes::_invokevirtual; aoqi@1: const bool is_invokespecial = code == Bytecodes::_invokespecial; aoqi@1: const bool load_receiver = (recv != noreg); aoqi@1: const bool save_flags = (flags != noreg); aoqi@1: assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic),""); aoqi@1: assert(save_flags == (is_invokeinterface || is_invokevirtual), "need flags for vfinal"); aoqi@1: assert(flags == noreg || flags == T1, "error flags reg."); aoqi@1: assert(recv == noreg || recv == T3, "error recv reg."); aoqi@6880: aoqi@1: // setup registers & access constant pool cache aoqi@1: if(recv == noreg) recv = T3; aoqi@1: if(flags == noreg) flags = T1; aoqi@1: assert_different_registers(method, index, recv, flags); aoqi@1: aoqi@1: // save 'interpreter return address' aoqi@1: __ save_bcp(); aoqi@1: aoqi@1: load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic); aoqi@6880: aoqi@1: if (is_invokedynamic || is_invokehandle) { aoqi@1: Label L_no_push; aoqi@1: __ move(AT, (1 << ConstantPoolCacheEntry::has_appendix_shift)); aoqi@1: __ andr(AT, AT, flags); aoqi@1: __ beq(AT, R0, L_no_push); aoqi@1: __ delayed()->nop(); aoqi@1: // Push the appendix as a trailing parameter. aoqi@1: // This must be done before we get the receiver, aoqi@1: // since the parameter_size includes it. aoqi@1: Register tmp = SSR; aoqi@1: __ push(tmp); aoqi@1: __ move(tmp, index); aoqi@1: assert(ConstantPoolCacheEntry::_indy_resolved_references_appendix_offset == 0, "appendix expected at index+0"); aoqi@1: __ load_resolved_reference_at_index(index, tmp); aoqi@1: __ pop(tmp); aoqi@1: __ push(index); // push appendix (MethodType, CallSite, etc.) aoqi@1: __ bind(L_no_push); aoqi@1: } aoqi@1: aoqi@6880: // load receiver if needed (after appendix is pushed so parameter size is correct) aoqi@6880: // Note: no return address pushed yet aoqi@1: if (load_receiver) { aoqi@6880: __ move(AT, ConstantPoolCacheEntry::parameter_size_mask); aoqi@6880: __ andr(recv, flags, AT); aoqi@6880: // 2014/07/31 Fu: Since we won't push RA on stack, no_return_pc_pushed_yet should be 0. aoqi@6880: const int no_return_pc_pushed_yet = 0; // argument slot correction before we push return address aoqi@6880: const int receiver_is_at_end = -1; // back off one slot to get receiver aoqi@6880: Address recv_addr = __ argument_address(recv, no_return_pc_pushed_yet + receiver_is_at_end); aoqi@6880: __ ld(recv, recv_addr); aoqi@6880: __ verify_oop(recv); aoqi@1: } aoqi@1: if(save_flags) { aoqi@1: __ move(BCP, flags); aoqi@1: } aoqi@6880: aoqi@1: // compute return type aoqi@1: __ dsrl(flags, flags, ConstantPoolCacheEntry::tos_state_shift); aoqi@1: __ andi(flags, flags, 0xf); aoqi@1: aoqi@1: // Make sure we don't need to mask flags for tos_state_shift after the above shift aoqi@1: ConstantPoolCacheEntry::verify_tos_state_shift(); aoqi@1: // load return address aoqi@6880: { aoqi@1: const address table = (address) Interpreter::invoke_return_entry_table_for(code); aoqi@1: __ li(AT, (long)table); aoqi@1: __ dsll(flags, flags, LogBytesPerWord); aoqi@1: __ dadd(AT, AT, flags); aoqi@1: __ ld(RA, AT, 0); aoqi@1: } aoqi@6880: aoqi@1: if (save_flags) { aoqi@1: __ move(flags, BCP); aoqi@1: __ restore_bcp(); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: // used registers : T0, T3, T1, T2 aoqi@1: // T3 : recv, this two register using convention is by prepare_invoke aoqi@1: // T1 : flags, klass aoqi@1: // Rmethod : method, index must be Rmethod aoqi@6880: void TemplateTable::invokevirtual_helper(Register index, aoqi@6880: Register recv, aoqi@6880: Register flags) { aoqi@1: aoqi@1: assert_different_registers(index, recv, flags, T2); aoqi@1: aoqi@1: // Test for an invoke of a final method aoqi@1: Label notFinal; aoqi@1: __ move(AT, (1 << ConstantPoolCacheEntry::is_vfinal_shift)); aoqi@1: __ andr(AT, flags, AT); aoqi@1: __ beq(AT, R0, notFinal); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: Register method = index; // method must be Rmethod aoqi@1: assert(method == Rmethod, "methodOop must be Rmethod for interpreter calling convention"); aoqi@1: aoqi@1: // do the call - the index is actually the method to call aoqi@6880: // the index is indeed methodOop, for this is vfinal, aoqi@1: // see ConstantPoolCacheEntry::set_method for more info aoqi@1: aoqi@1: __ verify_oop(method); aoqi@1: aoqi@1: // It's final, need a null check here! aoqi@1: __ null_check(recv); aoqi@1: aoqi@1: // profile this call aoqi@1: __ profile_final_call(T2); aoqi@1: aoqi@6880: // 2014/11/24 Fu aoqi@1: // T2: tmp, used for mdp aoqi@1: // method: callee aoqi@1: // T9: tmp aoqi@6880: // is_virtual: true aoqi@1: __ profile_arguments_type(T2, method, T9, true); aoqi@1: aoqi@1: __ jump_from_interpreted(method, T2); aoqi@1: aoqi@1: __ bind(notFinal); aoqi@1: aoqi@1: // get receiver klass aoqi@1: __ null_check(recv, oopDesc::klass_offset_in_bytes()); aoqi@1: __ load_klass(T2, recv); aoqi@1: __ verify_oop(T2); aoqi@6880: aoqi@1: // profile this call aoqi@1: __ profile_virtual_call(T2, T0, T1); aoqi@1: aoqi@1: // get target methodOop & entry point aoqi@6880: const int base = InstanceKlass::vtable_start_offset() * wordSize; fujie@211: assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below"); fujie@211: __ dsll(AT, index, Address::times_ptr); fujie@211: // T2: receiver aoqi@1: __ dadd(AT, T2, AT); aoqi@6880: //this is a ualign read aoqi@1: __ ld(method, AT, base + vtableEntry::method_offset_in_bytes()); fujie@211: __ profile_arguments_type(T2, method, T9, true); aoqi@1: __ jump_from_interpreted(method, T2); aoqi@1: aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::invokevirtual(int byte_no) { aoqi@1: transition(vtos, vtos); aoqi@1: assert(byte_no == f2_byte, "use this argument"); aoqi@1: prepare_invoke(byte_no, Rmethod, NOREG, T3, T1); aoqi@1: // now recv & flags in T3, T1 aoqi@1: invokevirtual_helper(Rmethod, T3, T1); aoqi@1: } aoqi@1: aoqi@1: // T9 : entry aoqi@1: // Rmethod : method aoqi@1: void TemplateTable::invokespecial(int byte_no) { aoqi@1: transition(vtos, vtos); aoqi@1: assert(byte_no == f1_byte, "use this argument"); aoqi@1: prepare_invoke(byte_no, Rmethod, NOREG, T3); aoqi@1: // now recv & flags in T3, T1 aoqi@1: __ verify_oop(T3); aoqi@1: __ null_check(T3); aoqi@1: __ profile_call(T9); aoqi@1: aoqi@6880: // 2014/11/24 Fu aoqi@1: // T8: tmp, used for mdp aoqi@1: // Rmethod: callee aoqi@1: // T9: tmp aoqi@6880: // is_virtual: false aoqi@1: __ profile_arguments_type(T8, Rmethod, T9, false); aoqi@1: aoqi@1: __ jump_from_interpreted(Rmethod, T9); aoqi@1: __ move(T0, T3);//aoqi ? aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::invokestatic(int byte_no) { aoqi@1: transition(vtos, vtos); aoqi@1: assert(byte_no == f1_byte, "use this argument"); aoqi@1: prepare_invoke(byte_no, Rmethod, NOREG); aoqi@1: __ verify_oop(Rmethod); aoqi@1: aoqi@1: __ profile_call(T9); aoqi@1: aoqi@6880: // 2014/11/24 Fu aoqi@1: // T8: tmp, used for mdp aoqi@1: // Rmethod: callee aoqi@1: // T9: tmp aoqi@6880: // is_virtual: false aoqi@1: __ profile_arguments_type(T8, Rmethod, T9, false); aoqi@1: aoqi@1: __ jump_from_interpreted(Rmethod, T9); aoqi@1: } aoqi@1: aoqi@6880: // i have no idea what to do here, now. for future change. FIXME. aoqi@1: void TemplateTable::fast_invokevfinal(int byte_no) { aoqi@6880: transition(vtos, vtos); aoqi@6880: assert(byte_no == f2_byte, "use this argument"); aoqi@6880: __ stop("fast_invokevfinal not used on mips64"); aoqi@1: } aoqi@1: aoqi@1: // used registers : T0, T1, T2, T3, T1, A7 aoqi@1: // T0 : itable, vtable, entry aoqi@1: // T1 : interface aoqi@1: // T3 : receiver aoqi@1: // T1 : flags, klass aoqi@1: // Rmethod : index, method, this is required by interpreter_entry aoqi@1: void TemplateTable::invokeinterface(int byte_no) { aoqi@1: transition(vtos, vtos); aoqi@1: //this method will use T1-T4 and T0 aoqi@1: assert(byte_no == f1_byte, "use this argument"); aoqi@1: prepare_invoke(byte_no, T2, Rmethod, T3, T1); aoqi@1: // T2: Interface aoqi@1: // Rmethod: index aoqi@6880: // T3: receiver aoqi@1: // T1: flags aoqi@6880: aoqi@6880: // Special case of invokeinterface called for virtual method of aoqi@6880: // java.lang.Object. See cpCacheOop.cpp for details. aoqi@6880: // This code isn't produced by javac, but could be produced by aoqi@6880: // another compliant java compiler. aoqi@1: Label notMethod; aoqi@1: __ move(AT, (1 << ConstantPoolCacheEntry::is_forced_virtual_shift)); aoqi@1: __ andr(AT, T1, AT); aoqi@1: __ beq(AT, R0, notMethod); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: invokevirtual_helper(Rmethod, T3, T1); aoqi@1: __ bind(notMethod); aoqi@1: // Get receiver klass into T1 - also a null check aoqi@1: //add for compressedoops aoqi@1: __ load_klass(T1, T3); aoqi@1: __ verify_oop(T1); aoqi@1: aoqi@1: // profile this call aoqi@1: __ profile_virtual_call(T1, T0, FSR); aoqi@1: aoqi@1: // Compute start of first itableOffsetEntry (which is at the end of the vtable) aoqi@1: // TODO: x86 add a new method lookup_interface_method // LEE aoqi@6880: const int base = InstanceKlass::vtable_start_offset() * wordSize; aoqi@1: assert(vtableEntry::size() * wordSize == 8, "adjust the scaling in the code below"); aoqi@1: __ lw(AT, T1, InstanceKlass::vtable_length_offset() * wordSize); aoqi@1: __ dsll(AT, AT, Address::times_8); aoqi@1: __ dadd(T0, T1, AT); aoqi@1: __ daddi(T0, T0, base); aoqi@1: if (HeapWordsPerLong > 1) { aoqi@1: // Round up to align_object_offset boundary aoqi@1: __ round_to(T0, BytesPerLong); aoqi@1: } aoqi@1: // now T0 is the begin of the itable aoqi@1: aoqi@1: Label entry, search, interface_ok; aoqi@1: aoqi@6880: ///__ jmp(entry); aoqi@1: __ b(entry); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ bind(search); aoqi@1: __ increment(T0, itableOffsetEntry::size() * wordSize); aoqi@1: aoqi@1: __ bind(entry); aoqi@1: aoqi@1: // Check that the entry is non-null. A null entry means that the receiver aoqi@1: // class doesn't implement the interface, and wasn't the same as the aoqi@1: // receiver class checked when the interface was resolved. aoqi@1: __ ld(AT, T0, itableOffsetEntry::interface_offset_in_bytes()); aoqi@1: __ bne(AT, R0, interface_ok); aoqi@1: __ delayed()->nop(); aoqi@1: // throw exception aoqi@1: // the call_VM checks for exception, so we should never return here. aoqi@1: aoqi@6880: //__ pop();//FIXME here, aoqi@6880: // pop return address (pushed by prepare_invoke). aoqi@1: // no need now, we just save the value in RA now aoqi@1: aoqi@1: __ call_VM(NOREG, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); aoqi@1: __ should_not_reach_here(); aoqi@1: aoqi@1: __ bind(interface_ok); aoqi@6880: //NOTICE here, no pop as x86 do aoqi@1: __ bne(AT, T2, search); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // now we get vtable of the interface aoqi@1: __ ld(T0, T0, itableOffsetEntry::offset_offset_in_bytes()); aoqi@1: __ daddu(T0, T1, T0); aoqi@1: assert(itableMethodEntry::size() * wordSize == 8, "adjust the scaling in the code below"); aoqi@1: __ dsll(AT, Rmethod, Address::times_8); aoqi@1: __ daddu(AT, T0, AT); aoqi@1: // now we get the method aoqi@1: __ ld(Rmethod, AT, 0); aoqi@1: // Rnext: methodOop to call aoqi@1: // T3: receiver aoqi@1: // Check for abstract method error aoqi@1: // Note: This should be done more efficiently via a throw_abstract_method_error aoqi@1: // interpreter entry point and a conditional jump to it in case of a null aoqi@1: // method. aoqi@6880: { aoqi@1: Label L; aoqi@1: __ bne(Rmethod, R0, L); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // throw exception aoqi@1: // note: must restore interpreter registers to canonical aoqi@1: // state for exception handling to work correctly! aoqi@1: ///__ popl(ebx); // pop return address (pushed by prepare_invoke) aoqi@6880: //__ restore_bcp(); // esi must be correct for exception handler aoqi@1: //(was destroyed) aoqi@6880: //__ restore_locals(); // make sure locals pointer aoqi@1: //is correct as well (was destroyed) aoqi@6880: ///__ call_VM(noreg, CAST_FROM_FN_PTR(address, aoqi@1: //InterpreterRuntime::throw_AbstractMethodError)); aoqi@1: __ call_VM(NOREG, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); aoqi@1: // the call_VM checks for exception, so we should never return here. aoqi@1: __ should_not_reach_here(); aoqi@1: __ bind(L); aoqi@1: } aoqi@6880: aoqi@6880: // 2014/11/24 Fu aoqi@1: // T8: tmp, used for mdp aoqi@1: // Rmethod: callee aoqi@1: // T9: tmp aoqi@1: // is_virtual: true aoqi@1: __ profile_arguments_type(T8, Rmethod, T9, true); aoqi@1: aoqi@1: __ jump_from_interpreted(Rmethod, T9); aoqi@1: } aoqi@1: aoqi@6880: aoqi@1: void TemplateTable::invokehandle(int byte_no) { aoqi@1: transition(vtos, vtos); aoqi@1: assert(byte_no == f1_byte, "use this argument"); aoqi@1: const Register T2_method = Rmethod; aoqi@1: const Register FSR_mtype = FSR; aoqi@1: const Register T3_recv = T3; aoqi@1: aoqi@1: if (!EnableInvokeDynamic) { aoqi@1: // rewriter does not generate this bytecode aoqi@1: __ should_not_reach_here(); aoqi@1: return; aoqi@1: } aoqi@6880: aoqi@1: prepare_invoke(byte_no, T2_method, FSR_mtype, T3_recv); aoqi@1: //??__ verify_method_ptr(T2_method); aoqi@1: __ verify_oop(T3_recv); aoqi@1: __ null_check(T3_recv); aoqi@6880: aoqi@1: // rax: MethodType object (from cpool->resolved_references[f1], if necessary) aoqi@1: // rbx: MH.invokeExact_MT method (from f2) aoqi@6880: aoqi@1: // Note: rax_mtype is already pushed (if necessary) by prepare_invoke aoqi@6880: aoqi@1: // FIXME: profile the LambdaForm also aoqi@1: __ profile_final_call(T9); aoqi@1: aoqi@6880: // 2014/11/24 Fu aoqi@1: // T8: tmp, used for mdp aoqi@1: // T2_method: callee aoqi@1: // T9: tmp aoqi@1: // is_virtual: true aoqi@1: __ profile_arguments_type(T8, T2_method, T9, true); aoqi@6880: aoqi@1: __ jump_from_interpreted(T2_method, T9); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::invokedynamic(int byte_no) { aoqi@1: transition(vtos, vtos); aoqi@1: assert(byte_no == f1_byte, "use this argument"); aoqi@6880: aoqi@1: if (!EnableInvokeDynamic) { aoqi@1: // We should not encounter this bytecode if !EnableInvokeDynamic. aoqi@1: // The verifier will stop it. However, if we get past the verifier, aoqi@1: // this will stop the thread in a reasonable way, without crashing the JVM. aoqi@1: __ call_VM(noreg, CAST_FROM_FN_PTR(address, aoqi@1: InterpreterRuntime::throw_IncompatibleClassChangeError)); aoqi@1: // the call_VM checks for exception, so we should never return here. aoqi@1: __ should_not_reach_here(); aoqi@1: return; aoqi@1: } aoqi@6880: aoqi@1: //const Register Rmethod = T2; aoqi@1: const Register T2_callsite = T2; aoqi@6880: aoqi@1: prepare_invoke(byte_no, Rmethod, T2_callsite); aoqi@6880: aoqi@1: // rax: CallSite object (from cpool->resolved_references[f1]) aoqi@1: // rbx: MH.linkToCallSite method (from f2) aoqi@6880: aoqi@1: // Note: rax_callsite is already pushed by prepare_invoke aoqi@1: // %%% should make a type profile for any invokedynamic that takes a ref argument aoqi@1: // profile this call aoqi@1: __ profile_call(T9); aoqi@1: aoqi@6880: // 2014/11/24 Fu aoqi@1: // T8: tmp, used for mdp aoqi@1: // Rmethod: callee aoqi@1: // T9: tmp aoqi@6880: // is_virtual: false aoqi@1: __ profile_arguments_type(T8, Rmethod, T9, false); aoqi@1: aoqi@1: __ verify_oop(T2_callsite); aoqi@6880: aoqi@1: __ jump_from_interpreted(Rmethod, T9); aoqi@1: } aoqi@1: aoqi@6880: //----------------------------------------------------------------------------- aoqi@1: // Allocation aoqi@1: // T1 : tags & buffer end & thread aoqi@1: // T2 : object end aoqi@1: // T3 : klass aoqi@1: // T1 : object size aoqi@1: // A1 : cpool aoqi@1: // A2 : cp index aoqi@1: // return object in FSR aoqi@1: void TemplateTable::_new() { aoqi@1: transition(vtos, atos); fujie@6884: __ get_unsigned_2_byte_index_at_bcp(A2, 1); aoqi@1: aoqi@1: Label slow_case; aoqi@1: Label done; aoqi@1: Label initialize_header; aoqi@6880: Label initialize_object; // including clearing the fields aoqi@1: Label allocate_shared; aoqi@1: aoqi@1: // get InstanceKlass in T3 aoqi@1: __ get_cpool_and_tags(A1, T1); fujie@6884: aoqi@1: __ dsll(AT, A2, Address::times_8); fujie@6884: if (UseLoongsonISA && Assembler::is_simm(sizeof(ConstantPool), 8)) { fujie@6884: __ gsldx(T3, A1, AT, sizeof(ConstantPool)); fujie@6884: } else { fujie@6884: __ dadd(AT, A1, AT); fujie@6884: __ ld(T3, AT, sizeof(ConstantPool)); fujie@6884: } aoqi@1: aoqi@6880: // make sure the class we're about to instantiate has been resolved. aoqi@1: // Note: slow_case does a pop of stack, which is why we loaded class/pushed above aoqi@1: const int tags_offset = Array::base_offset_in_bytes(); fujie@6884: if (UseLoongsonISA && Assembler::is_simm(tags_offset, 8)) { fujie@6884: __ gslbx(AT, T1, A2, tags_offset); fujie@6884: } else { fujie@6884: __ dadd(T1, T1, A2); fujie@6884: __ lb(AT, T1, tags_offset); fujie@6884: } aoqi@1: __ daddiu(AT, AT, - (int)JVM_CONSTANT_Class); aoqi@1: __ bne(AT, R0, slow_case); fujie@6884: //__ delayed()->nop(); aoqi@1: aoqi@6880: aoqi@6880: // make sure klass is initialized & doesn't have finalizer aoqi@1: // make sure klass is fully initialized Jin@2: __ lhu(T1, T3, in_bytes(InstanceKlass::init_state_offset())); aoqi@1: __ daddiu(AT, T1, - (int)InstanceKlass::fully_initialized); aoqi@1: __ bne(AT, R0, slow_case); fujie@6884: //__ delayed()->nop(); aoqi@1: aoqi@1: // has_finalizer fujie@6884: __ lw(T0, T3, in_bytes(Klass::layout_helper_offset()) ); fujie@6884: __ andi(AT, T0, Klass::_lh_instance_slow_path_bit); aoqi@1: __ bne(AT, R0, slow_case); fujie@6884: //__ delayed()->nop(); aoqi@1: aoqi@1: // Allocate the instance aoqi@1: // 1) Try to allocate in the TLAB aoqi@1: // 2) if fail and the object is large allocate in the shared Eden aoqi@1: // 3) if the above fails (or is not applicable), go to a slow case aoqi@1: // (creates a new TLAB, etc.) aoqi@1: aoqi@1: const bool allow_shared_alloc = aoqi@1: Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode; aoqi@1: aoqi@1: if (UseTLAB) { aoqi@1: #ifndef OPT_THREAD aoqi@1: const Register thread = T8; aoqi@1: __ get_thread(thread); aoqi@1: #else aoqi@1: const Register thread = TREG; aoqi@1: #endif aoqi@1: // get tlab_top aoqi@1: __ ld(FSR, thread, in_bytes(JavaThread::tlab_top_offset())); aoqi@1: // get tlab_end aoqi@1: __ ld(AT, thread, in_bytes(JavaThread::tlab_end_offset())); fujie@6884: __ dadd(T2, FSR, T0); aoqi@1: __ slt(AT, AT, T2); aoqi@1: __ bne(AT, R0, allow_shared_alloc ? allocate_shared : slow_case); aoqi@1: __ delayed()->nop(); aoqi@1: __ sd(T2, thread, in_bytes(JavaThread::tlab_top_offset())); aoqi@1: aoqi@1: if (ZeroTLAB) { aoqi@1: // the fields have been already cleared fujie@6884: __ beq(R0, R0, initialize_header); aoqi@1: } else { aoqi@1: // initialize both the header and fields fujie@6884: __ beq(R0, R0, initialize_object); aoqi@1: } aoqi@1: __ delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: // Allocation in the shared Eden , if allowed aoqi@1: // T0 : instance size in words aoqi@6880: if(allow_shared_alloc){ aoqi@1: __ bind(allocate_shared); aoqi@6880: aoqi@1: Label retry; aoqi@1: Address heap_top(T1); fujie@6884: __ set64(T1, (long)Universe::heap()->top_addr()); aoqi@1: __ ld(FSR, heap_top); fujie@6884: aoqi@1: __ bind(retry); fujie@6884: __ set64(AT, (long)Universe::heap()->end_addr()); fujie@6884: __ ld(AT, AT, 0); aoqi@1: __ dadd(T2, FSR, T0); aoqi@1: __ slt(AT, AT, T2); aoqi@1: __ bne(AT, R0, slow_case); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // Compare FSR with the top addr, and if still equal, store the new aoqi@1: // top addr in ebx at the address of the top addr pointer. Sets ZF if was aoqi@1: // equal, and clears it otherwise. Use lock prefix for atomicity on MPs. aoqi@1: // aoqi@1: // FSR: object begin aoqi@1: // T2: object end aoqi@1: // T0: instance size in words aoqi@1: aoqi@6880: // if someone beat us on the allocation, try again, otherwise continue aoqi@1: __ cmpxchg(T2, heap_top, FSR); aoqi@1: __ beq(AT, R0, retry); aoqi@1: __ delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) { aoqi@1: // The object is initialized before the header. If the object size is aoqi@1: // zero, go directly to the header initialization. aoqi@1: __ bind(initialize_object); fujie@6884: __ set64(AT, - sizeof(oopDesc)); aoqi@1: __ daddu(T0, T0, AT); fujie@6884: __ beq(T0, R0, initialize_header); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // initialize remaining object fields: T0 is a multiple of 2 aoqi@6880: { aoqi@1: Label loop; aoqi@1: __ dadd(T1, FSR, T0); aoqi@1: __ daddi(T1, T1, -oopSize); aoqi@1: aoqi@1: __ bind(loop); aoqi@1: __ sd(R0, T1, sizeof(oopDesc) + 0 * oopSize); aoqi@1: __ bne(T1, FSR, loop); //dont clear header aoqi@1: __ delayed()->daddi(T1, T1, -oopSize); aoqi@1: } fujie@6884: aoqi@6880: //klass in T3, aoqi@1: // initialize object header only. aoqi@1: __ bind(initialize_header); aoqi@1: if (UseBiasedLocking) { aoqi@6880: __ ld(AT, T3, in_bytes(Klass::prototype_header_offset())); aoqi@6880: __ sd(AT, FSR, oopDesc::mark_offset_in_bytes ()); aoqi@1: } else { fujie@6884: __ set64(AT, (long)markOopDesc::prototype()); aoqi@1: __ sd(AT, FSR, oopDesc::mark_offset_in_bytes()); aoqi@1: } aoqi@1: aoqi@1: __ store_klass_gap(FSR, R0); aoqi@1: __ store_klass(FSR, T3); aoqi@1: aoqi@1: { aoqi@1: SkipIfEqual skip_if(_masm, &DTraceAllocProbes, 0); aoqi@1: // Trigger dtrace event for fastpath aoqi@1: __ push(atos); aoqi@1: __ call_VM_leaf( aoqi@6880: CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), FSR); aoqi@1: __ pop(atos); aoqi@6880: aoqi@1: } aoqi@1: __ b(done); aoqi@1: __ delayed()->nop(); aoqi@6880: } aoqi@6880: aoqi@1: // slow case aoqi@1: __ bind(slow_case); aoqi@1: call_VM(FSR, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), A1, A2); aoqi@1: aoqi@1: // continue aoqi@1: __ bind(done); fujie@32: __ sync(); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::newarray() { aoqi@6880: transition(itos, atos); aoqi@6880: __ lbu(A1, at_bcp(1)); aoqi@6880: //type, count aoqi@6880: call_VM(FSR, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), A1, FSR); aoqi@6880: __ sync(); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::anewarray() { aoqi@1: transition(itos, atos); aoqi@16: __ get_2_byte_integer_at_bcp(A2, AT, 1); aoqi@1: __ huswap(A2); aoqi@1: __ get_constant_pool(A1); aoqi@1: // cp, index, count aoqi@1: call_VM(FSR, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), A1, A2, FSR); fujie@32: __ sync(); aoqi@1: } aoqi@1: aoqi@1: void TemplateTable::arraylength() { aoqi@1: transition(atos, itos); aoqi@1: __ null_check(FSR, arrayOopDesc::length_offset_in_bytes()); aoqi@1: __ lw(FSR, FSR, arrayOopDesc::length_offset_in_bytes()); aoqi@1: } aoqi@1: aoqi@1: // i use T2 as ebx, T3 as ecx, T1 as edx aoqi@1: // when invoke gen_subtype_check, super in T3, sub in T2, object in FSR(it's always) aoqi@1: // T2 : sub klass aoqi@1: // T3 : cpool aoqi@1: // T3 : super klass aoqi@1: void TemplateTable::checkcast() { aoqi@1: transition(atos, atos); aoqi@1: Label done, is_null, ok_is_subtype, quicked, resolved; aoqi@1: __ beq(FSR, R0, is_null); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // Get cpool & tags index aoqi@1: __ get_cpool_and_tags(T3, T1); aoqi@16: __ get_2_byte_integer_at_bcp(T2, AT, 1); aoqi@1: __ huswap(T2); aoqi@1: aoqi@1: // See if bytecode has already been quicked aoqi@1: __ dadd(AT, T1, T2); aoqi@1: __ lb(AT, AT, Array::base_offset_in_bytes()); aoqi@1: __ daddiu(AT, AT, - (int)JVM_CONSTANT_Class); aoqi@1: __ beq(AT, R0, quicked); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: /* 2012/6/2 Jin: In InterpreterRuntime::quicken_io_cc, lots of new classes may be loaded. aoqi@1: * Then, GC will move the object in V0 to another places in heap. aoqi@1: * Therefore, We should never save such an object in register. aoqi@1: * Instead, we should save it in the stack. It can be modified automatically by the GC thread. aoqi@1: * After GC, the object address in FSR is changed to a new place. aoqi@1: */ aoqi@1: __ push(atos); aoqi@1: const Register thread = TREG; aoqi@1: #ifndef OPT_THREAD aoqi@1: __ get_thread(thread); aoqi@1: #endif aoqi@1: call_VM(NOREG, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); aoqi@1: __ get_vm_result_2(T3, thread); aoqi@1: __ pop_ptr(FSR); aoqi@1: __ b(resolved); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // klass already in cp, get superklass in T3 aoqi@1: __ bind(quicked); aoqi@1: __ dsll(AT, T2, Address::times_8); aoqi@1: __ dadd(AT, T3, AT); aoqi@1: __ ld(T3, AT, sizeof(ConstantPool)); aoqi@1: aoqi@1: __ bind(resolved); aoqi@1: aoqi@1: // get subklass in T2 aoqi@1: //add for compressedoops aoqi@1: __ load_klass(T2, FSR); aoqi@1: // Superklass in T3. Subklass in T2. aoqi@1: __ gen_subtype_check(T3, T2, ok_is_subtype); aoqi@1: aoqi@1: // Come here on failure aoqi@1: // object is at FSR aoqi@1: __ jmp(Interpreter::_throw_ClassCastException_entry); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // Come here on success aoqi@1: __ bind(ok_is_subtype); aoqi@1: aoqi@1: // Collect counts on whether this check-cast sees NULLs a lot or not. aoqi@1: if (ProfileInterpreter) { aoqi@6880: __ b(done); aoqi@6880: __ delayed()->nop(); aoqi@6880: __ bind(is_null); aoqi@6880: __ profile_null_seen(T3); aoqi@1: } else { aoqi@6880: __ bind(is_null); aoqi@1: } aoqi@1: __ bind(done); aoqi@1: } aoqi@1: aoqi@1: // i use T3 as cpool, T1 as tags, T2 as index aoqi@1: // object always in FSR, superklass in T3, subklass in T2 aoqi@1: void TemplateTable::instanceof() { aoqi@1: transition(atos, itos); aoqi@1: Label done, is_null, ok_is_subtype, quicked, resolved; aoqi@1: aoqi@1: __ beq(FSR, R0, is_null); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // Get cpool & tags index aoqi@1: __ get_cpool_and_tags(T3, T1); aoqi@1: // get index aoqi@16: __ get_2_byte_integer_at_bcp(T2, AT, 1); aoqi@1: __ hswap(T2); aoqi@1: aoqi@1: // See if bytecode has already been quicked aoqi@1: // quicked aoqi@1: __ daddu(AT, T1, T2); aoqi@1: __ lb(AT, AT, Array::base_offset_in_bytes()); aoqi@1: __ daddiu(AT, AT, - (int)JVM_CONSTANT_Class); aoqi@1: __ beq(AT, R0, quicked); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: __ push(atos); aoqi@1: const Register thread = TREG; aoqi@1: #ifndef OPT_THREAD aoqi@1: __ get_thread(thread); aoqi@1: #endif aoqi@1: call_VM(NOREG, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); aoqi@1: __ get_vm_result_2(T3, thread); aoqi@6880: __ pop_ptr(FSR); aoqi@1: __ b(resolved); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // get superklass in T3, subklass in T2 aoqi@1: __ bind(quicked); aoqi@1: __ dsll(AT, T2, Address::times_8); aoqi@1: __ daddu(AT, T3, AT); aoqi@6880: __ ld(T3, AT, sizeof(ConstantPool)); aoqi@1: aoqi@1: __ bind(resolved); aoqi@1: // get subklass in T2 aoqi@1: //add for compressedoops aoqi@1: __ load_klass(T2, FSR); aoqi@6880: aoqi@1: // Superklass in T3. Subklass in T2. aoqi@1: __ gen_subtype_check(T3, T2, ok_is_subtype); aoqi@1: // Come here on failure aoqi@1: __ b(done); aoqi@1: __ delayed(); __ move(FSR, R0); aoqi@1: aoqi@1: // Come here on success aoqi@1: __ bind(ok_is_subtype); aoqi@1: __ move(FSR, 1); aoqi@1: aoqi@1: // Collect counts on whether this test sees NULLs a lot or not. aoqi@1: if (ProfileInterpreter) { aoqi@6880: __ beq(R0, R0, done); aoqi@6880: __ nop(); aoqi@6880: __ bind(is_null); aoqi@6880: __ profile_null_seen(T3); aoqi@1: } else { aoqi@6880: __ bind(is_null); // same as 'done' aoqi@1: } aoqi@1: __ bind(done); aoqi@1: // FSR = 0: obj == NULL or obj is not an instanceof the specified klass aoqi@1: // FSR = 1: obj != NULL and obj is an instanceof the specified klass aoqi@1: } aoqi@1: aoqi@1: //-------------------------------------------------------- aoqi@1: //-------------------------------------------- aoqi@1: // Breakpoints aoqi@1: void TemplateTable::_breakpoint() { aoqi@6880: // Note: We get here even if we are single stepping.. aoqi@6880: // jbug inists on setting breakpoints at every bytecode aoqi@6880: // even if we are in single step mode. aoqi@6880: aoqi@6880: transition(vtos, vtos); aoqi@6880: aoqi@6880: // get the unpatched byte code aoqi@6880: __ get_method(A1); aoqi@6880: __ call_VM(NOREG, aoqi@6880: CAST_FROM_FN_PTR(address, aoqi@6880: InterpreterRuntime::get_original_bytecode_at), aoqi@6880: A1, BCP); aoqi@6880: __ move(Rnext, V0); // Jin: Rnext will be used in dispatch_only_normal aoqi@6880: aoqi@6880: // post the breakpoint event aoqi@6880: __ get_method(A1); aoqi@6880: __ call_VM(NOREG, CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), A1, BCP); aoqi@6880: aoqi@6880: // complete the execution of original bytecode aoqi@6880: __ dispatch_only_normal(vtos); aoqi@6880: } aoqi@6880: aoqi@6880: //----------------------------------------------------------------------------- aoqi@1: // Exceptions aoqi@1: aoqi@1: void TemplateTable::athrow() { aoqi@6880: transition(atos, vtos); aoqi@6880: __ null_check(FSR); aoqi@6880: __ jmp(Interpreter::throw_exception_entry()); aoqi@6880: __ delayed()->nop(); aoqi@1: } aoqi@1: aoqi@6880: //----------------------------------------------------------------------------- aoqi@1: // Synchronization aoqi@1: // aoqi@1: // Note: monitorenter & exit are symmetric routines; which is reflected aoqi@1: // in the assembly code structure as well aoqi@1: // aoqi@1: // Stack layout: aoqi@1: // aoqi@1: // [expressions ] <--- SP = expression stack top aoqi@1: // .. aoqi@1: // [expressions ] aoqi@1: // [monitor entry] <--- monitor block top = expression stack bot aoqi@1: // .. aoqi@1: // [monitor entry] aoqi@1: // [frame data ] <--- monitor block bot aoqi@1: // ... aoqi@1: // [return addr ] <--- FP aoqi@1: aoqi@1: // we use T2 as monitor entry pointer, T3 as monitor top pointer, c_rarg0 as free slot pointer aoqi@1: // object always in FSR aoqi@1: void TemplateTable::monitorenter() { aoqi@1: transition(atos, vtos); aoqi@6880: aoqi@1: // check for NULL object aoqi@1: __ null_check(FSR); aoqi@1: aoqi@6880: const Address monitor_block_top(FP, frame::interpreter_frame_monitor_block_top_offset aoqi@1: * wordSize); aoqi@1: const int entry_size = (frame::interpreter_frame_monitor_size()* wordSize); aoqi@1: Label allocated; aoqi@1: aoqi@1: // initialize entry pointer aoqi@1: __ move(c_rarg0, R0); aoqi@1: aoqi@1: // find a free slot in the monitor block (result in edx) aoqi@6880: { aoqi@1: Label entry, loop, exit, next; aoqi@1: __ ld(T2, monitor_block_top); aoqi@1: __ b(entry); aoqi@1: __ delayed()->daddi(T3, FP, frame::interpreter_frame_initial_sp_offset * wordSize); aoqi@1: aoqi@1: // free slot? aoqi@1: __ bind(loop); aoqi@1: __ ld(AT, T2, BasicObjectLock::obj_offset_in_bytes()); aoqi@1: __ bne(AT, R0, next); aoqi@1: __ delayed()->nop(); aoqi@1: __ move(c_rarg0, T2); aoqi@1: aoqi@1: __ bind(next); aoqi@1: __ beq(FSR, AT, exit); aoqi@1: __ delayed()->nop(); aoqi@1: __ daddi(T2, T2, entry_size); aoqi@1: aoqi@1: __ bind(entry); aoqi@1: __ bne(T3, T2, loop); aoqi@1: __ delayed()->nop(); aoqi@1: __ bind(exit); aoqi@1: } aoqi@1: aoqi@1: __ bne(c_rarg0, R0, allocated); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // allocate one if there's no free slot aoqi@6880: { aoqi@1: Label entry, loop; aoqi@1: // 1. compute new pointers // SP: old expression stack top aoqi@1: __ ld(c_rarg0, monitor_block_top); aoqi@1: __ daddi(SP, SP, - entry_size); aoqi@1: __ daddi(c_rarg0, c_rarg0, - entry_size); aoqi@1: __ sd(c_rarg0, monitor_block_top); aoqi@1: __ b(entry); aoqi@1: __ delayed(); __ move(T3, SP); aoqi@1: aoqi@1: // 2. move expression stack contents aoqi@1: __ bind(loop); aoqi@1: __ ld(AT, T3, entry_size); aoqi@1: __ sd(AT, T3, 0); aoqi@6880: __ daddi(T3, T3, wordSize); aoqi@1: __ bind(entry); aoqi@1: __ bne(T3, c_rarg0, loop); aoqi@1: __ delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: __ bind(allocated); aoqi@6880: // Increment bcp to point to the next bytecode, aoqi@6880: // so exception handling for async. exceptions work correctly. aoqi@6880: // The object has already been poped from the stack, so the aoqi@1: // expression stack looks correct. aoqi@6880: __ daddi(BCP, BCP, 1); aoqi@1: __ sd(FSR, c_rarg0, BasicObjectLock::obj_offset_in_bytes()); aoqi@1: __ lock_object(c_rarg0); aoqi@1: // check to make sure this monitor doesn't cause stack overflow after locking aoqi@1: __ save_bcp(); // in case of exception aoqi@1: __ generate_stack_overflow_check(0); aoqi@1: // The bcp has already been incremented. Just need to dispatch to next instruction. aoqi@1: aoqi@1: __ dispatch_next(vtos); aoqi@1: } aoqi@1: aoqi@1: // T2 : top aoqi@1: // c_rarg0 : entry aoqi@1: void TemplateTable::monitorexit() { aoqi@1: transition(atos, vtos); aoqi@1: aoqi@1: __ null_check(FSR); aoqi@1: aoqi@1: const int entry_size =(frame::interpreter_frame_monitor_size()* wordSize); aoqi@1: Label found; aoqi@1: aoqi@1: // find matching slot aoqi@6880: { aoqi@1: Label entry, loop; aoqi@1: __ ld(c_rarg0, FP, frame::interpreter_frame_monitor_block_top_offset * wordSize); aoqi@1: __ b(entry); aoqi@1: __ delayed()->daddiu(T2, FP, frame::interpreter_frame_initial_sp_offset * wordSize); aoqi@1: aoqi@1: __ bind(loop); aoqi@1: __ ld(AT, c_rarg0, BasicObjectLock::obj_offset_in_bytes()); aoqi@1: __ beq(FSR, AT, found); aoqi@1: __ delayed()->nop(); aoqi@1: __ daddiu(c_rarg0, c_rarg0, entry_size); aoqi@1: __ bind(entry); aoqi@1: __ bne(T2, c_rarg0, loop); aoqi@1: __ delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: // error handling. Unlocking was not block-structured aoqi@1: Label end; aoqi@6880: __ call_VM(NOREG, CAST_FROM_FN_PTR(address, aoqi@6880: InterpreterRuntime::throw_illegal_monitor_state_exception)); aoqi@1: __ should_not_reach_here(); aoqi@1: aoqi@1: // call run-time routine aoqi@1: // c_rarg0: points to monitor entry aoqi@1: __ bind(found); aoqi@1: __ move(TSR, FSR); aoqi@1: __ unlock_object(c_rarg0); aoqi@1: __ move(FSR, TSR); aoqi@1: __ bind(end); aoqi@1: } aoqi@1: aoqi@6880: aoqi@6880: // Wide instructions aoqi@1: void TemplateTable::wide() { aoqi@1: transition(vtos, vtos); aoqi@1: // Note: the esi increment step is part of the individual wide bytecode implementations aoqi@1: __ lbu(Rnext, at_bcp(1)); aoqi@1: __ dsll(T9, Rnext, Address::times_8); aoqi@1: __ li(AT, (long)Interpreter::_wentry_point); aoqi@1: __ dadd(AT, T9, AT); aoqi@1: __ ld(T9, AT, 0); aoqi@1: __ jr(T9); aoqi@1: __ delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void TemplateTable::multianewarray() { aoqi@1: transition(vtos, atos); aoqi@1: // last dim is on top of stack; we want address of first one: aoqi@1: // first_addr = last_addr + (ndims - 1) * wordSize aoqi@6880: __ lbu(A1, at_bcp(3)); // dimension aoqi@6880: __ daddi(A1, A1, -1); aoqi@1: __ dsll(A1, A1, Address::times_8); aoqi@6880: __ dadd(A1, SP, A1); // now A1 pointer to the count array on the stack aoqi@1: call_VM(FSR, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), A1); aoqi@1: __ lbu(AT, at_bcp(3)); aoqi@1: __ dsll(AT, AT, Address::times_8); aoqi@1: __ dadd(SP, SP, AT); fujie@32: __ sync(); aoqi@1: } aoqi@1: #endif // !CC_INTERP