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