Fri, 29 Apr 2016 00:06:10 +0800
Added MIPS 64-bit port.
aoqi@1 | 1 | /* |
aoqi@1 | 2 | * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. |
aoqi@1 | 3 | * Copyright (c) 2015, 2016, Loongson Technology. All rights reserved. |
aoqi@1 | 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
aoqi@1 | 5 | * |
aoqi@1 | 6 | * This code is free software; you can redistribute it and/or modify it |
aoqi@1 | 7 | * under the terms of the GNU General Public License version 2 only, as |
aoqi@1 | 8 | * published by the Free Software Foundation. |
aoqi@1 | 9 | * |
aoqi@1 | 10 | * This code is distributed in the hope that it will be useful, but WITHOUT |
aoqi@1 | 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
aoqi@1 | 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
aoqi@1 | 13 | * version 2 for more details (a copy is included in the LICENSE file that |
aoqi@1 | 14 | * accompanied this code). |
aoqi@1 | 15 | * |
aoqi@1 | 16 | * You should have received a copy of the GNU General Public License version |
aoqi@1 | 17 | * 2 along with this work; if not, write to the Free Software Foundation, |
aoqi@1 | 18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
aoqi@1 | 19 | * |
aoqi@1 | 20 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
aoqi@1 | 21 | * or visit www.oracle.com if you need additional information or have any |
aoqi@1 | 22 | * questions. |
aoqi@1 | 23 | * |
aoqi@1 | 24 | */ |
aoqi@1 | 25 | |
aoqi@1 | 26 | #include "precompiled.hpp" |
aoqi@1 | 27 | #include "asm/macroAssembler.hpp" |
aoqi@1 | 28 | #include "code/vtableStubs.hpp" |
aoqi@1 | 29 | #include "interp_masm_mips_64.hpp" |
aoqi@1 | 30 | #include "memory/resourceArea.hpp" |
aoqi@1 | 31 | //#include "oops/InstanceKlass.hpp" |
aoqi@1 | 32 | #include "oops/klassVtable.hpp" |
aoqi@1 | 33 | #include "runtime/sharedRuntime.hpp" |
aoqi@1 | 34 | #include "vmreg_mips.inline.hpp" |
aoqi@1 | 35 | #ifdef COMPILER2 |
aoqi@1 | 36 | #include "opto/runtime.hpp" |
aoqi@1 | 37 | #endif |
aoqi@1 | 38 | |
aoqi@1 | 39 | |
aoqi@1 | 40 | // machine-dependent part of VtableStubs: create VtableStub of correct size and |
aoqi@1 | 41 | // initialize its code |
aoqi@1 | 42 | |
aoqi@1 | 43 | #define __ masm-> |
aoqi@1 | 44 | |
aoqi@1 | 45 | #ifndef PRODUCT |
aoqi@1 | 46 | extern "C" void bad_compiled_vtable_index(JavaThread* thread, |
aoqi@1 | 47 | oop receiver, |
aoqi@1 | 48 | int index); |
aoqi@1 | 49 | #endif |
aoqi@1 | 50 | |
aoqi@1 | 51 | // used by compiler only; reciever in T0. |
aoqi@1 | 52 | // used registers : |
aoqi@1 | 53 | // Rmethod : receiver klass & method |
aoqi@1 | 54 | // NOTE: If this code is used by the C1, the receiver_location is always 0. |
aoqi@1 | 55 | // when reach here, receiver in T0, klass in T8 |
aoqi@1 | 56 | VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { |
aoqi@1 | 57 | const int gs2_code_length = VtableStub::pd_code_size_limit(true); |
aoqi@1 | 58 | //VtableStub* s = new(gs2_code_length) VtableStub(true, vtable_index, receiver_location); |
aoqi@1 | 59 | //FIXME aoqi |
aoqi@1 | 60 | VtableStub* s = new(gs2_code_length) VtableStub(true, vtable_index); |
aoqi@1 | 61 | ResourceMark rm; |
aoqi@1 | 62 | CodeBuffer cb(s->entry_point(), gs2_code_length); |
aoqi@1 | 63 | MacroAssembler* masm = new MacroAssembler(&cb); |
aoqi@1 | 64 | Register t1 = T8, t2 = Rmethod; |
aoqi@1 | 65 | #ifndef PRODUCT |
aoqi@1 | 66 | //#ifdef COMPILER2 |
aoqi@1 | 67 | if (CountCompiledCalls) { |
aoqi@1 | 68 | __ li(AT, SharedRuntime::nof_megamorphic_calls_addr()); |
aoqi@1 | 69 | __ lw(t1, AT , 0); |
aoqi@1 | 70 | __ addiu(t1, t1, 1); |
aoqi@1 | 71 | __ sw(t1, AT,0); |
aoqi@1 | 72 | } |
aoqi@1 | 73 | //#endif |
aoqi@1 | 74 | #endif |
aoqi@1 | 75 | |
aoqi@1 | 76 | // get receiver (need to skip return address on top of stack) |
aoqi@1 | 77 | //assert(receiver_location == T0->as_VMReg(), "receiver expected in T0"); |
aoqi@1 | 78 | |
aoqi@1 | 79 | // get receiver klass |
aoqi@1 | 80 | address npe_addr = __ pc(); |
aoqi@1 | 81 | //__ ld_ptr(t1, T0, oopDesc::klass_offset_in_bytes()); |
aoqi@1 | 82 | //add for compressedoops |
aoqi@1 | 83 | __ load_klass(t1, T0); |
aoqi@1 | 84 | // compute entry offset (in words) |
aoqi@1 | 85 | int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); |
aoqi@1 | 86 | #ifndef PRODUCT |
aoqi@1 | 87 | if (DebugVtables) { |
aoqi@1 | 88 | Label L; |
aoqi@1 | 89 | // check offset vs vtable length |
aoqi@1 | 90 | __ lw(t2, t1, InstanceKlass::vtable_length_offset()*wordSize); |
aoqi@1 | 91 | assert(Assembler::is_simm16(vtable_index*vtableEntry::size()), "change this code"); |
aoqi@1 | 92 | __ move(AT, vtable_index*vtableEntry::size()); |
aoqi@1 | 93 | __ slt(AT, AT, t2); |
aoqi@1 | 94 | __ bne(AT, R0, L); |
aoqi@1 | 95 | __ delayed()->nop(); |
aoqi@1 | 96 | __ move(A2, vtable_index); |
aoqi@1 | 97 | __ move(A1, A0); |
aoqi@1 | 98 | __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), A1, A2); |
aoqi@1 | 99 | __ bind(L); |
aoqi@1 | 100 | } |
aoqi@1 | 101 | #endif // PRODUCT |
aoqi@1 | 102 | // load methodOop and target address |
aoqi@1 | 103 | const Register method = Rmethod; |
aoqi@1 | 104 | __ ld_ptr(method, t1, entry_offset*wordSize + vtableEntry::method_offset_in_bytes()); |
aoqi@1 | 105 | if (DebugVtables) { |
aoqi@1 | 106 | Label L; |
aoqi@1 | 107 | __ beq(method, R0, L); |
aoqi@1 | 108 | __ delayed()->nop(); |
aoqi@1 | 109 | // __ cmpl(Address(method, Method::from_compiled_offset()), NULL_WORD); |
aoqi@1 | 110 | __ lw(AT, method,in_bytes(Method::from_compiled_offset())); |
aoqi@1 | 111 | //__ jcc(Assembler::notZero, L); |
aoqi@1 | 112 | __ bne(AT, R0, L); |
aoqi@1 | 113 | __ delayed()->nop(); |
aoqi@1 | 114 | __ stop("Vtable entry is NULL"); |
aoqi@1 | 115 | __ bind(L); |
aoqi@1 | 116 | } |
aoqi@1 | 117 | // T8: receiver klass |
aoqi@1 | 118 | // T0: receiver |
aoqi@1 | 119 | // Rmethod: methodOop |
aoqi@1 | 120 | // T9: entry |
aoqi@1 | 121 | address ame_addr = __ pc(); |
aoqi@1 | 122 | __ ld_ptr(T9, method,in_bytes(Method::from_compiled_offset())); |
aoqi@1 | 123 | __ jr(T9); |
aoqi@1 | 124 | __ delayed()->nop(); |
aoqi@1 | 125 | masm->flush(); |
aoqi@1 | 126 | s->set_exception_points(npe_addr, ame_addr); |
aoqi@1 | 127 | return s; |
aoqi@1 | 128 | } |
aoqi@1 | 129 | |
aoqi@1 | 130 | |
aoqi@1 | 131 | // i am not sure which register to contain Interface, now i just assume A1. FIXME |
aoqi@1 | 132 | // used registers : |
aoqi@1 | 133 | // T1 T2 |
aoqi@1 | 134 | // when reach here, the receiver in T0, klass in T1 |
aoqi@1 | 135 | VtableStub* VtableStubs::create_itable_stub(int vtable_index) { |
aoqi@1 | 136 | // Note well: pd_code_size_limit is the absolute minimum we can get |
aoqi@1 | 137 | // away with. If you add code here, bump the code stub size |
aoqi@1 | 138 | // returned by pd_code_size_limit! |
aoqi@1 | 139 | const int gs2_code_length = VtableStub::pd_code_size_limit(false); |
aoqi@1 | 140 | VtableStub* s = new(gs2_code_length) VtableStub(false, vtable_index); |
aoqi@1 | 141 | ResourceMark rm; |
aoqi@1 | 142 | CodeBuffer cb(s->entry_point(), gs2_code_length); |
aoqi@1 | 143 | MacroAssembler* masm = new MacroAssembler(&cb); |
aoqi@1 | 144 | // we T8,T9 as temparary register, they are free from register allocator |
aoqi@1 | 145 | Register t1 = T8, t2 = T2; |
aoqi@1 | 146 | // Entry arguments: |
aoqi@1 | 147 | // T1: Interface |
aoqi@1 | 148 | // T0: Receiver |
aoqi@1 | 149 | #ifndef PRODUCT |
aoqi@1 | 150 | if (CountCompiledCalls) { |
aoqi@1 | 151 | //__ incl(Address((int)SharedRuntime::nof_megamorphic_calls_addr(), relocInfo::none)); |
aoqi@1 | 152 | __ li(AT, SharedRuntime::nof_megamorphic_calls_addr()); |
aoqi@1 | 153 | __ lw(T8, AT, 0); |
aoqi@1 | 154 | __ addi(T8, T8,1); |
aoqi@1 | 155 | __ sw(T8, AT, 0); |
aoqi@1 | 156 | } |
aoqi@1 | 157 | #endif /* PRODUCT */ |
aoqi@1 | 158 | //assert(receiver_location == T0->as_VMReg(), "receiver expected in T0"); |
aoqi@1 | 159 | // get receiver klass (also an implicit null-check) |
aoqi@1 | 160 | address npe_addr = __ pc(); |
aoqi@1 | 161 | //__ ld_ptr(t1, T0, oopDesc::klass_offset_in_bytes()); |
aoqi@1 | 162 | //add for compressedoops |
aoqi@1 | 163 | __ load_klass(t1, T0); |
aoqi@1 | 164 | // compute itable entry offset (in words) |
aoqi@1 | 165 | const int base = InstanceKlass::vtable_start_offset() * wordSize; |
aoqi@1 | 166 | assert(vtableEntry::size() * wordSize == 8, "adjust the scaling in the code below"); |
aoqi@1 | 167 | assert(Assembler::is_simm16(base), "change this code"); |
aoqi@1 | 168 | __ daddi(t2, t1, base); |
aoqi@1 | 169 | assert(Assembler::is_simm16(InstanceKlass::vtable_length_offset() * wordSize), "change this code"); |
aoqi@1 | 170 | __ lw(AT, t1, InstanceKlass::vtable_length_offset() * wordSize); |
aoqi@1 | 171 | __ dsll(AT, AT, Address::times_8); |
aoqi@1 | 172 | __ dadd(t2, t2, AT); |
aoqi@1 | 173 | if (HeapWordsPerLong > 1) { |
aoqi@1 | 174 | __ round_to(t2, BytesPerLong); |
aoqi@1 | 175 | } |
aoqi@1 | 176 | |
aoqi@1 | 177 | Label hit, entry; |
aoqi@1 | 178 | assert(Assembler::is_simm16(itableOffsetEntry::size() * wordSize), "change this code"); |
aoqi@1 | 179 | __ bind(entry); |
aoqi@1 | 180 | |
aoqi@1 | 181 | #ifdef ASSERT |
aoqi@1 | 182 | // Check that the entry is non-null |
aoqi@1 | 183 | if (DebugVtables) { |
aoqi@1 | 184 | Label L; |
aoqi@1 | 185 | assert(Assembler::is_simm16(itableOffsetEntry::interface_offset_in_bytes()), "change this code"); |
aoqi@1 | 186 | __ lw(AT, t1, itableOffsetEntry::interface_offset_in_bytes()); |
aoqi@1 | 187 | __ bne(AT, R0, L); |
aoqi@1 | 188 | __ delayed()->nop(); |
aoqi@1 | 189 | __ stop("null entry point found in itable's offset table"); |
aoqi@1 | 190 | __ bind(L); |
aoqi@1 | 191 | } |
aoqi@1 | 192 | #endif |
aoqi@1 | 193 | assert(Assembler::is_simm16(itableOffsetEntry::interface_offset_in_bytes()), "change this code"); |
aoqi@1 | 194 | __ ld_ptr(AT, t2, itableOffsetEntry::interface_offset_in_bytes()); |
aoqi@1 | 195 | __ bne(AT, T1, entry); |
aoqi@1 | 196 | __ delayed()->addi(t2, t2, itableOffsetEntry::size() * wordSize); |
aoqi@1 | 197 | |
aoqi@1 | 198 | // We found a hit, move offset into T9 |
aoqi@1 | 199 | __ ld_ptr(t2, t2, itableOffsetEntry::offset_offset_in_bytes() - itableOffsetEntry::size() * wordSize); |
aoqi@1 | 200 | |
aoqi@1 | 201 | // Compute itableMethodEntry. |
aoqi@1 | 202 | const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + |
aoqi@1 | 203 | itableMethodEntry::method_offset_in_bytes(); |
aoqi@1 | 204 | |
aoqi@1 | 205 | // Get methodOop and entrypoint for compiler |
aoqi@1 | 206 | // const Register method = ebx; |
aoqi@1 | 207 | const Register method = Rmethod; |
aoqi@1 | 208 | // __ movl(method, Address(esi, edx, Address::times_1, method_offset)); |
aoqi@1 | 209 | __ dsll(AT, t2, Address::times_1); |
aoqi@1 | 210 | __ add(AT, AT, t1 ); |
aoqi@1 | 211 | __ ld_ptr(method, AT, method_offset); |
aoqi@1 | 212 | |
aoqi@1 | 213 | |
aoqi@1 | 214 | |
aoqi@1 | 215 | #ifdef ASSERT |
aoqi@1 | 216 | if (DebugVtables) { |
aoqi@1 | 217 | Label L1; |
aoqi@1 | 218 | // __ cmpl(method, NULL_WORD); |
aoqi@1 | 219 | // __ jcc(Assembler::equal, L1); |
aoqi@1 | 220 | __ beq(method, R0, L1); |
aoqi@1 | 221 | __ delayed()->nop(); |
aoqi@1 | 222 | // __ cmpl(Address(method, Method::from_compiled_offset()), NULL_WORD); |
aoqi@1 | 223 | __ lw(AT, method,in_bytes(Method::from_compiled_offset())); |
aoqi@1 | 224 | // __ jcc(Assembler::notZero, L1); |
aoqi@1 | 225 | __ bne(AT, R0, L1); |
aoqi@1 | 226 | __ delayed()->nop(); |
aoqi@1 | 227 | __ stop("methodOop is null"); |
aoqi@1 | 228 | __ bind(L1); |
aoqi@1 | 229 | } |
aoqi@1 | 230 | #endif // ASSERT |
aoqi@1 | 231 | /* |
aoqi@1 | 232 | // Rmethod: methodOop |
aoqi@1 | 233 | // T0: receiver |
aoqi@1 | 234 | // T9: entry point |
aoqi@1 | 235 | __ jmp(T9); |
aoqi@1 | 236 | #endif // COMPILER2 |
aoqi@1 | 237 | */ |
aoqi@1 | 238 | address ame_addr = __ pc(); |
aoqi@1 | 239 | __ ld_ptr(T9, method,in_bytes(Method::from_compiled_offset())); |
aoqi@1 | 240 | __ jr(T9); |
aoqi@1 | 241 | __ delayed()->nop(); |
aoqi@1 | 242 | masm->flush(); |
aoqi@1 | 243 | s->set_exception_points(npe_addr, ame_addr); |
aoqi@1 | 244 | return s; |
aoqi@1 | 245 | } |
aoqi@1 | 246 | |
aoqi@1 | 247 | // NOTE : whenever you change the code above, dont forget to change the const here |
aoqi@1 | 248 | int VtableStub::pd_code_size_limit(bool is_vtable_stub) { |
aoqi@1 | 249 | if (is_vtable_stub) { |
aoqi@1 | 250 | return ( DebugVtables ? 600 : 28) + (CountCompiledCalls ? 24 : 0)+ |
aoqi@1 | 251 | (UseCompressedOops ? 16 : 0); |
aoqi@1 | 252 | } else { |
aoqi@1 | 253 | return ( DebugVtables ? 636 : 72) + (CountCompiledCalls ? 24 : 0)+ |
aoqi@1 | 254 | (UseCompressedOops ? 32 : 0); |
aoqi@1 | 255 | } |
aoqi@1 | 256 | } |
aoqi@1 | 257 | |
aoqi@1 | 258 | int VtableStub::pd_code_alignment() { |
aoqi@1 | 259 | return wordSize; |
aoqi@1 | 260 | } |