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