1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp Sat Dec 01 00:00:00 2007 +0000 1.3 @@ -0,0 +1,409 @@ 1.4 +/* 1.5 + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 + * have any questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "incls/_precompiled.incl" 1.29 +#include "incls/_c1_MacroAssembler_sparc.cpp.incl" 1.30 + 1.31 +void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) { 1.32 + Label L; 1.33 + const Register temp_reg = G3_scratch; 1.34 + // Note: needs more testing of out-of-line vs. inline slow case 1.35 + Address ic_miss(temp_reg, SharedRuntime::get_ic_miss_stub()); 1.36 + verify_oop(receiver); 1.37 + ld_ptr(receiver, oopDesc::klass_offset_in_bytes(), temp_reg); 1.38 + cmp(temp_reg, iCache); 1.39 + brx(Assembler::equal, true, Assembler::pt, L); 1.40 + delayed()->nop(); 1.41 + jump_to(ic_miss, 0); 1.42 + delayed()->nop(); 1.43 + align(CodeEntryAlignment); 1.44 + bind(L); 1.45 +} 1.46 + 1.47 + 1.48 +void C1_MacroAssembler::method_exit(bool restore_frame) { 1.49 + // this code must be structured this way so that the return 1.50 + // instruction can be a safepoint. 1.51 + if (restore_frame) { 1.52 + restore(); 1.53 + } 1.54 + retl(); 1.55 + delayed()->nop(); 1.56 +} 1.57 + 1.58 + 1.59 +void C1_MacroAssembler::explicit_null_check(Register base) { 1.60 + Unimplemented(); 1.61 +} 1.62 + 1.63 + 1.64 +void C1_MacroAssembler::build_frame(int frame_size_in_bytes) { 1.65 + 1.66 + generate_stack_overflow_check(frame_size_in_bytes); 1.67 + // Create the frame. 1.68 + save_frame_c1(frame_size_in_bytes); 1.69 +} 1.70 + 1.71 + 1.72 +void C1_MacroAssembler::unverified_entry(Register receiver, Register ic_klass) { 1.73 + if (C1Breakpoint) breakpoint_trap(); 1.74 + inline_cache_check(receiver, ic_klass); 1.75 +} 1.76 + 1.77 + 1.78 +void C1_MacroAssembler::verified_entry() { 1.79 + if (C1Breakpoint) breakpoint_trap(); 1.80 + // build frame 1.81 + verify_FPU(0, "method_entry"); 1.82 +} 1.83 + 1.84 + 1.85 +void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case) { 1.86 + assert_different_registers(Rmark, Roop, Rbox, Rscratch); 1.87 + 1.88 + Label done; 1.89 + 1.90 + Address mark_addr(Roop, 0, oopDesc::mark_offset_in_bytes()); 1.91 + 1.92 + // The following move must be the first instruction of emitted since debug 1.93 + // information may be generated for it. 1.94 + // Load object header 1.95 + ld_ptr(mark_addr, Rmark); 1.96 + 1.97 + verify_oop(Roop); 1.98 + 1.99 + // save object being locked into the BasicObjectLock 1.100 + st_ptr(Roop, Rbox, BasicObjectLock::obj_offset_in_bytes()); 1.101 + 1.102 + if (UseBiasedLocking) { 1.103 + biased_locking_enter(Roop, Rmark, Rscratch, done, &slow_case); 1.104 + } 1.105 + 1.106 + // Save Rbox in Rscratch to be used for the cas operation 1.107 + mov(Rbox, Rscratch); 1.108 + 1.109 + // and mark it unlocked 1.110 + or3(Rmark, markOopDesc::unlocked_value, Rmark); 1.111 + 1.112 + // save unlocked object header into the displaced header location on the stack 1.113 + st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes()); 1.114 + 1.115 + // compare object markOop with Rmark and if equal exchange Rscratch with object markOop 1.116 + assert(mark_addr.disp() == 0, "cas must take a zero displacement"); 1.117 + casx_under_lock(mark_addr.base(), Rmark, Rscratch, (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr()); 1.118 + // if compare/exchange succeeded we found an unlocked object and we now have locked it 1.119 + // hence we are done 1.120 + cmp(Rmark, Rscratch); 1.121 + brx(Assembler::equal, false, Assembler::pt, done); 1.122 + delayed()->sub(Rscratch, SP, Rscratch); //pull next instruction into delay slot 1.123 + // we did not find an unlocked object so see if this is a recursive case 1.124 + // sub(Rscratch, SP, Rscratch); 1.125 + assert(os::vm_page_size() > 0xfff, "page size too small - change the constant"); 1.126 + andcc(Rscratch, 0xfffff003, Rscratch); 1.127 + brx(Assembler::notZero, false, Assembler::pn, slow_case); 1.128 + delayed()->st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes()); 1.129 + bind(done); 1.130 +} 1.131 + 1.132 + 1.133 +void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case) { 1.134 + assert_different_registers(Rmark, Roop, Rbox); 1.135 + 1.136 + Label done; 1.137 + 1.138 + Address mark_addr(Roop, 0, oopDesc::mark_offset_in_bytes()); 1.139 + assert(mark_addr.disp() == 0, "cas must take a zero displacement"); 1.140 + 1.141 + if (UseBiasedLocking) { 1.142 + // load the object out of the BasicObjectLock 1.143 + ld_ptr(Rbox, BasicObjectLock::obj_offset_in_bytes(), Roop); 1.144 + verify_oop(Roop); 1.145 + biased_locking_exit(mark_addr, Rmark, done); 1.146 + } 1.147 + // Test first it it is a fast recursive unlock 1.148 + ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rmark); 1.149 + br_null(Rmark, false, Assembler::pt, done); 1.150 + delayed()->nop(); 1.151 + if (!UseBiasedLocking) { 1.152 + // load object 1.153 + ld_ptr(Rbox, BasicObjectLock::obj_offset_in_bytes(), Roop); 1.154 + verify_oop(Roop); 1.155 + } 1.156 + 1.157 + // Check if it is still a light weight lock, this is is true if we see 1.158 + // the stack address of the basicLock in the markOop of the object 1.159 + casx_under_lock(mark_addr.base(), Rbox, Rmark, (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr()); 1.160 + cmp(Rbox, Rmark); 1.161 + 1.162 + brx(Assembler::notEqual, false, Assembler::pn, slow_case); 1.163 + delayed()->nop(); 1.164 + // Done 1.165 + bind(done); 1.166 +} 1.167 + 1.168 + 1.169 +void C1_MacroAssembler::try_allocate( 1.170 + Register obj, // result: pointer to object after successful allocation 1.171 + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise 1.172 + int con_size_in_bytes, // object size in bytes if known at compile time 1.173 + Register t1, // temp register 1.174 + Register t2, // temp register 1.175 + Label& slow_case // continuation point if fast allocation fails 1.176 +) { 1.177 + if (UseTLAB) { 1.178 + tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case); 1.179 + } else { 1.180 + eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); 1.181 + } 1.182 +} 1.183 + 1.184 + 1.185 +void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) { 1.186 + assert_different_registers(obj, klass, len, t1, t2); 1.187 + if (UseBiasedLocking && !len->is_valid()) { 1.188 + ld_ptr(klass, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes(), t1); 1.189 + } else { 1.190 + set((intx)markOopDesc::prototype(), t1); 1.191 + } 1.192 + st_ptr(t1 , obj, oopDesc::mark_offset_in_bytes ()); 1.193 + st_ptr(klass, obj, oopDesc::klass_offset_in_bytes ()); 1.194 + if (len->is_valid()) st(len , obj, arrayOopDesc::length_offset_in_bytes()); 1.195 +} 1.196 + 1.197 + 1.198 +void C1_MacroAssembler::initialize_body(Register base, Register index) { 1.199 + assert_different_registers(base, index); 1.200 + Label loop; 1.201 + bind(loop); 1.202 + subcc(index, HeapWordSize, index); 1.203 + brx(Assembler::greaterEqual, true, Assembler::pt, loop); 1.204 + delayed()->st_ptr(G0, base, index); 1.205 +} 1.206 + 1.207 + 1.208 +void C1_MacroAssembler::allocate_object( 1.209 + Register obj, // result: pointer to object after successful allocation 1.210 + Register t1, // temp register 1.211 + Register t2, // temp register 1.212 + Register t3, // temp register 1.213 + int hdr_size, // object header size in words 1.214 + int obj_size, // object size in words 1.215 + Register klass, // object klass 1.216 + Label& slow_case // continuation point if fast allocation fails 1.217 +) { 1.218 + assert_different_registers(obj, t1, t2, t3, klass); 1.219 + assert(klass == G5, "must be G5"); 1.220 + 1.221 + // allocate space & initialize header 1.222 + if (!is_simm13(obj_size * wordSize)) { 1.223 + // would need to use extra register to load 1.224 + // object size => go the slow case for now 1.225 + br(Assembler::always, false, Assembler::pt, slow_case); 1.226 + delayed()->nop(); 1.227 + return; 1.228 + } 1.229 + try_allocate(obj, noreg, obj_size * wordSize, t2, t3, slow_case); 1.230 + 1.231 + initialize_object(obj, klass, noreg, obj_size * HeapWordSize, t1, t2); 1.232 +} 1.233 + 1.234 +void C1_MacroAssembler::initialize_object( 1.235 + Register obj, // result: pointer to object after successful allocation 1.236 + Register klass, // object klass 1.237 + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise 1.238 + int con_size_in_bytes, // object size in bytes if known at compile time 1.239 + Register t1, // temp register 1.240 + Register t2 // temp register 1.241 + ) { 1.242 + const int hdr_size_in_bytes = oopDesc::header_size_in_bytes(); 1.243 + 1.244 + initialize_header(obj, klass, noreg, t1, t2); 1.245 + 1.246 +#ifdef ASSERT 1.247 + { 1.248 + Label ok; 1.249 + ld(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes(), t1); 1.250 + if (var_size_in_bytes != noreg) { 1.251 + cmp(t1, var_size_in_bytes); 1.252 + } else { 1.253 + cmp(t1, con_size_in_bytes); 1.254 + } 1.255 + brx(Assembler::equal, false, Assembler::pt, ok); 1.256 + delayed()->nop(); 1.257 + stop("bad size in initialize_object"); 1.258 + should_not_reach_here(); 1.259 + 1.260 + bind(ok); 1.261 + } 1.262 + 1.263 +#endif 1.264 + 1.265 + // initialize body 1.266 + const int threshold = 5 * HeapWordSize; // approximate break even point for code size 1.267 + if (var_size_in_bytes != noreg) { 1.268 + // use a loop 1.269 + add(obj, hdr_size_in_bytes, t1); // compute address of first element 1.270 + sub(var_size_in_bytes, hdr_size_in_bytes, t2); // compute size of body 1.271 + initialize_body(t1, t2); 1.272 +#ifndef _LP64 1.273 + } else if (VM_Version::v9_instructions_work() && con_size_in_bytes < threshold * 2) { 1.274 + // on v9 we can do double word stores to fill twice as much space. 1.275 + assert(hdr_size_in_bytes % 8 == 0, "double word aligned"); 1.276 + assert(con_size_in_bytes % 8 == 0, "double word aligned"); 1.277 + for (int i = hdr_size_in_bytes; i < con_size_in_bytes; i += 2 * HeapWordSize) stx(G0, obj, i); 1.278 +#endif 1.279 + } else if (con_size_in_bytes <= threshold) { 1.280 + // use explicit NULL stores 1.281 + for (int i = hdr_size_in_bytes; i < con_size_in_bytes; i += HeapWordSize) st_ptr(G0, obj, i); 1.282 + } else if (con_size_in_bytes > hdr_size_in_bytes) { 1.283 + // use a loop 1.284 + const Register base = t1; 1.285 + const Register index = t2; 1.286 + add(obj, hdr_size_in_bytes, base); // compute address of first element 1.287 + // compute index = number of words to clear 1.288 + set(con_size_in_bytes - hdr_size_in_bytes, index); 1.289 + initialize_body(base, index); 1.290 + } 1.291 + 1.292 + if (DTraceAllocProbes) { 1.293 + assert(obj == O0, "must be"); 1.294 + call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)), 1.295 + relocInfo::runtime_call_type); 1.296 + delayed()->nop(); 1.297 + } 1.298 + 1.299 + verify_oop(obj); 1.300 +} 1.301 + 1.302 + 1.303 +void C1_MacroAssembler::allocate_array( 1.304 + Register obj, // result: pointer to array after successful allocation 1.305 + Register len, // array length 1.306 + Register t1, // temp register 1.307 + Register t2, // temp register 1.308 + Register t3, // temp register 1.309 + int hdr_size, // object header size in words 1.310 + int elt_size, // element size in bytes 1.311 + Register klass, // object klass 1.312 + Label& slow_case // continuation point if fast allocation fails 1.313 +) { 1.314 + assert_different_registers(obj, len, t1, t2, t3, klass); 1.315 + assert(klass == G5, "must be G5"); 1.316 + assert(t1 == G1, "must be G1"); 1.317 + 1.318 + // determine alignment mask 1.319 + assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work"); 1.320 + 1.321 + // check for negative or excessive length 1.322 + // note: the maximum length allowed is chosen so that arrays of any 1.323 + // element size with this length are always smaller or equal 1.324 + // to the largest integer (i.e., array size computation will 1.325 + // not overflow) 1.326 + set(max_array_allocation_length, t1); 1.327 + cmp(len, t1); 1.328 + br(Assembler::greaterUnsigned, false, Assembler::pn, slow_case); 1.329 + 1.330 + // compute array size 1.331 + // note: if 0 <= len <= max_length, len*elt_size + header + alignment is 1.332 + // smaller or equal to the largest integer; also, since top is always 1.333 + // aligned, we can do the alignment here instead of at the end address 1.334 + // computation 1.335 + const Register arr_size = t1; 1.336 + switch (elt_size) { 1.337 + case 1: delayed()->mov(len, arr_size); break; 1.338 + case 2: delayed()->sll(len, 1, arr_size); break; 1.339 + case 4: delayed()->sll(len, 2, arr_size); break; 1.340 + case 8: delayed()->sll(len, 3, arr_size); break; 1.341 + default: ShouldNotReachHere(); 1.342 + } 1.343 + add(arr_size, hdr_size * wordSize + MinObjAlignmentInBytesMask, arr_size); // add space for header & alignment 1.344 + and3(arr_size, ~MinObjAlignmentInBytesMask, arr_size); // align array size 1.345 + 1.346 + // allocate space & initialize header 1.347 + if (UseTLAB) { 1.348 + tlab_allocate(obj, arr_size, 0, t2, slow_case); 1.349 + } else { 1.350 + eden_allocate(obj, arr_size, 0, t2, t3, slow_case); 1.351 + } 1.352 + initialize_header(obj, klass, len, t2, t3); 1.353 + 1.354 + // initialize body 1.355 + const Register base = t2; 1.356 + const Register index = t3; 1.357 + add(obj, hdr_size * wordSize, base); // compute address of first element 1.358 + sub(arr_size, hdr_size * wordSize, index); // compute index = number of words to clear 1.359 + initialize_body(base, index); 1.360 + 1.361 + if (DTraceAllocProbes) { 1.362 + assert(obj == O0, "must be"); 1.363 + call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)), 1.364 + relocInfo::runtime_call_type); 1.365 + delayed()->nop(); 1.366 + } 1.367 + 1.368 + verify_oop(obj); 1.369 +} 1.370 + 1.371 + 1.372 +#ifndef PRODUCT 1.373 + 1.374 +void C1_MacroAssembler::verify_stack_oop(int stack_offset) { 1.375 + if (!VerifyOops) return; 1.376 + verify_oop_addr(Address(SP, 0, stack_offset + STACK_BIAS)); 1.377 +} 1.378 + 1.379 +void C1_MacroAssembler::verify_not_null_oop(Register r) { 1.380 + Label not_null; 1.381 + br_zero(Assembler::notEqual, false, Assembler::pt, r, not_null); 1.382 + delayed()->nop(); 1.383 + stop("non-null oop required"); 1.384 + bind(not_null); 1.385 + if (!VerifyOops) return; 1.386 + verify_oop(r); 1.387 +} 1.388 + 1.389 +void C1_MacroAssembler::invalidate_registers(bool iregisters, bool lregisters, bool oregisters, 1.390 + Register preserve1, Register preserve2) { 1.391 + if (iregisters) { 1.392 + for (int i = 0; i < 6; i++) { 1.393 + Register r = as_iRegister(i); 1.394 + if (r != preserve1 && r != preserve2) set(0xdead, r); 1.395 + } 1.396 + } 1.397 + if (oregisters) { 1.398 + for (int i = 0; i < 6; i++) { 1.399 + Register r = as_oRegister(i); 1.400 + if (r != preserve1 && r != preserve2) set(0xdead, r); 1.401 + } 1.402 + } 1.403 + if (lregisters) { 1.404 + for (int i = 0; i < 8; i++) { 1.405 + Register r = as_lRegister(i); 1.406 + if (r != preserve1 && r != preserve2) set(0xdead, r); 1.407 + } 1.408 + } 1.409 +} 1.410 + 1.411 + 1.412 +#endif