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