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