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 <limits.h> // For LONG_MIN, LONG_MAX. 6 7 #if V8_TARGET_ARCH_MIPS 8 9 #include "src/base/bits.h" 10 #include "src/base/division-by-constant.h" 11 #include "src/bootstrapper.h" 12 #include "src/codegen.h" 13 #include "src/debug/debug.h" 14 #include "src/mips/macro-assembler-mips.h" 15 #include "src/register-configuration.h" 16 #include "src/runtime/runtime.h" 17 18 namespace v8 { 19 namespace internal { 20 21 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size, 22 CodeObjectRequired create_code_object) 23 : Assembler(arg_isolate, buffer, size), 24 generating_stub_(false), 25 has_frame_(false), 26 has_double_zero_reg_set_(false) { 27 if (create_code_object == CodeObjectRequired::kYes) { 28 code_object_ = 29 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate()); 30 } 31 } 32 33 void MacroAssembler::Load(Register dst, 34 const MemOperand& src, 35 Representation r) { 36 DCHECK(!r.IsDouble()); 37 if (r.IsInteger8()) { 38 lb(dst, src); 39 } else if (r.IsUInteger8()) { 40 lbu(dst, src); 41 } else if (r.IsInteger16()) { 42 lh(dst, src); 43 } else if (r.IsUInteger16()) { 44 lhu(dst, src); 45 } else { 46 lw(dst, src); 47 } 48 } 49 50 51 void MacroAssembler::Store(Register src, 52 const MemOperand& dst, 53 Representation r) { 54 DCHECK(!r.IsDouble()); 55 if (r.IsInteger8() || r.IsUInteger8()) { 56 sb(src, dst); 57 } else if (r.IsInteger16() || r.IsUInteger16()) { 58 sh(src, dst); 59 } else { 60 if (r.IsHeapObject()) { 61 AssertNotSmi(src); 62 } else if (r.IsSmi()) { 63 AssertSmi(src); 64 } 65 sw(src, dst); 66 } 67 } 68 69 void MacroAssembler::LoadRoot(Register destination, 70 Heap::RootListIndex index) { 71 lw(destination, MemOperand(s6, index << kPointerSizeLog2)); 72 } 73 74 75 void MacroAssembler::LoadRoot(Register destination, 76 Heap::RootListIndex index, 77 Condition cond, 78 Register src1, const Operand& src2) { 79 Branch(2, NegateCondition(cond), src1, src2); 80 lw(destination, MemOperand(s6, index << kPointerSizeLog2)); 81 } 82 83 84 void MacroAssembler::StoreRoot(Register source, 85 Heap::RootListIndex index) { 86 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); 87 sw(source, MemOperand(s6, index << kPointerSizeLog2)); 88 } 89 90 91 void MacroAssembler::StoreRoot(Register source, 92 Heap::RootListIndex index, 93 Condition cond, 94 Register src1, const Operand& src2) { 95 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); 96 Branch(2, NegateCondition(cond), src1, src2); 97 sw(source, MemOperand(s6, index << kPointerSizeLog2)); 98 } 99 100 void MacroAssembler::PushCommonFrame(Register marker_reg) { 101 if (marker_reg.is_valid()) { 102 Push(ra, fp, marker_reg); 103 Addu(fp, sp, Operand(kPointerSize)); 104 } else { 105 Push(ra, fp); 106 mov(fp, sp); 107 } 108 } 109 110 void MacroAssembler::PopCommonFrame(Register marker_reg) { 111 if (marker_reg.is_valid()) { 112 Pop(ra, fp, marker_reg); 113 } else { 114 Pop(ra, fp); 115 } 116 } 117 118 void MacroAssembler::PushStandardFrame(Register function_reg) { 119 int offset = -StandardFrameConstants::kContextOffset; 120 if (function_reg.is_valid()) { 121 Push(ra, fp, cp, function_reg); 122 offset += kPointerSize; 123 } else { 124 Push(ra, fp, cp); 125 } 126 Addu(fp, sp, Operand(offset)); 127 } 128 129 // Push and pop all registers that can hold pointers. 130 void MacroAssembler::PushSafepointRegisters() { 131 // Safepoints expect a block of kNumSafepointRegisters values on the 132 // stack, so adjust the stack for unsaved registers. 133 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; 134 DCHECK(num_unsaved >= 0); 135 if (num_unsaved > 0) { 136 Subu(sp, sp, Operand(num_unsaved * kPointerSize)); 137 } 138 MultiPush(kSafepointSavedRegisters); 139 } 140 141 142 void MacroAssembler::PopSafepointRegisters() { 143 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; 144 MultiPop(kSafepointSavedRegisters); 145 if (num_unsaved > 0) { 146 Addu(sp, sp, Operand(num_unsaved * kPointerSize)); 147 } 148 } 149 150 151 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { 152 sw(src, SafepointRegisterSlot(dst)); 153 } 154 155 156 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { 157 lw(dst, SafepointRegisterSlot(src)); 158 } 159 160 161 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { 162 // The registers are pushed starting with the highest encoding, 163 // which means that lowest encodings are closest to the stack pointer. 164 return kSafepointRegisterStackIndexMap[reg_code]; 165 } 166 167 168 MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) { 169 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); 170 } 171 172 173 MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) { 174 UNIMPLEMENTED_MIPS(); 175 // General purpose registers are pushed last on the stack. 176 int doubles_size = DoubleRegister::kMaxNumRegisters * kDoubleSize; 177 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize; 178 return MemOperand(sp, doubles_size + register_offset); 179 } 180 181 182 void MacroAssembler::InNewSpace(Register object, 183 Register scratch, 184 Condition cc, 185 Label* branch) { 186 DCHECK(cc == eq || cc == ne); 187 CheckPageFlag(object, scratch, MemoryChunk::kIsInNewSpaceMask, cc, branch); 188 } 189 190 191 // Clobbers object, dst, value, and ra, if (ra_status == kRAHasBeenSaved) 192 // The register 'object' contains a heap object pointer. The heap object 193 // tag is shifted away. 194 void MacroAssembler::RecordWriteField( 195 Register object, 196 int offset, 197 Register value, 198 Register dst, 199 RAStatus ra_status, 200 SaveFPRegsMode save_fp, 201 RememberedSetAction remembered_set_action, 202 SmiCheck smi_check, 203 PointersToHereCheck pointers_to_here_check_for_value) { 204 DCHECK(!AreAliased(value, dst, t8, object)); 205 // First, check if a write barrier is even needed. The tests below 206 // catch stores of Smis. 207 Label done; 208 209 // Skip barrier if writing a smi. 210 if (smi_check == INLINE_SMI_CHECK) { 211 JumpIfSmi(value, &done); 212 } 213 214 // Although the object register is tagged, the offset is relative to the start 215 // of the object, so so offset must be a multiple of kPointerSize. 216 DCHECK(IsAligned(offset, kPointerSize)); 217 218 Addu(dst, object, Operand(offset - kHeapObjectTag)); 219 if (emit_debug_code()) { 220 Label ok; 221 And(t8, dst, Operand((1 << kPointerSizeLog2) - 1)); 222 Branch(&ok, eq, t8, Operand(zero_reg)); 223 stop("Unaligned cell in write barrier"); 224 bind(&ok); 225 } 226 227 RecordWrite(object, 228 dst, 229 value, 230 ra_status, 231 save_fp, 232 remembered_set_action, 233 OMIT_SMI_CHECK, 234 pointers_to_here_check_for_value); 235 236 bind(&done); 237 238 // Clobber clobbered input registers when running with the debug-code flag 239 // turned on to provoke errors. 240 if (emit_debug_code()) { 241 li(value, Operand(bit_cast<int32_t>(kZapValue + 4))); 242 li(dst, Operand(bit_cast<int32_t>(kZapValue + 8))); 243 } 244 } 245 246 247 // Clobbers object, dst, map, and ra, if (ra_status == kRAHasBeenSaved) 248 void MacroAssembler::RecordWriteForMap(Register object, 249 Register map, 250 Register dst, 251 RAStatus ra_status, 252 SaveFPRegsMode fp_mode) { 253 if (emit_debug_code()) { 254 DCHECK(!dst.is(at)); 255 lw(dst, FieldMemOperand(map, HeapObject::kMapOffset)); 256 Check(eq, 257 kWrongAddressOrValuePassedToRecordWrite, 258 dst, 259 Operand(isolate()->factory()->meta_map())); 260 } 261 262 if (!FLAG_incremental_marking) { 263 return; 264 } 265 266 if (emit_debug_code()) { 267 lw(at, FieldMemOperand(object, HeapObject::kMapOffset)); 268 Check(eq, 269 kWrongAddressOrValuePassedToRecordWrite, 270 map, 271 Operand(at)); 272 } 273 274 Label done; 275 276 // A single check of the map's pages interesting flag suffices, since it is 277 // only set during incremental collection, and then it's also guaranteed that 278 // the from object's page's interesting flag is also set. This optimization 279 // relies on the fact that maps can never be in new space. 280 CheckPageFlag(map, 281 map, // Used as scratch. 282 MemoryChunk::kPointersToHereAreInterestingMask, 283 eq, 284 &done); 285 286 Addu(dst, object, Operand(HeapObject::kMapOffset - kHeapObjectTag)); 287 if (emit_debug_code()) { 288 Label ok; 289 And(at, dst, Operand((1 << kPointerSizeLog2) - 1)); 290 Branch(&ok, eq, at, Operand(zero_reg)); 291 stop("Unaligned cell in write barrier"); 292 bind(&ok); 293 } 294 295 // Record the actual write. 296 if (ra_status == kRAHasNotBeenSaved) { 297 push(ra); 298 } 299 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET, 300 fp_mode); 301 CallStub(&stub); 302 if (ra_status == kRAHasNotBeenSaved) { 303 pop(ra); 304 } 305 306 bind(&done); 307 308 // Count number of write barriers in generated code. 309 isolate()->counters()->write_barriers_static()->Increment(); 310 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, at, dst); 311 312 // Clobber clobbered registers when running with the debug-code flag 313 // turned on to provoke errors. 314 if (emit_debug_code()) { 315 li(dst, Operand(bit_cast<int32_t>(kZapValue + 12))); 316 li(map, Operand(bit_cast<int32_t>(kZapValue + 16))); 317 } 318 } 319 320 321 // Clobbers object, address, value, and ra, if (ra_status == kRAHasBeenSaved) 322 // The register 'object' contains a heap object pointer. The heap object 323 // tag is shifted away. 324 void MacroAssembler::RecordWrite( 325 Register object, 326 Register address, 327 Register value, 328 RAStatus ra_status, 329 SaveFPRegsMode fp_mode, 330 RememberedSetAction remembered_set_action, 331 SmiCheck smi_check, 332 PointersToHereCheck pointers_to_here_check_for_value) { 333 DCHECK(!AreAliased(object, address, value, t8)); 334 DCHECK(!AreAliased(object, address, value, t9)); 335 336 if (emit_debug_code()) { 337 lw(at, MemOperand(address)); 338 Assert( 339 eq, kWrongAddressOrValuePassedToRecordWrite, at, Operand(value)); 340 } 341 342 if (remembered_set_action == OMIT_REMEMBERED_SET && 343 !FLAG_incremental_marking) { 344 return; 345 } 346 347 // First, check if a write barrier is even needed. The tests below 348 // catch stores of smis and stores into the young generation. 349 Label done; 350 351 if (smi_check == INLINE_SMI_CHECK) { 352 DCHECK_EQ(0, kSmiTag); 353 JumpIfSmi(value, &done); 354 } 355 356 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { 357 CheckPageFlag(value, 358 value, // Used as scratch. 359 MemoryChunk::kPointersToHereAreInterestingMask, 360 eq, 361 &done); 362 } 363 CheckPageFlag(object, 364 value, // Used as scratch. 365 MemoryChunk::kPointersFromHereAreInterestingMask, 366 eq, 367 &done); 368 369 // Record the actual write. 370 if (ra_status == kRAHasNotBeenSaved) { 371 push(ra); 372 } 373 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, 374 fp_mode); 375 CallStub(&stub); 376 if (ra_status == kRAHasNotBeenSaved) { 377 pop(ra); 378 } 379 380 bind(&done); 381 382 // Count number of write barriers in generated code. 383 isolate()->counters()->write_barriers_static()->Increment(); 384 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, at, 385 value); 386 387 // Clobber clobbered registers when running with the debug-code flag 388 // turned on to provoke errors. 389 if (emit_debug_code()) { 390 li(address, Operand(bit_cast<int32_t>(kZapValue + 12))); 391 li(value, Operand(bit_cast<int32_t>(kZapValue + 16))); 392 } 393 } 394 395 void MacroAssembler::RecordWriteCodeEntryField(Register js_function, 396 Register code_entry, 397 Register scratch) { 398 const int offset = JSFunction::kCodeEntryOffset; 399 400 // Since a code entry (value) is always in old space, we don't need to update 401 // remembered set. If incremental marking is off, there is nothing for us to 402 // do. 403 if (!FLAG_incremental_marking) return; 404 405 DCHECK(js_function.is(a1)); 406 DCHECK(code_entry.is(t0)); 407 DCHECK(scratch.is(t1)); 408 AssertNotSmi(js_function); 409 410 if (emit_debug_code()) { 411 Addu(scratch, js_function, Operand(offset - kHeapObjectTag)); 412 lw(at, MemOperand(scratch)); 413 Assert(eq, kWrongAddressOrValuePassedToRecordWrite, at, 414 Operand(code_entry)); 415 } 416 417 // First, check if a write barrier is even needed. The tests below 418 // catch stores of Smis and stores into young gen. 419 Label done; 420 421 CheckPageFlag(code_entry, scratch, 422 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done); 423 CheckPageFlag(js_function, scratch, 424 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done); 425 426 const Register dst = scratch; 427 Addu(dst, js_function, Operand(offset - kHeapObjectTag)); 428 429 // Save caller-saved registers. js_function and code_entry are in the 430 // caller-saved register list. 431 DCHECK(kJSCallerSaved & js_function.bit()); 432 DCHECK(kJSCallerSaved & code_entry.bit()); 433 MultiPush(kJSCallerSaved | ra.bit()); 434 435 int argument_count = 3; 436 437 PrepareCallCFunction(argument_count, 0, code_entry); 438 439 mov(a0, js_function); 440 mov(a1, dst); 441 li(a2, Operand(ExternalReference::isolate_address(isolate()))); 442 443 { 444 AllowExternalCallThatCantCauseGC scope(this); 445 CallCFunction( 446 ExternalReference::incremental_marking_record_write_code_entry_function( 447 isolate()), 448 argument_count); 449 } 450 451 // Restore caller-saved registers. 452 MultiPop(kJSCallerSaved | ra.bit()); 453 454 bind(&done); 455 } 456 457 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests. 458 Register address, 459 Register scratch, 460 SaveFPRegsMode fp_mode, 461 RememberedSetFinalAction and_then) { 462 Label done; 463 if (emit_debug_code()) { 464 Label ok; 465 JumpIfNotInNewSpace(object, scratch, &ok); 466 stop("Remembered set pointer is in new space"); 467 bind(&ok); 468 } 469 // Load store buffer top. 470 ExternalReference store_buffer = 471 ExternalReference::store_buffer_top(isolate()); 472 li(t8, Operand(store_buffer)); 473 lw(scratch, MemOperand(t8)); 474 // Store pointer to buffer and increment buffer top. 475 sw(address, MemOperand(scratch)); 476 Addu(scratch, scratch, kPointerSize); 477 // Write back new top of buffer. 478 sw(scratch, MemOperand(t8)); 479 // Call stub on end of buffer. 480 // Check for end of buffer. 481 And(t8, scratch, Operand(StoreBuffer::kStoreBufferMask)); 482 if (and_then == kFallThroughAtEnd) { 483 Branch(&done, ne, t8, Operand(zero_reg)); 484 } else { 485 DCHECK(and_then == kReturnAtEnd); 486 Ret(ne, t8, Operand(zero_reg)); 487 } 488 push(ra); 489 StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode); 490 CallStub(&store_buffer_overflow); 491 pop(ra); 492 bind(&done); 493 if (and_then == kReturnAtEnd) { 494 Ret(); 495 } 496 } 497 498 499 // ----------------------------------------------------------------------------- 500 // Allocation support. 501 502 503 // Compute the hash code from the untagged key. This must be kept in sync with 504 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in 505 // code-stub-hydrogen.cc 506 void MacroAssembler::GetNumberHash(Register reg0, Register scratch) { 507 // First of all we assign the hash seed to scratch. 508 LoadRoot(scratch, Heap::kHashSeedRootIndex); 509 SmiUntag(scratch); 510 511 // Xor original key with a seed. 512 xor_(reg0, reg0, scratch); 513 514 // Compute the hash code from the untagged key. This must be kept in sync 515 // with ComputeIntegerHash in utils.h. 516 // 517 // hash = ~hash + (hash << 15); 518 nor(scratch, reg0, zero_reg); 519 Lsa(reg0, scratch, reg0, 15); 520 521 // hash = hash ^ (hash >> 12); 522 srl(at, reg0, 12); 523 xor_(reg0, reg0, at); 524 525 // hash = hash + (hash << 2); 526 Lsa(reg0, reg0, reg0, 2); 527 528 // hash = hash ^ (hash >> 4); 529 srl(at, reg0, 4); 530 xor_(reg0, reg0, at); 531 532 // hash = hash * 2057; 533 sll(scratch, reg0, 11); 534 Lsa(reg0, reg0, reg0, 3); 535 addu(reg0, reg0, scratch); 536 537 // hash = hash ^ (hash >> 16); 538 srl(at, reg0, 16); 539 xor_(reg0, reg0, at); 540 And(reg0, reg0, Operand(0x3fffffff)); 541 } 542 543 // --------------------------------------------------------------------------- 544 // Instruction macros. 545 546 void MacroAssembler::Addu(Register rd, Register rs, const Operand& rt) { 547 if (rt.is_reg()) { 548 addu(rd, rs, rt.rm()); 549 } else { 550 if (is_int16(rt.imm32_) && !MustUseReg(rt.rmode_)) { 551 addiu(rd, rs, rt.imm32_); 552 } else { 553 // li handles the relocation. 554 DCHECK(!rs.is(at)); 555 li(at, rt); 556 addu(rd, rs, at); 557 } 558 } 559 } 560 561 562 void MacroAssembler::Subu(Register rd, Register rs, const Operand& rt) { 563 if (rt.is_reg()) { 564 subu(rd, rs, rt.rm()); 565 } else { 566 if (is_int16(rt.imm32_) && !MustUseReg(rt.rmode_)) { 567 addiu(rd, rs, -rt.imm32_); // No subiu instr, use addiu(x, y, -imm). 568 } else { 569 // li handles the relocation. 570 DCHECK(!rs.is(at)); 571 li(at, rt); 572 subu(rd, rs, at); 573 } 574 } 575 } 576 577 578 void MacroAssembler::Mul(Register rd, Register rs, const Operand& rt) { 579 if (rt.is_reg()) { 580 if (IsMipsArchVariant(kLoongson)) { 581 mult(rs, rt.rm()); 582 mflo(rd); 583 } else { 584 mul(rd, rs, rt.rm()); 585 } 586 } else { 587 // li handles the relocation. 588 DCHECK(!rs.is(at)); 589 li(at, rt); 590 if (IsMipsArchVariant(kLoongson)) { 591 mult(rs, at); 592 mflo(rd); 593 } else { 594 mul(rd, rs, at); 595 } 596 } 597 } 598 599 600 void MacroAssembler::Mul(Register rd_hi, Register rd_lo, 601 Register rs, const Operand& rt) { 602 if (rt.is_reg()) { 603 if (!IsMipsArchVariant(kMips32r6)) { 604 mult(rs, rt.rm()); 605 mflo(rd_lo); 606 mfhi(rd_hi); 607 } else { 608 if (rd_lo.is(rs)) { 609 DCHECK(!rd_hi.is(rs)); 610 DCHECK(!rd_hi.is(rt.rm()) && !rd_lo.is(rt.rm())); 611 muh(rd_hi, rs, rt.rm()); 612 mul(rd_lo, rs, rt.rm()); 613 } else { 614 DCHECK(!rd_hi.is(rt.rm()) && !rd_lo.is(rt.rm())); 615 mul(rd_lo, rs, rt.rm()); 616 muh(rd_hi, rs, rt.rm()); 617 } 618 } 619 } else { 620 // li handles the relocation. 621 DCHECK(!rs.is(at)); 622 li(at, rt); 623 if (!IsMipsArchVariant(kMips32r6)) { 624 mult(rs, at); 625 mflo(rd_lo); 626 mfhi(rd_hi); 627 } else { 628 if (rd_lo.is(rs)) { 629 DCHECK(!rd_hi.is(rs)); 630 DCHECK(!rd_hi.is(at) && !rd_lo.is(at)); 631 muh(rd_hi, rs, at); 632 mul(rd_lo, rs, at); 633 } else { 634 DCHECK(!rd_hi.is(at) && !rd_lo.is(at)); 635 mul(rd_lo, rs, at); 636 muh(rd_hi, rs, at); 637 } 638 } 639 } 640 } 641 642 void MacroAssembler::Mulu(Register rd_hi, Register rd_lo, Register rs, 643 const Operand& rt) { 644 Register reg; 645 if (rt.is_reg()) { 646 reg = rt.rm(); 647 } else { 648 DCHECK(!rs.is(at)); 649 reg = at; 650 li(reg, rt); 651 } 652 653 if (!IsMipsArchVariant(kMips32r6)) { 654 multu(rs, reg); 655 mflo(rd_lo); 656 mfhi(rd_hi); 657 } else { 658 if (rd_lo.is(rs)) { 659 DCHECK(!rd_hi.is(rs)); 660 DCHECK(!rd_hi.is(reg) && !rd_lo.is(reg)); 661 muhu(rd_hi, rs, reg); 662 mulu(rd_lo, rs, reg); 663 } else { 664 DCHECK(!rd_hi.is(reg) && !rd_lo.is(reg)); 665 mulu(rd_lo, rs, reg); 666 muhu(rd_hi, rs, reg); 667 } 668 } 669 } 670 671 void MacroAssembler::Mulh(Register rd, Register rs, const Operand& rt) { 672 if (rt.is_reg()) { 673 if (!IsMipsArchVariant(kMips32r6)) { 674 mult(rs, rt.rm()); 675 mfhi(rd); 676 } else { 677 muh(rd, rs, rt.rm()); 678 } 679 } else { 680 // li handles the relocation. 681 DCHECK(!rs.is(at)); 682 li(at, rt); 683 if (!IsMipsArchVariant(kMips32r6)) { 684 mult(rs, at); 685 mfhi(rd); 686 } else { 687 muh(rd, rs, at); 688 } 689 } 690 } 691 692 693 void MacroAssembler::Mult(Register rs, const Operand& rt) { 694 if (rt.is_reg()) { 695 mult(rs, rt.rm()); 696 } else { 697 // li handles the relocation. 698 DCHECK(!rs.is(at)); 699 li(at, rt); 700 mult(rs, at); 701 } 702 } 703 704 705 void MacroAssembler::Mulhu(Register rd, Register rs, const Operand& rt) { 706 if (rt.is_reg()) { 707 if (!IsMipsArchVariant(kMips32r6)) { 708 multu(rs, rt.rm()); 709 mfhi(rd); 710 } else { 711 muhu(rd, rs, rt.rm()); 712 } 713 } else { 714 // li handles the relocation. 715 DCHECK(!rs.is(at)); 716 li(at, rt); 717 if (!IsMipsArchVariant(kMips32r6)) { 718 multu(rs, at); 719 mfhi(rd); 720 } else { 721 muhu(rd, rs, at); 722 } 723 } 724 } 725 726 727 void MacroAssembler::Multu(Register rs, const Operand& rt) { 728 if (rt.is_reg()) { 729 multu(rs, rt.rm()); 730 } else { 731 // li handles the relocation. 732 DCHECK(!rs.is(at)); 733 li(at, rt); 734 multu(rs, at); 735 } 736 } 737 738 739 void MacroAssembler::Div(Register rs, const Operand& rt) { 740 if (rt.is_reg()) { 741 div(rs, rt.rm()); 742 } else { 743 // li handles the relocation. 744 DCHECK(!rs.is(at)); 745 li(at, rt); 746 div(rs, at); 747 } 748 } 749 750 751 void MacroAssembler::Div(Register rem, Register res, 752 Register rs, const Operand& rt) { 753 if (rt.is_reg()) { 754 if (!IsMipsArchVariant(kMips32r6)) { 755 div(rs, rt.rm()); 756 mflo(res); 757 mfhi(rem); 758 } else { 759 div(res, rs, rt.rm()); 760 mod(rem, rs, rt.rm()); 761 } 762 } else { 763 // li handles the relocation. 764 DCHECK(!rs.is(at)); 765 li(at, rt); 766 if (!IsMipsArchVariant(kMips32r6)) { 767 div(rs, at); 768 mflo(res); 769 mfhi(rem); 770 } else { 771 div(res, rs, at); 772 mod(rem, rs, at); 773 } 774 } 775 } 776 777 778 void MacroAssembler::Div(Register res, Register rs, const Operand& rt) { 779 if (rt.is_reg()) { 780 if (!IsMipsArchVariant(kMips32r6)) { 781 div(rs, rt.rm()); 782 mflo(res); 783 } else { 784 div(res, rs, rt.rm()); 785 } 786 } else { 787 // li handles the relocation. 788 DCHECK(!rs.is(at)); 789 li(at, rt); 790 if (!IsMipsArchVariant(kMips32r6)) { 791 div(rs, at); 792 mflo(res); 793 } else { 794 div(res, rs, at); 795 } 796 } 797 } 798 799 800 void MacroAssembler::Mod(Register rd, Register rs, const Operand& rt) { 801 if (rt.is_reg()) { 802 if (!IsMipsArchVariant(kMips32r6)) { 803 div(rs, rt.rm()); 804 mfhi(rd); 805 } else { 806 mod(rd, rs, rt.rm()); 807 } 808 } else { 809 // li handles the relocation. 810 DCHECK(!rs.is(at)); 811 li(at, rt); 812 if (!IsMipsArchVariant(kMips32r6)) { 813 div(rs, at); 814 mfhi(rd); 815 } else { 816 mod(rd, rs, at); 817 } 818 } 819 } 820 821 822 void MacroAssembler::Modu(Register rd, Register rs, const Operand& rt) { 823 if (rt.is_reg()) { 824 if (!IsMipsArchVariant(kMips32r6)) { 825 divu(rs, rt.rm()); 826 mfhi(rd); 827 } else { 828 modu(rd, rs, rt.rm()); 829 } 830 } else { 831 // li handles the relocation. 832 DCHECK(!rs.is(at)); 833 li(at, rt); 834 if (!IsMipsArchVariant(kMips32r6)) { 835 divu(rs, at); 836 mfhi(rd); 837 } else { 838 modu(rd, rs, at); 839 } 840 } 841 } 842 843 844 void MacroAssembler::Divu(Register rs, const Operand& rt) { 845 if (rt.is_reg()) { 846 divu(rs, rt.rm()); 847 } else { 848 // li handles the relocation. 849 DCHECK(!rs.is(at)); 850 li(at, rt); 851 divu(rs, at); 852 } 853 } 854 855 856 void MacroAssembler::Divu(Register res, Register rs, const Operand& rt) { 857 if (rt.is_reg()) { 858 if (!IsMipsArchVariant(kMips32r6)) { 859 divu(rs, rt.rm()); 860 mflo(res); 861 } else { 862 divu(res, rs, rt.rm()); 863 } 864 } else { 865 // li handles the relocation. 866 DCHECK(!rs.is(at)); 867 li(at, rt); 868 if (!IsMipsArchVariant(kMips32r6)) { 869 divu(rs, at); 870 mflo(res); 871 } else { 872 divu(res, rs, at); 873 } 874 } 875 } 876 877 878 void MacroAssembler::And(Register rd, Register rs, const Operand& rt) { 879 if (rt.is_reg()) { 880 and_(rd, rs, rt.rm()); 881 } else { 882 if (is_uint16(rt.imm32_) && !MustUseReg(rt.rmode_)) { 883 andi(rd, rs, rt.imm32_); 884 } else { 885 // li handles the relocation. 886 DCHECK(!rs.is(at)); 887 li(at, rt); 888 and_(rd, rs, at); 889 } 890 } 891 } 892 893 894 void MacroAssembler::Or(Register rd, Register rs, const Operand& rt) { 895 if (rt.is_reg()) { 896 or_(rd, rs, rt.rm()); 897 } else { 898 if (is_uint16(rt.imm32_) && !MustUseReg(rt.rmode_)) { 899 ori(rd, rs, rt.imm32_); 900 } else { 901 // li handles the relocation. 902 DCHECK(!rs.is(at)); 903 li(at, rt); 904 or_(rd, rs, at); 905 } 906 } 907 } 908 909 910 void MacroAssembler::Xor(Register rd, Register rs, const Operand& rt) { 911 if (rt.is_reg()) { 912 xor_(rd, rs, rt.rm()); 913 } else { 914 if (is_uint16(rt.imm32_) && !MustUseReg(rt.rmode_)) { 915 xori(rd, rs, rt.imm32_); 916 } else { 917 // li handles the relocation. 918 DCHECK(!rs.is(at)); 919 li(at, rt); 920 xor_(rd, rs, at); 921 } 922 } 923 } 924 925 926 void MacroAssembler::Nor(Register rd, Register rs, const Operand& rt) { 927 if (rt.is_reg()) { 928 nor(rd, rs, rt.rm()); 929 } else { 930 // li handles the relocation. 931 DCHECK(!rs.is(at)); 932 li(at, rt); 933 nor(rd, rs, at); 934 } 935 } 936 937 938 void MacroAssembler::Neg(Register rs, const Operand& rt) { 939 DCHECK(rt.is_reg()); 940 DCHECK(!at.is(rs)); 941 DCHECK(!at.is(rt.rm())); 942 li(at, -1); 943 xor_(rs, rt.rm(), at); 944 } 945 946 947 void MacroAssembler::Slt(Register rd, Register rs, const Operand& rt) { 948 if (rt.is_reg()) { 949 slt(rd, rs, rt.rm()); 950 } else { 951 if (is_int16(rt.imm32_) && !MustUseReg(rt.rmode_)) { 952 slti(rd, rs, rt.imm32_); 953 } else { 954 // li handles the relocation. 955 DCHECK(!rs.is(at)); 956 li(at, rt); 957 slt(rd, rs, at); 958 } 959 } 960 } 961 962 963 void MacroAssembler::Sltu(Register rd, Register rs, const Operand& rt) { 964 if (rt.is_reg()) { 965 sltu(rd, rs, rt.rm()); 966 } else { 967 const uint32_t int16_min = std::numeric_limits<int16_t>::min(); 968 if (is_uint15(rt.imm32_) && !MustUseReg(rt.rmode_)) { 969 // Imm range is: [0, 32767]. 970 sltiu(rd, rs, rt.imm32_); 971 } else if (is_uint15(rt.imm32_ - int16_min) && !MustUseReg(rt.rmode_)) { 972 // Imm range is: [max_unsigned-32767,max_unsigned]. 973 sltiu(rd, rs, static_cast<uint16_t>(rt.imm32_)); 974 } else { 975 // li handles the relocation. 976 DCHECK(!rs.is(at)); 977 li(at, rt); 978 sltu(rd, rs, at); 979 } 980 } 981 } 982 983 984 void MacroAssembler::Ror(Register rd, Register rs, const Operand& rt) { 985 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { 986 if (rt.is_reg()) { 987 rotrv(rd, rs, rt.rm()); 988 } else { 989 rotr(rd, rs, rt.imm32_ & 0x1f); 990 } 991 } else { 992 if (rt.is_reg()) { 993 subu(at, zero_reg, rt.rm()); 994 sllv(at, rs, at); 995 srlv(rd, rs, rt.rm()); 996 or_(rd, rd, at); 997 } else { 998 if (rt.imm32_ == 0) { 999 srl(rd, rs, 0); 1000 } else { 1001 srl(at, rs, rt.imm32_ & 0x1f); 1002 sll(rd, rs, (0x20 - (rt.imm32_ & 0x1f)) & 0x1f); 1003 or_(rd, rd, at); 1004 } 1005 } 1006 } 1007 } 1008 1009 1010 void MacroAssembler::Pref(int32_t hint, const MemOperand& rs) { 1011 if (IsMipsArchVariant(kLoongson)) { 1012 lw(zero_reg, rs); 1013 } else { 1014 pref(hint, rs); 1015 } 1016 } 1017 1018 1019 void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa, 1020 Register scratch) { 1021 DCHECK(sa >= 1 && sa <= 31); 1022 if (IsMipsArchVariant(kMips32r6) && sa <= 4) { 1023 lsa(rd, rt, rs, sa - 1); 1024 } else { 1025 Register tmp = rd.is(rt) ? scratch : rd; 1026 DCHECK(!tmp.is(rt)); 1027 sll(tmp, rs, sa); 1028 Addu(rd, rt, tmp); 1029 } 1030 } 1031 1032 void MacroAssembler::Bovc(Register rs, Register rt, Label* L) { 1033 if (is_trampoline_emitted()) { 1034 Label skip; 1035 bnvc(rs, rt, &skip); 1036 BranchLong(L, PROTECT); 1037 bind(&skip); 1038 } else { 1039 bovc(rs, rt, L); 1040 } 1041 } 1042 1043 void MacroAssembler::Bnvc(Register rs, Register rt, Label* L) { 1044 if (is_trampoline_emitted()) { 1045 Label skip; 1046 bovc(rs, rt, &skip); 1047 BranchLong(L, PROTECT); 1048 bind(&skip); 1049 } else { 1050 bnvc(rs, rt, L); 1051 } 1052 } 1053 1054 // ------------Pseudo-instructions------------- 1055 1056 // Word Swap Byte 1057 void MacroAssembler::ByteSwapSigned(Register dest, Register src, 1058 int operand_size) { 1059 DCHECK(operand_size == 1 || operand_size == 2 || operand_size == 4); 1060 1061 if (operand_size == 2) { 1062 Seh(src, src); 1063 } else if (operand_size == 1) { 1064 Seb(src, src); 1065 } 1066 // No need to do any preparation if operand_size is 4 1067 1068 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { 1069 wsbh(dest, src); 1070 rotr(dest, dest, 16); 1071 } else if (IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kLoongson)) { 1072 Register tmp = t0; 1073 Register tmp2 = t1; 1074 1075 andi(tmp2, src, 0xFF); 1076 sll(tmp2, tmp2, 24); 1077 or_(tmp, zero_reg, tmp2); 1078 1079 andi(tmp2, src, 0xFF00); 1080 sll(tmp2, tmp2, 8); 1081 or_(tmp, tmp, tmp2); 1082 1083 srl(src, src, 8); 1084 andi(tmp2, src, 0xFF00); 1085 or_(tmp, tmp, tmp2); 1086 1087 srl(src, src, 16); 1088 andi(tmp2, src, 0xFF); 1089 or_(tmp, tmp, tmp2); 1090 1091 or_(dest, tmp, zero_reg); 1092 } 1093 } 1094 1095 void MacroAssembler::ByteSwapUnsigned(Register dest, Register src, 1096 int operand_size) { 1097 DCHECK(operand_size == 1 || operand_size == 2); 1098 1099 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { 1100 if (operand_size == 1) { 1101 andi(src, src, 0xFF); 1102 } else { 1103 andi(src, src, 0xFFFF); 1104 } 1105 // No need to do any preparation if operand_size is 4 1106 1107 wsbh(dest, src); 1108 rotr(dest, dest, 16); 1109 } else if (IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kLoongson)) { 1110 if (operand_size == 1) { 1111 sll(src, src, 24); 1112 } else { 1113 Register tmp = t0; 1114 1115 andi(tmp, src, 0xFF00); 1116 sll(src, src, 24); 1117 sll(tmp, tmp, 8); 1118 or_(dest, tmp, src); 1119 } 1120 } 1121 } 1122 1123 void MacroAssembler::Ulw(Register rd, const MemOperand& rs) { 1124 DCHECK(!rd.is(at)); 1125 DCHECK(!rs.rm().is(at)); 1126 if (IsMipsArchVariant(kMips32r6)) { 1127 lw(rd, rs); 1128 } else { 1129 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1130 IsMipsArchVariant(kLoongson)); 1131 if (is_int16(rs.offset() + kMipsLwrOffset) && 1132 is_int16(rs.offset() + kMipsLwlOffset)) { 1133 if (!rd.is(rs.rm())) { 1134 lwr(rd, MemOperand(rs.rm(), rs.offset() + kMipsLwrOffset)); 1135 lwl(rd, MemOperand(rs.rm(), rs.offset() + kMipsLwlOffset)); 1136 } else { 1137 lwr(at, MemOperand(rs.rm(), rs.offset() + kMipsLwrOffset)); 1138 lwl(at, MemOperand(rs.rm(), rs.offset() + kMipsLwlOffset)); 1139 mov(rd, at); 1140 } 1141 } else { // Offset > 16 bits, use multiple instructions to load. 1142 LoadRegPlusOffsetToAt(rs); 1143 lwr(rd, MemOperand(at, kMipsLwrOffset)); 1144 lwl(rd, MemOperand(at, kMipsLwlOffset)); 1145 } 1146 } 1147 } 1148 1149 1150 void MacroAssembler::Usw(Register rd, const MemOperand& rs) { 1151 DCHECK(!rd.is(at)); 1152 DCHECK(!rs.rm().is(at)); 1153 if (IsMipsArchVariant(kMips32r6)) { 1154 sw(rd, rs); 1155 } else { 1156 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1157 IsMipsArchVariant(kLoongson)); 1158 if (is_int16(rs.offset() + kMipsSwrOffset) && 1159 is_int16(rs.offset() + kMipsSwlOffset)) { 1160 swr(rd, MemOperand(rs.rm(), rs.offset() + kMipsSwrOffset)); 1161 swl(rd, MemOperand(rs.rm(), rs.offset() + kMipsSwlOffset)); 1162 } else { 1163 LoadRegPlusOffsetToAt(rs); 1164 swr(rd, MemOperand(at, kMipsSwrOffset)); 1165 swl(rd, MemOperand(at, kMipsSwlOffset)); 1166 } 1167 } 1168 } 1169 1170 void MacroAssembler::Ulh(Register rd, const MemOperand& rs) { 1171 DCHECK(!rd.is(at)); 1172 DCHECK(!rs.rm().is(at)); 1173 if (IsMipsArchVariant(kMips32r6)) { 1174 lh(rd, rs); 1175 } else { 1176 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1177 IsMipsArchVariant(kLoongson)); 1178 if (is_int16(rs.offset()) && is_int16(rs.offset() + 1)) { 1179 #if defined(V8_TARGET_LITTLE_ENDIAN) 1180 lbu(at, rs); 1181 lb(rd, MemOperand(rs.rm(), rs.offset() + 1)); 1182 #elif defined(V8_TARGET_BIG_ENDIAN) 1183 lbu(at, MemOperand(rs.rm(), rs.offset() + 1)); 1184 lb(rd, rs); 1185 #endif 1186 } else { // Offset > 16 bits, use multiple instructions to load. 1187 LoadRegPlusOffsetToAt(rs); 1188 #if defined(V8_TARGET_LITTLE_ENDIAN) 1189 lb(rd, MemOperand(at, 1)); 1190 lbu(at, MemOperand(at, 0)); 1191 #elif defined(V8_TARGET_BIG_ENDIAN) 1192 lb(rd, MemOperand(at, 0)); 1193 lbu(at, MemOperand(at, 1)); 1194 #endif 1195 } 1196 sll(rd, rd, 8); 1197 or_(rd, rd, at); 1198 } 1199 } 1200 1201 void MacroAssembler::Ulhu(Register rd, const MemOperand& rs) { 1202 DCHECK(!rd.is(at)); 1203 DCHECK(!rs.rm().is(at)); 1204 if (IsMipsArchVariant(kMips32r6)) { 1205 lhu(rd, rs); 1206 } else { 1207 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1208 IsMipsArchVariant(kLoongson)); 1209 if (is_int16(rs.offset()) && is_int16(rs.offset() + 1)) { 1210 #if defined(V8_TARGET_LITTLE_ENDIAN) 1211 lbu(at, rs); 1212 lbu(rd, MemOperand(rs.rm(), rs.offset() + 1)); 1213 #elif defined(V8_TARGET_BIG_ENDIAN) 1214 lbu(at, MemOperand(rs.rm(), rs.offset() + 1)); 1215 lbu(rd, rs); 1216 #endif 1217 } else { // Offset > 16 bits, use multiple instructions to load. 1218 LoadRegPlusOffsetToAt(rs); 1219 #if defined(V8_TARGET_LITTLE_ENDIAN) 1220 lbu(rd, MemOperand(at, 1)); 1221 lbu(at, MemOperand(at, 0)); 1222 #elif defined(V8_TARGET_BIG_ENDIAN) 1223 lbu(rd, MemOperand(at, 0)); 1224 lbu(at, MemOperand(at, 1)); 1225 #endif 1226 } 1227 sll(rd, rd, 8); 1228 or_(rd, rd, at); 1229 } 1230 } 1231 1232 void MacroAssembler::Ush(Register rd, const MemOperand& rs, Register scratch) { 1233 DCHECK(!rd.is(at)); 1234 DCHECK(!rs.rm().is(at)); 1235 DCHECK(!rs.rm().is(scratch)); 1236 DCHECK(!scratch.is(at)); 1237 if (IsMipsArchVariant(kMips32r6)) { 1238 sh(rd, rs); 1239 } else { 1240 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1241 IsMipsArchVariant(kLoongson)); 1242 MemOperand source = rs; 1243 // If offset > 16 bits, load address to at with offset 0. 1244 if (!is_int16(rs.offset()) || !is_int16(rs.offset() + 1)) { 1245 LoadRegPlusOffsetToAt(rs); 1246 source = MemOperand(at, 0); 1247 } 1248 1249 if (!scratch.is(rd)) { 1250 mov(scratch, rd); 1251 } 1252 1253 #if defined(V8_TARGET_LITTLE_ENDIAN) 1254 sb(scratch, source); 1255 srl(scratch, scratch, 8); 1256 sb(scratch, MemOperand(source.rm(), source.offset() + 1)); 1257 #elif defined(V8_TARGET_BIG_ENDIAN) 1258 sb(scratch, MemOperand(source.rm(), source.offset() + 1)); 1259 srl(scratch, scratch, 8); 1260 sb(scratch, source); 1261 #endif 1262 } 1263 } 1264 1265 void MacroAssembler::Ulwc1(FPURegister fd, const MemOperand& rs, 1266 Register scratch) { 1267 if (IsMipsArchVariant(kMips32r6)) { 1268 lwc1(fd, rs); 1269 } else { 1270 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1271 IsMipsArchVariant(kLoongson)); 1272 Ulw(scratch, rs); 1273 mtc1(scratch, fd); 1274 } 1275 } 1276 1277 void MacroAssembler::Uswc1(FPURegister fd, const MemOperand& rs, 1278 Register scratch) { 1279 if (IsMipsArchVariant(kMips32r6)) { 1280 swc1(fd, rs); 1281 } else { 1282 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1283 IsMipsArchVariant(kLoongson)); 1284 mfc1(scratch, fd); 1285 Usw(scratch, rs); 1286 } 1287 } 1288 1289 void MacroAssembler::Uldc1(FPURegister fd, const MemOperand& rs, 1290 Register scratch) { 1291 DCHECK(!scratch.is(at)); 1292 if (IsMipsArchVariant(kMips32r6)) { 1293 ldc1(fd, rs); 1294 } else { 1295 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1296 IsMipsArchVariant(kLoongson)); 1297 Ulw(scratch, MemOperand(rs.rm(), rs.offset() + Register::kMantissaOffset)); 1298 mtc1(scratch, fd); 1299 Ulw(scratch, MemOperand(rs.rm(), rs.offset() + Register::kExponentOffset)); 1300 Mthc1(scratch, fd); 1301 } 1302 } 1303 1304 void MacroAssembler::Usdc1(FPURegister fd, const MemOperand& rs, 1305 Register scratch) { 1306 DCHECK(!scratch.is(at)); 1307 if (IsMipsArchVariant(kMips32r6)) { 1308 sdc1(fd, rs); 1309 } else { 1310 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1311 IsMipsArchVariant(kLoongson)); 1312 mfc1(scratch, fd); 1313 Usw(scratch, MemOperand(rs.rm(), rs.offset() + Register::kMantissaOffset)); 1314 Mfhc1(scratch, fd); 1315 Usw(scratch, MemOperand(rs.rm(), rs.offset() + Register::kExponentOffset)); 1316 } 1317 } 1318 1319 1320 void MacroAssembler::li(Register dst, Handle<Object> value, LiFlags mode) { 1321 li(dst, Operand(value), mode); 1322 } 1323 1324 1325 void MacroAssembler::li(Register rd, Operand j, LiFlags mode) { 1326 DCHECK(!j.is_reg()); 1327 BlockTrampolinePoolScope block_trampoline_pool(this); 1328 if (!MustUseReg(j.rmode_) && mode == OPTIMIZE_SIZE) { 1329 // Normal load of an immediate value which does not need Relocation Info. 1330 if (is_int16(j.imm32_)) { 1331 addiu(rd, zero_reg, j.imm32_); 1332 } else if (!(j.imm32_ & kHiMask)) { 1333 ori(rd, zero_reg, j.imm32_); 1334 } else if (!(j.imm32_ & kImm16Mask)) { 1335 lui(rd, (j.imm32_ >> kLuiShift) & kImm16Mask); 1336 } else { 1337 lui(rd, (j.imm32_ >> kLuiShift) & kImm16Mask); 1338 ori(rd, rd, (j.imm32_ & kImm16Mask)); 1339 } 1340 } else { 1341 if (MustUseReg(j.rmode_)) { 1342 RecordRelocInfo(j.rmode_, j.imm32_); 1343 } 1344 // We always need the same number of instructions as we may need to patch 1345 // this code to load another value which may need 2 instructions to load. 1346 lui(rd, (j.imm32_ >> kLuiShift) & kImm16Mask); 1347 ori(rd, rd, (j.imm32_ & kImm16Mask)); 1348 } 1349 } 1350 1351 1352 void MacroAssembler::MultiPush(RegList regs) { 1353 int16_t num_to_push = NumberOfBitsSet(regs); 1354 int16_t stack_offset = num_to_push * kPointerSize; 1355 1356 Subu(sp, sp, Operand(stack_offset)); 1357 for (int16_t i = kNumRegisters - 1; i >= 0; i--) { 1358 if ((regs & (1 << i)) != 0) { 1359 stack_offset -= kPointerSize; 1360 sw(ToRegister(i), MemOperand(sp, stack_offset)); 1361 } 1362 } 1363 } 1364 1365 1366 void MacroAssembler::MultiPushReversed(RegList regs) { 1367 int16_t num_to_push = NumberOfBitsSet(regs); 1368 int16_t stack_offset = num_to_push * kPointerSize; 1369 1370 Subu(sp, sp, Operand(stack_offset)); 1371 for (int16_t i = 0; i < kNumRegisters; i++) { 1372 if ((regs & (1 << i)) != 0) { 1373 stack_offset -= kPointerSize; 1374 sw(ToRegister(i), MemOperand(sp, stack_offset)); 1375 } 1376 } 1377 } 1378 1379 1380 void MacroAssembler::MultiPop(RegList regs) { 1381 int16_t stack_offset = 0; 1382 1383 for (int16_t i = 0; i < kNumRegisters; i++) { 1384 if ((regs & (1 << i)) != 0) { 1385 lw(ToRegister(i), MemOperand(sp, stack_offset)); 1386 stack_offset += kPointerSize; 1387 } 1388 } 1389 addiu(sp, sp, stack_offset); 1390 } 1391 1392 1393 void MacroAssembler::MultiPopReversed(RegList regs) { 1394 int16_t stack_offset = 0; 1395 1396 for (int16_t i = kNumRegisters - 1; i >= 0; i--) { 1397 if ((regs & (1 << i)) != 0) { 1398 lw(ToRegister(i), MemOperand(sp, stack_offset)); 1399 stack_offset += kPointerSize; 1400 } 1401 } 1402 addiu(sp, sp, stack_offset); 1403 } 1404 1405 1406 void MacroAssembler::MultiPushFPU(RegList regs) { 1407 int16_t num_to_push = NumberOfBitsSet(regs); 1408 int16_t stack_offset = num_to_push * kDoubleSize; 1409 1410 Subu(sp, sp, Operand(stack_offset)); 1411 for (int16_t i = kNumRegisters - 1; i >= 0; i--) { 1412 if ((regs & (1 << i)) != 0) { 1413 stack_offset -= kDoubleSize; 1414 sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset)); 1415 } 1416 } 1417 } 1418 1419 1420 void MacroAssembler::MultiPushReversedFPU(RegList regs) { 1421 int16_t num_to_push = NumberOfBitsSet(regs); 1422 int16_t stack_offset = num_to_push * kDoubleSize; 1423 1424 Subu(sp, sp, Operand(stack_offset)); 1425 for (int16_t i = 0; i < kNumRegisters; i++) { 1426 if ((regs & (1 << i)) != 0) { 1427 stack_offset -= kDoubleSize; 1428 sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset)); 1429 } 1430 } 1431 } 1432 1433 1434 void MacroAssembler::MultiPopFPU(RegList regs) { 1435 int16_t stack_offset = 0; 1436 1437 for (int16_t i = 0; i < kNumRegisters; i++) { 1438 if ((regs & (1 << i)) != 0) { 1439 ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset)); 1440 stack_offset += kDoubleSize; 1441 } 1442 } 1443 addiu(sp, sp, stack_offset); 1444 } 1445 1446 1447 void MacroAssembler::MultiPopReversedFPU(RegList regs) { 1448 int16_t stack_offset = 0; 1449 1450 for (int16_t i = kNumRegisters - 1; i >= 0; i--) { 1451 if ((regs & (1 << i)) != 0) { 1452 ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset)); 1453 stack_offset += kDoubleSize; 1454 } 1455 } 1456 addiu(sp, sp, stack_offset); 1457 } 1458 1459 void MacroAssembler::AddPair(Register dst_low, Register dst_high, 1460 Register left_low, Register left_high, 1461 Register right_low, Register right_high) { 1462 Label no_overflow; 1463 Register kScratchReg = s3; 1464 Register kScratchReg2 = s4; 1465 // Add lower word 1466 Addu(dst_low, left_low, right_low); 1467 Addu(dst_high, left_high, right_high); 1468 // Check for lower word unsigned overflow 1469 Sltu(kScratchReg, dst_low, left_low); 1470 Sltu(kScratchReg2, dst_low, right_low); 1471 Or(kScratchReg, kScratchReg2, kScratchReg); 1472 Branch(&no_overflow, eq, kScratchReg, Operand(zero_reg)); 1473 // Increment higher word if there was overflow 1474 Addu(dst_high, dst_high, 0x1); 1475 bind(&no_overflow); 1476 } 1477 1478 void MacroAssembler::SubPair(Register dst_low, Register dst_high, 1479 Register left_low, Register left_high, 1480 Register right_low, Register right_high) { 1481 Label no_overflow; 1482 Register kScratchReg = s3; 1483 // Subtract lower word 1484 Subu(dst_low, left_low, right_low); 1485 Subu(dst_high, left_high, right_high); 1486 // Check for lower word unsigned underflow 1487 Sltu(kScratchReg, left_low, right_low); 1488 Branch(&no_overflow, eq, kScratchReg, Operand(zero_reg)); 1489 // Decrement higher word if there was underflow 1490 Subu(dst_high, dst_high, 0x1); 1491 bind(&no_overflow); 1492 } 1493 1494 void MacroAssembler::ShlPair(Register dst_low, Register dst_high, 1495 Register src_low, Register src_high, 1496 Register shift) { 1497 Label less_than_32; 1498 Label zero_shift; 1499 Label word_shift; 1500 Label done; 1501 Register kScratchReg = s3; 1502 And(shift, shift, 0x3F); 1503 li(kScratchReg, 0x20); 1504 Branch(&less_than_32, lt, shift, Operand(kScratchReg)); 1505 1506 Branch(&word_shift, eq, shift, Operand(kScratchReg)); 1507 // Shift more than 32 1508 Subu(kScratchReg, shift, kScratchReg); 1509 mov(dst_low, zero_reg); 1510 sllv(dst_high, src_low, kScratchReg); 1511 Branch(&done); 1512 // Word shift 1513 bind(&word_shift); 1514 mov(dst_low, zero_reg); 1515 mov(dst_high, src_low); 1516 Branch(&done); 1517 1518 bind(&less_than_32); 1519 // Check if zero shift 1520 Branch(&zero_shift, eq, shift, Operand(zero_reg)); 1521 // Shift less than 32 1522 Subu(kScratchReg, kScratchReg, shift); 1523 sllv(dst_high, src_high, shift); 1524 sllv(dst_low, src_low, shift); 1525 srlv(kScratchReg, src_low, kScratchReg); 1526 Or(dst_high, dst_high, kScratchReg); 1527 Branch(&done); 1528 // Zero shift 1529 bind(&zero_shift); 1530 mov(dst_low, src_low); 1531 mov(dst_high, src_high); 1532 bind(&done); 1533 } 1534 1535 void MacroAssembler::ShlPair(Register dst_low, Register dst_high, 1536 Register src_low, Register src_high, 1537 uint32_t shift) { 1538 Register kScratchReg = s3; 1539 shift = shift & 0x3F; 1540 if (shift < 32) { 1541 if (shift == 0) { 1542 mov(dst_low, src_low); 1543 mov(dst_high, src_high); 1544 } else { 1545 sll(dst_high, src_high, shift); 1546 sll(dst_low, src_low, shift); 1547 shift = 32 - shift; 1548 srl(kScratchReg, src_low, shift); 1549 Or(dst_high, dst_high, kScratchReg); 1550 } 1551 } else { 1552 if (shift == 32) { 1553 mov(dst_low, zero_reg); 1554 mov(dst_high, src_low); 1555 } else { 1556 shift = shift - 32; 1557 mov(dst_low, zero_reg); 1558 sll(dst_high, src_low, shift); 1559 } 1560 } 1561 } 1562 1563 void MacroAssembler::ShrPair(Register dst_low, Register dst_high, 1564 Register src_low, Register src_high, 1565 Register shift) { 1566 Label less_than_32; 1567 Label zero_shift; 1568 Label word_shift; 1569 Label done; 1570 Register kScratchReg = s3; 1571 And(shift, shift, 0x3F); 1572 li(kScratchReg, 0x20); 1573 Branch(&less_than_32, lt, shift, Operand(kScratchReg)); 1574 1575 Branch(&word_shift, eq, shift, Operand(kScratchReg)); 1576 // Shift more than 32 1577 Subu(kScratchReg, shift, kScratchReg); 1578 mov(dst_high, zero_reg); 1579 srlv(dst_low, src_high, kScratchReg); 1580 Branch(&done); 1581 // Word shift 1582 bind(&word_shift); 1583 mov(dst_high, zero_reg); 1584 mov(dst_low, src_high); 1585 Branch(&done); 1586 1587 bind(&less_than_32); 1588 // Check if zero shift 1589 Branch(&zero_shift, eq, shift, Operand(zero_reg)); 1590 // Shift less than 32 1591 Subu(kScratchReg, kScratchReg, shift); 1592 srlv(dst_high, src_high, shift); 1593 srlv(dst_low, src_low, shift); 1594 sllv(kScratchReg, src_high, kScratchReg); 1595 Or(dst_low, dst_low, kScratchReg); 1596 Branch(&done); 1597 // Zero shift 1598 bind(&zero_shift); 1599 mov(dst_low, src_low); 1600 mov(dst_high, src_high); 1601 bind(&done); 1602 } 1603 1604 void MacroAssembler::ShrPair(Register dst_low, Register dst_high, 1605 Register src_low, Register src_high, 1606 uint32_t shift) { 1607 Register kScratchReg = s3; 1608 shift = shift & 0x3F; 1609 if (shift < 32) { 1610 if (shift == 0) { 1611 mov(dst_low, src_low); 1612 mov(dst_high, src_high); 1613 } else { 1614 srl(dst_high, src_high, shift); 1615 srl(dst_low, src_low, shift); 1616 shift = 32 - shift; 1617 sll(kScratchReg, src_high, shift); 1618 Or(dst_low, dst_low, kScratchReg); 1619 } 1620 } else { 1621 if (shift == 32) { 1622 mov(dst_high, zero_reg); 1623 mov(dst_low, src_high); 1624 } else { 1625 shift = shift - 32; 1626 mov(dst_high, zero_reg); 1627 srl(dst_low, src_high, shift); 1628 } 1629 } 1630 } 1631 1632 void MacroAssembler::SarPair(Register dst_low, Register dst_high, 1633 Register src_low, Register src_high, 1634 Register shift) { 1635 Label less_than_32; 1636 Label zero_shift; 1637 Label word_shift; 1638 Label done; 1639 Register kScratchReg = s3; 1640 Register kScratchReg2 = s4; 1641 And(shift, shift, 0x3F); 1642 li(kScratchReg, 0x20); 1643 Branch(&less_than_32, lt, shift, Operand(kScratchReg)); 1644 1645 Branch(&word_shift, eq, shift, Operand(kScratchReg)); 1646 1647 // Shift more than 32 1648 li(kScratchReg2, 0x1F); 1649 Subu(kScratchReg, shift, kScratchReg); 1650 srav(dst_high, src_high, kScratchReg2); 1651 srav(dst_low, src_high, kScratchReg); 1652 Branch(&done); 1653 // Word shift 1654 bind(&word_shift); 1655 li(kScratchReg2, 0x1F); 1656 srav(dst_high, src_high, kScratchReg2); 1657 mov(dst_low, src_high); 1658 Branch(&done); 1659 1660 bind(&less_than_32); 1661 // Check if zero shift 1662 Branch(&zero_shift, eq, shift, Operand(zero_reg)); 1663 1664 // Shift less than 32 1665 Subu(kScratchReg, kScratchReg, shift); 1666 srav(dst_high, src_high, shift); 1667 srlv(dst_low, src_low, shift); 1668 sllv(kScratchReg, src_high, kScratchReg); 1669 Or(dst_low, dst_low, kScratchReg); 1670 Branch(&done); 1671 // Zero shift 1672 bind(&zero_shift); 1673 mov(dst_low, src_low); 1674 mov(dst_high, src_high); 1675 bind(&done); 1676 } 1677 1678 void MacroAssembler::SarPair(Register dst_low, Register dst_high, 1679 Register src_low, Register src_high, 1680 uint32_t shift) { 1681 Register kScratchReg = s3; 1682 shift = shift & 0x3F; 1683 if (shift < 32) { 1684 if (shift == 0) { 1685 mov(dst_low, src_low); 1686 mov(dst_high, src_high); 1687 } else { 1688 sra(dst_high, src_high, shift); 1689 srl(dst_low, src_low, shift); 1690 shift = 32 - shift; 1691 sll(kScratchReg, src_high, shift); 1692 Or(dst_low, dst_low, kScratchReg); 1693 } 1694 } else { 1695 if (shift == 32) { 1696 sra(dst_high, src_high, 31); 1697 mov(dst_low, src_high); 1698 } else { 1699 shift = shift - 32; 1700 sra(dst_high, src_high, 31); 1701 sra(dst_low, src_high, shift); 1702 } 1703 } 1704 } 1705 1706 void MacroAssembler::Ext(Register rt, 1707 Register rs, 1708 uint16_t pos, 1709 uint16_t size) { 1710 DCHECK(pos < 32); 1711 DCHECK(pos + size < 33); 1712 1713 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { 1714 ext_(rt, rs, pos, size); 1715 } else { 1716 // Move rs to rt and shift it left then right to get the 1717 // desired bitfield on the right side and zeroes on the left. 1718 int shift_left = 32 - (pos + size); 1719 sll(rt, rs, shift_left); // Acts as a move if shift_left == 0. 1720 1721 int shift_right = 32 - size; 1722 if (shift_right > 0) { 1723 srl(rt, rt, shift_right); 1724 } 1725 } 1726 } 1727 1728 1729 void MacroAssembler::Ins(Register rt, 1730 Register rs, 1731 uint16_t pos, 1732 uint16_t size) { 1733 DCHECK(pos < 32); 1734 DCHECK(pos + size <= 32); 1735 DCHECK(size != 0); 1736 1737 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { 1738 ins_(rt, rs, pos, size); 1739 } else { 1740 DCHECK(!rt.is(t8) && !rs.is(t8)); 1741 Subu(at, zero_reg, Operand(1)); 1742 srl(at, at, 32 - size); 1743 and_(t8, rs, at); 1744 sll(t8, t8, pos); 1745 sll(at, at, pos); 1746 nor(at, at, zero_reg); 1747 and_(at, rt, at); 1748 or_(rt, t8, at); 1749 } 1750 } 1751 1752 void MacroAssembler::Seb(Register rd, Register rt) { 1753 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { 1754 seb(rd, rt); 1755 } else { 1756 DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kLoongson)); 1757 sll(rd, rt, 24); 1758 sra(rd, rd, 24); 1759 } 1760 } 1761 1762 void MacroAssembler::Seh(Register rd, Register rt) { 1763 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { 1764 seh(rd, rt); 1765 } else { 1766 DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kLoongson)); 1767 sll(rd, rt, 16); 1768 sra(rd, rd, 16); 1769 } 1770 } 1771 1772 void MacroAssembler::Neg_s(FPURegister fd, FPURegister fs) { 1773 if (IsMipsArchVariant(kMips32r6)) { 1774 // r6 neg_s changes the sign for NaN-like operands as well. 1775 neg_s(fd, fs); 1776 } else { 1777 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1778 IsMipsArchVariant(kLoongson)); 1779 Label is_nan, done; 1780 Register scratch1 = t8; 1781 Register scratch2 = t9; 1782 BranchF32(nullptr, &is_nan, eq, fs, fs); 1783 Branch(USE_DELAY_SLOT, &done); 1784 // For NaN input, neg_s will return the same NaN value, 1785 // while the sign has to be changed separately. 1786 neg_s(fd, fs); // In delay slot. 1787 bind(&is_nan); 1788 mfc1(scratch1, fs); 1789 And(scratch2, scratch1, Operand(~kBinary32SignMask)); 1790 And(scratch1, scratch1, Operand(kBinary32SignMask)); 1791 Xor(scratch1, scratch1, Operand(kBinary32SignMask)); 1792 Or(scratch2, scratch2, scratch1); 1793 mtc1(scratch2, fd); 1794 bind(&done); 1795 } 1796 } 1797 1798 void MacroAssembler::Neg_d(FPURegister fd, FPURegister fs) { 1799 if (IsMipsArchVariant(kMips32r6)) { 1800 // r6 neg_d changes the sign for NaN-like operands as well. 1801 neg_d(fd, fs); 1802 } else { 1803 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) || 1804 IsMipsArchVariant(kLoongson)); 1805 Label is_nan, done; 1806 Register scratch1 = t8; 1807 Register scratch2 = t9; 1808 BranchF64(nullptr, &is_nan, eq, fs, fs); 1809 Branch(USE_DELAY_SLOT, &done); 1810 // For NaN input, neg_d will return the same NaN value, 1811 // while the sign has to be changed separately. 1812 neg_d(fd, fs); // In delay slot. 1813 bind(&is_nan); 1814 Mfhc1(scratch1, fs); 1815 And(scratch2, scratch1, Operand(~HeapNumber::kSignMask)); 1816 And(scratch1, scratch1, Operand(HeapNumber::kSignMask)); 1817 Xor(scratch1, scratch1, Operand(HeapNumber::kSignMask)); 1818 Or(scratch2, scratch2, scratch1); 1819 Mthc1(scratch2, fd); 1820 bind(&done); 1821 } 1822 } 1823 1824 void MacroAssembler::Cvt_d_uw(FPURegister fd, Register rs, 1825 FPURegister scratch) { 1826 // In FP64Mode we do convertion from long. 1827 if (IsFp64Mode()) { 1828 mtc1(rs, scratch); 1829 Mthc1(zero_reg, scratch); 1830 cvt_d_l(fd, scratch); 1831 } else { 1832 // Convert rs to a FP value in fd. 1833 DCHECK(!fd.is(scratch)); 1834 DCHECK(!rs.is(at)); 1835 1836 Label msb_clear, conversion_done; 1837 // For a value which is < 2^31, regard it as a signed positve word. 1838 Branch(&msb_clear, ge, rs, Operand(zero_reg), USE_DELAY_SLOT); 1839 mtc1(rs, fd); 1840 1841 li(at, 0x41F00000); // FP value: 2^32. 1842 1843 // For unsigned inputs > 2^31, we convert to double as a signed int32, 1844 // then add 2^32 to move it back to unsigned value in range 2^31..2^31-1. 1845 mtc1(zero_reg, scratch); 1846 Mthc1(at, scratch); 1847 1848 cvt_d_w(fd, fd); 1849 1850 Branch(USE_DELAY_SLOT, &conversion_done); 1851 add_d(fd, fd, scratch); 1852 1853 bind(&msb_clear); 1854 cvt_d_w(fd, fd); 1855 1856 bind(&conversion_done); 1857 } 1858 } 1859 1860 1861 void MacroAssembler::Trunc_uw_d(FPURegister fd, 1862 FPURegister fs, 1863 FPURegister scratch) { 1864 Trunc_uw_d(fs, t8, scratch); 1865 mtc1(t8, fd); 1866 } 1867 1868 void MacroAssembler::Trunc_uw_s(FPURegister fd, FPURegister fs, 1869 FPURegister scratch) { 1870 Trunc_uw_s(fs, t8, scratch); 1871 mtc1(t8, fd); 1872 } 1873 1874 void MacroAssembler::Trunc_w_d(FPURegister fd, FPURegister fs) { 1875 if (IsMipsArchVariant(kLoongson) && fd.is(fs)) { 1876 Mfhc1(t8, fs); 1877 trunc_w_d(fd, fs); 1878 Mthc1(t8, fs); 1879 } else { 1880 trunc_w_d(fd, fs); 1881 } 1882 } 1883 1884 1885 void MacroAssembler::Round_w_d(FPURegister fd, FPURegister fs) { 1886 if (IsMipsArchVariant(kLoongson) && fd.is(fs)) { 1887 Mfhc1(t8, fs); 1888 round_w_d(fd, fs); 1889 Mthc1(t8, fs); 1890 } else { 1891 round_w_d(fd, fs); 1892 } 1893 } 1894 1895 1896 void MacroAssembler::Floor_w_d(FPURegister fd, FPURegister fs) { 1897 if (IsMipsArchVariant(kLoongson) && fd.is(fs)) { 1898 Mfhc1(t8, fs); 1899 floor_w_d(fd, fs); 1900 Mthc1(t8, fs); 1901 } else { 1902 floor_w_d(fd, fs); 1903 } 1904 } 1905 1906 1907 void MacroAssembler::Ceil_w_d(FPURegister fd, FPURegister fs) { 1908 if (IsMipsArchVariant(kLoongson) && fd.is(fs)) { 1909 Mfhc1(t8, fs); 1910 ceil_w_d(fd, fs); 1911 Mthc1(t8, fs); 1912 } else { 1913 ceil_w_d(fd, fs); 1914 } 1915 } 1916 1917 1918 void MacroAssembler::Trunc_uw_d(FPURegister fd, 1919 Register rs, 1920 FPURegister scratch) { 1921 DCHECK(!fd.is(scratch)); 1922 DCHECK(!rs.is(at)); 1923 1924 // Load 2^31 into scratch as its float representation. 1925 li(at, 0x41E00000); 1926 mtc1(zero_reg, scratch); 1927 Mthc1(at, scratch); 1928 // Test if scratch > fd. 1929 // If fd < 2^31 we can convert it normally. 1930 Label simple_convert; 1931 BranchF(&simple_convert, NULL, lt, fd, scratch); 1932 1933 // First we subtract 2^31 from fd, then trunc it to rs 1934 // and add 2^31 to rs. 1935 sub_d(scratch, fd, scratch); 1936 trunc_w_d(scratch, scratch); 1937 mfc1(rs, scratch); 1938 Or(rs, rs, 1 << 31); 1939 1940 Label done; 1941 Branch(&done); 1942 // Simple conversion. 1943 bind(&simple_convert); 1944 trunc_w_d(scratch, fd); 1945 mfc1(rs, scratch); 1946 1947 bind(&done); 1948 } 1949 1950 void MacroAssembler::Trunc_uw_s(FPURegister fd, Register rs, 1951 FPURegister scratch) { 1952 DCHECK(!fd.is(scratch)); 1953 DCHECK(!rs.is(at)); 1954 1955 // Load 2^31 into scratch as its float representation. 1956 li(at, 0x4F000000); 1957 mtc1(at, scratch); 1958 // Test if scratch > fd. 1959 // If fd < 2^31 we can convert it normally. 1960 Label simple_convert; 1961 BranchF32(&simple_convert, NULL, lt, fd, scratch); 1962 1963 // First we subtract 2^31 from fd, then trunc it to rs 1964 // and add 2^31 to rs. 1965 sub_s(scratch, fd, scratch); 1966 trunc_w_s(scratch, scratch); 1967 mfc1(rs, scratch); 1968 Or(rs, rs, 1 << 31); 1969 1970 Label done; 1971 Branch(&done); 1972 // Simple conversion. 1973 bind(&simple_convert); 1974 trunc_w_s(scratch, fd); 1975 mfc1(rs, scratch); 1976 1977 bind(&done); 1978 } 1979 1980 void MacroAssembler::Mthc1(Register rt, FPURegister fs) { 1981 if (IsFp32Mode()) { 1982 mtc1(rt, fs.high()); 1983 } else { 1984 DCHECK(IsFp64Mode() || IsFpxxMode()); 1985 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 1986 mthc1(rt, fs); 1987 } 1988 } 1989 1990 1991 void MacroAssembler::Mfhc1(Register rt, FPURegister fs) { 1992 if (IsFp32Mode()) { 1993 mfc1(rt, fs.high()); 1994 } else { 1995 DCHECK(IsFp64Mode() || IsFpxxMode()); 1996 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 1997 mfhc1(rt, fs); 1998 } 1999 } 2000 2001 void MacroAssembler::Madd_s(FPURegister fd, FPURegister fr, FPURegister fs, 2002 FPURegister ft, FPURegister scratch) { 2003 if (IsMipsArchVariant(kMips32r2)) { 2004 madd_s(fd, fr, fs, ft); 2005 } else { 2006 DCHECK(!fr.is(scratch) && !fs.is(scratch) && !ft.is(scratch)); 2007 mul_s(scratch, fs, ft); 2008 add_s(fd, fr, scratch); 2009 } 2010 } 2011 2012 void MacroAssembler::Madd_d(FPURegister fd, FPURegister fr, FPURegister fs, 2013 FPURegister ft, FPURegister scratch) { 2014 if (IsMipsArchVariant(kMips32r2)) { 2015 madd_d(fd, fr, fs, ft); 2016 } else { 2017 DCHECK(!fr.is(scratch) && !fs.is(scratch) && !ft.is(scratch)); 2018 mul_d(scratch, fs, ft); 2019 add_d(fd, fr, scratch); 2020 } 2021 } 2022 2023 void MacroAssembler::Msub_s(FPURegister fd, FPURegister fr, FPURegister fs, 2024 FPURegister ft, FPURegister scratch) { 2025 if (IsMipsArchVariant(kMips32r2)) { 2026 msub_s(fd, fr, fs, ft); 2027 } else { 2028 DCHECK(!fr.is(scratch) && !fs.is(scratch) && !ft.is(scratch)); 2029 mul_s(scratch, fs, ft); 2030 sub_s(fd, scratch, fr); 2031 } 2032 } 2033 2034 void MacroAssembler::Msub_d(FPURegister fd, FPURegister fr, FPURegister fs, 2035 FPURegister ft, FPURegister scratch) { 2036 if (IsMipsArchVariant(kMips32r2)) { 2037 msub_d(fd, fr, fs, ft); 2038 } else { 2039 DCHECK(!fr.is(scratch) && !fs.is(scratch) && !ft.is(scratch)); 2040 mul_d(scratch, fs, ft); 2041 sub_d(fd, scratch, fr); 2042 } 2043 } 2044 2045 void MacroAssembler::BranchFCommon(SecondaryField sizeField, Label* target, 2046 Label* nan, Condition cond, FPURegister cmp1, 2047 FPURegister cmp2, BranchDelaySlot bd) { 2048 { 2049 BlockTrampolinePoolScope block_trampoline_pool(this); 2050 if (cond == al) { 2051 Branch(bd, target); 2052 return; 2053 } 2054 2055 if (IsMipsArchVariant(kMips32r6)) { 2056 sizeField = sizeField == D ? L : W; 2057 } 2058 DCHECK(nan || target); 2059 // Check for unordered (NaN) cases. 2060 if (nan) { 2061 bool long_branch = 2062 nan->is_bound() ? !is_near(nan) : is_trampoline_emitted(); 2063 if (!IsMipsArchVariant(kMips32r6)) { 2064 if (long_branch) { 2065 Label skip; 2066 c(UN, sizeField, cmp1, cmp2); 2067 bc1f(&skip); 2068 nop(); 2069 BranchLong(nan, bd); 2070 bind(&skip); 2071 } else { 2072 c(UN, sizeField, cmp1, cmp2); 2073 bc1t(nan); 2074 if (bd == PROTECT) { 2075 nop(); 2076 } 2077 } 2078 } else { 2079 // Use kDoubleCompareReg for comparison result. It has to be unavailable 2080 // to lithium register allocator. 2081 DCHECK(!cmp1.is(kDoubleCompareReg) && !cmp2.is(kDoubleCompareReg)); 2082 if (long_branch) { 2083 Label skip; 2084 cmp(UN, sizeField, kDoubleCompareReg, cmp1, cmp2); 2085 bc1eqz(&skip, kDoubleCompareReg); 2086 nop(); 2087 BranchLong(nan, bd); 2088 bind(&skip); 2089 } else { 2090 cmp(UN, sizeField, kDoubleCompareReg, cmp1, cmp2); 2091 bc1nez(nan, kDoubleCompareReg); 2092 if (bd == PROTECT) { 2093 nop(); 2094 } 2095 } 2096 } 2097 } 2098 2099 if (target) { 2100 bool long_branch = 2101 target->is_bound() ? !is_near(target) : is_trampoline_emitted(); 2102 if (long_branch) { 2103 Label skip; 2104 Condition neg_cond = NegateFpuCondition(cond); 2105 BranchShortF(sizeField, &skip, neg_cond, cmp1, cmp2, bd); 2106 BranchLong(target, bd); 2107 bind(&skip); 2108 } else { 2109 BranchShortF(sizeField, target, cond, cmp1, cmp2, bd); 2110 } 2111 } 2112 } 2113 } 2114 2115 void MacroAssembler::BranchShortF(SecondaryField sizeField, Label* target, 2116 Condition cc, FPURegister cmp1, 2117 FPURegister cmp2, BranchDelaySlot bd) { 2118 if (!IsMipsArchVariant(kMips32r6)) { 2119 BlockTrampolinePoolScope block_trampoline_pool(this); 2120 if (target) { 2121 // Here NaN cases were either handled by this function or are assumed to 2122 // have been handled by the caller. 2123 switch (cc) { 2124 case lt: 2125 c(OLT, sizeField, cmp1, cmp2); 2126 bc1t(target); 2127 break; 2128 case ult: 2129 c(ULT, sizeField, cmp1, cmp2); 2130 bc1t(target); 2131 break; 2132 case gt: 2133 c(ULE, sizeField, cmp1, cmp2); 2134 bc1f(target); 2135 break; 2136 case ugt: 2137 c(OLE, sizeField, cmp1, cmp2); 2138 bc1f(target); 2139 break; 2140 case ge: 2141 c(ULT, sizeField, cmp1, cmp2); 2142 bc1f(target); 2143 break; 2144 case uge: 2145 c(OLT, sizeField, cmp1, cmp2); 2146 bc1f(target); 2147 break; 2148 case le: 2149 c(OLE, sizeField, cmp1, cmp2); 2150 bc1t(target); 2151 break; 2152 case ule: 2153 c(ULE, sizeField, cmp1, cmp2); 2154 bc1t(target); 2155 break; 2156 case eq: 2157 c(EQ, sizeField, cmp1, cmp2); 2158 bc1t(target); 2159 break; 2160 case ueq: 2161 c(UEQ, sizeField, cmp1, cmp2); 2162 bc1t(target); 2163 break; 2164 case ne: // Unordered or not equal. 2165 c(EQ, sizeField, cmp1, cmp2); 2166 bc1f(target); 2167 break; 2168 case ogl: 2169 c(UEQ, sizeField, cmp1, cmp2); 2170 bc1f(target); 2171 break; 2172 default: 2173 CHECK(0); 2174 } 2175 } 2176 } else { 2177 BlockTrampolinePoolScope block_trampoline_pool(this); 2178 if (target) { 2179 // Here NaN cases were either handled by this function or are assumed to 2180 // have been handled by the caller. 2181 // Unsigned conditions are treated as their signed counterpart. 2182 // Use kDoubleCompareReg for comparison result, it is 2183 // valid in fp64 (FR = 1) mode which is implied for mips32r6. 2184 DCHECK(!cmp1.is(kDoubleCompareReg) && !cmp2.is(kDoubleCompareReg)); 2185 switch (cc) { 2186 case lt: 2187 cmp(OLT, sizeField, kDoubleCompareReg, cmp1, cmp2); 2188 bc1nez(target, kDoubleCompareReg); 2189 break; 2190 case ult: 2191 cmp(ULT, sizeField, kDoubleCompareReg, cmp1, cmp2); 2192 bc1nez(target, kDoubleCompareReg); 2193 break; 2194 case gt: 2195 cmp(ULE, sizeField, kDoubleCompareReg, cmp1, cmp2); 2196 bc1eqz(target, kDoubleCompareReg); 2197 break; 2198 case ugt: 2199 cmp(OLE, sizeField, kDoubleCompareReg, cmp1, cmp2); 2200 bc1eqz(target, kDoubleCompareReg); 2201 break; 2202 case ge: 2203 cmp(ULT, sizeField, kDoubleCompareReg, cmp1, cmp2); 2204 bc1eqz(target, kDoubleCompareReg); 2205 break; 2206 case uge: 2207 cmp(OLT, sizeField, kDoubleCompareReg, cmp1, cmp2); 2208 bc1eqz(target, kDoubleCompareReg); 2209 break; 2210 case le: 2211 cmp(OLE, sizeField, kDoubleCompareReg, cmp1, cmp2); 2212 bc1nez(target, kDoubleCompareReg); 2213 break; 2214 case ule: 2215 cmp(ULE, sizeField, kDoubleCompareReg, cmp1, cmp2); 2216 bc1nez(target, kDoubleCompareReg); 2217 break; 2218 case eq: 2219 cmp(EQ, sizeField, kDoubleCompareReg, cmp1, cmp2); 2220 bc1nez(target, kDoubleCompareReg); 2221 break; 2222 case ueq: 2223 cmp(UEQ, sizeField, kDoubleCompareReg, cmp1, cmp2); 2224 bc1nez(target, kDoubleCompareReg); 2225 break; 2226 case ne: 2227 cmp(EQ, sizeField, kDoubleCompareReg, cmp1, cmp2); 2228 bc1eqz(target, kDoubleCompareReg); 2229 break; 2230 case ogl: 2231 cmp(UEQ, sizeField, kDoubleCompareReg, cmp1, cmp2); 2232 bc1eqz(target, kDoubleCompareReg); 2233 break; 2234 default: 2235 CHECK(0); 2236 } 2237 } 2238 } 2239 if (bd == PROTECT) { 2240 nop(); 2241 } 2242 } 2243 2244 2245 void MacroAssembler::FmoveLow(FPURegister dst, Register src_low) { 2246 if (IsFp32Mode()) { 2247 mtc1(src_low, dst); 2248 } else { 2249 DCHECK(IsFp64Mode() || IsFpxxMode()); 2250 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); 2251 DCHECK(!src_low.is(at)); 2252 mfhc1(at, dst); 2253 mtc1(src_low, dst); 2254 mthc1(at, dst); 2255 } 2256 } 2257 2258 2259 void MacroAssembler::Move(FPURegister dst, float imm) { 2260 li(at, Operand(bit_cast<int32_t>(imm))); 2261 mtc1(at, dst); 2262 } 2263 2264 2265 void MacroAssembler::Move(FPURegister dst, double imm) { 2266 int64_t imm_bits = bit_cast<int64_t>(imm); 2267 // Handle special values first. 2268 if (imm_bits == bit_cast<int64_t>(0.0) && has_double_zero_reg_set_) { 2269 mov_d(dst, kDoubleRegZero); 2270 } else if (imm_bits == bit_cast<int64_t>(-0.0) && has_double_zero_reg_set_) { 2271 Neg_d(dst, kDoubleRegZero); 2272 } else { 2273 uint32_t lo, hi; 2274 DoubleAsTwoUInt32(imm, &lo, &hi); 2275 // Move the low part of the double into the lower of the corresponding FPU 2276 // register of FPU register pair. 2277 if (lo != 0) { 2278 li(at, Operand(lo)); 2279 mtc1(at, dst); 2280 } else { 2281 mtc1(zero_reg, dst); 2282 } 2283 // Move the high part of the double into the higher of the corresponding FPU 2284 // register of FPU register pair. 2285 if (hi != 0) { 2286 li(at, Operand(hi)); 2287 Mthc1(at, dst); 2288 } else { 2289 Mthc1(zero_reg, dst); 2290 } 2291 if (dst.is(kDoubleRegZero)) has_double_zero_reg_set_ = true; 2292 } 2293 } 2294 2295 2296 void MacroAssembler::Movz(Register rd, Register rs, Register rt) { 2297 if (IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r6)) { 2298 Label done; 2299 Branch(&done, ne, rt, Operand(zero_reg)); 2300 mov(rd, rs); 2301 bind(&done); 2302 } else { 2303 movz(rd, rs, rt); 2304 } 2305 } 2306 2307 2308 void MacroAssembler::Movn(Register rd, Register rs, Register rt) { 2309 if (IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r6)) { 2310 Label done; 2311 Branch(&done, eq, rt, Operand(zero_reg)); 2312 mov(rd, rs); 2313 bind(&done); 2314 } else { 2315 movn(rd, rs, rt); 2316 } 2317 } 2318 2319 2320 void MacroAssembler::Movt(Register rd, Register rs, uint16_t cc) { 2321 if (IsMipsArchVariant(kLoongson)) { 2322 // Tests an FP condition code and then conditionally move rs to rd. 2323 // We do not currently use any FPU cc bit other than bit 0. 2324 DCHECK(cc == 0); 2325 DCHECK(!(rs.is(t8) || rd.is(t8))); 2326 Label done; 2327 Register scratch = t8; 2328 // For testing purposes we need to fetch content of the FCSR register and 2329 // than test its cc (floating point condition code) bit (for cc = 0, it is 2330 // 24. bit of the FCSR). 2331 cfc1(scratch, FCSR); 2332 // For the MIPS I, II and III architectures, the contents of scratch is 2333 // UNPREDICTABLE for the instruction immediately following CFC1. 2334 nop(); 2335 srl(scratch, scratch, 16); 2336 andi(scratch, scratch, 0x0080); 2337 Branch(&done, eq, scratch, Operand(zero_reg)); 2338 mov(rd, rs); 2339 bind(&done); 2340 } else { 2341 movt(rd, rs, cc); 2342 } 2343 } 2344 2345 2346 void MacroAssembler::Movf(Register rd, Register rs, uint16_t cc) { 2347 if (IsMipsArchVariant(kLoongson)) { 2348 // Tests an FP condition code and then conditionally move rs to rd. 2349 // We do not currently use any FPU cc bit other than bit 0. 2350 DCHECK(cc == 0); 2351 DCHECK(!(rs.is(t8) || rd.is(t8))); 2352 Label done; 2353 Register scratch = t8; 2354 // For testing purposes we need to fetch content of the FCSR register and 2355 // than test its cc (floating point condition code) bit (for cc = 0, it is 2356 // 24. bit of the FCSR). 2357 cfc1(scratch, FCSR); 2358 // For the MIPS I, II and III architectures, the contents of scratch is 2359 // UNPREDICTABLE for the instruction immediately following CFC1. 2360 nop(); 2361 srl(scratch, scratch, 16); 2362 andi(scratch, scratch, 0x0080); 2363 Branch(&done, ne, scratch, Operand(zero_reg)); 2364 mov(rd, rs); 2365 bind(&done); 2366 } else { 2367 movf(rd, rs, cc); 2368 } 2369 } 2370 2371 void MacroAssembler::Clz(Register rd, Register rs) { 2372 if (IsMipsArchVariant(kLoongson)) { 2373 DCHECK(!(rd.is(t8) || rd.is(t9)) && !(rs.is(t8) || rs.is(t9))); 2374 Register mask = t8; 2375 Register scratch = t9; 2376 Label loop, end; 2377 mov(at, rs); 2378 mov(rd, zero_reg); 2379 lui(mask, 0x8000); 2380 bind(&loop); 2381 and_(scratch, at, mask); 2382 Branch(&end, ne, scratch, Operand(zero_reg)); 2383 addiu(rd, rd, 1); 2384 Branch(&loop, ne, mask, Operand(zero_reg), USE_DELAY_SLOT); 2385 srl(mask, mask, 1); 2386 bind(&end); 2387 } else { 2388 clz(rd, rs); 2389 } 2390 } 2391 2392 2393 void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode, 2394 Register result, 2395 DoubleRegister double_input, 2396 Register scratch, 2397 DoubleRegister double_scratch, 2398 Register except_flag, 2399 CheckForInexactConversion check_inexact) { 2400 DCHECK(!result.is(scratch)); 2401 DCHECK(!double_input.is(double_scratch)); 2402 DCHECK(!except_flag.is(scratch)); 2403 2404 Label done; 2405 2406 // Clear the except flag (0 = no exception) 2407 mov(except_flag, zero_reg); 2408 2409 // Test for values that can be exactly represented as a signed 32-bit integer. 2410 cvt_w_d(double_scratch, double_input); 2411 mfc1(result, double_scratch); 2412 cvt_d_w(double_scratch, double_scratch); 2413 BranchF(&done, NULL, eq, double_input, double_scratch); 2414 2415 int32_t except_mask = kFCSRFlagMask; // Assume interested in all exceptions. 2416 2417 if (check_inexact == kDontCheckForInexactConversion) { 2418 // Ignore inexact exceptions. 2419 except_mask &= ~kFCSRInexactFlagMask; 2420 } 2421 2422 // Save FCSR. 2423 cfc1(scratch, FCSR); 2424 // Disable FPU exceptions. 2425 ctc1(zero_reg, FCSR); 2426 2427 // Do operation based on rounding mode. 2428 switch (rounding_mode) { 2429 case kRoundToNearest: 2430 Round_w_d(double_scratch, double_input); 2431 break; 2432 case kRoundToZero: 2433 Trunc_w_d(double_scratch, double_input); 2434 break; 2435 case kRoundToPlusInf: 2436 Ceil_w_d(double_scratch, double_input); 2437 break; 2438 case kRoundToMinusInf: 2439 Floor_w_d(double_scratch, double_input); 2440 break; 2441 } // End of switch-statement. 2442 2443 // Retrieve FCSR. 2444 cfc1(except_flag, FCSR); 2445 // Restore FCSR. 2446 ctc1(scratch, FCSR); 2447 // Move the converted value into the result register. 2448 mfc1(result, double_scratch); 2449 2450 // Check for fpu exceptions. 2451 And(except_flag, except_flag, Operand(except_mask)); 2452 2453 bind(&done); 2454 } 2455 2456 2457 void MacroAssembler::TryInlineTruncateDoubleToI(Register result, 2458 DoubleRegister double_input, 2459 Label* done) { 2460 DoubleRegister single_scratch = kLithiumScratchDouble.low(); 2461 Register scratch = at; 2462 Register scratch2 = t9; 2463 2464 // Clear cumulative exception flags and save the FCSR. 2465 cfc1(scratch2, FCSR); 2466 ctc1(zero_reg, FCSR); 2467 // Try a conversion to a signed integer. 2468 trunc_w_d(single_scratch, double_input); 2469 mfc1(result, single_scratch); 2470 // Retrieve and restore the FCSR. 2471 cfc1(scratch, FCSR); 2472 ctc1(scratch2, FCSR); 2473 // Check for overflow and NaNs. 2474 And(scratch, 2475 scratch, 2476 kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSRInvalidOpFlagMask); 2477 // If we had no exceptions we are done. 2478 Branch(done, eq, scratch, Operand(zero_reg)); 2479 } 2480 2481 2482 void MacroAssembler::TruncateDoubleToI(Register result, 2483 DoubleRegister double_input) { 2484 Label done; 2485 2486 TryInlineTruncateDoubleToI(result, double_input, &done); 2487 2488 // If we fell through then inline version didn't succeed - call stub instead. 2489 push(ra); 2490 Subu(sp, sp, Operand(kDoubleSize)); // Put input on stack. 2491 sdc1(double_input, MemOperand(sp, 0)); 2492 2493 DoubleToIStub stub(isolate(), sp, result, 0, true, true); 2494 CallStub(&stub); 2495 2496 Addu(sp, sp, Operand(kDoubleSize)); 2497 pop(ra); 2498 2499 bind(&done); 2500 } 2501 2502 2503 void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) { 2504 Label done; 2505 DoubleRegister double_scratch = f12; 2506 DCHECK(!result.is(object)); 2507 2508 ldc1(double_scratch, 2509 MemOperand(object, HeapNumber::kValueOffset - kHeapObjectTag)); 2510 TryInlineTruncateDoubleToI(result, double_scratch, &done); 2511 2512 // If we fell through then inline version didn't succeed - call stub instead. 2513 push(ra); 2514 DoubleToIStub stub(isolate(), 2515 object, 2516 result, 2517 HeapNumber::kValueOffset - kHeapObjectTag, 2518 true, 2519 true); 2520 CallStub(&stub); 2521 pop(ra); 2522 2523 bind(&done); 2524 } 2525 2526 2527 void MacroAssembler::TruncateNumberToI(Register object, 2528 Register result, 2529 Register heap_number_map, 2530 Register scratch, 2531 Label* not_number) { 2532 Label done; 2533 DCHECK(!result.is(object)); 2534 2535 UntagAndJumpIfSmi(result, object, &done); 2536 JumpIfNotHeapNumber(object, heap_number_map, scratch, not_number); 2537 TruncateHeapNumberToI(result, object); 2538 2539 bind(&done); 2540 } 2541 2542 2543 void MacroAssembler::GetLeastBitsFromSmi(Register dst, 2544 Register src, 2545 int num_least_bits) { 2546 Ext(dst, src, kSmiTagSize, num_least_bits); 2547 } 2548 2549 2550 void MacroAssembler::GetLeastBitsFromInt32(Register dst, 2551 Register src, 2552 int num_least_bits) { 2553 And(dst, src, Operand((1 << num_least_bits) - 1)); 2554 } 2555 2556 2557 // Emulated condtional branches do not emit a nop in the branch delay slot. 2558 // 2559 // BRANCH_ARGS_CHECK checks that conditional jump arguments are correct. 2560 #define BRANCH_ARGS_CHECK(cond, rs, rt) DCHECK( \ 2561 (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \ 2562 (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg)))) 2563 2564 2565 void MacroAssembler::Branch(int32_t offset, BranchDelaySlot bdslot) { 2566 DCHECK(IsMipsArchVariant(kMips32r6) ? is_int26(offset) : is_int16(offset)); 2567 BranchShort(offset, bdslot); 2568 } 2569 2570 2571 void MacroAssembler::Branch(int32_t offset, Condition cond, Register rs, 2572 const Operand& rt, BranchDelaySlot bdslot) { 2573 bool is_near = BranchShortCheck(offset, nullptr, cond, rs, rt, bdslot); 2574 DCHECK(is_near); 2575 USE(is_near); 2576 } 2577 2578 2579 void MacroAssembler::Branch(Label* L, BranchDelaySlot bdslot) { 2580 if (L->is_bound()) { 2581 if (is_near_branch(L)) { 2582 BranchShort(L, bdslot); 2583 } else { 2584 BranchLong(L, bdslot); 2585 } 2586 } else { 2587 if (is_trampoline_emitted()) { 2588 BranchLong(L, bdslot); 2589 } else { 2590 BranchShort(L, bdslot); 2591 } 2592 } 2593 } 2594 2595 2596 void MacroAssembler::Branch(Label* L, Condition cond, Register rs, 2597 const Operand& rt, 2598 BranchDelaySlot bdslot) { 2599 if (L->is_bound()) { 2600 if (!BranchShortCheck(0, L, cond, rs, rt, bdslot)) { 2601 if (cond != cc_always) { 2602 Label skip; 2603 Condition neg_cond = NegateCondition(cond); 2604 BranchShort(&skip, neg_cond, rs, rt); 2605 BranchLong(L, bdslot); 2606 bind(&skip); 2607 } else { 2608 BranchLong(L, bdslot); 2609 } 2610 } 2611 } else { 2612 if (is_trampoline_emitted()) { 2613 if (cond != cc_always) { 2614 Label skip; 2615 Condition neg_cond = NegateCondition(cond); 2616 BranchShort(&skip, neg_cond, rs, rt); 2617 BranchLong(L, bdslot); 2618 bind(&skip); 2619 } else { 2620 BranchLong(L, bdslot); 2621 } 2622 } else { 2623 BranchShort(L, cond, rs, rt, bdslot); 2624 } 2625 } 2626 } 2627 2628 2629 void MacroAssembler::Branch(Label* L, 2630 Condition cond, 2631 Register rs, 2632 Heap::RootListIndex index, 2633 BranchDelaySlot bdslot) { 2634 LoadRoot(at, index); 2635 Branch(L, cond, rs, Operand(at), bdslot); 2636 } 2637 2638 2639 void MacroAssembler::BranchShortHelper(int16_t offset, Label* L, 2640 BranchDelaySlot bdslot) { 2641 DCHECK(L == nullptr || offset == 0); 2642 offset = GetOffset(offset, L, OffsetSize::kOffset16); 2643 b(offset); 2644 2645 // Emit a nop in the branch delay slot if required. 2646 if (bdslot == PROTECT) 2647 nop(); 2648 } 2649 2650 2651 void MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L) { 2652 DCHECK(L == nullptr || offset == 0); 2653 offset = GetOffset(offset, L, OffsetSize::kOffset26); 2654 bc(offset); 2655 } 2656 2657 2658 void MacroAssembler::BranchShort(int32_t offset, BranchDelaySlot bdslot) { 2659 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { 2660 DCHECK(is_int26(offset)); 2661 BranchShortHelperR6(offset, nullptr); 2662 } else { 2663 DCHECK(is_int16(offset)); 2664 BranchShortHelper(offset, nullptr, bdslot); 2665 } 2666 } 2667 2668 2669 void MacroAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) { 2670 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { 2671 BranchShortHelperR6(0, L); 2672 } else { 2673 BranchShortHelper(0, L, bdslot); 2674 } 2675 } 2676 2677 2678 static inline bool IsZero(const Operand& rt) { 2679 if (rt.is_reg()) { 2680 return rt.rm().is(zero_reg); 2681 } else { 2682 return rt.immediate() == 0; 2683 } 2684 } 2685 2686 2687 int32_t MacroAssembler::GetOffset(int32_t offset, Label* L, OffsetSize bits) { 2688 if (L) { 2689 offset = branch_offset_helper(L, bits) >> 2; 2690 } else { 2691 DCHECK(is_intn(offset, bits)); 2692 } 2693 return offset; 2694 } 2695 2696 2697 Register MacroAssembler::GetRtAsRegisterHelper(const Operand& rt, 2698 Register scratch) { 2699 Register r2 = no_reg; 2700 if (rt.is_reg()) { 2701 r2 = rt.rm_; 2702 } else { 2703 r2 = scratch; 2704 li(r2, rt); 2705 } 2706 2707 return r2; 2708 } 2709 2710 2711 bool MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L, 2712 Condition cond, Register rs, 2713 const Operand& rt) { 2714 DCHECK(L == nullptr || offset == 0); 2715 Register scratch = rs.is(at) ? t8 : at; 2716 OffsetSize bits = OffsetSize::kOffset16; 2717 2718 // Be careful to always use shifted_branch_offset only just before the 2719 // branch instruction, as the location will be remember for patching the 2720 // target. 2721 { 2722 BlockTrampolinePoolScope block_trampoline_pool(this); 2723 switch (cond) { 2724 case cc_always: 2725 bits = OffsetSize::kOffset26; 2726 if (!is_near(L, bits)) return false; 2727 offset = GetOffset(offset, L, bits); 2728 bc(offset); 2729 break; 2730 case eq: 2731 if (rs.code() == rt.rm_.reg_code) { 2732 // Pre R6 beq is used here to make the code patchable. Otherwise bc 2733 // should be used which has no condition field so is not patchable. 2734 bits = OffsetSize::kOffset16; 2735 if (!is_near(L, bits)) return false; 2736 scratch = GetRtAsRegisterHelper(rt, scratch); 2737 offset = GetOffset(offset, L, bits); 2738 beq(rs, scratch, offset); 2739 nop(); 2740 } else if (IsZero(rt)) { 2741 bits = OffsetSize::kOffset21; 2742 if (!is_near(L, bits)) return false; 2743 offset = GetOffset(offset, L, bits); 2744 beqzc(rs, offset); 2745 } else { 2746 // We don't want any other register but scratch clobbered. 2747 bits = OffsetSize::kOffset16; 2748 if (!is_near(L, bits)) return false; 2749 scratch = GetRtAsRegisterHelper(rt, scratch); 2750 offset = GetOffset(offset, L, bits); 2751 beqc(rs, scratch, offset); 2752 } 2753 break; 2754 case ne: 2755 if (rs.code() == rt.rm_.reg_code) { 2756 // Pre R6 bne is used here to make the code patchable. Otherwise we 2757 // should not generate any instruction. 2758 bits = OffsetSize::kOffset16; 2759 if (!is_near(L, bits)) return false; 2760 scratch = GetRtAsRegisterHelper(rt, scratch); 2761 offset = GetOffset(offset, L, bits); 2762 bne(rs, scratch, offset); 2763 nop(); 2764 } else if (IsZero(rt)) { 2765 bits = OffsetSize::kOffset21; 2766 if (!is_near(L, bits)) return false; 2767 offset = GetOffset(offset, L, bits); 2768 bnezc(rs, offset); 2769 } else { 2770 // We don't want any other register but scratch clobbered. 2771 bits = OffsetSize::kOffset16; 2772 if (!is_near(L, bits)) return false; 2773 scratch = GetRtAsRegisterHelper(rt, scratch); 2774 offset = GetOffset(offset, L, bits); 2775 bnec(rs, scratch, offset); 2776 } 2777 break; 2778 2779 // Signed comparison. 2780 case greater: 2781 // rs > rt 2782 if (rs.code() == rt.rm_.reg_code) { 2783 break; // No code needs to be emitted. 2784 } else if (rs.is(zero_reg)) { 2785 bits = OffsetSize::kOffset16; 2786 if (!is_near(L, bits)) return false; 2787 scratch = GetRtAsRegisterHelper(rt, scratch); 2788 offset = GetOffset(offset, L, bits); 2789 bltzc(scratch, offset); 2790 } else if (IsZero(rt)) { 2791 bits = OffsetSize::kOffset16; 2792 if (!is_near(L, bits)) return false; 2793 offset = GetOffset(offset, L, bits); 2794 bgtzc(rs, offset); 2795 } else { 2796 bits = OffsetSize::kOffset16; 2797 if (!is_near(L, bits)) return false; 2798 scratch = GetRtAsRegisterHelper(rt, scratch); 2799 DCHECK(!rs.is(scratch)); 2800 offset = GetOffset(offset, L, bits); 2801 bltc(scratch, rs, offset); 2802 } 2803 break; 2804 case greater_equal: 2805 // rs >= rt 2806 if (rs.code() == rt.rm_.reg_code) { 2807 bits = OffsetSize::kOffset26; 2808 if (!is_near(L, bits)) return false; 2809 offset = GetOffset(offset, L, bits); 2810 bc(offset); 2811 } else if (rs.is(zero_reg)) { 2812 bits = OffsetSize::kOffset16; 2813 if (!is_near(L, bits)) return false; 2814 scratch = GetRtAsRegisterHelper(rt, scratch); 2815 offset = GetOffset(offset, L, bits); 2816 blezc(scratch, offset); 2817 } else if (IsZero(rt)) { 2818 bits = OffsetSize::kOffset16; 2819 if (!is_near(L, bits)) return false; 2820 offset = GetOffset(offset, L, bits); 2821 bgezc(rs, offset); 2822 } else { 2823 bits = OffsetSize::kOffset16; 2824 if (!is_near(L, bits)) return false; 2825 scratch = GetRtAsRegisterHelper(rt, scratch); 2826 DCHECK(!rs.is(scratch)); 2827 offset = GetOffset(offset, L, bits); 2828 bgec(rs, scratch, offset); 2829 } 2830 break; 2831 case less: 2832 // rs < rt 2833 if (rs.code() == rt.rm_.reg_code) { 2834 break; // No code needs to be emitted. 2835 } else if (rs.is(zero_reg)) { 2836 bits = OffsetSize::kOffset16; 2837 if (!is_near(L, bits)) return false; 2838 scratch = GetRtAsRegisterHelper(rt, scratch); 2839 offset = GetOffset(offset, L, bits); 2840 bgtzc(scratch, offset); 2841 } else if (IsZero(rt)) { 2842 bits = OffsetSize::kOffset16; 2843 if (!is_near(L, bits)) return false; 2844 offset = GetOffset(offset, L, bits); 2845 bltzc(rs, offset); 2846 } else { 2847 bits = OffsetSize::kOffset16; 2848 if (!is_near(L, bits)) return false; 2849 scratch = GetRtAsRegisterHelper(rt, scratch); 2850 DCHECK(!rs.is(scratch)); 2851 offset = GetOffset(offset, L, bits); 2852 bltc(rs, scratch, offset); 2853 } 2854 break; 2855 case less_equal: 2856 // rs <= rt 2857 if (rs.code() == rt.rm_.reg_code) { 2858 bits = OffsetSize::kOffset26; 2859 if (!is_near(L, bits)) return false; 2860 offset = GetOffset(offset, L, bits); 2861 bc(offset); 2862 } else if (rs.is(zero_reg)) { 2863 bits = OffsetSize::kOffset16; 2864 if (!is_near(L, bits)) return false; 2865 scratch = GetRtAsRegisterHelper(rt, scratch); 2866 offset = GetOffset(offset, L, bits); 2867 bgezc(scratch, offset); 2868 } else if (IsZero(rt)) { 2869 bits = OffsetSize::kOffset16; 2870 if (!is_near(L, bits)) return false; 2871 offset = GetOffset(offset, L, bits); 2872 blezc(rs, offset); 2873 } else { 2874 bits = OffsetSize::kOffset16; 2875 if (!is_near(L, bits)) return false; 2876 scratch = GetRtAsRegisterHelper(rt, scratch); 2877 DCHECK(!rs.is(scratch)); 2878 offset = GetOffset(offset, L, bits); 2879 bgec(scratch, rs, offset); 2880 } 2881 break; 2882 2883 // Unsigned comparison. 2884 case Ugreater: 2885 // rs > rt 2886 if (rs.code() == rt.rm_.reg_code) { 2887 break; // No code needs to be emitted. 2888 } else if (rs.is(zero_reg)) { 2889 bits = OffsetSize::kOffset21; 2890 if (!is_near(L, bits)) return false; 2891 scratch = GetRtAsRegisterHelper(rt, scratch); 2892 offset = GetOffset(offset, L, bits); 2893 bnezc(scratch, offset); 2894 } else if (IsZero(rt)) { 2895 bits = OffsetSize::kOffset21; 2896 if (!is_near(L, bits)) return false; 2897 offset = GetOffset(offset, L, bits); 2898 bnezc(rs, offset); 2899 } else { 2900 bits = OffsetSize::kOffset16; 2901 if (!is_near(L, bits)) return false; 2902 scratch = GetRtAsRegisterHelper(rt, scratch); 2903 DCHECK(!rs.is(scratch)); 2904 offset = GetOffset(offset, L, bits); 2905 bltuc(scratch, rs, offset); 2906 } 2907 break; 2908 case Ugreater_equal: 2909 // rs >= rt 2910 if (rs.code() == rt.rm_.reg_code) { 2911 bits = OffsetSize::kOffset26; 2912 if (!is_near(L, bits)) return false; 2913 offset = GetOffset(offset, L, bits); 2914 bc(offset); 2915 } else if (rs.is(zero_reg)) { 2916 bits = OffsetSize::kOffset21; 2917 if (!is_near(L, bits)) return false; 2918 scratch = GetRtAsRegisterHelper(rt, scratch); 2919 offset = GetOffset(offset, L, bits); 2920 beqzc(scratch, offset); 2921 } else if (IsZero(rt)) { 2922 bits = OffsetSize::kOffset26; 2923 if (!is_near(L, bits)) return false; 2924 offset = GetOffset(offset, L, bits); 2925 bc(offset); 2926 } else { 2927 bits = OffsetSize::kOffset16; 2928 if (!is_near(L, bits)) return false; 2929 scratch = GetRtAsRegisterHelper(rt, scratch); 2930 DCHECK(!rs.is(scratch)); 2931 offset = GetOffset(offset, L, bits); 2932 bgeuc(rs, scratch, offset); 2933 } 2934 break; 2935 case Uless: 2936 // rs < rt 2937 if (rs.code() == rt.rm_.reg_code) { 2938 break; // No code needs to be emitted. 2939 } else if (rs.is(zero_reg)) { 2940 bits = OffsetSize::kOffset21; 2941 if (!is_near(L, bits)) return false; 2942 scratch = GetRtAsRegisterHelper(rt, scratch); 2943 offset = GetOffset(offset, L, bits); 2944 bnezc(scratch, offset); 2945 } else if (IsZero(rt)) { 2946 break; // No code needs to be emitted. 2947 } else { 2948 bits = OffsetSize::kOffset16; 2949 if (!is_near(L, bits)) return false; 2950 scratch = GetRtAsRegisterHelper(rt, scratch); 2951 DCHECK(!rs.is(scratch)); 2952 offset = GetOffset(offset, L, bits); 2953 bltuc(rs, scratch, offset); 2954 } 2955 break; 2956 case Uless_equal: 2957 // rs <= rt 2958 if (rs.code() == rt.rm_.reg_code) { 2959 bits = OffsetSize::kOffset26; 2960 if (!is_near(L, bits)) return false; 2961 offset = GetOffset(offset, L, bits); 2962 bc(offset); 2963 } else if (rs.is(zero_reg)) { 2964 bits = OffsetSize::kOffset26; 2965 if (!is_near(L, bits)) return false; 2966 scratch = GetRtAsRegisterHelper(rt, scratch); 2967 offset = GetOffset(offset, L, bits); 2968 bc(offset); 2969 } else if (IsZero(rt)) { 2970 bits = OffsetSize::kOffset21; 2971 if (!is_near(L, bits)) return false; 2972 offset = GetOffset(offset, L, bits); 2973 beqzc(rs, offset); 2974 } else { 2975 bits = OffsetSize::kOffset16; 2976 if (!is_near(L, bits)) return false; 2977 scratch = GetRtAsRegisterHelper(rt, scratch); 2978 DCHECK(!rs.is(scratch)); 2979 offset = GetOffset(offset, L, bits); 2980 bgeuc(scratch, rs, offset); 2981 } 2982 break; 2983 default: 2984 UNREACHABLE(); 2985 } 2986 } 2987 CheckTrampolinePoolQuick(1); 2988 return true; 2989 } 2990 2991 2992 bool MacroAssembler::BranchShortHelper(int16_t offset, Label* L, Condition cond, 2993 Register rs, const Operand& rt, 2994 BranchDelaySlot bdslot) { 2995 DCHECK(L == nullptr || offset == 0); 2996 if (!is_near(L, OffsetSize::kOffset16)) return false; 2997 2998 Register scratch = at; 2999 int32_t offset32; 3000 3001 // Be careful to always use shifted_branch_offset only just before the 3002 // branch instruction, as the location will be remember for patching the 3003 // target. 3004 { 3005 BlockTrampolinePoolScope block_trampoline_pool(this); 3006 switch (cond) { 3007 case cc_always: 3008 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3009 b(offset32); 3010 break; 3011 case eq: 3012 if (IsZero(rt)) { 3013 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3014 beq(rs, zero_reg, offset32); 3015 } else { 3016 // We don't want any other register but scratch clobbered. 3017 scratch = GetRtAsRegisterHelper(rt, scratch); 3018 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3019 beq(rs, scratch, offset32); 3020 } 3021 break; 3022 case ne: 3023 if (IsZero(rt)) { 3024 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3025 bne(rs, zero_reg, offset32); 3026 } else { 3027 // We don't want any other register but scratch clobbered. 3028 scratch = GetRtAsRegisterHelper(rt, scratch); 3029 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3030 bne(rs, scratch, offset32); 3031 } 3032 break; 3033 3034 // Signed comparison. 3035 case greater: 3036 if (IsZero(rt)) { 3037 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3038 bgtz(rs, offset32); 3039 } else { 3040 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3041 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3042 bne(scratch, zero_reg, offset32); 3043 } 3044 break; 3045 case greater_equal: 3046 if (IsZero(rt)) { 3047 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3048 bgez(rs, offset32); 3049 } else { 3050 Slt(scratch, rs, rt); 3051 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3052 beq(scratch, zero_reg, offset32); 3053 } 3054 break; 3055 case less: 3056 if (IsZero(rt)) { 3057 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3058 bltz(rs, offset32); 3059 } else { 3060 Slt(scratch, rs, rt); 3061 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3062 bne(scratch, zero_reg, offset32); 3063 } 3064 break; 3065 case less_equal: 3066 if (IsZero(rt)) { 3067 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3068 blez(rs, offset32); 3069 } else { 3070 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3071 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3072 beq(scratch, zero_reg, offset32); 3073 } 3074 break; 3075 3076 // Unsigned comparison. 3077 case Ugreater: 3078 if (IsZero(rt)) { 3079 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3080 bne(rs, zero_reg, offset32); 3081 } else { 3082 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3083 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3084 bne(scratch, zero_reg, offset32); 3085 } 3086 break; 3087 case Ugreater_equal: 3088 if (IsZero(rt)) { 3089 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3090 b(offset32); 3091 } else { 3092 Sltu(scratch, rs, rt); 3093 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3094 beq(scratch, zero_reg, offset32); 3095 } 3096 break; 3097 case Uless: 3098 if (IsZero(rt)) { 3099 return true; // No code needs to be emitted. 3100 } else { 3101 Sltu(scratch, rs, rt); 3102 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3103 bne(scratch, zero_reg, offset32); 3104 } 3105 break; 3106 case Uless_equal: 3107 if (IsZero(rt)) { 3108 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3109 beq(rs, zero_reg, offset32); 3110 } else { 3111 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3112 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); 3113 beq(scratch, zero_reg, offset32); 3114 } 3115 break; 3116 default: 3117 UNREACHABLE(); 3118 } 3119 } 3120 // Emit a nop in the branch delay slot if required. 3121 if (bdslot == PROTECT) 3122 nop(); 3123 3124 return true; 3125 } 3126 3127 3128 bool MacroAssembler::BranchShortCheck(int32_t offset, Label* L, Condition cond, 3129 Register rs, const Operand& rt, 3130 BranchDelaySlot bdslot) { 3131 BRANCH_ARGS_CHECK(cond, rs, rt); 3132 if (!L) { 3133 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { 3134 DCHECK(is_int26(offset)); 3135 return BranchShortHelperR6(offset, nullptr, cond, rs, rt); 3136 } else { 3137 DCHECK(is_int16(offset)); 3138 return BranchShortHelper(offset, nullptr, cond, rs, rt, bdslot); 3139 } 3140 } else { 3141 DCHECK(offset == 0); 3142 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { 3143 return BranchShortHelperR6(0, L, cond, rs, rt); 3144 } else { 3145 return BranchShortHelper(0, L, cond, rs, rt, bdslot); 3146 } 3147 } 3148 return false; 3149 } 3150 3151 3152 void MacroAssembler::BranchShort(int32_t offset, Condition cond, Register rs, 3153 const Operand& rt, BranchDelaySlot bdslot) { 3154 BranchShortCheck(offset, nullptr, cond, rs, rt, bdslot); 3155 } 3156 3157 3158 void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, 3159 const Operand& rt, BranchDelaySlot bdslot) { 3160 BranchShortCheck(0, L, cond, rs, rt, bdslot); 3161 } 3162 3163 3164 void MacroAssembler::BranchAndLink(int32_t offset, BranchDelaySlot bdslot) { 3165 BranchAndLinkShort(offset, bdslot); 3166 } 3167 3168 3169 void MacroAssembler::BranchAndLink(int32_t offset, Condition cond, Register rs, 3170 const Operand& rt, BranchDelaySlot bdslot) { 3171 bool is_near = BranchAndLinkShortCheck(offset, nullptr, cond, rs, rt, bdslot); 3172 DCHECK(is_near); 3173 USE(is_near); 3174 } 3175 3176 3177 void MacroAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) { 3178 if (L->is_bound()) { 3179 if (is_near_branch(L)) { 3180 BranchAndLinkShort(L, bdslot); 3181 } else { 3182 BranchAndLinkLong(L, bdslot); 3183 } 3184 } else { 3185 if (is_trampoline_emitted()) { 3186 BranchAndLinkLong(L, bdslot); 3187 } else { 3188 BranchAndLinkShort(L, bdslot); 3189 } 3190 } 3191 } 3192 3193 3194 void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs, 3195 const Operand& rt, 3196 BranchDelaySlot bdslot) { 3197 if (L->is_bound()) { 3198 if (!BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot)) { 3199 Label skip; 3200 Condition neg_cond = NegateCondition(cond); 3201 BranchShort(&skip, neg_cond, rs, rt); 3202 BranchAndLinkLong(L, bdslot); 3203 bind(&skip); 3204 } 3205 } else { 3206 if (is_trampoline_emitted()) { 3207 Label skip; 3208 Condition neg_cond = NegateCondition(cond); 3209 BranchShort(&skip, neg_cond, rs, rt); 3210 BranchAndLinkLong(L, bdslot); 3211 bind(&skip); 3212 } else { 3213 BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot); 3214 } 3215 } 3216 } 3217 3218 3219 void MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L, 3220 BranchDelaySlot bdslot) { 3221 DCHECK(L == nullptr || offset == 0); 3222 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3223 bal(offset); 3224 3225 // Emit a nop in the branch delay slot if required. 3226 if (bdslot == PROTECT) 3227 nop(); 3228 } 3229 3230 3231 void MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L) { 3232 DCHECK(L == nullptr || offset == 0); 3233 offset = GetOffset(offset, L, OffsetSize::kOffset26); 3234 balc(offset); 3235 } 3236 3237 3238 void MacroAssembler::BranchAndLinkShort(int32_t offset, 3239 BranchDelaySlot bdslot) { 3240 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { 3241 DCHECK(is_int26(offset)); 3242 BranchAndLinkShortHelperR6(offset, nullptr); 3243 } else { 3244 DCHECK(is_int16(offset)); 3245 BranchAndLinkShortHelper(offset, nullptr, bdslot); 3246 } 3247 } 3248 3249 3250 void MacroAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) { 3251 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { 3252 BranchAndLinkShortHelperR6(0, L); 3253 } else { 3254 BranchAndLinkShortHelper(0, L, bdslot); 3255 } 3256 } 3257 3258 3259 bool MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L, 3260 Condition cond, Register rs, 3261 const Operand& rt) { 3262 DCHECK(L == nullptr || offset == 0); 3263 Register scratch = rs.is(at) ? t8 : at; 3264 OffsetSize bits = OffsetSize::kOffset16; 3265 3266 BlockTrampolinePoolScope block_trampoline_pool(this); 3267 DCHECK((cond == cc_always && is_int26(offset)) || is_int16(offset)); 3268 switch (cond) { 3269 case cc_always: 3270 bits = OffsetSize::kOffset26; 3271 if (!is_near(L, bits)) return false; 3272 offset = GetOffset(offset, L, bits); 3273 balc(offset); 3274 break; 3275 case eq: 3276 if (!is_near(L, bits)) return false; 3277 Subu(scratch, rs, rt); 3278 offset = GetOffset(offset, L, bits); 3279 beqzalc(scratch, offset); 3280 break; 3281 case ne: 3282 if (!is_near(L, bits)) return false; 3283 Subu(scratch, rs, rt); 3284 offset = GetOffset(offset, L, bits); 3285 bnezalc(scratch, offset); 3286 break; 3287 3288 // Signed comparison. 3289 case greater: 3290 // rs > rt 3291 if (rs.code() == rt.rm_.reg_code) { 3292 break; // No code needs to be emitted. 3293 } else if (rs.is(zero_reg)) { 3294 if (!is_near(L, bits)) return false; 3295 scratch = GetRtAsRegisterHelper(rt, scratch); 3296 offset = GetOffset(offset, L, bits); 3297 bltzalc(scratch, offset); 3298 } else if (IsZero(rt)) { 3299 if (!is_near(L, bits)) return false; 3300 offset = GetOffset(offset, L, bits); 3301 bgtzalc(rs, offset); 3302 } else { 3303 if (!is_near(L, bits)) return false; 3304 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3305 offset = GetOffset(offset, L, bits); 3306 bnezalc(scratch, offset); 3307 } 3308 break; 3309 case greater_equal: 3310 // rs >= rt 3311 if (rs.code() == rt.rm_.reg_code) { 3312 bits = OffsetSize::kOffset26; 3313 if (!is_near(L, bits)) return false; 3314 offset = GetOffset(offset, L, bits); 3315 balc(offset); 3316 } else if (rs.is(zero_reg)) { 3317 if (!is_near(L, bits)) return false; 3318 scratch = GetRtAsRegisterHelper(rt, scratch); 3319 offset = GetOffset(offset, L, bits); 3320 blezalc(scratch, offset); 3321 } else if (IsZero(rt)) { 3322 if (!is_near(L, bits)) return false; 3323 offset = GetOffset(offset, L, bits); 3324 bgezalc(rs, offset); 3325 } else { 3326 if (!is_near(L, bits)) return false; 3327 Slt(scratch, rs, rt); 3328 offset = GetOffset(offset, L, bits); 3329 beqzalc(scratch, offset); 3330 } 3331 break; 3332 case less: 3333 // rs < rt 3334 if (rs.code() == rt.rm_.reg_code) { 3335 break; // No code needs to be emitted. 3336 } else if (rs.is(zero_reg)) { 3337 if (!is_near(L, bits)) return false; 3338 scratch = GetRtAsRegisterHelper(rt, scratch); 3339 offset = GetOffset(offset, L, bits); 3340 bgtzalc(scratch, offset); 3341 } else if (IsZero(rt)) { 3342 if (!is_near(L, bits)) return false; 3343 offset = GetOffset(offset, L, bits); 3344 bltzalc(rs, offset); 3345 } else { 3346 if (!is_near(L, bits)) return false; 3347 Slt(scratch, rs, rt); 3348 offset = GetOffset(offset, L, bits); 3349 bnezalc(scratch, offset); 3350 } 3351 break; 3352 case less_equal: 3353 // rs <= r2 3354 if (rs.code() == rt.rm_.reg_code) { 3355 bits = OffsetSize::kOffset26; 3356 if (!is_near(L, bits)) return false; 3357 offset = GetOffset(offset, L, bits); 3358 balc(offset); 3359 } else if (rs.is(zero_reg)) { 3360 if (!is_near(L, bits)) return false; 3361 scratch = GetRtAsRegisterHelper(rt, scratch); 3362 offset = GetOffset(offset, L, bits); 3363 bgezalc(scratch, offset); 3364 } else if (IsZero(rt)) { 3365 if (!is_near(L, bits)) return false; 3366 offset = GetOffset(offset, L, bits); 3367 blezalc(rs, offset); 3368 } else { 3369 if (!is_near(L, bits)) return false; 3370 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3371 offset = GetOffset(offset, L, bits); 3372 beqzalc(scratch, offset); 3373 } 3374 break; 3375 3376 3377 // Unsigned comparison. 3378 case Ugreater: 3379 // rs > r2 3380 if (!is_near(L, bits)) return false; 3381 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3382 offset = GetOffset(offset, L, bits); 3383 bnezalc(scratch, offset); 3384 break; 3385 case Ugreater_equal: 3386 // rs >= r2 3387 if (!is_near(L, bits)) return false; 3388 Sltu(scratch, rs, rt); 3389 offset = GetOffset(offset, L, bits); 3390 beqzalc(scratch, offset); 3391 break; 3392 case Uless: 3393 // rs < r2 3394 if (!is_near(L, bits)) return false; 3395 Sltu(scratch, rs, rt); 3396 offset = GetOffset(offset, L, bits); 3397 bnezalc(scratch, offset); 3398 break; 3399 case Uless_equal: 3400 // rs <= r2 3401 if (!is_near(L, bits)) return false; 3402 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3403 offset = GetOffset(offset, L, bits); 3404 beqzalc(scratch, offset); 3405 break; 3406 default: 3407 UNREACHABLE(); 3408 } 3409 return true; 3410 } 3411 3412 3413 // Pre r6 we need to use a bgezal or bltzal, but they can't be used directly 3414 // with the slt instructions. We could use sub or add instead but we would miss 3415 // overflow cases, so we keep slt and add an intermediate third instruction. 3416 bool MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L, 3417 Condition cond, Register rs, 3418 const Operand& rt, 3419 BranchDelaySlot bdslot) { 3420 DCHECK(L == nullptr || offset == 0); 3421 if (!is_near(L, OffsetSize::kOffset16)) return false; 3422 3423 Register scratch = t8; 3424 BlockTrampolinePoolScope block_trampoline_pool(this); 3425 3426 switch (cond) { 3427 case cc_always: 3428 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3429 bal(offset); 3430 break; 3431 case eq: 3432 bne(rs, GetRtAsRegisterHelper(rt, scratch), 2); 3433 nop(); 3434 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3435 bal(offset); 3436 break; 3437 case ne: 3438 beq(rs, GetRtAsRegisterHelper(rt, scratch), 2); 3439 nop(); 3440 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3441 bal(offset); 3442 break; 3443 3444 // Signed comparison. 3445 case greater: 3446 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3447 addiu(scratch, scratch, -1); 3448 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3449 bgezal(scratch, offset); 3450 break; 3451 case greater_equal: 3452 Slt(scratch, rs, rt); 3453 addiu(scratch, scratch, -1); 3454 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3455 bltzal(scratch, offset); 3456 break; 3457 case less: 3458 Slt(scratch, rs, rt); 3459 addiu(scratch, scratch, -1); 3460 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3461 bgezal(scratch, offset); 3462 break; 3463 case less_equal: 3464 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3465 addiu(scratch, scratch, -1); 3466 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3467 bltzal(scratch, offset); 3468 break; 3469 3470 // Unsigned comparison. 3471 case Ugreater: 3472 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3473 addiu(scratch, scratch, -1); 3474 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3475 bgezal(scratch, offset); 3476 break; 3477 case Ugreater_equal: 3478 Sltu(scratch, rs, rt); 3479 addiu(scratch, scratch, -1); 3480 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3481 bltzal(scratch, offset); 3482 break; 3483 case Uless: 3484 Sltu(scratch, rs, rt); 3485 addiu(scratch, scratch, -1); 3486 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3487 bgezal(scratch, offset); 3488 break; 3489 case Uless_equal: 3490 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); 3491 addiu(scratch, scratch, -1); 3492 offset = GetOffset(offset, L, OffsetSize::kOffset16); 3493 bltzal(scratch, offset); 3494 break; 3495 3496 default: 3497 UNREACHABLE(); 3498 } 3499 3500 // Emit a nop in the branch delay slot if required. 3501 if (bdslot == PROTECT) 3502 nop(); 3503 3504 return true; 3505 } 3506 3507 3508 bool MacroAssembler::BranchAndLinkShortCheck(int32_t offset, Label* L, 3509 Condition cond, Register rs, 3510 const Operand& rt, 3511 BranchDelaySlot bdslot) { 3512 BRANCH_ARGS_CHECK(cond, rs, rt); 3513 3514 if (!L) { 3515 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { 3516 DCHECK(is_int26(offset)); 3517 return BranchAndLinkShortHelperR6(offset, nullptr, cond, rs, rt); 3518 } else { 3519 DCHECK(is_int16(offset)); 3520 return BranchAndLinkShortHelper(offset, nullptr, cond, rs, rt, bdslot); 3521 } 3522 } else { 3523 DCHECK(offset == 0); 3524 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { 3525 return BranchAndLinkShortHelperR6(0, L, cond, rs, rt); 3526 } else { 3527 return BranchAndLinkShortHelper(0, L, cond, rs, rt, bdslot); 3528 } 3529 } 3530 return false; 3531 } 3532 3533 3534 void MacroAssembler::Jump(Register target, 3535 Condition cond, 3536 Register rs, 3537 const Operand& rt, 3538 BranchDelaySlot bd) { 3539 BlockTrampolinePoolScope block_trampoline_pool(this); 3540 if (IsMipsArchVariant(kMips32r6) && bd == PROTECT) { 3541 if (cond == cc_always) { 3542 jic(target, 0); 3543 } else { 3544 BRANCH_ARGS_CHECK(cond, rs, rt); 3545 Branch(2, NegateCondition(cond), rs, rt); 3546 jic(target, 0); 3547 } 3548 } else { 3549 if (cond == cc_always) { 3550 jr(target); 3551 } else { 3552 BRANCH_ARGS_CHECK(cond, rs, rt); 3553 Branch(2, NegateCondition(cond), rs, rt); 3554 jr(target); 3555 } 3556 // Emit a nop in the branch delay slot if required. 3557 if (bd == PROTECT) nop(); 3558 } 3559 } 3560 3561 3562 void MacroAssembler::Jump(intptr_t target, 3563 RelocInfo::Mode rmode, 3564 Condition cond, 3565 Register rs, 3566 const Operand& rt, 3567 BranchDelaySlot bd) { 3568 Label skip; 3569 if (cond != cc_always) { 3570 Branch(USE_DELAY_SLOT, &skip, NegateCondition(cond), rs, rt); 3571 } 3572 // The first instruction of 'li' may be placed in the delay slot. 3573 // This is not an issue, t9 is expected to be clobbered anyway. 3574 li(t9, Operand(target, rmode)); 3575 Jump(t9, al, zero_reg, Operand(zero_reg), bd); 3576 bind(&skip); 3577 } 3578 3579 3580 void MacroAssembler::Jump(Address target, 3581 RelocInfo::Mode rmode, 3582 Condition cond, 3583 Register rs, 3584 const Operand& rt, 3585 BranchDelaySlot bd) { 3586 DCHECK(!RelocInfo::IsCodeTarget(rmode)); 3587 Jump(reinterpret_cast<intptr_t>(target), rmode, cond, rs, rt, bd); 3588 } 3589 3590 3591 void MacroAssembler::Jump(Handle<Code> code, 3592 RelocInfo::Mode rmode, 3593 Condition cond, 3594 Register rs, 3595 const Operand& rt, 3596 BranchDelaySlot bd) { 3597 DCHECK(RelocInfo::IsCodeTarget(rmode)); 3598 AllowDeferredHandleDereference embedding_raw_address; 3599 Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond, rs, rt, bd); 3600 } 3601 3602 3603 int MacroAssembler::CallSize(Register target, 3604 Condition cond, 3605 Register rs, 3606 const Operand& rt, 3607 BranchDelaySlot bd) { 3608 int size = 0; 3609 3610 if (cond == cc_always) { 3611 size += 1; 3612 } else { 3613 size += 3; 3614 } 3615 3616 if (bd == PROTECT && !IsMipsArchVariant(kMips32r6)) size += 1; 3617 3618 return size * kInstrSize; 3619 } 3620 3621 3622 // Note: To call gcc-compiled C code on mips, you must call thru t9. 3623 void MacroAssembler::Call(Register target, 3624 Condition cond, 3625 Register rs, 3626 const Operand& rt, 3627 BranchDelaySlot bd) { 3628 #ifdef DEBUG 3629 int size = IsPrevInstrCompactBranch() ? kInstrSize : 0; 3630 #endif 3631 3632 BlockTrampolinePoolScope block_trampoline_pool(this); 3633 Label start; 3634 bind(&start); 3635 if (IsMipsArchVariant(kMips32r6) && bd == PROTECT) { 3636 if (cond == cc_always) { 3637 jialc(target, 0); 3638 } else { 3639 BRANCH_ARGS_CHECK(cond, rs, rt); 3640 Branch(2, NegateCondition(cond), rs, rt); 3641 jialc(target, 0); 3642 } 3643 } else { 3644 if (cond == cc_always) { 3645 jalr(target); 3646 } else { 3647 BRANCH_ARGS_CHECK(cond, rs, rt); 3648 Branch(2, NegateCondition(cond), rs, rt); 3649 jalr(target); 3650 } 3651 // Emit a nop in the branch delay slot if required. 3652 if (bd == PROTECT) nop(); 3653 } 3654 3655 #ifdef DEBUG 3656 CHECK_EQ(size + CallSize(target, cond, rs, rt, bd), 3657 SizeOfCodeGeneratedSince(&start)); 3658 #endif 3659 } 3660 3661 3662 int MacroAssembler::CallSize(Address target, 3663 RelocInfo::Mode rmode, 3664 Condition cond, 3665 Register rs, 3666 const Operand& rt, 3667 BranchDelaySlot bd) { 3668 int size = CallSize(t9, cond, rs, rt, bd); 3669 return size + 2 * kInstrSize; 3670 } 3671 3672 3673 void MacroAssembler::Call(Address target, 3674 RelocInfo::Mode rmode, 3675 Condition cond, 3676 Register rs, 3677 const Operand& rt, 3678 BranchDelaySlot bd) { 3679 BlockTrampolinePoolScope block_trampoline_pool(this); 3680 Label start; 3681 bind(&start); 3682 int32_t target_int = reinterpret_cast<int32_t>(target); 3683 li(t9, Operand(target_int, rmode), CONSTANT_SIZE); 3684 Call(t9, cond, rs, rt, bd); 3685 DCHECK_EQ(CallSize(target, rmode, cond, rs, rt, bd), 3686 SizeOfCodeGeneratedSince(&start)); 3687 } 3688 3689 3690 int MacroAssembler::CallSize(Handle<Code> code, 3691 RelocInfo::Mode rmode, 3692 TypeFeedbackId ast_id, 3693 Condition cond, 3694 Register rs, 3695 const Operand& rt, 3696 BranchDelaySlot bd) { 3697 AllowDeferredHandleDereference using_raw_address; 3698 return CallSize(reinterpret_cast<Address>(code.location()), 3699 rmode, cond, rs, rt, bd); 3700 } 3701 3702 3703 void MacroAssembler::Call(Handle<Code> code, 3704 RelocInfo::Mode rmode, 3705 TypeFeedbackId ast_id, 3706 Condition cond, 3707 Register rs, 3708 const Operand& rt, 3709 BranchDelaySlot bd) { 3710 BlockTrampolinePoolScope block_trampoline_pool(this); 3711 Label start; 3712 bind(&start); 3713 DCHECK(RelocInfo::IsCodeTarget(rmode)); 3714 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) { 3715 SetRecordedAstId(ast_id); 3716 rmode = RelocInfo::CODE_TARGET_WITH_ID; 3717 } 3718 AllowDeferredHandleDereference embedding_raw_address; 3719 Call(reinterpret_cast<Address>(code.location()), rmode, cond, rs, rt, bd); 3720 DCHECK_EQ(CallSize(code, rmode, ast_id, cond, rs, rt, bd), 3721 SizeOfCodeGeneratedSince(&start)); 3722 } 3723 3724 3725 void MacroAssembler::Ret(Condition cond, 3726 Register rs, 3727 const Operand& rt, 3728 BranchDelaySlot bd) { 3729 Jump(ra, cond, rs, rt, bd); 3730 } 3731 3732 3733 void MacroAssembler::BranchLong(Label* L, BranchDelaySlot bdslot) { 3734 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT && 3735 (!L->is_bound() || is_near_r6(L))) { 3736 BranchShortHelperR6(0, L); 3737 } else { 3738 BlockTrampolinePoolScope block_trampoline_pool(this); 3739 uint32_t imm32; 3740 imm32 = jump_address(L); 3741 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { 3742 uint32_t lui_offset, jic_offset; 3743 UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset); 3744 { 3745 BlockGrowBufferScope block_buf_growth(this); 3746 // Buffer growth (and relocation) must be blocked for internal 3747 // references until associated instructions are emitted and 3748 // available to be patched. 3749 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); 3750 lui(at, lui_offset); 3751 jic(at, jic_offset); 3752 } 3753 CheckBuffer(); 3754 } else { 3755 { 3756 BlockGrowBufferScope block_buf_growth(this); 3757 // Buffer growth (and relocation) must be blocked for internal 3758 // references 3759 // until associated instructions are emitted and available to be 3760 // patched. 3761 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); 3762 lui(at, (imm32 & kHiMask) >> kLuiShift); 3763 ori(at, at, (imm32 & kImm16Mask)); 3764 } 3765 CheckBuffer(); 3766 jr(at); 3767 // Emit a nop in the branch delay slot if required. 3768 if (bdslot == PROTECT) nop(); 3769 } 3770 } 3771 } 3772 3773 3774 void MacroAssembler::BranchAndLinkLong(Label* L, BranchDelaySlot bdslot) { 3775 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT && 3776 (!L->is_bound() || is_near_r6(L))) { 3777 BranchAndLinkShortHelperR6(0, L); 3778 } else { 3779 BlockTrampolinePoolScope block_trampoline_pool(this); 3780 uint32_t imm32; 3781 imm32 = jump_address(L); 3782 if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { 3783 uint32_t lui_offset, jic_offset; 3784 UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset); 3785 { 3786 BlockGrowBufferScope block_buf_growth(this); 3787 // Buffer growth (and relocation) must be blocked for internal 3788 // references until associated instructions are emitted and 3789 // available to be patched. 3790 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); 3791 lui(at, lui_offset); 3792 jialc(at, jic_offset); 3793 } 3794 CheckBuffer(); 3795 } else { 3796 { 3797 BlockGrowBufferScope block_buf_growth(this); 3798 // Buffer growth (and relocation) must be blocked for internal 3799 // references 3800 // until associated instructions are emitted and available to be 3801 // patched. 3802 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); 3803 lui(at, (imm32 & kHiMask) >> kLuiShift); 3804 ori(at, at, (imm32 & kImm16Mask)); 3805 } 3806 CheckBuffer(); 3807 jalr(at); 3808 // Emit a nop in the branch delay slot if required. 3809 if (bdslot == PROTECT) nop(); 3810 } 3811 } 3812 } 3813 3814 3815 void MacroAssembler::DropAndRet(int drop) { 3816 DCHECK(is_int16(drop * kPointerSize)); 3817 Ret(USE_DELAY_SLOT); 3818 addiu(sp, sp, drop * kPointerSize); 3819 } 3820 3821 void MacroAssembler::DropAndRet(int drop, 3822 Condition cond, 3823 Register r1, 3824 const Operand& r2) { 3825 // Both Drop and Ret need to be conditional. 3826 Label skip; 3827 if (cond != cc_always) { 3828 Branch(&skip, NegateCondition(cond), r1, r2); 3829 } 3830 3831 Drop(drop); 3832 Ret(); 3833 3834 if (cond != cc_always) { 3835 bind(&skip); 3836 } 3837 } 3838 3839 3840 void MacroAssembler::Drop(int count, 3841 Condition cond, 3842 Register reg, 3843 const Operand& op) { 3844 if (count <= 0) { 3845 return; 3846 } 3847 3848 Label skip; 3849 3850 if (cond != al) { 3851 Branch(&skip, NegateCondition(cond), reg, op); 3852 } 3853 3854 Addu(sp, sp, Operand(count * kPointerSize)); 3855 3856 if (cond != al) { 3857 bind(&skip); 3858 } 3859 } 3860 3861 3862 3863 void MacroAssembler::Swap(Register reg1, 3864 Register reg2, 3865 Register scratch) { 3866 if (scratch.is(no_reg)) { 3867 Xor(reg1, reg1, Operand(reg2)); 3868 Xor(reg2, reg2, Operand(reg1)); 3869 Xor(reg1, reg1, Operand(reg2)); 3870 } else { 3871 mov(scratch, reg1); 3872 mov(reg1, reg2); 3873 mov(reg2, scratch); 3874 } 3875 } 3876 3877 3878 void MacroAssembler::Call(Label* target) { 3879 BranchAndLink(target); 3880 } 3881 3882 3883 void MacroAssembler::Push(Handle<Object> handle) { 3884 li(at, Operand(handle)); 3885 push(at); 3886 } 3887 3888 void MacroAssembler::MaybeDropFrames() { 3889 // Check whether we need to drop frames to restart a function on the stack. 3890 ExternalReference restart_fp = 3891 ExternalReference::debug_restart_fp_address(isolate()); 3892 li(a1, Operand(restart_fp)); 3893 lw(a1, MemOperand(a1)); 3894 Jump(isolate()->builtins()->FrameDropperTrampoline(), RelocInfo::CODE_TARGET, 3895 ne, a1, Operand(zero_reg)); 3896 } 3897 3898 // --------------------------------------------------------------------------- 3899 // Exception handling. 3900 3901 void MacroAssembler::PushStackHandler() { 3902 // Adjust this code if not the case. 3903 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); 3904 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); 3905 3906 // Link the current handler as the next handler. 3907 li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); 3908 lw(t1, MemOperand(t2)); 3909 push(t1); 3910 3911 // Set this new handler as the current one. 3912 sw(sp, MemOperand(t2)); 3913 } 3914 3915 3916 void MacroAssembler::PopStackHandler() { 3917 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 3918 pop(a1); 3919 Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); 3920 li(at, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); 3921 sw(a1, MemOperand(at)); 3922 } 3923 3924 3925 void MacroAssembler::Allocate(int object_size, 3926 Register result, 3927 Register scratch1, 3928 Register scratch2, 3929 Label* gc_required, 3930 AllocationFlags flags) { 3931 DCHECK(object_size <= kMaxRegularHeapObjectSize); 3932 DCHECK((flags & ALLOCATION_FOLDED) == 0); 3933 if (!FLAG_inline_new) { 3934 if (emit_debug_code()) { 3935 // Trash the registers to simulate an allocation failure. 3936 li(result, 0x7091); 3937 li(scratch1, 0x7191); 3938 li(scratch2, 0x7291); 3939 } 3940 jmp(gc_required); 3941 return; 3942 } 3943 3944 DCHECK(!AreAliased(result, scratch1, scratch2, t9, at)); 3945 3946 // Make object size into bytes. 3947 if ((flags & SIZE_IN_WORDS) != 0) { 3948 object_size *= kPointerSize; 3949 } 3950 DCHECK_EQ(0, object_size & kObjectAlignmentMask); 3951 3952 // Check relative positions of allocation top and limit addresses. 3953 // ARM adds additional checks to make sure the ldm instruction can be 3954 // used. On MIPS we don't have ldm so we don't need additional checks either. 3955 ExternalReference allocation_top = 3956 AllocationUtils::GetAllocationTopReference(isolate(), flags); 3957 ExternalReference allocation_limit = 3958 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 3959 3960 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address()); 3961 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address()); 3962 DCHECK((limit - top) == kPointerSize); 3963 3964 // Set up allocation top address and allocation limit registers. 3965 Register top_address = scratch1; 3966 // This code stores a temporary value in t9. 3967 Register alloc_limit = t9; 3968 Register result_end = scratch2; 3969 li(top_address, Operand(allocation_top)); 3970 3971 if ((flags & RESULT_CONTAINS_TOP) == 0) { 3972 // Load allocation top into result and allocation limit into alloc_limit. 3973 lw(result, MemOperand(top_address)); 3974 lw(alloc_limit, MemOperand(top_address, kPointerSize)); 3975 } else { 3976 if (emit_debug_code()) { 3977 // Assert that result actually contains top on entry. 3978 lw(alloc_limit, MemOperand(top_address)); 3979 Check(eq, kUnexpectedAllocationTop, result, Operand(alloc_limit)); 3980 } 3981 // Load allocation limit. Result already contains allocation top. 3982 lw(alloc_limit, MemOperand(top_address, limit - top)); 3983 } 3984 3985 if ((flags & DOUBLE_ALIGNMENT) != 0) { 3986 // Align the next allocation. Storing the filler map without checking top is 3987 // safe in new-space because the limit of the heap is aligned there. 3988 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 3989 And(result_end, result, Operand(kDoubleAlignmentMask)); 3990 Label aligned; 3991 Branch(&aligned, eq, result_end, Operand(zero_reg)); 3992 if ((flags & PRETENURE) != 0) { 3993 Branch(gc_required, Ugreater_equal, result, Operand(alloc_limit)); 3994 } 3995 li(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); 3996 sw(result_end, MemOperand(result)); 3997 Addu(result, result, Operand(kDoubleSize / 2)); 3998 bind(&aligned); 3999 } 4000 4001 // Calculate new top and bail out if new space is exhausted. Use result 4002 // to calculate the new top. 4003 Addu(result_end, result, Operand(object_size)); 4004 Branch(gc_required, Ugreater, result_end, Operand(alloc_limit)); 4005 4006 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) { 4007 // The top pointer is not updated for allocation folding dominators. 4008 sw(result_end, MemOperand(top_address)); 4009 } 4010 4011 // Tag object. 4012 Addu(result, result, Operand(kHeapObjectTag)); 4013 } 4014 4015 4016 void MacroAssembler::Allocate(Register object_size, Register result, 4017 Register result_end, Register scratch, 4018 Label* gc_required, AllocationFlags flags) { 4019 DCHECK((flags & ALLOCATION_FOLDED) == 0); 4020 if (!FLAG_inline_new) { 4021 if (emit_debug_code()) { 4022 // Trash the registers to simulate an allocation failure. 4023 li(result, 0x7091); 4024 li(scratch, 0x7191); 4025 li(result_end, 0x7291); 4026 } 4027 jmp(gc_required); 4028 return; 4029 } 4030 4031 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag 4032 // is not specified. Other registers must not overlap. 4033 DCHECK(!AreAliased(object_size, result, scratch, t9, at)); 4034 DCHECK(!AreAliased(result_end, result, scratch, t9, at)); 4035 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end)); 4036 4037 // Check relative positions of allocation top and limit addresses. 4038 // ARM adds additional checks to make sure the ldm instruction can be 4039 // used. On MIPS we don't have ldm so we don't need additional checks either. 4040 ExternalReference allocation_top = 4041 AllocationUtils::GetAllocationTopReference(isolate(), flags); 4042 ExternalReference allocation_limit = 4043 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 4044 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address()); 4045 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address()); 4046 DCHECK((limit - top) == kPointerSize); 4047 4048 // Set up allocation top address and allocation limit registers. 4049 Register top_address = scratch; 4050 // This code stores a temporary value in t9. 4051 Register alloc_limit = t9; 4052 li(top_address, Operand(allocation_top)); 4053 4054 if ((flags & RESULT_CONTAINS_TOP) == 0) { 4055 // Load allocation top into result and allocation limit into alloc_limit. 4056 lw(result, MemOperand(top_address)); 4057 lw(alloc_limit, MemOperand(top_address, kPointerSize)); 4058 } else { 4059 if (emit_debug_code()) { 4060 // Assert that result actually contains top on entry. 4061 lw(alloc_limit, MemOperand(top_address)); 4062 Check(eq, kUnexpectedAllocationTop, result, Operand(alloc_limit)); 4063 } 4064 // Load allocation limit. Result already contains allocation top. 4065 lw(alloc_limit, MemOperand(top_address, limit - top)); 4066 } 4067 4068 if ((flags & DOUBLE_ALIGNMENT) != 0) { 4069 // Align the next allocation. Storing the filler map without checking top is 4070 // safe in new-space because the limit of the heap is aligned there. 4071 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 4072 And(result_end, result, Operand(kDoubleAlignmentMask)); 4073 Label aligned; 4074 Branch(&aligned, eq, result_end, Operand(zero_reg)); 4075 if ((flags & PRETENURE) != 0) { 4076 Branch(gc_required, Ugreater_equal, result, Operand(alloc_limit)); 4077 } 4078 li(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); 4079 sw(result_end, MemOperand(result)); 4080 Addu(result, result, Operand(kDoubleSize / 2)); 4081 bind(&aligned); 4082 } 4083 4084 // Calculate new top and bail out if new space is exhausted. Use result 4085 // to calculate the new top. Object size may be in words so a shift is 4086 // required to get the number of bytes. 4087 if ((flags & SIZE_IN_WORDS) != 0) { 4088 Lsa(result_end, result, object_size, kPointerSizeLog2); 4089 } else { 4090 Addu(result_end, result, Operand(object_size)); 4091 } 4092 4093 Branch(gc_required, Ugreater, result_end, Operand(alloc_limit)); 4094 4095 // Update allocation top. result temporarily holds the new top. 4096 if (emit_debug_code()) { 4097 And(alloc_limit, result_end, Operand(kObjectAlignmentMask)); 4098 Check(eq, kUnalignedAllocationInNewSpace, alloc_limit, Operand(zero_reg)); 4099 } 4100 4101 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) { 4102 // The top pointer is not updated for allocation folding dominators. 4103 sw(result_end, MemOperand(top_address)); 4104 } 4105 4106 // Tag object. 4107 Addu(result, result, Operand(kHeapObjectTag)); 4108 } 4109 4110 void MacroAssembler::FastAllocate(int object_size, Register result, 4111 Register scratch1, Register scratch2, 4112 AllocationFlags flags) { 4113 DCHECK(object_size <= kMaxRegularHeapObjectSize); 4114 DCHECK(!AreAliased(result, scratch1, scratch2, t9, at)); 4115 4116 // Make object size into bytes. 4117 if ((flags & SIZE_IN_WORDS) != 0) { 4118 object_size *= kPointerSize; 4119 } 4120 DCHECK_EQ(0, object_size & kObjectAlignmentMask); 4121 4122 ExternalReference allocation_top = 4123 AllocationUtils::GetAllocationTopReference(isolate(), flags); 4124 4125 // Set up allocation top address and allocation limit registers. 4126 Register top_address = scratch1; 4127 // This code stores a temporary value in t9. 4128 Register result_end = scratch2; 4129 li(top_address, Operand(allocation_top)); 4130 lw(result, MemOperand(top_address)); 4131 4132 if ((flags & DOUBLE_ALIGNMENT) != 0) { 4133 // Align the next allocation. Storing the filler map without checking top is 4134 // safe in new-space because the limit of the heap is aligned there. 4135 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 4136 And(result_end, result, Operand(kDoubleAlignmentMask)); 4137 Label aligned; 4138 Branch(&aligned, eq, result_end, Operand(zero_reg)); 4139 li(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); 4140 sw(result_end, MemOperand(result)); 4141 Addu(result, result, Operand(kDoubleSize / 2)); 4142 bind(&aligned); 4143 } 4144 4145 Addu(result_end, result, Operand(object_size)); 4146 4147 // The top pointer is not updated for allocation folding dominators. 4148 sw(result_end, MemOperand(top_address)); 4149 4150 Addu(result, result, Operand(kHeapObjectTag)); 4151 } 4152 4153 void MacroAssembler::FastAllocate(Register object_size, Register result, 4154 Register result_end, Register scratch, 4155 AllocationFlags flags) { 4156 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag 4157 // is not specified. Other registers must not overlap. 4158 DCHECK(!AreAliased(object_size, result, scratch, t9, at)); 4159 DCHECK(!AreAliased(result_end, result, scratch, t9, at)); 4160 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end)); 4161 4162 ExternalReference allocation_top = 4163 AllocationUtils::GetAllocationTopReference(isolate(), flags); 4164 4165 // Set up allocation top address and allocation limit registers. 4166 Register top_address = scratch; 4167 // This code stores a temporary value in t9. 4168 li(top_address, Operand(allocation_top)); 4169 lw(result, MemOperand(top_address)); 4170 4171 if ((flags & DOUBLE_ALIGNMENT) != 0) { 4172 // Align the next allocation. Storing the filler map without checking top is 4173 // safe in new-space because the limit of the heap is aligned there. 4174 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 4175 And(result_end, result, Operand(kDoubleAlignmentMask)); 4176 Label aligned; 4177 Branch(&aligned, eq, result_end, Operand(zero_reg)); 4178 li(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); 4179 sw(result_end, MemOperand(result)); 4180 Addu(result, result, Operand(kDoubleSize / 2)); 4181 bind(&aligned); 4182 } 4183 4184 // Calculate new top and bail out if new space is exhausted. Use result 4185 // to calculate the new top. Object size may be in words so a shift is 4186 // required to get the number of bytes. 4187 if ((flags & SIZE_IN_WORDS) != 0) { 4188 Lsa(result_end, result, object_size, kPointerSizeLog2); 4189 } else { 4190 Addu(result_end, result, Operand(object_size)); 4191 } 4192 4193 // The top pointer is not updated for allocation folding dominators. 4194 sw(result_end, MemOperand(top_address)); 4195 4196 Addu(result, result, Operand(kHeapObjectTag)); 4197 } 4198 4199 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg, 4200 Label* not_unique_name) { 4201 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); 4202 Label succeed; 4203 And(at, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask)); 4204 Branch(&succeed, eq, at, Operand(zero_reg)); 4205 Branch(not_unique_name, ne, reg, Operand(SYMBOL_TYPE)); 4206 4207 bind(&succeed); 4208 } 4209 4210 4211 // Allocates a heap number or jumps to the label if the young space is full and 4212 // a scavenge is needed. 4213 void MacroAssembler::AllocateHeapNumber(Register result, 4214 Register scratch1, 4215 Register scratch2, 4216 Register heap_number_map, 4217 Label* need_gc, 4218 MutableMode mode) { 4219 // Allocate an object in the heap for the heap number and tag it as a heap 4220 // object. 4221 Allocate(HeapNumber::kSize, result, scratch1, scratch2, need_gc, 4222 NO_ALLOCATION_FLAGS); 4223 4224 Heap::RootListIndex map_index = mode == MUTABLE 4225 ? Heap::kMutableHeapNumberMapRootIndex 4226 : Heap::kHeapNumberMapRootIndex; 4227 AssertIsRoot(heap_number_map, map_index); 4228 4229 // Store heap number map in the allocated object. 4230 sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset)); 4231 } 4232 4233 4234 void MacroAssembler::AllocateHeapNumberWithValue(Register result, 4235 FPURegister value, 4236 Register scratch1, 4237 Register scratch2, 4238 Label* gc_required) { 4239 LoadRoot(t8, Heap::kHeapNumberMapRootIndex); 4240 AllocateHeapNumber(result, scratch1, scratch2, t8, gc_required); 4241 sdc1(value, FieldMemOperand(result, HeapNumber::kValueOffset)); 4242 } 4243 4244 4245 void MacroAssembler::AllocateJSValue(Register result, Register constructor, 4246 Register value, Register scratch1, 4247 Register scratch2, Label* gc_required) { 4248 DCHECK(!result.is(constructor)); 4249 DCHECK(!result.is(scratch1)); 4250 DCHECK(!result.is(scratch2)); 4251 DCHECK(!result.is(value)); 4252 4253 // Allocate JSValue in new space. 4254 Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, 4255 NO_ALLOCATION_FLAGS); 4256 4257 // Initialize the JSValue. 4258 LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2); 4259 sw(scratch1, FieldMemOperand(result, HeapObject::kMapOffset)); 4260 LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex); 4261 sw(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset)); 4262 sw(scratch1, FieldMemOperand(result, JSObject::kElementsOffset)); 4263 sw(value, FieldMemOperand(result, JSValue::kValueOffset)); 4264 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); 4265 } 4266 4267 void MacroAssembler::InitializeFieldsWithFiller(Register current_address, 4268 Register end_address, 4269 Register filler) { 4270 Label loop, entry; 4271 Branch(&entry); 4272 bind(&loop); 4273 sw(filler, MemOperand(current_address)); 4274 Addu(current_address, current_address, kPointerSize); 4275 bind(&entry); 4276 Branch(&loop, ult, current_address, Operand(end_address)); 4277 } 4278 4279 void MacroAssembler::CompareMapAndBranch(Register obj, 4280 Register scratch, 4281 Handle<Map> map, 4282 Label* early_success, 4283 Condition cond, 4284 Label* branch_to) { 4285 lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); 4286 CompareMapAndBranch(scratch, map, early_success, cond, branch_to); 4287 } 4288 4289 4290 void MacroAssembler::CompareMapAndBranch(Register obj_map, 4291 Handle<Map> map, 4292 Label* early_success, 4293 Condition cond, 4294 Label* branch_to) { 4295 Branch(branch_to, cond, obj_map, Operand(map)); 4296 } 4297 4298 4299 void MacroAssembler::CheckMap(Register obj, 4300 Register scratch, 4301 Handle<Map> map, 4302 Label* fail, 4303 SmiCheckType smi_check_type) { 4304 if (smi_check_type == DO_SMI_CHECK) { 4305 JumpIfSmi(obj, fail); 4306 } 4307 Label success; 4308 CompareMapAndBranch(obj, scratch, map, &success, ne, fail); 4309 bind(&success); 4310 } 4311 4312 4313 void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1, 4314 Register scratch2, Handle<WeakCell> cell, 4315 Handle<Code> success, 4316 SmiCheckType smi_check_type) { 4317 Label fail; 4318 if (smi_check_type == DO_SMI_CHECK) { 4319 JumpIfSmi(obj, &fail); 4320 } 4321 lw(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset)); 4322 GetWeakValue(scratch2, cell); 4323 Jump(success, RelocInfo::CODE_TARGET, eq, scratch1, Operand(scratch2)); 4324 bind(&fail); 4325 } 4326 4327 4328 void MacroAssembler::CheckMap(Register obj, 4329 Register scratch, 4330 Heap::RootListIndex index, 4331 Label* fail, 4332 SmiCheckType smi_check_type) { 4333 if (smi_check_type == DO_SMI_CHECK) { 4334 JumpIfSmi(obj, fail); 4335 } 4336 lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); 4337 LoadRoot(at, index); 4338 Branch(fail, ne, scratch, Operand(at)); 4339 } 4340 4341 void MacroAssembler::FPUCanonicalizeNaN(const DoubleRegister dst, 4342 const DoubleRegister src) { 4343 sub_d(dst, src, kDoubleRegZero); 4344 } 4345 4346 void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) { 4347 li(value, Operand(cell)); 4348 lw(value, FieldMemOperand(value, WeakCell::kValueOffset)); 4349 } 4350 4351 4352 void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell, 4353 Label* miss) { 4354 GetWeakValue(value, cell); 4355 JumpIfSmi(value, miss); 4356 } 4357 4358 4359 void MacroAssembler::MovFromFloatResult(DoubleRegister dst) { 4360 if (IsMipsSoftFloatABI) { 4361 if (kArchEndian == kLittle) { 4362 Move(dst, v0, v1); 4363 } else { 4364 Move(dst, v1, v0); 4365 } 4366 } else { 4367 Move(dst, f0); // Reg f0 is o32 ABI FP return value. 4368 } 4369 } 4370 4371 4372 void MacroAssembler::MovFromFloatParameter(DoubleRegister dst) { 4373 if (IsMipsSoftFloatABI) { 4374 if (kArchEndian == kLittle) { 4375 Move(dst, a0, a1); 4376 } else { 4377 Move(dst, a1, a0); 4378 } 4379 } else { 4380 Move(dst, f12); // Reg f12 is o32 ABI FP first argument value. 4381 } 4382 } 4383 4384 4385 void MacroAssembler::MovToFloatParameter(DoubleRegister src) { 4386 if (!IsMipsSoftFloatABI) { 4387 Move(f12, src); 4388 } else { 4389 if (kArchEndian == kLittle) { 4390 Move(a0, a1, src); 4391 } else { 4392 Move(a1, a0, src); 4393 } 4394 } 4395 } 4396 4397 4398 void MacroAssembler::MovToFloatResult(DoubleRegister src) { 4399 if (!IsMipsSoftFloatABI) { 4400 Move(f0, src); 4401 } else { 4402 if (kArchEndian == kLittle) { 4403 Move(v0, v1, src); 4404 } else { 4405 Move(v1, v0, src); 4406 } 4407 } 4408 } 4409 4410 4411 void MacroAssembler::MovToFloatParameters(DoubleRegister src1, 4412 DoubleRegister src2) { 4413 if (!IsMipsSoftFloatABI) { 4414 if (src2.is(f12)) { 4415 DCHECK(!src1.is(f14)); 4416 Move(f14, src2); 4417 Move(f12, src1); 4418 } else { 4419 Move(f12, src1); 4420 Move(f14, src2); 4421 } 4422 } else { 4423 if (kArchEndian == kLittle) { 4424 Move(a0, a1, src1); 4425 Move(a2, a3, src2); 4426 } else { 4427 Move(a1, a0, src1); 4428 Move(a3, a2, src2); 4429 } 4430 } 4431 } 4432 4433 4434 // ----------------------------------------------------------------------------- 4435 // JavaScript invokes. 4436 4437 void MacroAssembler::PrepareForTailCall(const ParameterCount& callee_args_count, 4438 Register caller_args_count_reg, 4439 Register scratch0, Register scratch1) { 4440 #if DEBUG 4441 if (callee_args_count.is_reg()) { 4442 DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0, 4443 scratch1)); 4444 } else { 4445 DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1)); 4446 } 4447 #endif 4448 4449 // Calculate the end of destination area where we will put the arguments 4450 // after we drop current frame. We add kPointerSize to count the receiver 4451 // argument which is not included into formal parameters count. 4452 Register dst_reg = scratch0; 4453 Lsa(dst_reg, fp, caller_args_count_reg, kPointerSizeLog2); 4454 Addu(dst_reg, dst_reg, 4455 Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize)); 4456 4457 Register src_reg = caller_args_count_reg; 4458 // Calculate the end of source area. +kPointerSize is for the receiver. 4459 if (callee_args_count.is_reg()) { 4460 Lsa(src_reg, sp, callee_args_count.reg(), kPointerSizeLog2); 4461 Addu(src_reg, src_reg, Operand(kPointerSize)); 4462 } else { 4463 Addu(src_reg, sp, 4464 Operand((callee_args_count.immediate() + 1) * kPointerSize)); 4465 } 4466 4467 if (FLAG_debug_code) { 4468 Check(lo, kStackAccessBelowStackPointer, src_reg, Operand(dst_reg)); 4469 } 4470 4471 // Restore caller's frame pointer and return address now as they will be 4472 // overwritten by the copying loop. 4473 lw(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); 4474 lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 4475 4476 // Now copy callee arguments to the caller frame going backwards to avoid 4477 // callee arguments corruption (source and destination areas could overlap). 4478 4479 // Both src_reg and dst_reg are pointing to the word after the one to copy, 4480 // so they must be pre-decremented in the loop. 4481 Register tmp_reg = scratch1; 4482 Label loop, entry; 4483 Branch(&entry); 4484 bind(&loop); 4485 Subu(src_reg, src_reg, Operand(kPointerSize)); 4486 Subu(dst_reg, dst_reg, Operand(kPointerSize)); 4487 lw(tmp_reg, MemOperand(src_reg)); 4488 sw(tmp_reg, MemOperand(dst_reg)); 4489 bind(&entry); 4490 Branch(&loop, ne, sp, Operand(src_reg)); 4491 4492 // Leave current frame. 4493 mov(sp, dst_reg); 4494 } 4495 4496 void MacroAssembler::InvokePrologue(const ParameterCount& expected, 4497 const ParameterCount& actual, 4498 Label* done, 4499 bool* definitely_mismatches, 4500 InvokeFlag flag, 4501 const CallWrapper& call_wrapper) { 4502 bool definitely_matches = false; 4503 *definitely_mismatches = false; 4504 Label regular_invoke; 4505 4506 // Check whether the expected and actual arguments count match. If not, 4507 // setup registers according to contract with ArgumentsAdaptorTrampoline: 4508 // a0: actual arguments count 4509 // a1: function (passed through to callee) 4510 // a2: expected arguments count 4511 4512 // The code below is made a lot easier because the calling code already sets 4513 // up actual and expected registers according to the contract if values are 4514 // passed in registers. 4515 DCHECK(actual.is_immediate() || actual.reg().is(a0)); 4516 DCHECK(expected.is_immediate() || expected.reg().is(a2)); 4517 4518 if (expected.is_immediate()) { 4519 DCHECK(actual.is_immediate()); 4520 li(a0, Operand(actual.immediate())); 4521 if (expected.immediate() == actual.immediate()) { 4522 definitely_matches = true; 4523 } else { 4524 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel; 4525 if (expected.immediate() == sentinel) { 4526 // Don't worry about adapting arguments for builtins that 4527 // don't want that done. Skip adaption code by making it look 4528 // like we have a match between expected and actual number of 4529 // arguments. 4530 definitely_matches = true; 4531 } else { 4532 *definitely_mismatches = true; 4533 li(a2, Operand(expected.immediate())); 4534 } 4535 } 4536 } else if (actual.is_immediate()) { 4537 li(a0, Operand(actual.immediate())); 4538 Branch(®ular_invoke, eq, expected.reg(), Operand(a0)); 4539 } else { 4540 Branch(®ular_invoke, eq, expected.reg(), Operand(actual.reg())); 4541 } 4542 4543 if (!definitely_matches) { 4544 Handle<Code> adaptor = 4545 isolate()->builtins()->ArgumentsAdaptorTrampoline(); 4546 if (flag == CALL_FUNCTION) { 4547 call_wrapper.BeforeCall(CallSize(adaptor)); 4548 Call(adaptor); 4549 call_wrapper.AfterCall(); 4550 if (!*definitely_mismatches) { 4551 Branch(done); 4552 } 4553 } else { 4554 Jump(adaptor, RelocInfo::CODE_TARGET); 4555 } 4556 bind(®ular_invoke); 4557 } 4558 } 4559 4560 void MacroAssembler::CheckDebugHook(Register fun, Register new_target, 4561 const ParameterCount& expected, 4562 const ParameterCount& actual) { 4563 Label skip_hook; 4564 ExternalReference debug_hook_active = 4565 ExternalReference::debug_hook_on_function_call_address(isolate()); 4566 li(t0, Operand(debug_hook_active)); 4567 lb(t0, MemOperand(t0)); 4568 Branch(&skip_hook, eq, t0, Operand(zero_reg)); 4569 { 4570 FrameScope frame(this, 4571 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); 4572 if (expected.is_reg()) { 4573 SmiTag(expected.reg()); 4574 Push(expected.reg()); 4575 } 4576 if (actual.is_reg()) { 4577 SmiTag(actual.reg()); 4578 Push(actual.reg()); 4579 } 4580 if (new_target.is_valid()) { 4581 Push(new_target); 4582 } 4583 Push(fun); 4584 Push(fun); 4585 CallRuntime(Runtime::kDebugOnFunctionCall); 4586 Pop(fun); 4587 if (new_target.is_valid()) { 4588 Pop(new_target); 4589 } 4590 if (actual.is_reg()) { 4591 Pop(actual.reg()); 4592 SmiUntag(actual.reg()); 4593 } 4594 if (expected.is_reg()) { 4595 Pop(expected.reg()); 4596 SmiUntag(expected.reg()); 4597 } 4598 } 4599 bind(&skip_hook); 4600 } 4601 4602 4603 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, 4604 const ParameterCount& expected, 4605 const ParameterCount& actual, 4606 InvokeFlag flag, 4607 const CallWrapper& call_wrapper) { 4608 // You can't call a function without a valid frame. 4609 DCHECK(flag == JUMP_FUNCTION || has_frame()); 4610 DCHECK(function.is(a1)); 4611 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(a3)); 4612 4613 if (call_wrapper.NeedsDebugHookCheck()) { 4614 CheckDebugHook(function, new_target, expected, actual); 4615 } 4616 4617 // Clear the new.target register if not given. 4618 if (!new_target.is_valid()) { 4619 LoadRoot(a3, Heap::kUndefinedValueRootIndex); 4620 } 4621 4622 Label done; 4623 bool definitely_mismatches = false; 4624 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag, 4625 call_wrapper); 4626 if (!definitely_mismatches) { 4627 // We call indirectly through the code field in the function to 4628 // allow recompilation to take effect without changing any of the 4629 // call sites. 4630 Register code = t0; 4631 lw(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); 4632 if (flag == CALL_FUNCTION) { 4633 call_wrapper.BeforeCall(CallSize(code)); 4634 Call(code); 4635 call_wrapper.AfterCall(); 4636 } else { 4637 DCHECK(flag == JUMP_FUNCTION); 4638 Jump(code); 4639 } 4640 // Continue here if InvokePrologue does handle the invocation due to 4641 // mismatched parameter counts. 4642 bind(&done); 4643 } 4644 } 4645 4646 4647 void MacroAssembler::InvokeFunction(Register function, 4648 Register new_target, 4649 const ParameterCount& actual, 4650 InvokeFlag flag, 4651 const CallWrapper& call_wrapper) { 4652 // You can't call a function without a valid frame. 4653 DCHECK(flag == JUMP_FUNCTION || has_frame()); 4654 4655 // Contract with called JS functions requires that function is passed in a1. 4656 DCHECK(function.is(a1)); 4657 Register expected_reg = a2; 4658 Register temp_reg = t0; 4659 4660 lw(temp_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); 4661 lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); 4662 lw(expected_reg, 4663 FieldMemOperand(temp_reg, 4664 SharedFunctionInfo::kFormalParameterCountOffset)); 4665 sra(expected_reg, expected_reg, kSmiTagSize); 4666 4667 ParameterCount expected(expected_reg); 4668 InvokeFunctionCode(function, new_target, expected, actual, flag, 4669 call_wrapper); 4670 } 4671 4672 4673 void MacroAssembler::InvokeFunction(Register function, 4674 const ParameterCount& expected, 4675 const ParameterCount& actual, 4676 InvokeFlag flag, 4677 const CallWrapper& call_wrapper) { 4678 // You can't call a function without a valid frame. 4679 DCHECK(flag == JUMP_FUNCTION || has_frame()); 4680 4681 // Contract with called JS functions requires that function is passed in a1. 4682 DCHECK(function.is(a1)); 4683 4684 // Get the function and setup the context. 4685 lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); 4686 4687 InvokeFunctionCode(a1, no_reg, expected, actual, flag, call_wrapper); 4688 } 4689 4690 4691 void MacroAssembler::InvokeFunction(Handle<JSFunction> function, 4692 const ParameterCount& expected, 4693 const ParameterCount& actual, 4694 InvokeFlag flag, 4695 const CallWrapper& call_wrapper) { 4696 li(a1, function); 4697 InvokeFunction(a1, expected, actual, flag, call_wrapper); 4698 } 4699 4700 4701 void MacroAssembler::IsObjectJSStringType(Register object, 4702 Register scratch, 4703 Label* fail) { 4704 DCHECK(kNotStringTag != 0); 4705 4706 lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 4707 lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); 4708 And(scratch, scratch, Operand(kIsNotStringMask)); 4709 Branch(fail, ne, scratch, Operand(zero_reg)); 4710 } 4711 4712 4713 void MacroAssembler::IsObjectNameType(Register object, 4714 Register scratch, 4715 Label* fail) { 4716 lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 4717 lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); 4718 Branch(fail, hi, scratch, Operand(LAST_NAME_TYPE)); 4719 } 4720 4721 4722 // --------------------------------------------------------------------------- 4723 // Support functions. 4724 4725 4726 void MacroAssembler::GetMapConstructor(Register result, Register map, 4727 Register temp, Register temp2) { 4728 Label done, loop; 4729 lw(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); 4730 bind(&loop); 4731 JumpIfSmi(result, &done); 4732 GetObjectType(result, temp, temp2); 4733 Branch(&done, ne, temp2, Operand(MAP_TYPE)); 4734 lw(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); 4735 Branch(&loop); 4736 bind(&done); 4737 } 4738 4739 void MacroAssembler::GetObjectType(Register object, 4740 Register map, 4741 Register type_reg) { 4742 lw(map, FieldMemOperand(object, HeapObject::kMapOffset)); 4743 lbu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); 4744 } 4745 4746 4747 // ----------------------------------------------------------------------------- 4748 // Runtime calls. 4749 4750 void MacroAssembler::CallStub(CodeStub* stub, 4751 TypeFeedbackId ast_id, 4752 Condition cond, 4753 Register r1, 4754 const Operand& r2, 4755 BranchDelaySlot bd) { 4756 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. 4757 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, 4758 cond, r1, r2, bd); 4759 } 4760 4761 4762 void MacroAssembler::TailCallStub(CodeStub* stub, 4763 Condition cond, 4764 Register r1, 4765 const Operand& r2, 4766 BranchDelaySlot bd) { 4767 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond, r1, r2, bd); 4768 } 4769 4770 4771 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { 4772 return has_frame_ || !stub->SometimesSetsUpAFrame(); 4773 } 4774 4775 void MacroAssembler::ObjectToDoubleFPURegister(Register object, 4776 FPURegister result, 4777 Register scratch1, 4778 Register scratch2, 4779 Register heap_number_map, 4780 Label* not_number, 4781 ObjectToDoubleFlags flags) { 4782 Label done; 4783 if ((flags & OBJECT_NOT_SMI) == 0) { 4784 Label not_smi; 4785 JumpIfNotSmi(object, ¬_smi); 4786 // Remove smi tag and convert to double. 4787 sra(scratch1, object, kSmiTagSize); 4788 mtc1(scratch1, result); 4789 cvt_d_w(result, result); 4790 Branch(&done); 4791 bind(¬_smi); 4792 } 4793 // Check for heap number and load double value from it. 4794 lw(scratch1, FieldMemOperand(object, HeapObject::kMapOffset)); 4795 Branch(not_number, ne, scratch1, Operand(heap_number_map)); 4796 4797 if ((flags & AVOID_NANS_AND_INFINITIES) != 0) { 4798 // If exponent is all ones the number is either a NaN or +/-Infinity. 4799 Register exponent = scratch1; 4800 Register mask_reg = scratch2; 4801 lw(exponent, FieldMemOperand(object, HeapNumber::kExponentOffset)); 4802 li(mask_reg, HeapNumber::kExponentMask); 4803 4804 And(exponent, exponent, mask_reg); 4805 Branch(not_number, eq, exponent, Operand(mask_reg)); 4806 } 4807 ldc1(result, FieldMemOperand(object, HeapNumber::kValueOffset)); 4808 bind(&done); 4809 } 4810 4811 4812 void MacroAssembler::SmiToDoubleFPURegister(Register smi, 4813 FPURegister value, 4814 Register scratch1) { 4815 sra(scratch1, smi, kSmiTagSize); 4816 mtc1(scratch1, value); 4817 cvt_d_w(value, value); 4818 } 4819 4820 4821 static inline void BranchOvfHelper(MacroAssembler* masm, Register overflow_dst, 4822 Label* overflow_label, 4823 Label* no_overflow_label) { 4824 DCHECK(overflow_label || no_overflow_label); 4825 if (!overflow_label) { 4826 DCHECK(no_overflow_label); 4827 masm->Branch(no_overflow_label, ge, overflow_dst, Operand(zero_reg)); 4828 } else { 4829 masm->Branch(overflow_label, lt, overflow_dst, Operand(zero_reg)); 4830 if (no_overflow_label) masm->Branch(no_overflow_label); 4831 } 4832 } 4833 4834 4835 void MacroAssembler::AddBranchOvf(Register dst, Register left, 4836 const Operand& right, Label* overflow_label, 4837 Label* no_overflow_label, Register scratch) { 4838 if (right.is_reg()) { 4839 AddBranchOvf(dst, left, right.rm(), overflow_label, no_overflow_label, 4840 scratch); 4841 } else { 4842 if (IsMipsArchVariant(kMips32r6)) { 4843 Register right_reg = t9; 4844 DCHECK(!left.is(right_reg)); 4845 li(right_reg, Operand(right)); 4846 AddBranchOvf(dst, left, right_reg, overflow_label, no_overflow_label); 4847 } else { 4848 Register overflow_dst = t9; 4849 DCHECK(!dst.is(scratch)); 4850 DCHECK(!dst.is(overflow_dst)); 4851 DCHECK(!scratch.is(overflow_dst)); 4852 DCHECK(!left.is(overflow_dst)); 4853 if (dst.is(left)) { 4854 mov(scratch, left); // Preserve left. 4855 Addu(dst, left, right.immediate()); // Left is overwritten. 4856 xor_(scratch, dst, scratch); // Original left. 4857 // Load right since xori takes uint16 as immediate. 4858 Addu(overflow_dst, zero_reg, right); 4859 xor_(overflow_dst, dst, overflow_dst); 4860 and_(overflow_dst, overflow_dst, scratch); 4861 } else { 4862 Addu(dst, left, right.immediate()); 4863 xor_(overflow_dst, dst, left); 4864 // Load right since xori takes uint16 as immediate. 4865 Addu(scratch, zero_reg, right); 4866 xor_(scratch, dst, scratch); 4867 and_(overflow_dst, scratch, overflow_dst); 4868 } 4869 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label); 4870 } 4871 } 4872 } 4873 4874 4875 void MacroAssembler::AddBranchOvf(Register dst, Register left, Register right, 4876 Label* overflow_label, 4877 Label* no_overflow_label, Register scratch) { 4878 if (IsMipsArchVariant(kMips32r6)) { 4879 if (!overflow_label) { 4880 DCHECK(no_overflow_label); 4881 DCHECK(!dst.is(scratch)); 4882 Register left_reg = left.is(dst) ? scratch : left; 4883 Register right_reg = right.is(dst) ? t9 : right; 4884 DCHECK(!dst.is(left_reg)); 4885 DCHECK(!dst.is(right_reg)); 4886 Move(left_reg, left); 4887 Move(right_reg, right); 4888 addu(dst, left, right); 4889 Bnvc(left_reg, right_reg, no_overflow_label); 4890 } else { 4891 Bovc(left, right, overflow_label); 4892 addu(dst, left, right); 4893 if (no_overflow_label) bc(no_overflow_label); 4894 } 4895 } else { 4896 Register overflow_dst = t9; 4897 DCHECK(!dst.is(scratch)); 4898 DCHECK(!dst.is(overflow_dst)); 4899 DCHECK(!scratch.is(overflow_dst)); 4900 DCHECK(!left.is(overflow_dst)); 4901 DCHECK(!right.is(overflow_dst)); 4902 DCHECK(!left.is(scratch)); 4903 DCHECK(!right.is(scratch)); 4904 4905 if (left.is(right) && dst.is(left)) { 4906 mov(overflow_dst, right); 4907 right = overflow_dst; 4908 } 4909 4910 if (dst.is(left)) { 4911 mov(scratch, left); // Preserve left. 4912 addu(dst, left, right); // Left is overwritten. 4913 xor_(scratch, dst, scratch); // Original left. 4914 xor_(overflow_dst, dst, right); 4915 and_(overflow_dst, overflow_dst, scratch); 4916 } else if (dst.is(right)) { 4917 mov(scratch, right); // Preserve right. 4918 addu(dst, left, right); // Right is overwritten. 4919 xor_(scratch, dst, scratch); // Original right. 4920 xor_(overflow_dst, dst, left); 4921 and_(overflow_dst, overflow_dst, scratch); 4922 } else { 4923 addu(dst, left, right); 4924 xor_(overflow_dst, dst, left); 4925 xor_(scratch, dst, right); 4926 and_(overflow_dst, scratch, overflow_dst); 4927 } 4928 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label); 4929 } 4930 } 4931 4932 4933 void MacroAssembler::SubBranchOvf(Register dst, Register left, 4934 const Operand& right, Label* overflow_label, 4935 Label* no_overflow_label, Register scratch) { 4936 DCHECK(overflow_label || no_overflow_label); 4937 if (right.is_reg()) { 4938 SubBranchOvf(dst, left, right.rm(), overflow_label, no_overflow_label, 4939 scratch); 4940 } else { 4941 Register overflow_dst = t9; 4942 DCHECK(!dst.is(scratch)); 4943 DCHECK(!dst.is(overflow_dst)); 4944 DCHECK(!scratch.is(overflow_dst)); 4945 DCHECK(!left.is(overflow_dst)); 4946 DCHECK(!left.is(scratch)); 4947 if (dst.is(left)) { 4948 mov(scratch, left); // Preserve left. 4949 Subu(dst, left, right.immediate()); // Left is overwritten. 4950 // Load right since xori takes uint16 as immediate. 4951 Addu(overflow_dst, zero_reg, right); 4952 xor_(overflow_dst, scratch, overflow_dst); // scratch is original left. 4953 xor_(scratch, dst, scratch); // scratch is original left. 4954 and_(overflow_dst, scratch, overflow_dst); 4955 } else { 4956 Subu(dst, left, right); 4957 xor_(overflow_dst, dst, left); 4958 // Load right since xori takes uint16 as immediate. 4959 Addu(scratch, zero_reg, right); 4960 xor_(scratch, left, scratch); 4961 and_(overflow_dst, scratch, overflow_dst); 4962 } 4963 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label); 4964 } 4965 } 4966 4967 4968 void MacroAssembler::SubBranchOvf(Register dst, Register left, Register right, 4969 Label* overflow_label, 4970 Label* no_overflow_label, Register scratch) { 4971 DCHECK(overflow_label || no_overflow_label); 4972 Register overflow_dst = t9; 4973 DCHECK(!dst.is(scratch)); 4974 DCHECK(!dst.is(overflow_dst)); 4975 DCHECK(!scratch.is(overflow_dst)); 4976 DCHECK(!overflow_dst.is(left)); 4977 DCHECK(!overflow_dst.is(right)); 4978 DCHECK(!scratch.is(left)); 4979 DCHECK(!scratch.is(right)); 4980 4981 // This happens with some crankshaft code. Since Subu works fine if 4982 // left == right, let's not make that restriction here. 4983 if (left.is(right)) { 4984 mov(dst, zero_reg); 4985 if (no_overflow_label) { 4986 Branch(no_overflow_label); 4987 } 4988 } 4989 4990 if (dst.is(left)) { 4991 mov(scratch, left); // Preserve left. 4992 subu(dst, left, right); // Left is overwritten. 4993 xor_(overflow_dst, dst, scratch); // scratch is original left. 4994 xor_(scratch, scratch, right); // scratch is original left. 4995 and_(overflow_dst, scratch, overflow_dst); 4996 } else if (dst.is(right)) { 4997 mov(scratch, right); // Preserve right. 4998 subu(dst, left, right); // Right is overwritten. 4999 xor_(overflow_dst, dst, left); 5000 xor_(scratch, left, scratch); // Original right. 5001 and_(overflow_dst, scratch, overflow_dst); 5002 } else { 5003 subu(dst, left, right); 5004 xor_(overflow_dst, dst, left); 5005 xor_(scratch, left, right); 5006 and_(overflow_dst, scratch, overflow_dst); 5007 } 5008 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label); 5009 } 5010 5011 static inline void BranchOvfHelperMult(MacroAssembler* masm, 5012 Register overflow_dst, 5013 Label* overflow_label, 5014 Label* no_overflow_label) { 5015 DCHECK(overflow_label || no_overflow_label); 5016 if (!overflow_label) { 5017 DCHECK(no_overflow_label); 5018 masm->Branch(no_overflow_label, eq, overflow_dst, Operand(zero_reg)); 5019 } else { 5020 masm->Branch(overflow_label, ne, overflow_dst, Operand(zero_reg)); 5021 if (no_overflow_label) masm->Branch(no_overflow_label); 5022 } 5023 } 5024 5025 void MacroAssembler::MulBranchOvf(Register dst, Register left, 5026 const Operand& right, Label* overflow_label, 5027 Label* no_overflow_label, Register scratch) { 5028 DCHECK(overflow_label || no_overflow_label); 5029 if (right.is_reg()) { 5030 MulBranchOvf(dst, left, right.rm(), overflow_label, no_overflow_label, 5031 scratch); 5032 } else { 5033 Register overflow_dst = t9; 5034 DCHECK(!dst.is(scratch)); 5035 DCHECK(!dst.is(overflow_dst)); 5036 DCHECK(!scratch.is(overflow_dst)); 5037 DCHECK(!left.is(overflow_dst)); 5038 DCHECK(!left.is(scratch)); 5039 5040 Mul(overflow_dst, dst, left, right.immediate()); 5041 sra(scratch, dst, 31); 5042 xor_(overflow_dst, overflow_dst, scratch); 5043 5044 BranchOvfHelperMult(this, overflow_dst, overflow_label, no_overflow_label); 5045 } 5046 } 5047 5048 void MacroAssembler::MulBranchOvf(Register dst, Register left, Register right, 5049 Label* overflow_label, 5050 Label* no_overflow_label, Register scratch) { 5051 DCHECK(overflow_label || no_overflow_label); 5052 Register overflow_dst = t9; 5053 DCHECK(!dst.is(scratch)); 5054 DCHECK(!dst.is(overflow_dst)); 5055 DCHECK(!scratch.is(overflow_dst)); 5056 DCHECK(!overflow_dst.is(left)); 5057 DCHECK(!overflow_dst.is(right)); 5058 DCHECK(!scratch.is(left)); 5059 DCHECK(!scratch.is(right)); 5060 5061 if (IsMipsArchVariant(kMips32r6) && dst.is(right)) { 5062 mov(scratch, right); 5063 Mul(overflow_dst, dst, left, scratch); 5064 sra(scratch, dst, 31); 5065 xor_(overflow_dst, overflow_dst, scratch); 5066 } else { 5067 Mul(overflow_dst, dst, left, right); 5068 sra(scratch, dst, 31); 5069 xor_(overflow_dst, overflow_dst, scratch); 5070 } 5071 5072 BranchOvfHelperMult(this, overflow_dst, overflow_label, no_overflow_label); 5073 } 5074 5075 void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments, 5076 SaveFPRegsMode save_doubles, 5077 BranchDelaySlot bd) { 5078 // All parameters are on the stack. v0 has the return value after call. 5079 5080 // If the expected number of arguments of the runtime function is 5081 // constant, we check that the actual number of arguments match the 5082 // expectation. 5083 CHECK(f->nargs < 0 || f->nargs == num_arguments); 5084 5085 // TODO(1236192): Most runtime routines don't need the number of 5086 // arguments passed in because it is constant. At some point we 5087 // should remove this need and make the runtime routine entry code 5088 // smarter. 5089 PrepareCEntryArgs(num_arguments); 5090 PrepareCEntryFunction(ExternalReference(f, isolate())); 5091 CEntryStub stub(isolate(), 1, save_doubles); 5092 CallStub(&stub, TypeFeedbackId::None(), al, zero_reg, Operand(zero_reg), bd); 5093 } 5094 5095 5096 void MacroAssembler::CallExternalReference(const ExternalReference& ext, 5097 int num_arguments, 5098 BranchDelaySlot bd) { 5099 PrepareCEntryArgs(num_arguments); 5100 PrepareCEntryFunction(ext); 5101 5102 CEntryStub stub(isolate(), 1); 5103 CallStub(&stub, TypeFeedbackId::None(), al, zero_reg, Operand(zero_reg), bd); 5104 } 5105 5106 5107 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { 5108 const Runtime::Function* function = Runtime::FunctionForId(fid); 5109 DCHECK_EQ(1, function->result_size); 5110 if (function->nargs >= 0) { 5111 PrepareCEntryArgs(function->nargs); 5112 } 5113 JumpToExternalReference(ExternalReference(fid, isolate())); 5114 } 5115 5116 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin, 5117 BranchDelaySlot bd, 5118 bool builtin_exit_frame) { 5119 PrepareCEntryFunction(builtin); 5120 CEntryStub stub(isolate(), 1, kDontSaveFPRegs, kArgvOnStack, 5121 builtin_exit_frame); 5122 Jump(stub.GetCode(), 5123 RelocInfo::CODE_TARGET, 5124 al, 5125 zero_reg, 5126 Operand(zero_reg), 5127 bd); 5128 } 5129 5130 void MacroAssembler::SetCounter(StatsCounter* counter, int value, 5131 Register scratch1, Register scratch2) { 5132 if (FLAG_native_code_counters && counter->Enabled()) { 5133 li(scratch1, Operand(value)); 5134 li(scratch2, Operand(ExternalReference(counter))); 5135 sw(scratch1, MemOperand(scratch2)); 5136 } 5137 } 5138 5139 5140 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value, 5141 Register scratch1, Register scratch2) { 5142 DCHECK(value > 0); 5143 if (FLAG_native_code_counters && counter->Enabled()) { 5144 li(scratch2, Operand(ExternalReference(counter))); 5145 lw(scratch1, MemOperand(scratch2)); 5146 Addu(scratch1, scratch1, Operand(value)); 5147 sw(scratch1, MemOperand(scratch2)); 5148 } 5149 } 5150 5151 5152 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, 5153 Register scratch1, Register scratch2) { 5154 DCHECK(value > 0); 5155 if (FLAG_native_code_counters && counter->Enabled()) { 5156 li(scratch2, Operand(ExternalReference(counter))); 5157 lw(scratch1, MemOperand(scratch2)); 5158 Subu(scratch1, scratch1, Operand(value)); 5159 sw(scratch1, MemOperand(scratch2)); 5160 } 5161 } 5162 5163 5164 // ----------------------------------------------------------------------------- 5165 // Debugging. 5166 5167 void MacroAssembler::Assert(Condition cc, BailoutReason reason, 5168 Register rs, Operand rt) { 5169 if (emit_debug_code()) 5170 Check(cc, reason, rs, rt); 5171 } 5172 5173 5174 void MacroAssembler::AssertFastElements(Register elements) { 5175 if (emit_debug_code()) { 5176 DCHECK(!elements.is(at)); 5177 Label ok; 5178 push(elements); 5179 lw(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); 5180 LoadRoot(at, Heap::kFixedArrayMapRootIndex); 5181 Branch(&ok, eq, elements, Operand(at)); 5182 LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex); 5183 Branch(&ok, eq, elements, Operand(at)); 5184 LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex); 5185 Branch(&ok, eq, elements, Operand(at)); 5186 Abort(kJSObjectWithFastElementsMapHasSlowElements); 5187 bind(&ok); 5188 pop(elements); 5189 } 5190 } 5191 5192 5193 void MacroAssembler::Check(Condition cc, BailoutReason reason, 5194 Register rs, Operand rt) { 5195 Label L; 5196 Branch(&L, cc, rs, rt); 5197 Abort(reason); 5198 // Will not return here. 5199 bind(&L); 5200 } 5201 5202 5203 void MacroAssembler::Abort(BailoutReason reason) { 5204 Label abort_start; 5205 bind(&abort_start); 5206 #ifdef DEBUG 5207 const char* msg = GetBailoutReason(reason); 5208 if (msg != NULL) { 5209 RecordComment("Abort message: "); 5210 RecordComment(msg); 5211 } 5212 5213 if (FLAG_trap_on_abort) { 5214 stop(msg); 5215 return; 5216 } 5217 #endif 5218 5219 // Check if Abort() has already been initialized. 5220 DCHECK(isolate()->builtins()->Abort()->IsHeapObject()); 5221 5222 Move(a0, Smi::FromInt(static_cast<int>(reason))); 5223 5224 // Disable stub call restrictions to always allow calls to abort. 5225 if (!has_frame_) { 5226 // We don't actually want to generate a pile of code for this, so just 5227 // claim there is a stack frame, without generating one. 5228 FrameScope scope(this, StackFrame::NONE); 5229 Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET); 5230 } else { 5231 Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET); 5232 } 5233 // Will not return here. 5234 if (is_trampoline_pool_blocked()) { 5235 // If the calling code cares about the exact number of 5236 // instructions generated, we insert padding here to keep the size 5237 // of the Abort macro constant. 5238 // Currently in debug mode with debug_code enabled the number of 5239 // generated instructions is 10, so we use this as a maximum value. 5240 static const int kExpectedAbortInstructions = 10; 5241 int abort_instructions = InstructionsGeneratedSince(&abort_start); 5242 DCHECK(abort_instructions <= kExpectedAbortInstructions); 5243 while (abort_instructions++ < kExpectedAbortInstructions) { 5244 nop(); 5245 } 5246 } 5247 } 5248 5249 5250 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { 5251 if (context_chain_length > 0) { 5252 // Move up the chain of contexts to the context containing the slot. 5253 lw(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX))); 5254 for (int i = 1; i < context_chain_length; i++) { 5255 lw(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); 5256 } 5257 } else { 5258 // Slot is in the current function context. Move it into the 5259 // destination register in case we store into it (the write barrier 5260 // cannot be allowed to destroy the context in esi). 5261 Move(dst, cp); 5262 } 5263 } 5264 5265 void MacroAssembler::LoadNativeContextSlot(int index, Register dst) { 5266 lw(dst, NativeContextMemOperand()); 5267 lw(dst, ContextMemOperand(dst, index)); 5268 } 5269 5270 5271 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, 5272 Register map, 5273 Register scratch) { 5274 // Load the initial map. The global functions all have initial maps. 5275 lw(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 5276 if (emit_debug_code()) { 5277 Label ok, fail; 5278 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); 5279 Branch(&ok); 5280 bind(&fail); 5281 Abort(kGlobalFunctionsMustHaveInitialMap); 5282 bind(&ok); 5283 } 5284 } 5285 5286 void MacroAssembler::StubPrologue(StackFrame::Type type) { 5287 li(at, Operand(StackFrame::TypeToMarker(type))); 5288 PushCommonFrame(at); 5289 } 5290 5291 5292 void MacroAssembler::Prologue(bool code_pre_aging) { 5293 PredictableCodeSizeScope predictible_code_size_scope( 5294 this, kNoCodeAgeSequenceLength); 5295 // The following three instructions must remain together and unmodified 5296 // for code aging to work properly. 5297 if (code_pre_aging) { 5298 // Pre-age the code. 5299 Code* stub = Code::GetPreAgedCodeAgeStub(isolate()); 5300 nop(Assembler::CODE_AGE_MARKER_NOP); 5301 // Load the stub address to t9 and call it, 5302 // GetCodeAge() extracts the stub address from this instruction. 5303 li(t9, 5304 Operand(reinterpret_cast<uint32_t>(stub->instruction_start())), 5305 CONSTANT_SIZE); 5306 nop(); // Prevent jalr to jal optimization. 5307 jalr(t9, a0); 5308 nop(); // Branch delay slot nop. 5309 nop(); // Pad the empty space. 5310 } else { 5311 PushStandardFrame(a1); 5312 nop(Assembler::CODE_AGE_SEQUENCE_NOP); 5313 } 5314 } 5315 5316 void MacroAssembler::EmitLoadFeedbackVector(Register vector) { 5317 lw(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 5318 lw(vector, FieldMemOperand(vector, JSFunction::kFeedbackVectorOffset)); 5319 lw(vector, FieldMemOperand(vector, Cell::kValueOffset)); 5320 } 5321 5322 5323 void MacroAssembler::EnterFrame(StackFrame::Type type, 5324 bool load_constant_pool_pointer_reg) { 5325 // Out-of-line constant pool not implemented on mips. 5326 UNREACHABLE(); 5327 } 5328 5329 5330 void MacroAssembler::EnterFrame(StackFrame::Type type) { 5331 int stack_offset, fp_offset; 5332 if (type == StackFrame::INTERNAL) { 5333 stack_offset = -4 * kPointerSize; 5334 fp_offset = 2 * kPointerSize; 5335 } else { 5336 stack_offset = -3 * kPointerSize; 5337 fp_offset = 1 * kPointerSize; 5338 } 5339 addiu(sp, sp, stack_offset); 5340 stack_offset = -stack_offset - kPointerSize; 5341 sw(ra, MemOperand(sp, stack_offset)); 5342 stack_offset -= kPointerSize; 5343 sw(fp, MemOperand(sp, stack_offset)); 5344 stack_offset -= kPointerSize; 5345 li(t9, Operand(StackFrame::TypeToMarker(type))); 5346 sw(t9, MemOperand(sp, stack_offset)); 5347 if (type == StackFrame::INTERNAL) { 5348 DCHECK_EQ(stack_offset, kPointerSize); 5349 li(t9, Operand(CodeObject())); 5350 sw(t9, MemOperand(sp, 0)); 5351 } else { 5352 DCHECK_EQ(stack_offset, 0); 5353 } 5354 // Adjust FP to point to saved FP. 5355 Addu(fp, sp, Operand(fp_offset)); 5356 } 5357 5358 5359 void MacroAssembler::LeaveFrame(StackFrame::Type type) { 5360 addiu(sp, fp, 2 * kPointerSize); 5361 lw(ra, MemOperand(fp, 1 * kPointerSize)); 5362 lw(fp, MemOperand(fp, 0 * kPointerSize)); 5363 } 5364 5365 void MacroAssembler::EnterBuiltinFrame(Register context, Register target, 5366 Register argc) { 5367 Push(ra, fp); 5368 Move(fp, sp); 5369 Push(context, target, argc); 5370 } 5371 5372 void MacroAssembler::LeaveBuiltinFrame(Register context, Register target, 5373 Register argc) { 5374 Pop(context, target, argc); 5375 Pop(ra, fp); 5376 } 5377 5378 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space, 5379 StackFrame::Type frame_type) { 5380 DCHECK(frame_type == StackFrame::EXIT || 5381 frame_type == StackFrame::BUILTIN_EXIT); 5382 5383 // Set up the frame structure on the stack. 5384 STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement); 5385 STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset); 5386 STATIC_ASSERT(0 * kPointerSize == ExitFrameConstants::kCallerFPOffset); 5387 5388 // This is how the stack will look: 5389 // fp + 2 (==kCallerSPDisplacement) - old stack's end 5390 // [fp + 1 (==kCallerPCOffset)] - saved old ra 5391 // [fp + 0 (==kCallerFPOffset)] - saved old fp 5392 // [fp - 1 StackFrame::EXIT Smi 5393 // [fp - 2 (==kSPOffset)] - sp of the called function 5394 // [fp - 3 (==kCodeOffset)] - CodeObject 5395 // fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the 5396 // new stack (will contain saved ra) 5397 5398 // Save registers and reserve room for saved entry sp and code object. 5399 addiu(sp, sp, -2 * kPointerSize - ExitFrameConstants::kFixedFrameSizeFromFp); 5400 sw(ra, MemOperand(sp, 4 * kPointerSize)); 5401 sw(fp, MemOperand(sp, 3 * kPointerSize)); 5402 li(at, Operand(StackFrame::TypeToMarker(frame_type))); 5403 sw(at, MemOperand(sp, 2 * kPointerSize)); 5404 // Set up new frame pointer. 5405 addiu(fp, sp, ExitFrameConstants::kFixedFrameSizeFromFp); 5406 5407 if (emit_debug_code()) { 5408 sw(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset)); 5409 } 5410 5411 // Accessed from ExitFrame::code_slot. 5412 li(t8, Operand(CodeObject()), CONSTANT_SIZE); 5413 sw(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset)); 5414 5415 // Save the frame pointer and the context in top. 5416 li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); 5417 sw(fp, MemOperand(t8)); 5418 li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); 5419 sw(cp, MemOperand(t8)); 5420 5421 const int frame_alignment = MacroAssembler::ActivationFrameAlignment(); 5422 if (save_doubles) { 5423 // The stack must be allign to 0 modulo 8 for stores with sdc1. 5424 DCHECK(kDoubleSize == frame_alignment); 5425 if (frame_alignment > 0) { 5426 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 5427 And(sp, sp, Operand(-frame_alignment)); // Align stack. 5428 } 5429 int space = FPURegister::kMaxNumRegisters * kDoubleSize; 5430 Subu(sp, sp, Operand(space)); 5431 // Remember: we only need to save every 2nd double FPU value. 5432 for (int i = 0; i < FPURegister::kMaxNumRegisters; i+=2) { 5433 FPURegister reg = FPURegister::from_code(i); 5434 sdc1(reg, MemOperand(sp, i * kDoubleSize)); 5435 } 5436 } 5437 5438 // Reserve place for the return address, stack space and an optional slot 5439 // (used by the DirectCEntryStub to hold the return value if a struct is 5440 // returned) and align the frame preparing for calling the runtime function. 5441 DCHECK(stack_space >= 0); 5442 Subu(sp, sp, Operand((stack_space + 2) * kPointerSize)); 5443 if (frame_alignment > 0) { 5444 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 5445 And(sp, sp, Operand(-frame_alignment)); // Align stack. 5446 } 5447 5448 // Set the exit frame sp value to point just before the return address 5449 // location. 5450 addiu(at, sp, kPointerSize); 5451 sw(at, MemOperand(fp, ExitFrameConstants::kSPOffset)); 5452 } 5453 5454 5455 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count, 5456 bool restore_context, bool do_return, 5457 bool argument_count_is_length) { 5458 // Optionally restore all double registers. 5459 if (save_doubles) { 5460 // Remember: we only need to restore every 2nd double FPU value. 5461 lw(t8, MemOperand(fp, ExitFrameConstants::kSPOffset)); 5462 for (int i = 0; i < FPURegister::kMaxNumRegisters; i+=2) { 5463 FPURegister reg = FPURegister::from_code(i); 5464 ldc1(reg, MemOperand(t8, i * kDoubleSize + kPointerSize)); 5465 } 5466 } 5467 5468 // Clear top frame. 5469 li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); 5470 sw(zero_reg, MemOperand(t8)); 5471 5472 // Restore current context from top and clear it in debug mode. 5473 if (restore_context) { 5474 li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); 5475 lw(cp, MemOperand(t8)); 5476 } 5477 #ifdef DEBUG 5478 li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); 5479 sw(a3, MemOperand(t8)); 5480 #endif 5481 5482 // Pop the arguments, restore registers, and return. 5483 mov(sp, fp); // Respect ABI stack constraint. 5484 lw(fp, MemOperand(sp, ExitFrameConstants::kCallerFPOffset)); 5485 lw(ra, MemOperand(sp, ExitFrameConstants::kCallerPCOffset)); 5486 5487 if (argument_count.is_valid()) { 5488 if (argument_count_is_length) { 5489 addu(sp, sp, argument_count); 5490 } else { 5491 Lsa(sp, sp, argument_count, kPointerSizeLog2, t8); 5492 } 5493 } 5494 5495 if (do_return) { 5496 Ret(USE_DELAY_SLOT); 5497 // If returning, the instruction in the delay slot will be the addiu below. 5498 } 5499 addiu(sp, sp, 8); 5500 } 5501 5502 int MacroAssembler::ActivationFrameAlignment() { 5503 #if V8_HOST_ARCH_MIPS 5504 // Running on the real platform. Use the alignment as mandated by the local 5505 // environment. 5506 // Note: This will break if we ever start generating snapshots on one Mips 5507 // platform for another Mips platform with a different alignment. 5508 return base::OS::ActivationFrameAlignment(); 5509 #else // V8_HOST_ARCH_MIPS 5510 // If we are using the simulator then we should always align to the expected 5511 // alignment. As the simulator is used to generate snapshots we do not know 5512 // if the target platform will need alignment, so this is controlled from a 5513 // flag. 5514 return FLAG_sim_stack_alignment; 5515 #endif // V8_HOST_ARCH_MIPS 5516 } 5517 5518 5519 void MacroAssembler::AssertStackIsAligned() { 5520 if (emit_debug_code()) { 5521 const int frame_alignment = ActivationFrameAlignment(); 5522 const int frame_alignment_mask = frame_alignment - 1; 5523 5524 if (frame_alignment > kPointerSize) { 5525 Label alignment_as_expected; 5526 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 5527 andi(at, sp, frame_alignment_mask); 5528 Branch(&alignment_as_expected, eq, at, Operand(zero_reg)); 5529 // Don't use Check here, as it will call Runtime_Abort re-entering here. 5530 stop("Unexpected stack alignment"); 5531 bind(&alignment_as_expected); 5532 } 5533 } 5534 } 5535 5536 5537 void MacroAssembler::JumpIfNotPowerOfTwoOrZero( 5538 Register reg, 5539 Register scratch, 5540 Label* not_power_of_two_or_zero) { 5541 Subu(scratch, reg, Operand(1)); 5542 Branch(USE_DELAY_SLOT, not_power_of_two_or_zero, lt, 5543 scratch, Operand(zero_reg)); 5544 and_(at, scratch, reg); // In the delay slot. 5545 Branch(not_power_of_two_or_zero, ne, at, Operand(zero_reg)); 5546 } 5547 5548 5549 void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) { 5550 DCHECK(!reg.is(overflow)); 5551 mov(overflow, reg); // Save original value. 5552 SmiTag(reg); 5553 xor_(overflow, overflow, reg); // Overflow if (value ^ 2 * value) < 0. 5554 } 5555 5556 5557 void MacroAssembler::SmiTagCheckOverflow(Register dst, 5558 Register src, 5559 Register overflow) { 5560 if (dst.is(src)) { 5561 // Fall back to slower case. 5562 SmiTagCheckOverflow(dst, overflow); 5563 } else { 5564 DCHECK(!dst.is(src)); 5565 DCHECK(!dst.is(overflow)); 5566 DCHECK(!src.is(overflow)); 5567 SmiTag(dst, src); 5568 xor_(overflow, dst, src); // Overflow if (value ^ 2 * value) < 0. 5569 } 5570 } 5571 5572 5573 void MacroAssembler::UntagAndJumpIfSmi(Register dst, 5574 Register src, 5575 Label* smi_case) { 5576 JumpIfSmi(src, smi_case, at, USE_DELAY_SLOT); 5577 SmiUntag(dst, src); 5578 } 5579 5580 void MacroAssembler::JumpIfSmi(Register value, 5581 Label* smi_label, 5582 Register scratch, 5583 BranchDelaySlot bd) { 5584 DCHECK_EQ(0, kSmiTag); 5585 andi(scratch, value, kSmiTagMask); 5586 Branch(bd, smi_label, eq, scratch, Operand(zero_reg)); 5587 } 5588 5589 void MacroAssembler::JumpIfNotSmi(Register value, 5590 Label* not_smi_label, 5591 Register scratch, 5592 BranchDelaySlot bd) { 5593 DCHECK_EQ(0, kSmiTag); 5594 andi(scratch, value, kSmiTagMask); 5595 Branch(bd, not_smi_label, ne, scratch, Operand(zero_reg)); 5596 } 5597 5598 5599 void MacroAssembler::JumpIfNotBothSmi(Register reg1, 5600 Register reg2, 5601 Label* on_not_both_smi) { 5602 STATIC_ASSERT(kSmiTag == 0); 5603 DCHECK_EQ(1, kSmiTagMask); 5604 or_(at, reg1, reg2); 5605 JumpIfNotSmi(at, on_not_both_smi); 5606 } 5607 5608 5609 void MacroAssembler::JumpIfEitherSmi(Register reg1, 5610 Register reg2, 5611 Label* on_either_smi) { 5612 STATIC_ASSERT(kSmiTag == 0); 5613 DCHECK_EQ(1, kSmiTagMask); 5614 // Both Smi tags must be 1 (not Smi). 5615 and_(at, reg1, reg2); 5616 JumpIfSmi(at, on_either_smi); 5617 } 5618 5619 void MacroAssembler::AssertNotNumber(Register object) { 5620 if (emit_debug_code()) { 5621 STATIC_ASSERT(kSmiTag == 0); 5622 andi(at, object, kSmiTagMask); 5623 Check(ne, kOperandIsANumber, at, Operand(zero_reg)); 5624 GetObjectType(object, t8, t8); 5625 Check(ne, kOperandIsNotANumber, t8, Operand(HEAP_NUMBER_TYPE)); 5626 } 5627 } 5628 5629 void MacroAssembler::AssertNotSmi(Register object) { 5630 if (emit_debug_code()) { 5631 STATIC_ASSERT(kSmiTag == 0); 5632 andi(at, object, kSmiTagMask); 5633 Check(ne, kOperandIsASmi, at, Operand(zero_reg)); 5634 } 5635 } 5636 5637 5638 void MacroAssembler::AssertSmi(Register object) { 5639 if (emit_debug_code()) { 5640 STATIC_ASSERT(kSmiTag == 0); 5641 andi(at, object, kSmiTagMask); 5642 Check(eq, kOperandIsASmi, at, Operand(zero_reg)); 5643 } 5644 } 5645 5646 5647 void MacroAssembler::AssertString(Register object) { 5648 if (emit_debug_code()) { 5649 STATIC_ASSERT(kSmiTag == 0); 5650 SmiTst(object, t8); 5651 Check(ne, kOperandIsASmiAndNotAString, t8, Operand(zero_reg)); 5652 GetObjectType(object, t8, t8); 5653 Check(lo, kOperandIsNotAString, t8, Operand(FIRST_NONSTRING_TYPE)); 5654 } 5655 } 5656 5657 5658 void MacroAssembler::AssertName(Register object) { 5659 if (emit_debug_code()) { 5660 STATIC_ASSERT(kSmiTag == 0); 5661 SmiTst(object, t8); 5662 Check(ne, kOperandIsASmiAndNotAName, t8, Operand(zero_reg)); 5663 GetObjectType(object, t8, t8); 5664 Check(le, kOperandIsNotAName, t8, Operand(LAST_NAME_TYPE)); 5665 } 5666 } 5667 5668 5669 void MacroAssembler::AssertFunction(Register object) { 5670 if (emit_debug_code()) { 5671 STATIC_ASSERT(kSmiTag == 0); 5672 SmiTst(object, t8); 5673 Check(ne, kOperandIsASmiAndNotAFunction, t8, Operand(zero_reg)); 5674 GetObjectType(object, t8, t8); 5675 Check(eq, kOperandIsNotAFunction, t8, Operand(JS_FUNCTION_TYPE)); 5676 } 5677 } 5678 5679 5680 void MacroAssembler::AssertBoundFunction(Register object) { 5681 if (emit_debug_code()) { 5682 STATIC_ASSERT(kSmiTag == 0); 5683 SmiTst(object, t8); 5684 Check(ne, kOperandIsASmiAndNotABoundFunction, t8, Operand(zero_reg)); 5685 GetObjectType(object, t8, t8); 5686 Check(eq, kOperandIsNotABoundFunction, t8, Operand(JS_BOUND_FUNCTION_TYPE)); 5687 } 5688 } 5689 5690 void MacroAssembler::AssertGeneratorObject(Register object) { 5691 if (emit_debug_code()) { 5692 STATIC_ASSERT(kSmiTag == 0); 5693 SmiTst(object, t8); 5694 Check(ne, kOperandIsASmiAndNotAGeneratorObject, t8, Operand(zero_reg)); 5695 GetObjectType(object, t8, t8); 5696 Check(eq, kOperandIsNotAGeneratorObject, t8, 5697 Operand(JS_GENERATOR_OBJECT_TYPE)); 5698 } 5699 } 5700 5701 void MacroAssembler::AssertReceiver(Register object) { 5702 if (emit_debug_code()) { 5703 STATIC_ASSERT(kSmiTag == 0); 5704 SmiTst(object, t8); 5705 Check(ne, kOperandIsASmiAndNotAReceiver, t8, Operand(zero_reg)); 5706 GetObjectType(object, t8, t8); 5707 Check(ge, kOperandIsNotAReceiver, t8, Operand(FIRST_JS_RECEIVER_TYPE)); 5708 } 5709 } 5710 5711 5712 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object, 5713 Register scratch) { 5714 if (emit_debug_code()) { 5715 Label done_checking; 5716 AssertNotSmi(object); 5717 LoadRoot(scratch, Heap::kUndefinedValueRootIndex); 5718 Branch(&done_checking, eq, object, Operand(scratch)); 5719 lw(t8, FieldMemOperand(object, HeapObject::kMapOffset)); 5720 LoadRoot(scratch, Heap::kAllocationSiteMapRootIndex); 5721 Assert(eq, kExpectedUndefinedOrCell, t8, Operand(scratch)); 5722 bind(&done_checking); 5723 } 5724 } 5725 5726 5727 void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) { 5728 if (emit_debug_code()) { 5729 DCHECK(!reg.is(at)); 5730 LoadRoot(at, index); 5731 Check(eq, kHeapNumberMapRegisterClobbered, reg, Operand(at)); 5732 } 5733 } 5734 5735 5736 void MacroAssembler::JumpIfNotHeapNumber(Register object, 5737 Register heap_number_map, 5738 Register scratch, 5739 Label* on_not_heap_number) { 5740 lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 5741 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 5742 Branch(on_not_heap_number, ne, scratch, Operand(heap_number_map)); 5743 } 5744 5745 5746 void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings( 5747 Register first, Register second, Register scratch1, Register scratch2, 5748 Label* failure) { 5749 // Test that both first and second are sequential one-byte strings. 5750 // Assume that they are non-smis. 5751 lw(scratch1, FieldMemOperand(first, HeapObject::kMapOffset)); 5752 lw(scratch2, FieldMemOperand(second, HeapObject::kMapOffset)); 5753 lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); 5754 lbu(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset)); 5755 5756 JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1, 5757 scratch2, failure); 5758 } 5759 5760 5761 void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first, 5762 Register second, 5763 Register scratch1, 5764 Register scratch2, 5765 Label* failure) { 5766 // Check that neither is a smi. 5767 STATIC_ASSERT(kSmiTag == 0); 5768 And(scratch1, first, Operand(second)); 5769 JumpIfSmi(scratch1, failure); 5770 JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1, 5771 scratch2, failure); 5772 } 5773 5774 void MacroAssembler::Float32Max(FPURegister dst, FPURegister src1, 5775 FPURegister src2, Label* out_of_line) { 5776 if (src1.is(src2)) { 5777 Move_s(dst, src1); 5778 return; 5779 } 5780 5781 // Check if one of operands is NaN. 5782 BranchF32(nullptr, out_of_line, eq, src1, src2); 5783 5784 if (IsMipsArchVariant(kMips32r6)) { 5785 max_s(dst, src1, src2); 5786 } else { 5787 Label return_left, return_right, done; 5788 5789 BranchF32(&return_right, nullptr, lt, src1, src2); 5790 BranchF32(&return_left, nullptr, lt, src2, src1); 5791 5792 // Operands are equal, but check for +/-0. 5793 mfc1(t8, src1); 5794 Branch(&return_left, eq, t8, Operand(zero_reg)); 5795 Branch(&return_right); 5796 5797 bind(&return_right); 5798 if (!src2.is(dst)) { 5799 Move_s(dst, src2); 5800 } 5801 Branch(&done); 5802 5803 bind(&return_left); 5804 if (!src1.is(dst)) { 5805 Move_s(dst, src1); 5806 } 5807 5808 bind(&done); 5809 } 5810 } 5811 5812 void MacroAssembler::Float32MaxOutOfLine(FPURegister dst, FPURegister src1, 5813 FPURegister src2) { 5814 add_s(dst, src1, src2); 5815 } 5816 5817 void MacroAssembler::Float32Min(FPURegister dst, FPURegister src1, 5818 FPURegister src2, Label* out_of_line) { 5819 if (src1.is(src2)) { 5820 Move_s(dst, src1); 5821 return; 5822 } 5823 5824 // Check if one of operands is NaN. 5825 BranchF32(nullptr, out_of_line, eq, src1, src2); 5826 5827 if (IsMipsArchVariant(kMips32r6)) { 5828 min_s(dst, src1, src2); 5829 } else { 5830 Label return_left, return_right, done; 5831 5832 BranchF32(&return_left, nullptr, lt, src1, src2); 5833 BranchF32(&return_right, nullptr, lt, src2, src1); 5834 5835 // Left equals right => check for -0. 5836 mfc1(t8, src1); 5837 Branch(&return_right, eq, t8, Operand(zero_reg)); 5838 Branch(&return_left); 5839 5840 bind(&return_right); 5841 if (!src2.is(dst)) { 5842 Move_s(dst, src2); 5843 } 5844 Branch(&done); 5845 5846 bind(&return_left); 5847 if (!src1.is(dst)) { 5848 Move_s(dst, src1); 5849 } 5850 5851 bind(&done); 5852 } 5853 } 5854 5855 void MacroAssembler::Float32MinOutOfLine(FPURegister dst, FPURegister src1, 5856 FPURegister src2) { 5857 add_s(dst, src1, src2); 5858 } 5859 5860 void MacroAssembler::Float64Max(DoubleRegister dst, DoubleRegister src1, 5861 DoubleRegister src2, Label* out_of_line) { 5862 if (src1.is(src2)) { 5863 Move_d(dst, src1); 5864 return; 5865 } 5866 5867 // Check if one of operands is NaN. 5868 BranchF64(nullptr, out_of_line, eq, src1, src2); 5869 5870 if (IsMipsArchVariant(kMips32r6)) { 5871 max_d(dst, src1, src2); 5872 } else { 5873 Label return_left, return_right, done; 5874 5875 BranchF64(&return_right, nullptr, lt, src1, src2); 5876 BranchF64(&return_left, nullptr, lt, src2, src1); 5877 5878 // Left equals right => check for -0. 5879 Mfhc1(t8, src1); 5880 Branch(&return_left, eq, t8, Operand(zero_reg)); 5881 Branch(&return_right); 5882 5883 bind(&return_right); 5884 if (!src2.is(dst)) { 5885 Move_d(dst, src2); 5886 } 5887 Branch(&done); 5888 5889 bind(&return_left); 5890 if (!src1.is(dst)) { 5891 Move_d(dst, src1); 5892 } 5893 5894 bind(&done); 5895 } 5896 } 5897 5898 void MacroAssembler::Float64MaxOutOfLine(DoubleRegister dst, 5899 DoubleRegister src1, 5900 DoubleRegister src2) { 5901 add_d(dst, src1, src2); 5902 } 5903 5904 void MacroAssembler::Float64Min(DoubleRegister dst, DoubleRegister src1, 5905 DoubleRegister src2, Label* out_of_line) { 5906 if (src1.is(src2)) { 5907 Move_d(dst, src1); 5908 return; 5909 } 5910 5911 // Check if one of operands is NaN. 5912 BranchF64(nullptr, out_of_line, eq, src1, src2); 5913 5914 if (IsMipsArchVariant(kMips32r6)) { 5915 min_d(dst, src1, src2); 5916 } else { 5917 Label return_left, return_right, done; 5918 5919 BranchF64(&return_left, nullptr, lt, src1, src2); 5920 BranchF64(&return_right, nullptr, lt, src2, src1); 5921 5922 // Left equals right => check for -0. 5923 Mfhc1(t8, src1); 5924 Branch(&return_right, eq, t8, Operand(zero_reg)); 5925 Branch(&return_left); 5926 5927 bind(&return_right); 5928 if (!src2.is(dst)) { 5929 Move_d(dst, src2); 5930 } 5931 Branch(&done); 5932 5933 bind(&return_left); 5934 if (!src1.is(dst)) { 5935 Move_d(dst, src1); 5936 } 5937 5938 bind(&done); 5939 } 5940 } 5941 5942 void MacroAssembler::Float64MinOutOfLine(DoubleRegister dst, 5943 DoubleRegister src1, 5944 DoubleRegister src2) { 5945 add_d(dst, src1, src2); 5946 } 5947 5948 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte( 5949 Register first, Register second, Register scratch1, Register scratch2, 5950 Label* failure) { 5951 const int kFlatOneByteStringMask = 5952 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; 5953 const int kFlatOneByteStringTag = 5954 kStringTag | kOneByteStringTag | kSeqStringTag; 5955 DCHECK(kFlatOneByteStringTag <= 0xffff); // Ensure this fits 16-bit immed. 5956 andi(scratch1, first, kFlatOneByteStringMask); 5957 Branch(failure, ne, scratch1, Operand(kFlatOneByteStringTag)); 5958 andi(scratch2, second, kFlatOneByteStringMask); 5959 Branch(failure, ne, scratch2, Operand(kFlatOneByteStringTag)); 5960 } 5961 5962 static const int kRegisterPassedArguments = 4; 5963 5964 int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments, 5965 int num_double_arguments) { 5966 int stack_passed_words = 0; 5967 num_reg_arguments += 2 * num_double_arguments; 5968 5969 // Up to four simple arguments are passed in registers a0..a3. 5970 if (num_reg_arguments > kRegisterPassedArguments) { 5971 stack_passed_words += num_reg_arguments - kRegisterPassedArguments; 5972 } 5973 stack_passed_words += kCArgSlotCount; 5974 return stack_passed_words; 5975 } 5976 5977 5978 void MacroAssembler::EmitSeqStringSetCharCheck(Register string, 5979 Register index, 5980 Register value, 5981 Register scratch, 5982 uint32_t encoding_mask) { 5983 Label is_object; 5984 SmiTst(string, at); 5985 Check(ne, kNonObject, at, Operand(zero_reg)); 5986 5987 lw(at, FieldMemOperand(string, HeapObject::kMapOffset)); 5988 lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset)); 5989 5990 andi(at, at, kStringRepresentationMask | kStringEncodingMask); 5991 li(scratch, Operand(encoding_mask)); 5992 Check(eq, kUnexpectedStringType, at, Operand(scratch)); 5993 5994 // The index is assumed to be untagged coming in, tag it to compare with the 5995 // string length without using a temp register, it is restored at the end of 5996 // this function. 5997 Label index_tag_ok, index_tag_bad; 5998 TrySmiTag(index, scratch, &index_tag_bad); 5999 Branch(&index_tag_ok); 6000 bind(&index_tag_bad); 6001 Abort(kIndexIsTooLarge); 6002 bind(&index_tag_ok); 6003 6004 lw(at, FieldMemOperand(string, String::kLengthOffset)); 6005 Check(lt, kIndexIsTooLarge, index, Operand(at)); 6006 6007 DCHECK(Smi::kZero == 0); 6008 Check(ge, kIndexIsNegative, index, Operand(zero_reg)); 6009 6010 SmiUntag(index, index); 6011 } 6012 6013 6014 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, 6015 int num_double_arguments, 6016 Register scratch) { 6017 int frame_alignment = ActivationFrameAlignment(); 6018 6019 // Up to four simple arguments are passed in registers a0..a3. 6020 // Those four arguments must have reserved argument slots on the stack for 6021 // mips, even though those argument slots are not normally used. 6022 // Remaining arguments are pushed on the stack, above (higher address than) 6023 // the argument slots. 6024 int stack_passed_arguments = CalculateStackPassedWords( 6025 num_reg_arguments, num_double_arguments); 6026 if (frame_alignment > kPointerSize) { 6027 // Make stack end at alignment and make room for num_arguments - 4 words 6028 // and the original value of sp. 6029 mov(scratch, sp); 6030 Subu(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize)); 6031 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 6032 And(sp, sp, Operand(-frame_alignment)); 6033 sw(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); 6034 } else { 6035 Subu(sp, sp, Operand(stack_passed_arguments * kPointerSize)); 6036 } 6037 } 6038 6039 6040 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, 6041 Register scratch) { 6042 PrepareCallCFunction(num_reg_arguments, 0, scratch); 6043 } 6044 6045 6046 void MacroAssembler::CallCFunction(ExternalReference function, 6047 int num_reg_arguments, 6048 int num_double_arguments) { 6049 li(t8, Operand(function)); 6050 CallCFunctionHelper(t8, num_reg_arguments, num_double_arguments); 6051 } 6052 6053 6054 void MacroAssembler::CallCFunction(Register function, 6055 int num_reg_arguments, 6056 int num_double_arguments) { 6057 CallCFunctionHelper(function, num_reg_arguments, num_double_arguments); 6058 } 6059 6060 6061 void MacroAssembler::CallCFunction(ExternalReference function, 6062 int num_arguments) { 6063 CallCFunction(function, num_arguments, 0); 6064 } 6065 6066 6067 void MacroAssembler::CallCFunction(Register function, 6068 int num_arguments) { 6069 CallCFunction(function, num_arguments, 0); 6070 } 6071 6072 6073 void MacroAssembler::CallCFunctionHelper(Register function, 6074 int num_reg_arguments, 6075 int num_double_arguments) { 6076 DCHECK(has_frame()); 6077 // Make sure that the stack is aligned before calling a C function unless 6078 // running in the simulator. The simulator has its own alignment check which 6079 // provides more information. 6080 // The argument stots are presumed to have been set up by 6081 // PrepareCallCFunction. The C function must be called via t9, for mips ABI. 6082 6083 #if V8_HOST_ARCH_MIPS 6084 if (emit_debug_code()) { 6085 int frame_alignment = base::OS::ActivationFrameAlignment(); 6086 int frame_alignment_mask = frame_alignment - 1; 6087 if (frame_alignment > kPointerSize) { 6088 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 6089 Label alignment_as_expected; 6090 And(at, sp, Operand(frame_alignment_mask)); 6091 Branch(&alignment_as_expected, eq, at, Operand(zero_reg)); 6092 // Don't use Check here, as it will call Runtime_Abort possibly 6093 // re-entering here. 6094 stop("Unexpected alignment in CallCFunction"); 6095 bind(&alignment_as_expected); 6096 } 6097 } 6098 #endif // V8_HOST_ARCH_MIPS 6099 6100 // Just call directly. The function called cannot cause a GC, or 6101 // allow preemption, so the return address in the link register 6102 // stays correct. 6103 6104 if (!function.is(t9)) { 6105 mov(t9, function); 6106 function = t9; 6107 } 6108 6109 Call(function); 6110 6111 int stack_passed_arguments = CalculateStackPassedWords( 6112 num_reg_arguments, num_double_arguments); 6113 6114 if (base::OS::ActivationFrameAlignment() > kPointerSize) { 6115 lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); 6116 } else { 6117 Addu(sp, sp, Operand(stack_passed_arguments * kPointerSize)); 6118 } 6119 } 6120 6121 6122 #undef BRANCH_ARGS_CHECK 6123 6124 6125 void MacroAssembler::CheckPageFlag( 6126 Register object, 6127 Register scratch, 6128 int mask, 6129 Condition cc, 6130 Label* condition_met) { 6131 And(scratch, object, Operand(~Page::kPageAlignmentMask)); 6132 lw(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset)); 6133 And(scratch, scratch, Operand(mask)); 6134 Branch(condition_met, cc, scratch, Operand(zero_reg)); 6135 } 6136 6137 6138 void MacroAssembler::JumpIfBlack(Register object, 6139 Register scratch0, 6140 Register scratch1, 6141 Label* on_black) { 6142 HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern. 6143 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 6144 } 6145 6146 6147 void MacroAssembler::HasColor(Register object, 6148 Register bitmap_scratch, 6149 Register mask_scratch, 6150 Label* has_color, 6151 int first_bit, 6152 int second_bit) { 6153 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, t8)); 6154 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, t9)); 6155 6156 GetMarkBits(object, bitmap_scratch, mask_scratch); 6157 6158 Label other_color, word_boundary; 6159 lw(t9, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); 6160 And(t8, t9, Operand(mask_scratch)); 6161 Branch(&other_color, first_bit == 1 ? eq : ne, t8, Operand(zero_reg)); 6162 // Shift left 1 by adding. 6163 Addu(mask_scratch, mask_scratch, Operand(mask_scratch)); 6164 Branch(&word_boundary, eq, mask_scratch, Operand(zero_reg)); 6165 And(t8, t9, Operand(mask_scratch)); 6166 Branch(has_color, second_bit == 1 ? ne : eq, t8, Operand(zero_reg)); 6167 jmp(&other_color); 6168 6169 bind(&word_boundary); 6170 lw(t9, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize)); 6171 And(t9, t9, Operand(1)); 6172 Branch(has_color, second_bit == 1 ? ne : eq, t9, Operand(zero_reg)); 6173 bind(&other_color); 6174 } 6175 6176 6177 void MacroAssembler::GetMarkBits(Register addr_reg, 6178 Register bitmap_reg, 6179 Register mask_reg) { 6180 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg)); 6181 And(bitmap_reg, addr_reg, Operand(~Page::kPageAlignmentMask)); 6182 Ext(mask_reg, addr_reg, kPointerSizeLog2, Bitmap::kBitsPerCellLog2); 6183 const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2; 6184 Ext(t8, addr_reg, kLowBits, kPageSizeBits - kLowBits); 6185 Lsa(bitmap_reg, bitmap_reg, t8, kPointerSizeLog2, t8); 6186 li(t8, Operand(1)); 6187 sllv(mask_reg, t8, mask_reg); 6188 } 6189 6190 6191 void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch, 6192 Register mask_scratch, Register load_scratch, 6193 Label* value_is_white) { 6194 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, t8)); 6195 GetMarkBits(value, bitmap_scratch, mask_scratch); 6196 6197 // If the value is black or grey we don't need to do anything. 6198 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); 6199 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 6200 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); 6201 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); 6202 6203 // Since both black and grey have a 1 in the first position and white does 6204 // not have a 1 there we only need to check one bit. 6205 lw(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); 6206 And(t8, mask_scratch, load_scratch); 6207 Branch(value_is_white, eq, t8, Operand(zero_reg)); 6208 } 6209 6210 6211 void MacroAssembler::LoadInstanceDescriptors(Register map, 6212 Register descriptors) { 6213 lw(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset)); 6214 } 6215 6216 6217 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { 6218 lw(dst, FieldMemOperand(map, Map::kBitField3Offset)); 6219 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); 6220 } 6221 6222 6223 void MacroAssembler::EnumLength(Register dst, Register map) { 6224 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0); 6225 lw(dst, FieldMemOperand(map, Map::kBitField3Offset)); 6226 And(dst, dst, Operand(Map::EnumLengthBits::kMask)); 6227 SmiTag(dst); 6228 } 6229 6230 6231 void MacroAssembler::LoadAccessor(Register dst, Register holder, 6232 int accessor_index, 6233 AccessorComponent accessor) { 6234 lw(dst, FieldMemOperand(holder, HeapObject::kMapOffset)); 6235 LoadInstanceDescriptors(dst, dst); 6236 lw(dst, 6237 FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index))); 6238 int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset 6239 : AccessorPair::kSetterOffset; 6240 lw(dst, FieldMemOperand(dst, offset)); 6241 } 6242 6243 6244 void MacroAssembler::CheckEnumCache(Label* call_runtime) { 6245 Register null_value = t1; 6246 Register empty_fixed_array_value = t2; 6247 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); 6248 Label next, start; 6249 mov(a2, a0); 6250 6251 // Check if the enum length field is properly initialized, indicating that 6252 // there is an enum cache. 6253 lw(a1, FieldMemOperand(a2, HeapObject::kMapOffset)); 6254 6255 EnumLength(a3, a1); 6256 Branch( 6257 call_runtime, eq, a3, Operand(Smi::FromInt(kInvalidEnumCacheSentinel))); 6258 6259 LoadRoot(null_value, Heap::kNullValueRootIndex); 6260 jmp(&start); 6261 6262 bind(&next); 6263 lw(a1, FieldMemOperand(a2, HeapObject::kMapOffset)); 6264 6265 // For all objects but the receiver, check that the cache is empty. 6266 EnumLength(a3, a1); 6267 Branch(call_runtime, ne, a3, Operand(Smi::kZero)); 6268 6269 bind(&start); 6270 6271 // Check that there are no elements. Register a2 contains the current JS 6272 // object we've reached through the prototype chain. 6273 Label no_elements; 6274 lw(a2, FieldMemOperand(a2, JSObject::kElementsOffset)); 6275 Branch(&no_elements, eq, a2, Operand(empty_fixed_array_value)); 6276 6277 // Second chance, the object may be using the empty slow element dictionary. 6278 LoadRoot(at, Heap::kEmptySlowElementDictionaryRootIndex); 6279 Branch(call_runtime, ne, a2, Operand(at)); 6280 6281 bind(&no_elements); 6282 lw(a2, FieldMemOperand(a1, Map::kPrototypeOffset)); 6283 Branch(&next, ne, a2, Operand(null_value)); 6284 } 6285 6286 6287 void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) { 6288 DCHECK(!output_reg.is(input_reg)); 6289 Label done; 6290 li(output_reg, Operand(255)); 6291 // Normal branch: nop in delay slot. 6292 Branch(&done, gt, input_reg, Operand(output_reg)); 6293 // Use delay slot in this branch. 6294 Branch(USE_DELAY_SLOT, &done, lt, input_reg, Operand(zero_reg)); 6295 mov(output_reg, zero_reg); // In delay slot. 6296 mov(output_reg, input_reg); // Value is in range 0..255. 6297 bind(&done); 6298 } 6299 6300 6301 void MacroAssembler::ClampDoubleToUint8(Register result_reg, 6302 DoubleRegister input_reg, 6303 DoubleRegister temp_double_reg) { 6304 Label above_zero; 6305 Label done; 6306 Label in_bounds; 6307 6308 Move(temp_double_reg, 0.0); 6309 BranchF(&above_zero, NULL, gt, input_reg, temp_double_reg); 6310 6311 // Double value is less than zero, NaN or Inf, return 0. 6312 mov(result_reg, zero_reg); 6313 Branch(&done); 6314 6315 // Double value is >= 255, return 255. 6316 bind(&above_zero); 6317 Move(temp_double_reg, 255.0); 6318 BranchF(&in_bounds, NULL, le, input_reg, temp_double_reg); 6319 li(result_reg, Operand(255)); 6320 Branch(&done); 6321 6322 // In 0-255 range, round and truncate. 6323 bind(&in_bounds); 6324 cvt_w_d(temp_double_reg, input_reg); 6325 mfc1(result_reg, temp_double_reg); 6326 bind(&done); 6327 } 6328 6329 void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg, 6330 Register scratch_reg, 6331 Label* no_memento_found) { 6332 Label map_check; 6333 Label top_check; 6334 ExternalReference new_space_allocation_top_adr = 6335 ExternalReference::new_space_allocation_top_address(isolate()); 6336 const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag; 6337 const int kMementoLastWordOffset = 6338 kMementoMapOffset + AllocationMemento::kSize - kPointerSize; 6339 6340 // Bail out if the object is not in new space. 6341 JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found); 6342 // If the object is in new space, we need to check whether it is on the same 6343 // page as the current top. 6344 Addu(scratch_reg, receiver_reg, Operand(kMementoLastWordOffset)); 6345 li(at, Operand(new_space_allocation_top_adr)); 6346 lw(at, MemOperand(at)); 6347 Xor(scratch_reg, scratch_reg, Operand(at)); 6348 And(scratch_reg, scratch_reg, Operand(~Page::kPageAlignmentMask)); 6349 Branch(&top_check, eq, scratch_reg, Operand(zero_reg)); 6350 // The object is on a different page than allocation top. Bail out if the 6351 // object sits on the page boundary as no memento can follow and we cannot 6352 // touch the memory following it. 6353 Addu(scratch_reg, receiver_reg, Operand(kMementoLastWordOffset)); 6354 Xor(scratch_reg, scratch_reg, Operand(receiver_reg)); 6355 And(scratch_reg, scratch_reg, Operand(~Page::kPageAlignmentMask)); 6356 Branch(no_memento_found, ne, scratch_reg, Operand(zero_reg)); 6357 // Continue with the actual map check. 6358 jmp(&map_check); 6359 // If top is on the same page as the current object, we need to check whether 6360 // we are below top. 6361 bind(&top_check); 6362 Addu(scratch_reg, receiver_reg, Operand(kMementoLastWordOffset)); 6363 li(at, Operand(new_space_allocation_top_adr)); 6364 lw(at, MemOperand(at)); 6365 Branch(no_memento_found, ge, scratch_reg, Operand(at)); 6366 // Memento map check. 6367 bind(&map_check); 6368 lw(scratch_reg, MemOperand(receiver_reg, kMementoMapOffset)); 6369 Branch(no_memento_found, ne, scratch_reg, 6370 Operand(isolate()->factory()->allocation_memento_map())); 6371 } 6372 6373 6374 Register GetRegisterThatIsNotOneOf(Register reg1, 6375 Register reg2, 6376 Register reg3, 6377 Register reg4, 6378 Register reg5, 6379 Register reg6) { 6380 RegList regs = 0; 6381 if (reg1.is_valid()) regs |= reg1.bit(); 6382 if (reg2.is_valid()) regs |= reg2.bit(); 6383 if (reg3.is_valid()) regs |= reg3.bit(); 6384 if (reg4.is_valid()) regs |= reg4.bit(); 6385 if (reg5.is_valid()) regs |= reg5.bit(); 6386 if (reg6.is_valid()) regs |= reg6.bit(); 6387 6388 const RegisterConfiguration* config = RegisterConfiguration::Crankshaft(); 6389 for (int i = 0; i < config->num_allocatable_general_registers(); ++i) { 6390 int code = config->GetAllocatableGeneralCode(i); 6391 Register candidate = Register::from_code(code); 6392 if (regs & candidate.bit()) continue; 6393 return candidate; 6394 } 6395 UNREACHABLE(); 6396 return no_reg; 6397 } 6398 6399 bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4, 6400 Register reg5, Register reg6, Register reg7, Register reg8, 6401 Register reg9, Register reg10) { 6402 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() + 6403 reg4.is_valid() + reg5.is_valid() + reg6.is_valid() + 6404 reg7.is_valid() + reg8.is_valid() + reg9.is_valid() + 6405 reg10.is_valid(); 6406 6407 RegList regs = 0; 6408 if (reg1.is_valid()) regs |= reg1.bit(); 6409 if (reg2.is_valid()) regs |= reg2.bit(); 6410 if (reg3.is_valid()) regs |= reg3.bit(); 6411 if (reg4.is_valid()) regs |= reg4.bit(); 6412 if (reg5.is_valid()) regs |= reg5.bit(); 6413 if (reg6.is_valid()) regs |= reg6.bit(); 6414 if (reg7.is_valid()) regs |= reg7.bit(); 6415 if (reg8.is_valid()) regs |= reg8.bit(); 6416 if (reg9.is_valid()) regs |= reg9.bit(); 6417 if (reg10.is_valid()) regs |= reg10.bit(); 6418 int n_of_non_aliasing_regs = NumRegs(regs); 6419 6420 return n_of_valid_regs != n_of_non_aliasing_regs; 6421 } 6422 6423 6424 CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions, 6425 FlushICache flush_cache) 6426 : address_(address), 6427 size_(instructions * Assembler::kInstrSize), 6428 masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo), 6429 flush_cache_(flush_cache) { 6430 // Create a new macro assembler pointing to the address of the code to patch. 6431 // The size is adjusted with kGap on order for the assembler to generate size 6432 // bytes of instructions without failing with buffer size constraints. 6433 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 6434 } 6435 6436 6437 CodePatcher::~CodePatcher() { 6438 // Indicate that code has changed. 6439 if (flush_cache_ == FLUSH) { 6440 Assembler::FlushICache(masm_.isolate(), address_, size_); 6441 } 6442 6443 // Check that the code was patched as expected. 6444 DCHECK(masm_.pc_ == address_ + size_); 6445 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 6446 } 6447 6448 6449 void CodePatcher::Emit(Instr instr) { 6450 masm()->emit(instr); 6451 } 6452 6453 6454 void CodePatcher::Emit(Address addr) { 6455 masm()->emit(reinterpret_cast<Instr>(addr)); 6456 } 6457 6458 6459 void CodePatcher::ChangeBranchCondition(Instr current_instr, 6460 uint32_t new_opcode) { 6461 current_instr = (current_instr & ~kOpcodeMask) | new_opcode; 6462 masm_.emit(current_instr); 6463 } 6464 6465 6466 void MacroAssembler::TruncatingDiv(Register result, 6467 Register dividend, 6468 int32_t divisor) { 6469 DCHECK(!dividend.is(result)); 6470 DCHECK(!dividend.is(at)); 6471 DCHECK(!result.is(at)); 6472 base::MagicNumbersForDivision<uint32_t> mag = 6473 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor)); 6474 li(at, Operand(mag.multiplier)); 6475 Mulh(result, dividend, Operand(at)); 6476 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0; 6477 if (divisor > 0 && neg) { 6478 Addu(result, result, Operand(dividend)); 6479 } 6480 if (divisor < 0 && !neg && mag.multiplier > 0) { 6481 Subu(result, result, Operand(dividend)); 6482 } 6483 if (mag.shift > 0) sra(result, result, mag.shift); 6484 srl(at, dividend, 31); 6485 Addu(result, result, Operand(at)); 6486 } 6487 6488 6489 } // namespace internal 6490 } // namespace v8 6491 6492 #endif // V8_TARGET_ARCH_MIPS 6493