1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/v8.h" 6 7 #if V8_TARGET_ARCH_MIPS 8 9 #include "src/codegen.h" 10 #include "src/macro-assembler.h" 11 #include "src/mips/simulator-mips.h" 12 13 namespace v8 { 14 namespace internal { 15 16 17 #define __ masm. 18 19 20 #if defined(USE_SIMULATOR) 21 byte* fast_exp_mips_machine_code = NULL; 22 double fast_exp_simulator(double x) { 23 return Simulator::current(Isolate::Current())->CallFP( 24 fast_exp_mips_machine_code, x, 0); 25 } 26 #endif 27 28 29 UnaryMathFunction CreateExpFunction() { 30 if (!FLAG_fast_math) return &std::exp; 31 size_t actual_size; 32 byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true)); 33 if (buffer == NULL) return &std::exp; 34 ExternalReference::InitializeMathExpData(); 35 36 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); 37 38 { 39 DoubleRegister input = f12; 40 DoubleRegister result = f0; 41 DoubleRegister double_scratch1 = f4; 42 DoubleRegister double_scratch2 = f6; 43 Register temp1 = t0; 44 Register temp2 = t1; 45 Register temp3 = t2; 46 47 __ MovFromFloatParameter(input); 48 __ Push(temp3, temp2, temp1); 49 MathExpGenerator::EmitMathExp( 50 &masm, input, result, double_scratch1, double_scratch2, 51 temp1, temp2, temp3); 52 __ Pop(temp3, temp2, temp1); 53 __ MovToFloatResult(result); 54 __ Ret(); 55 } 56 57 CodeDesc desc; 58 masm.GetCode(&desc); 59 ASSERT(!RelocInfo::RequiresRelocation(desc)); 60 61 CPU::FlushICache(buffer, actual_size); 62 OS::ProtectCode(buffer, actual_size); 63 64 #if !defined(USE_SIMULATOR) 65 return FUNCTION_CAST<UnaryMathFunction>(buffer); 66 #else 67 fast_exp_mips_machine_code = buffer; 68 return &fast_exp_simulator; 69 #endif 70 } 71 72 73 #if defined(V8_HOST_ARCH_MIPS) 74 MemCopyUint8Function CreateMemCopyUint8Function(MemCopyUint8Function stub) { 75 #if defined(USE_SIMULATOR) 76 return stub; 77 #else 78 size_t actual_size; 79 byte* buffer = static_cast<byte*>(OS::Allocate(3 * KB, &actual_size, true)); 80 if (buffer == NULL) return stub; 81 82 // This code assumes that cache lines are 32 bytes and if the cache line is 83 // larger it will not work correctly. 84 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); 85 86 { 87 Label lastb, unaligned, aligned, chkw, 88 loop16w, chk1w, wordCopy_loop, skip_pref, lastbloop, 89 leave, ua_chk16w, ua_loop16w, ua_skip_pref, ua_chkw, 90 ua_chk1w, ua_wordCopy_loop, ua_smallCopy, ua_smallCopy_loop; 91 92 // The size of each prefetch. 93 uint32_t pref_chunk = 32; 94 // The maximum size of a prefetch, it must not be less then pref_chunk. 95 // If the real size of a prefetch is greater then max_pref_size and 96 // the kPrefHintPrepareForStore hint is used, the code will not work 97 // correctly. 98 uint32_t max_pref_size = 128; 99 ASSERT(pref_chunk < max_pref_size); 100 101 // pref_limit is set based on the fact that we never use an offset 102 // greater then 5 on a store pref and that a single pref can 103 // never be larger then max_pref_size. 104 uint32_t pref_limit = (5 * pref_chunk) + max_pref_size; 105 int32_t pref_hint_load = kPrefHintLoadStreamed; 106 int32_t pref_hint_store = kPrefHintPrepareForStore; 107 uint32_t loadstore_chunk = 4; 108 109 // The initial prefetches may fetch bytes that are before the buffer being 110 // copied. Start copies with an offset of 4 so avoid this situation when 111 // using kPrefHintPrepareForStore. 112 ASSERT(pref_hint_store != kPrefHintPrepareForStore || 113 pref_chunk * 4 >= max_pref_size); 114 115 // If the size is less than 8, go to lastb. Regardless of size, 116 // copy dst pointer to v0 for the retuen value. 117 __ slti(t2, a2, 2 * loadstore_chunk); 118 __ bne(t2, zero_reg, &lastb); 119 __ mov(v0, a0); // In delay slot. 120 121 // If src and dst have different alignments, go to unaligned, if they 122 // have the same alignment (but are not actually aligned) do a partial 123 // load/store to make them aligned. If they are both already aligned 124 // we can start copying at aligned. 125 __ xor_(t8, a1, a0); 126 __ andi(t8, t8, loadstore_chunk - 1); // t8 is a0/a1 word-displacement. 127 __ bne(t8, zero_reg, &unaligned); 128 __ subu(a3, zero_reg, a0); // In delay slot. 129 130 __ andi(a3, a3, loadstore_chunk - 1); // Copy a3 bytes to align a0/a1. 131 __ beq(a3, zero_reg, &aligned); // Already aligned. 132 __ subu(a2, a2, a3); // In delay slot. a2 is the remining bytes count. 133 134 if (kArchEndian == kLittle) { 135 __ lwr(t8, MemOperand(a1)); 136 __ addu(a1, a1, a3); 137 __ swr(t8, MemOperand(a0)); 138 __ addu(a0, a0, a3); 139 } else { 140 __ lwl(t8, MemOperand(a1)); 141 __ addu(a1, a1, a3); 142 __ swl(t8, MemOperand(a0)); 143 __ addu(a0, a0, a3); 144 } 145 // Now dst/src are both aligned to (word) aligned addresses. Set a2 to 146 // count how many bytes we have to copy after all the 64 byte chunks are 147 // copied and a3 to the dst pointer after all the 64 byte chunks have been 148 // copied. We will loop, incrementing a0 and a1 until a0 equals a3. 149 __ bind(&aligned); 150 __ andi(t8, a2, 0x3f); 151 __ beq(a2, t8, &chkw); // Less than 64? 152 __ subu(a3, a2, t8); // In delay slot. 153 __ addu(a3, a0, a3); // Now a3 is the final dst after loop. 154 155 // When in the loop we prefetch with kPrefHintPrepareForStore hint, 156 // in this case the a0+x should be past the "t0-32" address. This means: 157 // for x=128 the last "safe" a0 address is "t0-160". Alternatively, for 158 // x=64 the last "safe" a0 address is "t0-96". In the current version we 159 // will use "pref hint, 128(a0)", so "t0-160" is the limit. 160 if (pref_hint_store == kPrefHintPrepareForStore) { 161 __ addu(t0, a0, a2); // t0 is the "past the end" address. 162 __ Subu(t9, t0, pref_limit); // t9 is the "last safe pref" address. 163 } 164 165 __ Pref(pref_hint_load, MemOperand(a1, 0 * pref_chunk)); 166 __ Pref(pref_hint_load, MemOperand(a1, 1 * pref_chunk)); 167 __ Pref(pref_hint_load, MemOperand(a1, 2 * pref_chunk)); 168 __ Pref(pref_hint_load, MemOperand(a1, 3 * pref_chunk)); 169 170 if (pref_hint_store != kPrefHintPrepareForStore) { 171 __ Pref(pref_hint_store, MemOperand(a0, 1 * pref_chunk)); 172 __ Pref(pref_hint_store, MemOperand(a0, 2 * pref_chunk)); 173 __ Pref(pref_hint_store, MemOperand(a0, 3 * pref_chunk)); 174 } 175 __ bind(&loop16w); 176 __ lw(t0, MemOperand(a1)); 177 178 if (pref_hint_store == kPrefHintPrepareForStore) { 179 __ sltu(v1, t9, a0); // If a0 > t9, don't use next prefetch. 180 __ Branch(USE_DELAY_SLOT, &skip_pref, gt, v1, Operand(zero_reg)); 181 } 182 __ lw(t1, MemOperand(a1, 1, loadstore_chunk)); // Maybe in delay slot. 183 184 __ Pref(pref_hint_store, MemOperand(a0, 4 * pref_chunk)); 185 __ Pref(pref_hint_store, MemOperand(a0, 5 * pref_chunk)); 186 187 __ bind(&skip_pref); 188 __ lw(t2, MemOperand(a1, 2, loadstore_chunk)); 189 __ lw(t3, MemOperand(a1, 3, loadstore_chunk)); 190 __ lw(t4, MemOperand(a1, 4, loadstore_chunk)); 191 __ lw(t5, MemOperand(a1, 5, loadstore_chunk)); 192 __ lw(t6, MemOperand(a1, 6, loadstore_chunk)); 193 __ lw(t7, MemOperand(a1, 7, loadstore_chunk)); 194 __ Pref(pref_hint_load, MemOperand(a1, 4 * pref_chunk)); 195 196 __ sw(t0, MemOperand(a0)); 197 __ sw(t1, MemOperand(a0, 1, loadstore_chunk)); 198 __ sw(t2, MemOperand(a0, 2, loadstore_chunk)); 199 __ sw(t3, MemOperand(a0, 3, loadstore_chunk)); 200 __ sw(t4, MemOperand(a0, 4, loadstore_chunk)); 201 __ sw(t5, MemOperand(a0, 5, loadstore_chunk)); 202 __ sw(t6, MemOperand(a0, 6, loadstore_chunk)); 203 __ sw(t7, MemOperand(a0, 7, loadstore_chunk)); 204 205 __ lw(t0, MemOperand(a1, 8, loadstore_chunk)); 206 __ lw(t1, MemOperand(a1, 9, loadstore_chunk)); 207 __ lw(t2, MemOperand(a1, 10, loadstore_chunk)); 208 __ lw(t3, MemOperand(a1, 11, loadstore_chunk)); 209 __ lw(t4, MemOperand(a1, 12, loadstore_chunk)); 210 __ lw(t5, MemOperand(a1, 13, loadstore_chunk)); 211 __ lw(t6, MemOperand(a1, 14, loadstore_chunk)); 212 __ lw(t7, MemOperand(a1, 15, loadstore_chunk)); 213 __ Pref(pref_hint_load, MemOperand(a1, 5 * pref_chunk)); 214 215 __ sw(t0, MemOperand(a0, 8, loadstore_chunk)); 216 __ sw(t1, MemOperand(a0, 9, loadstore_chunk)); 217 __ sw(t2, MemOperand(a0, 10, loadstore_chunk)); 218 __ sw(t3, MemOperand(a0, 11, loadstore_chunk)); 219 __ sw(t4, MemOperand(a0, 12, loadstore_chunk)); 220 __ sw(t5, MemOperand(a0, 13, loadstore_chunk)); 221 __ sw(t6, MemOperand(a0, 14, loadstore_chunk)); 222 __ sw(t7, MemOperand(a0, 15, loadstore_chunk)); 223 __ addiu(a0, a0, 16 * loadstore_chunk); 224 __ bne(a0, a3, &loop16w); 225 __ addiu(a1, a1, 16 * loadstore_chunk); // In delay slot. 226 __ mov(a2, t8); 227 228 // Here we have src and dest word-aligned but less than 64-bytes to go. 229 // Check for a 32 bytes chunk and copy if there is one. Otherwise jump 230 // down to chk1w to handle the tail end of the copy. 231 __ bind(&chkw); 232 __ Pref(pref_hint_load, MemOperand(a1, 0 * pref_chunk)); 233 __ andi(t8, a2, 0x1f); 234 __ beq(a2, t8, &chk1w); // Less than 32? 235 __ nop(); // In delay slot. 236 __ lw(t0, MemOperand(a1)); 237 __ lw(t1, MemOperand(a1, 1, loadstore_chunk)); 238 __ lw(t2, MemOperand(a1, 2, loadstore_chunk)); 239 __ lw(t3, MemOperand(a1, 3, loadstore_chunk)); 240 __ lw(t4, MemOperand(a1, 4, loadstore_chunk)); 241 __ lw(t5, MemOperand(a1, 5, loadstore_chunk)); 242 __ lw(t6, MemOperand(a1, 6, loadstore_chunk)); 243 __ lw(t7, MemOperand(a1, 7, loadstore_chunk)); 244 __ addiu(a1, a1, 8 * loadstore_chunk); 245 __ sw(t0, MemOperand(a0)); 246 __ sw(t1, MemOperand(a0, 1, loadstore_chunk)); 247 __ sw(t2, MemOperand(a0, 2, loadstore_chunk)); 248 __ sw(t3, MemOperand(a0, 3, loadstore_chunk)); 249 __ sw(t4, MemOperand(a0, 4, loadstore_chunk)); 250 __ sw(t5, MemOperand(a0, 5, loadstore_chunk)); 251 __ sw(t6, MemOperand(a0, 6, loadstore_chunk)); 252 __ sw(t7, MemOperand(a0, 7, loadstore_chunk)); 253 __ addiu(a0, a0, 8 * loadstore_chunk); 254 255 // Here we have less than 32 bytes to copy. Set up for a loop to copy 256 // one word at a time. Set a2 to count how many bytes we have to copy 257 // after all the word chunks are copied and a3 to the dst pointer after 258 // all the word chunks have been copied. We will loop, incrementing a0 259 // and a1 untill a0 equals a3. 260 __ bind(&chk1w); 261 __ andi(a2, t8, loadstore_chunk - 1); 262 __ beq(a2, t8, &lastb); 263 __ subu(a3, t8, a2); // In delay slot. 264 __ addu(a3, a0, a3); 265 266 __ bind(&wordCopy_loop); 267 __ lw(t3, MemOperand(a1)); 268 __ addiu(a0, a0, loadstore_chunk); 269 __ addiu(a1, a1, loadstore_chunk); 270 __ bne(a0, a3, &wordCopy_loop); 271 __ sw(t3, MemOperand(a0, -1, loadstore_chunk)); // In delay slot. 272 273 __ bind(&lastb); 274 __ Branch(&leave, le, a2, Operand(zero_reg)); 275 __ addu(a3, a0, a2); 276 277 __ bind(&lastbloop); 278 __ lb(v1, MemOperand(a1)); 279 __ addiu(a0, a0, 1); 280 __ addiu(a1, a1, 1); 281 __ bne(a0, a3, &lastbloop); 282 __ sb(v1, MemOperand(a0, -1)); // In delay slot. 283 284 __ bind(&leave); 285 __ jr(ra); 286 __ nop(); 287 288 // Unaligned case. Only the dst gets aligned so we need to do partial 289 // loads of the source followed by normal stores to the dst (once we 290 // have aligned the destination). 291 __ bind(&unaligned); 292 __ andi(a3, a3, loadstore_chunk - 1); // Copy a3 bytes to align a0/a1. 293 __ beq(a3, zero_reg, &ua_chk16w); 294 __ subu(a2, a2, a3); // In delay slot. 295 296 if (kArchEndian == kLittle) { 297 __ lwr(v1, MemOperand(a1)); 298 __ lwl(v1, 299 MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one)); 300 __ addu(a1, a1, a3); 301 __ swr(v1, MemOperand(a0)); 302 __ addu(a0, a0, a3); 303 } else { 304 __ lwl(v1, MemOperand(a1)); 305 __ lwr(v1, 306 MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one)); 307 __ addu(a1, a1, a3); 308 __ swl(v1, MemOperand(a0)); 309 __ addu(a0, a0, a3); 310 } 311 312 // Now the dst (but not the source) is aligned. Set a2 to count how many 313 // bytes we have to copy after all the 64 byte chunks are copied and a3 to 314 // the dst pointer after all the 64 byte chunks have been copied. We will 315 // loop, incrementing a0 and a1 until a0 equals a3. 316 __ bind(&ua_chk16w); 317 __ andi(t8, a2, 0x3f); 318 __ beq(a2, t8, &ua_chkw); 319 __ subu(a3, a2, t8); // In delay slot. 320 __ addu(a3, a0, a3); 321 322 if (pref_hint_store == kPrefHintPrepareForStore) { 323 __ addu(t0, a0, a2); 324 __ Subu(t9, t0, pref_limit); 325 } 326 327 __ Pref(pref_hint_load, MemOperand(a1, 0 * pref_chunk)); 328 __ Pref(pref_hint_load, MemOperand(a1, 1 * pref_chunk)); 329 __ Pref(pref_hint_load, MemOperand(a1, 2 * pref_chunk)); 330 331 if (pref_hint_store != kPrefHintPrepareForStore) { 332 __ Pref(pref_hint_store, MemOperand(a0, 1 * pref_chunk)); 333 __ Pref(pref_hint_store, MemOperand(a0, 2 * pref_chunk)); 334 __ Pref(pref_hint_store, MemOperand(a0, 3 * pref_chunk)); 335 } 336 337 __ bind(&ua_loop16w); 338 __ Pref(pref_hint_load, MemOperand(a1, 3 * pref_chunk)); 339 if (kArchEndian == kLittle) { 340 __ lwr(t0, MemOperand(a1)); 341 __ lwr(t1, MemOperand(a1, 1, loadstore_chunk)); 342 __ lwr(t2, MemOperand(a1, 2, loadstore_chunk)); 343 344 if (pref_hint_store == kPrefHintPrepareForStore) { 345 __ sltu(v1, t9, a0); 346 __ Branch(USE_DELAY_SLOT, &ua_skip_pref, gt, v1, Operand(zero_reg)); 347 } 348 __ lwr(t3, MemOperand(a1, 3, loadstore_chunk)); // Maybe in delay slot. 349 350 __ Pref(pref_hint_store, MemOperand(a0, 4 * pref_chunk)); 351 __ Pref(pref_hint_store, MemOperand(a0, 5 * pref_chunk)); 352 353 __ bind(&ua_skip_pref); 354 __ lwr(t4, MemOperand(a1, 4, loadstore_chunk)); 355 __ lwr(t5, MemOperand(a1, 5, loadstore_chunk)); 356 __ lwr(t6, MemOperand(a1, 6, loadstore_chunk)); 357 __ lwr(t7, MemOperand(a1, 7, loadstore_chunk)); 358 __ lwl(t0, 359 MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one)); 360 __ lwl(t1, 361 MemOperand(a1, 2, loadstore_chunk, MemOperand::offset_minus_one)); 362 __ lwl(t2, 363 MemOperand(a1, 3, loadstore_chunk, MemOperand::offset_minus_one)); 364 __ lwl(t3, 365 MemOperand(a1, 4, loadstore_chunk, MemOperand::offset_minus_one)); 366 __ lwl(t4, 367 MemOperand(a1, 5, loadstore_chunk, MemOperand::offset_minus_one)); 368 __ lwl(t5, 369 MemOperand(a1, 6, loadstore_chunk, MemOperand::offset_minus_one)); 370 __ lwl(t6, 371 MemOperand(a1, 7, loadstore_chunk, MemOperand::offset_minus_one)); 372 __ lwl(t7, 373 MemOperand(a1, 8, loadstore_chunk, MemOperand::offset_minus_one)); 374 } else { 375 __ lwl(t0, MemOperand(a1)); 376 __ lwl(t1, MemOperand(a1, 1, loadstore_chunk)); 377 __ lwl(t2, MemOperand(a1, 2, loadstore_chunk)); 378 379 if (pref_hint_store == kPrefHintPrepareForStore) { 380 __ sltu(v1, t9, a0); 381 __ Branch(USE_DELAY_SLOT, &ua_skip_pref, gt, v1, Operand(zero_reg)); 382 } 383 __ lwl(t3, MemOperand(a1, 3, loadstore_chunk)); // Maybe in delay slot. 384 385 __ Pref(pref_hint_store, MemOperand(a0, 4 * pref_chunk)); 386 __ Pref(pref_hint_store, MemOperand(a0, 5 * pref_chunk)); 387 388 __ bind(&ua_skip_pref); 389 __ lwl(t4, MemOperand(a1, 4, loadstore_chunk)); 390 __ lwl(t5, MemOperand(a1, 5, loadstore_chunk)); 391 __ lwl(t6, MemOperand(a1, 6, loadstore_chunk)); 392 __ lwl(t7, MemOperand(a1, 7, loadstore_chunk)); 393 __ lwr(t0, 394 MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one)); 395 __ lwr(t1, 396 MemOperand(a1, 2, loadstore_chunk, MemOperand::offset_minus_one)); 397 __ lwr(t2, 398 MemOperand(a1, 3, loadstore_chunk, MemOperand::offset_minus_one)); 399 __ lwr(t3, 400 MemOperand(a1, 4, loadstore_chunk, MemOperand::offset_minus_one)); 401 __ lwr(t4, 402 MemOperand(a1, 5, loadstore_chunk, MemOperand::offset_minus_one)); 403 __ lwr(t5, 404 MemOperand(a1, 6, loadstore_chunk, MemOperand::offset_minus_one)); 405 __ lwr(t6, 406 MemOperand(a1, 7, loadstore_chunk, MemOperand::offset_minus_one)); 407 __ lwr(t7, 408 MemOperand(a1, 8, loadstore_chunk, MemOperand::offset_minus_one)); 409 } 410 __ Pref(pref_hint_load, MemOperand(a1, 4 * pref_chunk)); 411 __ sw(t0, MemOperand(a0)); 412 __ sw(t1, MemOperand(a0, 1, loadstore_chunk)); 413 __ sw(t2, MemOperand(a0, 2, loadstore_chunk)); 414 __ sw(t3, MemOperand(a0, 3, loadstore_chunk)); 415 __ sw(t4, MemOperand(a0, 4, loadstore_chunk)); 416 __ sw(t5, MemOperand(a0, 5, loadstore_chunk)); 417 __ sw(t6, MemOperand(a0, 6, loadstore_chunk)); 418 __ sw(t7, MemOperand(a0, 7, loadstore_chunk)); 419 if (kArchEndian == kLittle) { 420 __ lwr(t0, MemOperand(a1, 8, loadstore_chunk)); 421 __ lwr(t1, MemOperand(a1, 9, loadstore_chunk)); 422 __ lwr(t2, MemOperand(a1, 10, loadstore_chunk)); 423 __ lwr(t3, MemOperand(a1, 11, loadstore_chunk)); 424 __ lwr(t4, MemOperand(a1, 12, loadstore_chunk)); 425 __ lwr(t5, MemOperand(a1, 13, loadstore_chunk)); 426 __ lwr(t6, MemOperand(a1, 14, loadstore_chunk)); 427 __ lwr(t7, MemOperand(a1, 15, loadstore_chunk)); 428 __ lwl(t0, 429 MemOperand(a1, 9, loadstore_chunk, MemOperand::offset_minus_one)); 430 __ lwl(t1, 431 MemOperand(a1, 10, loadstore_chunk, MemOperand::offset_minus_one)); 432 __ lwl(t2, 433 MemOperand(a1, 11, loadstore_chunk, MemOperand::offset_minus_one)); 434 __ lwl(t3, 435 MemOperand(a1, 12, loadstore_chunk, MemOperand::offset_minus_one)); 436 __ lwl(t4, 437 MemOperand(a1, 13, loadstore_chunk, MemOperand::offset_minus_one)); 438 __ lwl(t5, 439 MemOperand(a1, 14, loadstore_chunk, MemOperand::offset_minus_one)); 440 __ lwl(t6, 441 MemOperand(a1, 15, loadstore_chunk, MemOperand::offset_minus_one)); 442 __ lwl(t7, 443 MemOperand(a1, 16, loadstore_chunk, MemOperand::offset_minus_one)); 444 } else { 445 __ lwl(t0, MemOperand(a1, 8, loadstore_chunk)); 446 __ lwl(t1, MemOperand(a1, 9, loadstore_chunk)); 447 __ lwl(t2, MemOperand(a1, 10, loadstore_chunk)); 448 __ lwl(t3, MemOperand(a1, 11, loadstore_chunk)); 449 __ lwl(t4, MemOperand(a1, 12, loadstore_chunk)); 450 __ lwl(t5, MemOperand(a1, 13, loadstore_chunk)); 451 __ lwl(t6, MemOperand(a1, 14, loadstore_chunk)); 452 __ lwl(t7, MemOperand(a1, 15, loadstore_chunk)); 453 __ lwr(t0, 454 MemOperand(a1, 9, loadstore_chunk, MemOperand::offset_minus_one)); 455 __ lwr(t1, 456 MemOperand(a1, 10, loadstore_chunk, MemOperand::offset_minus_one)); 457 __ lwr(t2, 458 MemOperand(a1, 11, loadstore_chunk, MemOperand::offset_minus_one)); 459 __ lwr(t3, 460 MemOperand(a1, 12, loadstore_chunk, MemOperand::offset_minus_one)); 461 __ lwr(t4, 462 MemOperand(a1, 13, loadstore_chunk, MemOperand::offset_minus_one)); 463 __ lwr(t5, 464 MemOperand(a1, 14, loadstore_chunk, MemOperand::offset_minus_one)); 465 __ lwr(t6, 466 MemOperand(a1, 15, loadstore_chunk, MemOperand::offset_minus_one)); 467 __ lwr(t7, 468 MemOperand(a1, 16, loadstore_chunk, MemOperand::offset_minus_one)); 469 } 470 __ Pref(pref_hint_load, MemOperand(a1, 5 * pref_chunk)); 471 __ sw(t0, MemOperand(a0, 8, loadstore_chunk)); 472 __ sw(t1, MemOperand(a0, 9, loadstore_chunk)); 473 __ sw(t2, MemOperand(a0, 10, loadstore_chunk)); 474 __ sw(t3, MemOperand(a0, 11, loadstore_chunk)); 475 __ sw(t4, MemOperand(a0, 12, loadstore_chunk)); 476 __ sw(t5, MemOperand(a0, 13, loadstore_chunk)); 477 __ sw(t6, MemOperand(a0, 14, loadstore_chunk)); 478 __ sw(t7, MemOperand(a0, 15, loadstore_chunk)); 479 __ addiu(a0, a0, 16 * loadstore_chunk); 480 __ bne(a0, a3, &ua_loop16w); 481 __ addiu(a1, a1, 16 * loadstore_chunk); // In delay slot. 482 __ mov(a2, t8); 483 484 // Here less than 64-bytes. Check for 485 // a 32 byte chunk and copy if there is one. Otherwise jump down to 486 // ua_chk1w to handle the tail end of the copy. 487 __ bind(&ua_chkw); 488 __ Pref(pref_hint_load, MemOperand(a1)); 489 __ andi(t8, a2, 0x1f); 490 491 __ beq(a2, t8, &ua_chk1w); 492 __ nop(); // In delay slot. 493 if (kArchEndian == kLittle) { 494 __ lwr(t0, MemOperand(a1)); 495 __ lwr(t1, MemOperand(a1, 1, loadstore_chunk)); 496 __ lwr(t2, MemOperand(a1, 2, loadstore_chunk)); 497 __ lwr(t3, MemOperand(a1, 3, loadstore_chunk)); 498 __ lwr(t4, MemOperand(a1, 4, loadstore_chunk)); 499 __ lwr(t5, MemOperand(a1, 5, loadstore_chunk)); 500 __ lwr(t6, MemOperand(a1, 6, loadstore_chunk)); 501 __ lwr(t7, MemOperand(a1, 7, loadstore_chunk)); 502 __ lwl(t0, 503 MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one)); 504 __ lwl(t1, 505 MemOperand(a1, 2, loadstore_chunk, MemOperand::offset_minus_one)); 506 __ lwl(t2, 507 MemOperand(a1, 3, loadstore_chunk, MemOperand::offset_minus_one)); 508 __ lwl(t3, 509 MemOperand(a1, 4, loadstore_chunk, MemOperand::offset_minus_one)); 510 __ lwl(t4, 511 MemOperand(a1, 5, loadstore_chunk, MemOperand::offset_minus_one)); 512 __ lwl(t5, 513 MemOperand(a1, 6, loadstore_chunk, MemOperand::offset_minus_one)); 514 __ lwl(t6, 515 MemOperand(a1, 7, loadstore_chunk, MemOperand::offset_minus_one)); 516 __ lwl(t7, 517 MemOperand(a1, 8, loadstore_chunk, MemOperand::offset_minus_one)); 518 } else { 519 __ lwl(t0, MemOperand(a1)); 520 __ lwl(t1, MemOperand(a1, 1, loadstore_chunk)); 521 __ lwl(t2, MemOperand(a1, 2, loadstore_chunk)); 522 __ lwl(t3, MemOperand(a1, 3, loadstore_chunk)); 523 __ lwl(t4, MemOperand(a1, 4, loadstore_chunk)); 524 __ lwl(t5, MemOperand(a1, 5, loadstore_chunk)); 525 __ lwl(t6, MemOperand(a1, 6, loadstore_chunk)); 526 __ lwl(t7, MemOperand(a1, 7, loadstore_chunk)); 527 __ lwr(t0, 528 MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one)); 529 __ lwr(t1, 530 MemOperand(a1, 2, loadstore_chunk, MemOperand::offset_minus_one)); 531 __ lwr(t2, 532 MemOperand(a1, 3, loadstore_chunk, MemOperand::offset_minus_one)); 533 __ lwr(t3, 534 MemOperand(a1, 4, loadstore_chunk, MemOperand::offset_minus_one)); 535 __ lwr(t4, 536 MemOperand(a1, 5, loadstore_chunk, MemOperand::offset_minus_one)); 537 __ lwr(t5, 538 MemOperand(a1, 6, loadstore_chunk, MemOperand::offset_minus_one)); 539 __ lwr(t6, 540 MemOperand(a1, 7, loadstore_chunk, MemOperand::offset_minus_one)); 541 __ lwr(t7, 542 MemOperand(a1, 8, loadstore_chunk, MemOperand::offset_minus_one)); 543 } 544 __ addiu(a1, a1, 8 * loadstore_chunk); 545 __ sw(t0, MemOperand(a0)); 546 __ sw(t1, MemOperand(a0, 1, loadstore_chunk)); 547 __ sw(t2, MemOperand(a0, 2, loadstore_chunk)); 548 __ sw(t3, MemOperand(a0, 3, loadstore_chunk)); 549 __ sw(t4, MemOperand(a0, 4, loadstore_chunk)); 550 __ sw(t5, MemOperand(a0, 5, loadstore_chunk)); 551 __ sw(t6, MemOperand(a0, 6, loadstore_chunk)); 552 __ sw(t7, MemOperand(a0, 7, loadstore_chunk)); 553 __ addiu(a0, a0, 8 * loadstore_chunk); 554 555 // Less than 32 bytes to copy. Set up for a loop to 556 // copy one word at a time. 557 __ bind(&ua_chk1w); 558 __ andi(a2, t8, loadstore_chunk - 1); 559 __ beq(a2, t8, &ua_smallCopy); 560 __ subu(a3, t8, a2); // In delay slot. 561 __ addu(a3, a0, a3); 562 563 __ bind(&ua_wordCopy_loop); 564 if (kArchEndian == kLittle) { 565 __ lwr(v1, MemOperand(a1)); 566 __ lwl(v1, 567 MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one)); 568 } else { 569 __ lwl(v1, MemOperand(a1)); 570 __ lwr(v1, 571 MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one)); 572 } 573 __ addiu(a0, a0, loadstore_chunk); 574 __ addiu(a1, a1, loadstore_chunk); 575 __ bne(a0, a3, &ua_wordCopy_loop); 576 __ sw(v1, MemOperand(a0, -1, loadstore_chunk)); // In delay slot. 577 578 // Copy the last 8 bytes. 579 __ bind(&ua_smallCopy); 580 __ beq(a2, zero_reg, &leave); 581 __ addu(a3, a0, a2); // In delay slot. 582 583 __ bind(&ua_smallCopy_loop); 584 __ lb(v1, MemOperand(a1)); 585 __ addiu(a0, a0, 1); 586 __ addiu(a1, a1, 1); 587 __ bne(a0, a3, &ua_smallCopy_loop); 588 __ sb(v1, MemOperand(a0, -1)); // In delay slot. 589 590 __ jr(ra); 591 __ nop(); 592 } 593 CodeDesc desc; 594 masm.GetCode(&desc); 595 ASSERT(!RelocInfo::RequiresRelocation(desc)); 596 597 CPU::FlushICache(buffer, actual_size); 598 OS::ProtectCode(buffer, actual_size); 599 return FUNCTION_CAST<MemCopyUint8Function>(buffer); 600 #endif 601 } 602 #endif 603 604 UnaryMathFunction CreateSqrtFunction() { 605 #if defined(USE_SIMULATOR) 606 return &std::sqrt; 607 #else 608 size_t actual_size; 609 byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true)); 610 if (buffer == NULL) return &std::sqrt; 611 612 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); 613 614 __ MovFromFloatParameter(f12); 615 __ sqrt_d(f0, f12); 616 __ MovToFloatResult(f0); 617 __ Ret(); 618 619 CodeDesc desc; 620 masm.GetCode(&desc); 621 ASSERT(!RelocInfo::RequiresRelocation(desc)); 622 623 CPU::FlushICache(buffer, actual_size); 624 OS::ProtectCode(buffer, actual_size); 625 return FUNCTION_CAST<UnaryMathFunction>(buffer); 626 #endif 627 } 628 629 #undef __ 630 631 632 // ------------------------------------------------------------------------- 633 // Platform-specific RuntimeCallHelper functions. 634 635 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { 636 masm->EnterFrame(StackFrame::INTERNAL); 637 ASSERT(!masm->has_frame()); 638 masm->set_has_frame(true); 639 } 640 641 642 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { 643 masm->LeaveFrame(StackFrame::INTERNAL); 644 ASSERT(masm->has_frame()); 645 masm->set_has_frame(false); 646 } 647 648 649 // ------------------------------------------------------------------------- 650 // Code generators 651 652 #define __ ACCESS_MASM(masm) 653 654 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( 655 MacroAssembler* masm, AllocationSiteMode mode, 656 Label* allocation_memento_found) { 657 // ----------- S t a t e ------------- 658 // -- a0 : value 659 // -- a1 : key 660 // -- a2 : receiver 661 // -- ra : return address 662 // -- a3 : target map, scratch for subsequent call 663 // -- t0 : scratch (elements) 664 // ----------------------------------- 665 if (mode == TRACK_ALLOCATION_SITE) { 666 ASSERT(allocation_memento_found != NULL); 667 __ JumpIfJSArrayHasAllocationMemento(a2, t0, allocation_memento_found); 668 } 669 670 // Set transitioned map. 671 __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset)); 672 __ RecordWriteField(a2, 673 HeapObject::kMapOffset, 674 a3, 675 t5, 676 kRAHasNotBeenSaved, 677 kDontSaveFPRegs, 678 EMIT_REMEMBERED_SET, 679 OMIT_SMI_CHECK); 680 } 681 682 683 void ElementsTransitionGenerator::GenerateSmiToDouble( 684 MacroAssembler* masm, AllocationSiteMode mode, Label* fail) { 685 // ----------- S t a t e ------------- 686 // -- a0 : value 687 // -- a1 : key 688 // -- a2 : receiver 689 // -- ra : return address 690 // -- a3 : target map, scratch for subsequent call 691 // -- t0 : scratch (elements) 692 // ----------------------------------- 693 Label loop, entry, convert_hole, gc_required, only_change_map, done; 694 695 Register scratch = t6; 696 697 if (mode == TRACK_ALLOCATION_SITE) { 698 __ JumpIfJSArrayHasAllocationMemento(a2, t0, fail); 699 } 700 701 // Check for empty arrays, which only require a map transition and no changes 702 // to the backing store. 703 __ lw(t0, FieldMemOperand(a2, JSObject::kElementsOffset)); 704 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex); 705 __ Branch(&only_change_map, eq, at, Operand(t0)); 706 707 __ push(ra); 708 __ lw(t1, FieldMemOperand(t0, FixedArray::kLengthOffset)); 709 // t0: source FixedArray 710 // t1: number of elements (smi-tagged) 711 712 // Allocate new FixedDoubleArray. 713 __ sll(scratch, t1, 2); 714 __ Addu(scratch, scratch, FixedDoubleArray::kHeaderSize); 715 __ Allocate(scratch, t2, t3, t5, &gc_required, DOUBLE_ALIGNMENT); 716 // t2: destination FixedDoubleArray, not tagged as heap object 717 718 // Set destination FixedDoubleArray's length and map. 719 __ LoadRoot(t5, Heap::kFixedDoubleArrayMapRootIndex); 720 __ sw(t1, MemOperand(t2, FixedDoubleArray::kLengthOffset)); 721 __ sw(t5, MemOperand(t2, HeapObject::kMapOffset)); 722 // Update receiver's map. 723 724 __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset)); 725 __ RecordWriteField(a2, 726 HeapObject::kMapOffset, 727 a3, 728 t5, 729 kRAHasBeenSaved, 730 kDontSaveFPRegs, 731 OMIT_REMEMBERED_SET, 732 OMIT_SMI_CHECK); 733 // Replace receiver's backing store with newly created FixedDoubleArray. 734 __ Addu(a3, t2, Operand(kHeapObjectTag)); 735 __ sw(a3, FieldMemOperand(a2, JSObject::kElementsOffset)); 736 __ RecordWriteField(a2, 737 JSObject::kElementsOffset, 738 a3, 739 t5, 740 kRAHasBeenSaved, 741 kDontSaveFPRegs, 742 EMIT_REMEMBERED_SET, 743 OMIT_SMI_CHECK); 744 745 746 // Prepare for conversion loop. 747 __ Addu(a3, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 748 __ Addu(t3, t2, Operand(FixedDoubleArray::kHeaderSize)); 749 __ sll(t2, t1, 2); 750 __ Addu(t2, t2, t3); 751 __ li(t0, Operand(kHoleNanLower32)); 752 __ li(t1, Operand(kHoleNanUpper32)); 753 // t0: kHoleNanLower32 754 // t1: kHoleNanUpper32 755 // t2: end of destination FixedDoubleArray, not tagged 756 // t3: begin of FixedDoubleArray element fields, not tagged 757 758 __ Branch(&entry); 759 760 __ bind(&only_change_map); 761 __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset)); 762 __ RecordWriteField(a2, 763 HeapObject::kMapOffset, 764 a3, 765 t5, 766 kRAHasNotBeenSaved, 767 kDontSaveFPRegs, 768 OMIT_REMEMBERED_SET, 769 OMIT_SMI_CHECK); 770 __ Branch(&done); 771 772 // Call into runtime if GC is required. 773 __ bind(&gc_required); 774 __ pop(ra); 775 __ Branch(fail); 776 777 // Convert and copy elements. 778 __ bind(&loop); 779 __ lw(t5, MemOperand(a3)); 780 __ Addu(a3, a3, kIntSize); 781 // t5: current element 782 __ UntagAndJumpIfNotSmi(t5, t5, &convert_hole); 783 784 // Normal smi, convert to double and store. 785 __ mtc1(t5, f0); 786 __ cvt_d_w(f0, f0); 787 __ sdc1(f0, MemOperand(t3)); 788 __ Addu(t3, t3, kDoubleSize); 789 790 __ Branch(&entry); 791 792 // Hole found, store the-hole NaN. 793 __ bind(&convert_hole); 794 if (FLAG_debug_code) { 795 // Restore a "smi-untagged" heap object. 796 __ SmiTag(t5); 797 __ Or(t5, t5, Operand(1)); 798 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); 799 __ Assert(eq, kObjectFoundInSmiOnlyArray, at, Operand(t5)); 800 } 801 __ sw(t0, MemOperand(t3, Register::kMantissaOffset)); // mantissa 802 __ sw(t1, MemOperand(t3, Register::kExponentOffset)); // exponent 803 __ Addu(t3, t3, kDoubleSize); 804 805 __ bind(&entry); 806 __ Branch(&loop, lt, t3, Operand(t2)); 807 808 __ pop(ra); 809 __ bind(&done); 810 } 811 812 813 void ElementsTransitionGenerator::GenerateDoubleToObject( 814 MacroAssembler* masm, AllocationSiteMode mode, Label* fail) { 815 // ----------- S t a t e ------------- 816 // -- a0 : value 817 // -- a1 : key 818 // -- a2 : receiver 819 // -- ra : return address 820 // -- a3 : target map, scratch for subsequent call 821 // -- t0 : scratch (elements) 822 // ----------------------------------- 823 Label entry, loop, convert_hole, gc_required, only_change_map; 824 825 if (mode == TRACK_ALLOCATION_SITE) { 826 __ JumpIfJSArrayHasAllocationMemento(a2, t0, fail); 827 } 828 829 // Check for empty arrays, which only require a map transition and no changes 830 // to the backing store. 831 __ lw(t0, FieldMemOperand(a2, JSObject::kElementsOffset)); 832 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex); 833 __ Branch(&only_change_map, eq, at, Operand(t0)); 834 835 __ MultiPush(a0.bit() | a1.bit() | a2.bit() | a3.bit() | ra.bit()); 836 837 __ lw(t1, FieldMemOperand(t0, FixedArray::kLengthOffset)); 838 // t0: source FixedArray 839 // t1: number of elements (smi-tagged) 840 841 // Allocate new FixedArray. 842 __ sll(a0, t1, 1); 843 __ Addu(a0, a0, FixedDoubleArray::kHeaderSize); 844 __ Allocate(a0, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS); 845 // t2: destination FixedArray, not tagged as heap object 846 // Set destination FixedDoubleArray's length and map. 847 __ LoadRoot(t5, Heap::kFixedArrayMapRootIndex); 848 __ sw(t1, MemOperand(t2, FixedDoubleArray::kLengthOffset)); 849 __ sw(t5, MemOperand(t2, HeapObject::kMapOffset)); 850 851 // Prepare for conversion loop. 852 __ Addu(t0, t0, Operand( 853 FixedDoubleArray::kHeaderSize - kHeapObjectTag 854 + Register::kExponentOffset)); 855 __ Addu(a3, t2, Operand(FixedArray::kHeaderSize)); 856 __ Addu(t2, t2, Operand(kHeapObjectTag)); 857 __ sll(t1, t1, 1); 858 __ Addu(t1, a3, t1); 859 __ LoadRoot(t3, Heap::kTheHoleValueRootIndex); 860 __ LoadRoot(t5, Heap::kHeapNumberMapRootIndex); 861 // Using offsetted addresses. 862 // a3: begin of destination FixedArray element fields, not tagged 863 // t0: begin of source FixedDoubleArray element fields, not tagged, 864 // points to the exponent 865 // t1: end of destination FixedArray, not tagged 866 // t2: destination FixedArray 867 // t3: the-hole pointer 868 // t5: heap number map 869 __ Branch(&entry); 870 871 // Call into runtime if GC is required. 872 __ bind(&gc_required); 873 __ MultiPop(a0.bit() | a1.bit() | a2.bit() | a3.bit() | ra.bit()); 874 875 __ Branch(fail); 876 877 __ bind(&loop); 878 __ lw(a1, MemOperand(t0)); 879 __ Addu(t0, t0, kDoubleSize); 880 // a1: current element's upper 32 bit 881 // t0: address of next element's upper 32 bit 882 __ Branch(&convert_hole, eq, a1, Operand(kHoleNanUpper32)); 883 884 // Non-hole double, copy value into a heap number. 885 __ AllocateHeapNumber(a2, a0, t6, t5, &gc_required); 886 // a2: new heap number 887 // Load mantissa of current element, t0 point to exponent of next element. 888 __ lw(a0, MemOperand(t0, (Register::kMantissaOffset 889 - Register::kExponentOffset - kDoubleSize))); 890 __ sw(a0, FieldMemOperand(a2, HeapNumber::kMantissaOffset)); 891 __ sw(a1, FieldMemOperand(a2, HeapNumber::kExponentOffset)); 892 __ mov(a0, a3); 893 __ sw(a2, MemOperand(a3)); 894 __ Addu(a3, a3, kIntSize); 895 __ RecordWrite(t2, 896 a0, 897 a2, 898 kRAHasBeenSaved, 899 kDontSaveFPRegs, 900 EMIT_REMEMBERED_SET, 901 OMIT_SMI_CHECK); 902 __ Branch(&entry); 903 904 // Replace the-hole NaN with the-hole pointer. 905 __ bind(&convert_hole); 906 __ sw(t3, MemOperand(a3)); 907 __ Addu(a3, a3, kIntSize); 908 909 __ bind(&entry); 910 __ Branch(&loop, lt, a3, Operand(t1)); 911 912 __ MultiPop(a2.bit() | a3.bit() | a0.bit() | a1.bit()); 913 // Replace receiver's backing store with newly created and filled FixedArray. 914 __ sw(t2, FieldMemOperand(a2, JSObject::kElementsOffset)); 915 __ RecordWriteField(a2, 916 JSObject::kElementsOffset, 917 t2, 918 t5, 919 kRAHasBeenSaved, 920 kDontSaveFPRegs, 921 EMIT_REMEMBERED_SET, 922 OMIT_SMI_CHECK); 923 __ pop(ra); 924 925 __ bind(&only_change_map); 926 // Update receiver's map. 927 __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset)); 928 __ RecordWriteField(a2, 929 HeapObject::kMapOffset, 930 a3, 931 t5, 932 kRAHasNotBeenSaved, 933 kDontSaveFPRegs, 934 OMIT_REMEMBERED_SET, 935 OMIT_SMI_CHECK); 936 } 937 938 939 void StringCharLoadGenerator::Generate(MacroAssembler* masm, 940 Register string, 941 Register index, 942 Register result, 943 Label* call_runtime) { 944 // Fetch the instance type of the receiver into result register. 945 __ lw(result, FieldMemOperand(string, HeapObject::kMapOffset)); 946 __ lbu(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); 947 948 // We need special handling for indirect strings. 949 Label check_sequential; 950 __ And(at, result, Operand(kIsIndirectStringMask)); 951 __ Branch(&check_sequential, eq, at, Operand(zero_reg)); 952 953 // Dispatch on the indirect string shape: slice or cons. 954 Label cons_string; 955 __ And(at, result, Operand(kSlicedNotConsMask)); 956 __ Branch(&cons_string, eq, at, Operand(zero_reg)); 957 958 // Handle slices. 959 Label indirect_string_loaded; 960 __ lw(result, FieldMemOperand(string, SlicedString::kOffsetOffset)); 961 __ lw(string, FieldMemOperand(string, SlicedString::kParentOffset)); 962 __ sra(at, result, kSmiTagSize); 963 __ Addu(index, index, at); 964 __ jmp(&indirect_string_loaded); 965 966 // Handle cons strings. 967 // Check whether the right hand side is the empty string (i.e. if 968 // this is really a flat string in a cons string). If that is not 969 // the case we would rather go to the runtime system now to flatten 970 // the string. 971 __ bind(&cons_string); 972 __ lw(result, FieldMemOperand(string, ConsString::kSecondOffset)); 973 __ LoadRoot(at, Heap::kempty_stringRootIndex); 974 __ Branch(call_runtime, ne, result, Operand(at)); 975 // Get the first of the two strings and load its instance type. 976 __ lw(string, FieldMemOperand(string, ConsString::kFirstOffset)); 977 978 __ bind(&indirect_string_loaded); 979 __ lw(result, FieldMemOperand(string, HeapObject::kMapOffset)); 980 __ lbu(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); 981 982 // Distinguish sequential and external strings. Only these two string 983 // representations can reach here (slices and flat cons strings have been 984 // reduced to the underlying sequential or external string). 985 Label external_string, check_encoding; 986 __ bind(&check_sequential); 987 STATIC_ASSERT(kSeqStringTag == 0); 988 __ And(at, result, Operand(kStringRepresentationMask)); 989 __ Branch(&external_string, ne, at, Operand(zero_reg)); 990 991 // Prepare sequential strings 992 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); 993 __ Addu(string, 994 string, 995 SeqTwoByteString::kHeaderSize - kHeapObjectTag); 996 __ jmp(&check_encoding); 997 998 // Handle external strings. 999 __ bind(&external_string); 1000 if (FLAG_debug_code) { 1001 // Assert that we do not have a cons or slice (indirect strings) here. 1002 // Sequential strings have already been ruled out. 1003 __ And(at, result, Operand(kIsIndirectStringMask)); 1004 __ Assert(eq, kExternalStringExpectedButNotFound, 1005 at, Operand(zero_reg)); 1006 } 1007 // Rule out short external strings. 1008 STATIC_ASSERT(kShortExternalStringTag != 0); 1009 __ And(at, result, Operand(kShortExternalStringMask)); 1010 __ Branch(call_runtime, ne, at, Operand(zero_reg)); 1011 __ lw(string, FieldMemOperand(string, ExternalString::kResourceDataOffset)); 1012 1013 Label ascii, done; 1014 __ bind(&check_encoding); 1015 STATIC_ASSERT(kTwoByteStringTag == 0); 1016 __ And(at, result, Operand(kStringEncodingMask)); 1017 __ Branch(&ascii, ne, at, Operand(zero_reg)); 1018 // Two-byte string. 1019 __ sll(at, index, 1); 1020 __ Addu(at, string, at); 1021 __ lhu(result, MemOperand(at)); 1022 __ jmp(&done); 1023 __ bind(&ascii); 1024 // Ascii string. 1025 __ Addu(at, string, index); 1026 __ lbu(result, MemOperand(at)); 1027 __ bind(&done); 1028 } 1029 1030 1031 static MemOperand ExpConstant(int index, Register base) { 1032 return MemOperand(base, index * kDoubleSize); 1033 } 1034 1035 1036 void MathExpGenerator::EmitMathExp(MacroAssembler* masm, 1037 DoubleRegister input, 1038 DoubleRegister result, 1039 DoubleRegister double_scratch1, 1040 DoubleRegister double_scratch2, 1041 Register temp1, 1042 Register temp2, 1043 Register temp3) { 1044 ASSERT(!input.is(result)); 1045 ASSERT(!input.is(double_scratch1)); 1046 ASSERT(!input.is(double_scratch2)); 1047 ASSERT(!result.is(double_scratch1)); 1048 ASSERT(!result.is(double_scratch2)); 1049 ASSERT(!double_scratch1.is(double_scratch2)); 1050 ASSERT(!temp1.is(temp2)); 1051 ASSERT(!temp1.is(temp3)); 1052 ASSERT(!temp2.is(temp3)); 1053 ASSERT(ExternalReference::math_exp_constants(0).address() != NULL); 1054 1055 Label zero, infinity, done; 1056 1057 __ li(temp3, Operand(ExternalReference::math_exp_constants(0))); 1058 1059 __ ldc1(double_scratch1, ExpConstant(0, temp3)); 1060 __ BranchF(&zero, NULL, ge, double_scratch1, input); 1061 1062 __ ldc1(double_scratch2, ExpConstant(1, temp3)); 1063 __ BranchF(&infinity, NULL, ge, input, double_scratch2); 1064 1065 __ ldc1(double_scratch1, ExpConstant(3, temp3)); 1066 __ ldc1(result, ExpConstant(4, temp3)); 1067 __ mul_d(double_scratch1, double_scratch1, input); 1068 __ add_d(double_scratch1, double_scratch1, result); 1069 __ FmoveLow(temp2, double_scratch1); 1070 __ sub_d(double_scratch1, double_scratch1, result); 1071 __ ldc1(result, ExpConstant(6, temp3)); 1072 __ ldc1(double_scratch2, ExpConstant(5, temp3)); 1073 __ mul_d(double_scratch1, double_scratch1, double_scratch2); 1074 __ sub_d(double_scratch1, double_scratch1, input); 1075 __ sub_d(result, result, double_scratch1); 1076 __ mul_d(double_scratch2, double_scratch1, double_scratch1); 1077 __ mul_d(result, result, double_scratch2); 1078 __ ldc1(double_scratch2, ExpConstant(7, temp3)); 1079 __ mul_d(result, result, double_scratch2); 1080 __ sub_d(result, result, double_scratch1); 1081 // Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1. 1082 ASSERT(*reinterpret_cast<double*> 1083 (ExternalReference::math_exp_constants(8).address()) == 1); 1084 __ Move(double_scratch2, 1); 1085 __ add_d(result, result, double_scratch2); 1086 __ srl(temp1, temp2, 11); 1087 __ Ext(temp2, temp2, 0, 11); 1088 __ Addu(temp1, temp1, Operand(0x3ff)); 1089 1090 // Must not call ExpConstant() after overwriting temp3! 1091 __ li(temp3, Operand(ExternalReference::math_exp_log_table())); 1092 __ sll(at, temp2, 3); 1093 __ Addu(temp3, temp3, Operand(at)); 1094 __ lw(temp2, MemOperand(temp3, Register::kMantissaOffset)); 1095 __ lw(temp3, MemOperand(temp3, Register::kExponentOffset)); 1096 // The first word is loaded is the lower number register. 1097 if (temp2.code() < temp3.code()) { 1098 __ sll(at, temp1, 20); 1099 __ Or(temp1, temp3, at); 1100 __ Move(double_scratch1, temp2, temp1); 1101 } else { 1102 __ sll(at, temp1, 20); 1103 __ Or(temp1, temp2, at); 1104 __ Move(double_scratch1, temp3, temp1); 1105 } 1106 __ mul_d(result, result, double_scratch1); 1107 __ BranchShort(&done); 1108 1109 __ bind(&zero); 1110 __ Move(result, kDoubleRegZero); 1111 __ BranchShort(&done); 1112 1113 __ bind(&infinity); 1114 __ ldc1(result, ExpConstant(2, temp3)); 1115 1116 __ bind(&done); 1117 } 1118 1119 #ifdef DEBUG 1120 // nop(CODE_AGE_MARKER_NOP) 1121 static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180; 1122 #endif 1123 1124 1125 CodeAgingHelper::CodeAgingHelper() { 1126 ASSERT(young_sequence_.length() == kNoCodeAgeSequenceLength); 1127 // Since patcher is a large object, allocate it dynamically when needed, 1128 // to avoid overloading the stack in stress conditions. 1129 // DONT_FLUSH is used because the CodeAgingHelper is initialized early in 1130 // the process, before MIPS simulator ICache is setup. 1131 SmartPointer<CodePatcher> patcher( 1132 new CodePatcher(young_sequence_.start(), 1133 young_sequence_.length() / Assembler::kInstrSize, 1134 CodePatcher::DONT_FLUSH)); 1135 PredictableCodeSizeScope scope(patcher->masm(), young_sequence_.length()); 1136 patcher->masm()->Push(ra, fp, cp, a1); 1137 patcher->masm()->nop(Assembler::CODE_AGE_SEQUENCE_NOP); 1138 patcher->masm()->Addu( 1139 fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); 1140 } 1141 1142 1143 #ifdef DEBUG 1144 bool CodeAgingHelper::IsOld(byte* candidate) const { 1145 return Memory::uint32_at(candidate) == kCodeAgePatchFirstInstruction; 1146 } 1147 #endif 1148 1149 1150 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) { 1151 bool result = isolate->code_aging_helper()->IsYoung(sequence); 1152 ASSERT(result || isolate->code_aging_helper()->IsOld(sequence)); 1153 return result; 1154 } 1155 1156 1157 void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age, 1158 MarkingParity* parity) { 1159 if (IsYoungSequence(isolate, sequence)) { 1160 *age = kNoAgeCodeAge; 1161 *parity = NO_MARKING_PARITY; 1162 } else { 1163 Address target_address = Assembler::target_address_at( 1164 sequence + Assembler::kInstrSize); 1165 Code* stub = GetCodeFromTargetAddress(target_address); 1166 GetCodeAgeAndParity(stub, age, parity); 1167 } 1168 } 1169 1170 1171 void Code::PatchPlatformCodeAge(Isolate* isolate, 1172 byte* sequence, 1173 Code::Age age, 1174 MarkingParity parity) { 1175 uint32_t young_length = isolate->code_aging_helper()->young_sequence_length(); 1176 if (age == kNoAgeCodeAge) { 1177 isolate->code_aging_helper()->CopyYoungSequenceTo(sequence); 1178 CPU::FlushICache(sequence, young_length); 1179 } else { 1180 Code* stub = GetCodeAgeStub(isolate, age, parity); 1181 CodePatcher patcher(sequence, young_length / Assembler::kInstrSize); 1182 // Mark this code sequence for FindPlatformCodeAgeSequence(). 1183 patcher.masm()->nop(Assembler::CODE_AGE_MARKER_NOP); 1184 // Load the stub address to t9 and call it, 1185 // GetCodeAgeAndParity() extracts the stub address from this instruction. 1186 patcher.masm()->li( 1187 t9, 1188 Operand(reinterpret_cast<uint32_t>(stub->instruction_start())), 1189 CONSTANT_SIZE); 1190 patcher.masm()->nop(); // Prevent jalr to jal optimization. 1191 patcher.masm()->jalr(t9, a0); 1192 patcher.masm()->nop(); // Branch delay slot nop. 1193 patcher.masm()->nop(); // Pad the empty space. 1194 } 1195 } 1196 1197 1198 #undef __ 1199 1200 } } // namespace v8::internal 1201 1202 #endif // V8_TARGET_ARCH_MIPS 1203