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 #if V8_TARGET_ARCH_X64 6 7 #include "src/base/bits.h" 8 #include "src/base/division-by-constant.h" 9 #include "src/bootstrapper.h" 10 #include "src/codegen.h" 11 #include "src/debug/debug.h" 12 #include "src/heap/heap.h" 13 #include "src/register-configuration.h" 14 #include "src/x64/assembler-x64.h" 15 #include "src/x64/macro-assembler-x64.h" 16 17 namespace v8 { 18 namespace internal { 19 20 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size, 21 CodeObjectRequired create_code_object) 22 : Assembler(arg_isolate, buffer, size), 23 generating_stub_(false), 24 has_frame_(false), 25 root_array_available_(true) { 26 if (create_code_object == CodeObjectRequired::kYes) { 27 code_object_ = 28 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate()); 29 } 30 } 31 32 33 static const int64_t kInvalidRootRegisterDelta = -1; 34 35 36 int64_t MacroAssembler::RootRegisterDelta(ExternalReference other) { 37 if (predictable_code_size() && 38 (other.address() < reinterpret_cast<Address>(isolate()) || 39 other.address() >= reinterpret_cast<Address>(isolate() + 1))) { 40 return kInvalidRootRegisterDelta; 41 } 42 Address roots_register_value = kRootRegisterBias + 43 reinterpret_cast<Address>(isolate()->heap()->roots_array_start()); 44 45 int64_t delta = kInvalidRootRegisterDelta; // Bogus initialization. 46 if (kPointerSize == kInt64Size) { 47 delta = other.address() - roots_register_value; 48 } else { 49 // For x32, zero extend the address to 64-bit and calculate the delta. 50 uint64_t o = static_cast<uint32_t>( 51 reinterpret_cast<intptr_t>(other.address())); 52 uint64_t r = static_cast<uint32_t>( 53 reinterpret_cast<intptr_t>(roots_register_value)); 54 delta = o - r; 55 } 56 return delta; 57 } 58 59 60 Operand MacroAssembler::ExternalOperand(ExternalReference target, 61 Register scratch) { 62 if (root_array_available_ && !serializer_enabled()) { 63 int64_t delta = RootRegisterDelta(target); 64 if (delta != kInvalidRootRegisterDelta && is_int32(delta)) { 65 return Operand(kRootRegister, static_cast<int32_t>(delta)); 66 } 67 } 68 Move(scratch, target); 69 return Operand(scratch, 0); 70 } 71 72 73 void MacroAssembler::Load(Register destination, ExternalReference source) { 74 if (root_array_available_ && !serializer_enabled()) { 75 int64_t delta = RootRegisterDelta(source); 76 if (delta != kInvalidRootRegisterDelta && is_int32(delta)) { 77 movp(destination, Operand(kRootRegister, static_cast<int32_t>(delta))); 78 return; 79 } 80 } 81 // Safe code. 82 if (destination.is(rax)) { 83 load_rax(source); 84 } else { 85 Move(kScratchRegister, source); 86 movp(destination, Operand(kScratchRegister, 0)); 87 } 88 } 89 90 91 void MacroAssembler::Store(ExternalReference destination, Register source) { 92 if (root_array_available_ && !serializer_enabled()) { 93 int64_t delta = RootRegisterDelta(destination); 94 if (delta != kInvalidRootRegisterDelta && is_int32(delta)) { 95 movp(Operand(kRootRegister, static_cast<int32_t>(delta)), source); 96 return; 97 } 98 } 99 // Safe code. 100 if (source.is(rax)) { 101 store_rax(destination); 102 } else { 103 Move(kScratchRegister, destination); 104 movp(Operand(kScratchRegister, 0), source); 105 } 106 } 107 108 109 void MacroAssembler::LoadAddress(Register destination, 110 ExternalReference source) { 111 if (root_array_available_ && !serializer_enabled()) { 112 int64_t delta = RootRegisterDelta(source); 113 if (delta != kInvalidRootRegisterDelta && is_int32(delta)) { 114 leap(destination, Operand(kRootRegister, static_cast<int32_t>(delta))); 115 return; 116 } 117 } 118 // Safe code. 119 Move(destination, source); 120 } 121 122 123 int MacroAssembler::LoadAddressSize(ExternalReference source) { 124 if (root_array_available_ && !serializer_enabled()) { 125 // This calculation depends on the internals of LoadAddress. 126 // It's correctness is ensured by the asserts in the Call 127 // instruction below. 128 int64_t delta = RootRegisterDelta(source); 129 if (delta != kInvalidRootRegisterDelta && is_int32(delta)) { 130 // Operand is leap(scratch, Operand(kRootRegister, delta)); 131 // Opcodes : REX.W 8D ModRM Disp8/Disp32 - 4 or 7. 132 int size = 4; 133 if (!is_int8(static_cast<int32_t>(delta))) { 134 size += 3; // Need full four-byte displacement in lea. 135 } 136 return size; 137 } 138 } 139 // Size of movp(destination, src); 140 return Assembler::kMoveAddressIntoScratchRegisterInstructionLength; 141 } 142 143 144 void MacroAssembler::PushAddress(ExternalReference source) { 145 int64_t address = reinterpret_cast<int64_t>(source.address()); 146 if (is_int32(address) && !serializer_enabled()) { 147 if (emit_debug_code()) { 148 Move(kScratchRegister, kZapValue, Assembler::RelocInfoNone()); 149 } 150 Push(Immediate(static_cast<int32_t>(address))); 151 return; 152 } 153 LoadAddress(kScratchRegister, source); 154 Push(kScratchRegister); 155 } 156 157 158 void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) { 159 DCHECK(root_array_available_); 160 movp(destination, Operand(kRootRegister, 161 (index << kPointerSizeLog2) - kRootRegisterBias)); 162 } 163 164 165 void MacroAssembler::LoadRootIndexed(Register destination, 166 Register variable_offset, 167 int fixed_offset) { 168 DCHECK(root_array_available_); 169 movp(destination, 170 Operand(kRootRegister, 171 variable_offset, times_pointer_size, 172 (fixed_offset << kPointerSizeLog2) - kRootRegisterBias)); 173 } 174 175 176 void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index) { 177 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); 178 DCHECK(root_array_available_); 179 movp(Operand(kRootRegister, (index << kPointerSizeLog2) - kRootRegisterBias), 180 source); 181 } 182 183 184 void MacroAssembler::PushRoot(Heap::RootListIndex index) { 185 DCHECK(root_array_available_); 186 Push(Operand(kRootRegister, (index << kPointerSizeLog2) - kRootRegisterBias)); 187 } 188 189 190 void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) { 191 DCHECK(root_array_available_); 192 cmpp(with, Operand(kRootRegister, 193 (index << kPointerSizeLog2) - kRootRegisterBias)); 194 } 195 196 197 void MacroAssembler::CompareRoot(const Operand& with, 198 Heap::RootListIndex index) { 199 DCHECK(root_array_available_); 200 DCHECK(!with.AddressUsesRegister(kScratchRegister)); 201 LoadRoot(kScratchRegister, index); 202 cmpp(with, kScratchRegister); 203 } 204 205 206 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests. 207 Register addr, 208 Register scratch, 209 SaveFPRegsMode save_fp, 210 RememberedSetFinalAction and_then) { 211 if (emit_debug_code()) { 212 Label ok; 213 JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear); 214 int3(); 215 bind(&ok); 216 } 217 // Load store buffer top. 218 LoadRoot(scratch, Heap::kStoreBufferTopRootIndex); 219 // Store pointer to buffer. 220 movp(Operand(scratch, 0), addr); 221 // Increment buffer top. 222 addp(scratch, Immediate(kPointerSize)); 223 // Write back new top of buffer. 224 StoreRoot(scratch, Heap::kStoreBufferTopRootIndex); 225 // Call stub on end of buffer. 226 Label done; 227 // Check for end of buffer. 228 testp(scratch, Immediate(StoreBuffer::kStoreBufferOverflowBit)); 229 if (and_then == kReturnAtEnd) { 230 Label buffer_overflowed; 231 j(not_equal, &buffer_overflowed, Label::kNear); 232 ret(0); 233 bind(&buffer_overflowed); 234 } else { 235 DCHECK(and_then == kFallThroughAtEnd); 236 j(equal, &done, Label::kNear); 237 } 238 StoreBufferOverflowStub store_buffer_overflow(isolate(), save_fp); 239 CallStub(&store_buffer_overflow); 240 if (and_then == kReturnAtEnd) { 241 ret(0); 242 } else { 243 DCHECK(and_then == kFallThroughAtEnd); 244 bind(&done); 245 } 246 } 247 248 249 void MacroAssembler::InNewSpace(Register object, 250 Register scratch, 251 Condition cc, 252 Label* branch, 253 Label::Distance distance) { 254 if (serializer_enabled()) { 255 // Can't do arithmetic on external references if it might get serialized. 256 // The mask isn't really an address. We load it as an external reference in 257 // case the size of the new space is different between the snapshot maker 258 // and the running system. 259 if (scratch.is(object)) { 260 Move(kScratchRegister, ExternalReference::new_space_mask(isolate())); 261 andp(scratch, kScratchRegister); 262 } else { 263 Move(scratch, ExternalReference::new_space_mask(isolate())); 264 andp(scratch, object); 265 } 266 Move(kScratchRegister, ExternalReference::new_space_start(isolate())); 267 cmpp(scratch, kScratchRegister); 268 j(cc, branch, distance); 269 } else { 270 DCHECK(kPointerSize == kInt64Size 271 ? is_int32(static_cast<int64_t>(isolate()->heap()->NewSpaceMask())) 272 : kPointerSize == kInt32Size); 273 intptr_t new_space_start = 274 reinterpret_cast<intptr_t>(isolate()->heap()->NewSpaceStart()); 275 Move(kScratchRegister, reinterpret_cast<Address>(-new_space_start), 276 Assembler::RelocInfoNone()); 277 if (scratch.is(object)) { 278 addp(scratch, kScratchRegister); 279 } else { 280 leap(scratch, Operand(object, kScratchRegister, times_1, 0)); 281 } 282 andp(scratch, 283 Immediate(static_cast<int32_t>(isolate()->heap()->NewSpaceMask()))); 284 j(cc, branch, distance); 285 } 286 } 287 288 289 void MacroAssembler::RecordWriteField( 290 Register object, 291 int offset, 292 Register value, 293 Register dst, 294 SaveFPRegsMode save_fp, 295 RememberedSetAction remembered_set_action, 296 SmiCheck smi_check, 297 PointersToHereCheck pointers_to_here_check_for_value) { 298 // First, check if a write barrier is even needed. The tests below 299 // catch stores of Smis. 300 Label done; 301 302 // Skip barrier if writing a smi. 303 if (smi_check == INLINE_SMI_CHECK) { 304 JumpIfSmi(value, &done); 305 } 306 307 // Although the object register is tagged, the offset is relative to the start 308 // of the object, so so offset must be a multiple of kPointerSize. 309 DCHECK(IsAligned(offset, kPointerSize)); 310 311 leap(dst, FieldOperand(object, offset)); 312 if (emit_debug_code()) { 313 Label ok; 314 testb(dst, Immediate((1 << kPointerSizeLog2) - 1)); 315 j(zero, &ok, Label::kNear); 316 int3(); 317 bind(&ok); 318 } 319 320 RecordWrite(object, dst, value, save_fp, remembered_set_action, 321 OMIT_SMI_CHECK, pointers_to_here_check_for_value); 322 323 bind(&done); 324 325 // Clobber clobbered input registers when running with the debug-code flag 326 // turned on to provoke errors. 327 if (emit_debug_code()) { 328 Move(value, kZapValue, Assembler::RelocInfoNone()); 329 Move(dst, kZapValue, Assembler::RelocInfoNone()); 330 } 331 } 332 333 334 void MacroAssembler::RecordWriteArray( 335 Register object, 336 Register value, 337 Register index, 338 SaveFPRegsMode save_fp, 339 RememberedSetAction remembered_set_action, 340 SmiCheck smi_check, 341 PointersToHereCheck pointers_to_here_check_for_value) { 342 // First, check if a write barrier is even needed. The tests below 343 // catch stores of Smis. 344 Label done; 345 346 // Skip barrier if writing a smi. 347 if (smi_check == INLINE_SMI_CHECK) { 348 JumpIfSmi(value, &done); 349 } 350 351 // Array access: calculate the destination address. Index is not a smi. 352 Register dst = index; 353 leap(dst, Operand(object, index, times_pointer_size, 354 FixedArray::kHeaderSize - kHeapObjectTag)); 355 356 RecordWrite(object, dst, value, save_fp, remembered_set_action, 357 OMIT_SMI_CHECK, pointers_to_here_check_for_value); 358 359 bind(&done); 360 361 // Clobber clobbered input registers when running with the debug-code flag 362 // turned on to provoke errors. 363 if (emit_debug_code()) { 364 Move(value, kZapValue, Assembler::RelocInfoNone()); 365 Move(index, kZapValue, Assembler::RelocInfoNone()); 366 } 367 } 368 369 370 void MacroAssembler::RecordWriteForMap(Register object, 371 Register map, 372 Register dst, 373 SaveFPRegsMode fp_mode) { 374 DCHECK(!object.is(kScratchRegister)); 375 DCHECK(!object.is(map)); 376 DCHECK(!object.is(dst)); 377 DCHECK(!map.is(dst)); 378 AssertNotSmi(object); 379 380 if (emit_debug_code()) { 381 Label ok; 382 if (map.is(kScratchRegister)) pushq(map); 383 CompareMap(map, isolate()->factory()->meta_map()); 384 if (map.is(kScratchRegister)) popq(map); 385 j(equal, &ok, Label::kNear); 386 int3(); 387 bind(&ok); 388 } 389 390 if (!FLAG_incremental_marking) { 391 return; 392 } 393 394 if (emit_debug_code()) { 395 Label ok; 396 if (map.is(kScratchRegister)) pushq(map); 397 cmpp(map, FieldOperand(object, HeapObject::kMapOffset)); 398 if (map.is(kScratchRegister)) popq(map); 399 j(equal, &ok, Label::kNear); 400 int3(); 401 bind(&ok); 402 } 403 404 // Compute the address. 405 leap(dst, FieldOperand(object, HeapObject::kMapOffset)); 406 407 // First, check if a write barrier is even needed. The tests below 408 // catch stores of smis and stores into the young generation. 409 Label done; 410 411 // A single check of the map's pages interesting flag suffices, since it is 412 // only set during incremental collection, and then it's also guaranteed that 413 // the from object's page's interesting flag is also set. This optimization 414 // relies on the fact that maps can never be in new space. 415 CheckPageFlag(map, 416 map, // Used as scratch. 417 MemoryChunk::kPointersToHereAreInterestingMask, 418 zero, 419 &done, 420 Label::kNear); 421 422 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET, 423 fp_mode); 424 CallStub(&stub); 425 426 bind(&done); 427 428 // Count number of write barriers in generated code. 429 isolate()->counters()->write_barriers_static()->Increment(); 430 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1); 431 432 // Clobber clobbered registers when running with the debug-code flag 433 // turned on to provoke errors. 434 if (emit_debug_code()) { 435 Move(dst, kZapValue, Assembler::RelocInfoNone()); 436 Move(map, kZapValue, Assembler::RelocInfoNone()); 437 } 438 } 439 440 441 void MacroAssembler::RecordWrite( 442 Register object, 443 Register address, 444 Register value, 445 SaveFPRegsMode fp_mode, 446 RememberedSetAction remembered_set_action, 447 SmiCheck smi_check, 448 PointersToHereCheck pointers_to_here_check_for_value) { 449 DCHECK(!object.is(value)); 450 DCHECK(!object.is(address)); 451 DCHECK(!value.is(address)); 452 AssertNotSmi(object); 453 454 if (remembered_set_action == OMIT_REMEMBERED_SET && 455 !FLAG_incremental_marking) { 456 return; 457 } 458 459 if (emit_debug_code()) { 460 Label ok; 461 cmpp(value, Operand(address, 0)); 462 j(equal, &ok, Label::kNear); 463 int3(); 464 bind(&ok); 465 } 466 467 // First, check if a write barrier is even needed. The tests below 468 // catch stores of smis and stores into the young generation. 469 Label done; 470 471 if (smi_check == INLINE_SMI_CHECK) { 472 // Skip barrier if writing a smi. 473 JumpIfSmi(value, &done); 474 } 475 476 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { 477 CheckPageFlag(value, 478 value, // Used as scratch. 479 MemoryChunk::kPointersToHereAreInterestingMask, 480 zero, 481 &done, 482 Label::kNear); 483 } 484 485 CheckPageFlag(object, 486 value, // Used as scratch. 487 MemoryChunk::kPointersFromHereAreInterestingMask, 488 zero, 489 &done, 490 Label::kNear); 491 492 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, 493 fp_mode); 494 CallStub(&stub); 495 496 bind(&done); 497 498 // Count number of write barriers in generated code. 499 isolate()->counters()->write_barriers_static()->Increment(); 500 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1); 501 502 // Clobber clobbered registers when running with the debug-code flag 503 // turned on to provoke errors. 504 if (emit_debug_code()) { 505 Move(address, kZapValue, Assembler::RelocInfoNone()); 506 Move(value, kZapValue, Assembler::RelocInfoNone()); 507 } 508 } 509 510 511 void MacroAssembler::Assert(Condition cc, BailoutReason reason) { 512 if (emit_debug_code()) Check(cc, reason); 513 } 514 515 516 void MacroAssembler::AssertFastElements(Register elements) { 517 if (emit_debug_code()) { 518 Label ok; 519 CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), 520 Heap::kFixedArrayMapRootIndex); 521 j(equal, &ok, Label::kNear); 522 CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), 523 Heap::kFixedDoubleArrayMapRootIndex); 524 j(equal, &ok, Label::kNear); 525 CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), 526 Heap::kFixedCOWArrayMapRootIndex); 527 j(equal, &ok, Label::kNear); 528 Abort(kJSObjectWithFastElementsMapHasSlowElements); 529 bind(&ok); 530 } 531 } 532 533 534 void MacroAssembler::Check(Condition cc, BailoutReason reason) { 535 Label L; 536 j(cc, &L, Label::kNear); 537 Abort(reason); 538 // Control will not return here. 539 bind(&L); 540 } 541 542 543 void MacroAssembler::CheckStackAlignment() { 544 int frame_alignment = base::OS::ActivationFrameAlignment(); 545 int frame_alignment_mask = frame_alignment - 1; 546 if (frame_alignment > kPointerSize) { 547 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 548 Label alignment_as_expected; 549 testp(rsp, Immediate(frame_alignment_mask)); 550 j(zero, &alignment_as_expected, Label::kNear); 551 // Abort if stack is not aligned. 552 int3(); 553 bind(&alignment_as_expected); 554 } 555 } 556 557 558 void MacroAssembler::NegativeZeroTest(Register result, 559 Register op, 560 Label* then_label) { 561 Label ok; 562 testl(result, result); 563 j(not_zero, &ok, Label::kNear); 564 testl(op, op); 565 j(sign, then_label); 566 bind(&ok); 567 } 568 569 570 void MacroAssembler::Abort(BailoutReason reason) { 571 #ifdef DEBUG 572 const char* msg = GetBailoutReason(reason); 573 if (msg != NULL) { 574 RecordComment("Abort message: "); 575 RecordComment(msg); 576 } 577 578 if (FLAG_trap_on_abort) { 579 int3(); 580 return; 581 } 582 #endif 583 584 Move(kScratchRegister, Smi::FromInt(static_cast<int>(reason)), 585 Assembler::RelocInfoNone()); 586 Push(kScratchRegister); 587 588 if (!has_frame_) { 589 // We don't actually want to generate a pile of code for this, so just 590 // claim there is a stack frame, without generating one. 591 FrameScope scope(this, StackFrame::NONE); 592 CallRuntime(Runtime::kAbort, 1); 593 } else { 594 CallRuntime(Runtime::kAbort, 1); 595 } 596 // Control will not return here. 597 int3(); 598 } 599 600 601 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) { 602 DCHECK(AllowThisStubCall(stub)); // Calls are not allowed in some stubs 603 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id); 604 } 605 606 607 void MacroAssembler::TailCallStub(CodeStub* stub) { 608 Jump(stub->GetCode(), RelocInfo::CODE_TARGET); 609 } 610 611 612 void MacroAssembler::StubReturn(int argc) { 613 DCHECK(argc >= 1 && generating_stub()); 614 ret((argc - 1) * kPointerSize); 615 } 616 617 618 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { 619 return has_frame_ || !stub->SometimesSetsUpAFrame(); 620 } 621 622 623 void MacroAssembler::IndexFromHash(Register hash, Register index) { 624 // The assert checks that the constants for the maximum number of digits 625 // for an array index cached in the hash field and the number of bits 626 // reserved for it does not conflict. 627 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < 628 (1 << String::kArrayIndexValueBits)); 629 if (!hash.is(index)) { 630 movl(index, hash); 631 } 632 DecodeFieldToSmi<String::ArrayIndexValueBits>(index); 633 } 634 635 636 void MacroAssembler::CallRuntime(const Runtime::Function* f, 637 int num_arguments, 638 SaveFPRegsMode save_doubles) { 639 // If the expected number of arguments of the runtime function is 640 // constant, we check that the actual number of arguments match the 641 // expectation. 642 CHECK(f->nargs < 0 || f->nargs == num_arguments); 643 644 // TODO(1236192): Most runtime routines don't need the number of 645 // arguments passed in because it is constant. At some point we 646 // should remove this need and make the runtime routine entry code 647 // smarter. 648 Set(rax, num_arguments); 649 LoadAddress(rbx, ExternalReference(f, isolate())); 650 CEntryStub ces(isolate(), f->result_size, save_doubles); 651 CallStub(&ces); 652 } 653 654 655 void MacroAssembler::CallExternalReference(const ExternalReference& ext, 656 int num_arguments) { 657 Set(rax, num_arguments); 658 LoadAddress(rbx, ext); 659 660 CEntryStub stub(isolate(), 1); 661 CallStub(&stub); 662 } 663 664 665 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { 666 // ----------- S t a t e ------------- 667 // -- rsp[0] : return address 668 // -- rsp[8] : argument num_arguments - 1 669 // ... 670 // -- rsp[8 * num_arguments] : argument 0 (receiver) 671 // 672 // For runtime functions with variable arguments: 673 // -- rax : number of arguments 674 // ----------------------------------- 675 676 const Runtime::Function* function = Runtime::FunctionForId(fid); 677 DCHECK_EQ(1, function->result_size); 678 if (function->nargs >= 0) { 679 Set(rax, function->nargs); 680 } 681 JumpToExternalReference(ExternalReference(fid, isolate())); 682 } 683 684 685 void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) { 686 // Set the entry point and jump to the C entry runtime stub. 687 LoadAddress(rbx, ext); 688 CEntryStub ces(isolate(), 1); 689 jmp(ces.GetCode(), RelocInfo::CODE_TARGET); 690 } 691 692 693 void MacroAssembler::InvokeBuiltin(int native_context_index, InvokeFlag flag, 694 const CallWrapper& call_wrapper) { 695 // You can't call a builtin without a valid frame. 696 DCHECK(flag == JUMP_FUNCTION || has_frame()); 697 698 // Fake a parameter count to avoid emitting code to do the check. 699 ParameterCount expected(0); 700 LoadNativeContextSlot(native_context_index, rdi); 701 InvokeFunctionCode(rdi, no_reg, expected, expected, flag, call_wrapper); 702 } 703 704 705 #define REG(Name) \ 706 { Register::kCode_##Name } 707 708 static const Register saved_regs[] = { 709 REG(rax), REG(rcx), REG(rdx), REG(rbx), REG(rbp), REG(rsi), REG(rdi), REG(r8), 710 REG(r9), REG(r10), REG(r11) 711 }; 712 713 #undef REG 714 715 static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register); 716 717 718 void MacroAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, 719 Register exclusion1, 720 Register exclusion2, 721 Register exclusion3) { 722 // We don't allow a GC during a store buffer overflow so there is no need to 723 // store the registers in any particular way, but we do have to store and 724 // restore them. 725 for (int i = 0; i < kNumberOfSavedRegs; i++) { 726 Register reg = saved_regs[i]; 727 if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { 728 pushq(reg); 729 } 730 } 731 // R12 to r15 are callee save on all platforms. 732 if (fp_mode == kSaveFPRegs) { 733 subp(rsp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters)); 734 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { 735 XMMRegister reg = XMMRegister::from_code(i); 736 Movsd(Operand(rsp, i * kDoubleSize), reg); 737 } 738 } 739 } 740 741 742 void MacroAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, 743 Register exclusion1, 744 Register exclusion2, 745 Register exclusion3) { 746 if (fp_mode == kSaveFPRegs) { 747 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { 748 XMMRegister reg = XMMRegister::from_code(i); 749 Movsd(reg, Operand(rsp, i * kDoubleSize)); 750 } 751 addp(rsp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters)); 752 } 753 for (int i = kNumberOfSavedRegs - 1; i >= 0; i--) { 754 Register reg = saved_regs[i]; 755 if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { 756 popq(reg); 757 } 758 } 759 } 760 761 762 void MacroAssembler::Cvtss2sd(XMMRegister dst, XMMRegister src) { 763 if (CpuFeatures::IsSupported(AVX)) { 764 CpuFeatureScope scope(this, AVX); 765 vcvtss2sd(dst, src, src); 766 } else { 767 cvtss2sd(dst, src); 768 } 769 } 770 771 772 void MacroAssembler::Cvtss2sd(XMMRegister dst, const Operand& src) { 773 if (CpuFeatures::IsSupported(AVX)) { 774 CpuFeatureScope scope(this, AVX); 775 vcvtss2sd(dst, dst, src); 776 } else { 777 cvtss2sd(dst, src); 778 } 779 } 780 781 782 void MacroAssembler::Cvtsd2ss(XMMRegister dst, XMMRegister src) { 783 if (CpuFeatures::IsSupported(AVX)) { 784 CpuFeatureScope scope(this, AVX); 785 vcvtsd2ss(dst, src, src); 786 } else { 787 cvtsd2ss(dst, src); 788 } 789 } 790 791 792 void MacroAssembler::Cvtsd2ss(XMMRegister dst, const Operand& src) { 793 if (CpuFeatures::IsSupported(AVX)) { 794 CpuFeatureScope scope(this, AVX); 795 vcvtsd2ss(dst, dst, src); 796 } else { 797 cvtsd2ss(dst, src); 798 } 799 } 800 801 802 void MacroAssembler::Cvtlsi2sd(XMMRegister dst, Register src) { 803 if (CpuFeatures::IsSupported(AVX)) { 804 CpuFeatureScope scope(this, AVX); 805 vxorpd(dst, dst, dst); 806 vcvtlsi2sd(dst, dst, src); 807 } else { 808 xorpd(dst, dst); 809 cvtlsi2sd(dst, src); 810 } 811 } 812 813 814 void MacroAssembler::Cvtlsi2sd(XMMRegister dst, const Operand& src) { 815 if (CpuFeatures::IsSupported(AVX)) { 816 CpuFeatureScope scope(this, AVX); 817 vxorpd(dst, dst, dst); 818 vcvtlsi2sd(dst, dst, src); 819 } else { 820 xorpd(dst, dst); 821 cvtlsi2sd(dst, src); 822 } 823 } 824 825 826 void MacroAssembler::Cvtqsi2ss(XMMRegister dst, Register src) { 827 if (CpuFeatures::IsSupported(AVX)) { 828 CpuFeatureScope scope(this, AVX); 829 vxorps(dst, dst, dst); 830 vcvtqsi2ss(dst, dst, src); 831 } else { 832 xorps(dst, dst); 833 cvtqsi2ss(dst, src); 834 } 835 } 836 837 838 void MacroAssembler::Cvtqsi2ss(XMMRegister dst, const Operand& src) { 839 if (CpuFeatures::IsSupported(AVX)) { 840 CpuFeatureScope scope(this, AVX); 841 vxorps(dst, dst, dst); 842 vcvtqsi2ss(dst, dst, src); 843 } else { 844 xorps(dst, dst); 845 cvtqsi2ss(dst, src); 846 } 847 } 848 849 850 void MacroAssembler::Cvtqsi2sd(XMMRegister dst, Register src) { 851 if (CpuFeatures::IsSupported(AVX)) { 852 CpuFeatureScope scope(this, AVX); 853 vxorpd(dst, dst, dst); 854 vcvtqsi2sd(dst, dst, src); 855 } else { 856 xorpd(dst, dst); 857 cvtqsi2sd(dst, src); 858 } 859 } 860 861 862 void MacroAssembler::Cvtqsi2sd(XMMRegister dst, const Operand& src) { 863 if (CpuFeatures::IsSupported(AVX)) { 864 CpuFeatureScope scope(this, AVX); 865 vxorpd(dst, dst, dst); 866 vcvtqsi2sd(dst, dst, src); 867 } else { 868 xorpd(dst, dst); 869 cvtqsi2sd(dst, src); 870 } 871 } 872 873 874 void MacroAssembler::Cvtqui2ss(XMMRegister dst, Register src, Register tmp) { 875 Label msb_set_src; 876 Label jmp_return; 877 testq(src, src); 878 j(sign, &msb_set_src, Label::kNear); 879 Cvtqsi2ss(dst, src); 880 jmp(&jmp_return, Label::kNear); 881 bind(&msb_set_src); 882 movq(tmp, src); 883 shrq(src, Immediate(1)); 884 // Recover the least significant bit to avoid rounding errors. 885 andq(tmp, Immediate(1)); 886 orq(src, tmp); 887 Cvtqsi2ss(dst, src); 888 addss(dst, dst); 889 bind(&jmp_return); 890 } 891 892 893 void MacroAssembler::Cvtqui2sd(XMMRegister dst, Register src, Register tmp) { 894 Label msb_set_src; 895 Label jmp_return; 896 testq(src, src); 897 j(sign, &msb_set_src, Label::kNear); 898 Cvtqsi2sd(dst, src); 899 jmp(&jmp_return, Label::kNear); 900 bind(&msb_set_src); 901 movq(tmp, src); 902 shrq(src, Immediate(1)); 903 andq(tmp, Immediate(1)); 904 orq(src, tmp); 905 Cvtqsi2sd(dst, src); 906 addsd(dst, dst); 907 bind(&jmp_return); 908 } 909 910 911 void MacroAssembler::Cvtsd2si(Register dst, XMMRegister src) { 912 if (CpuFeatures::IsSupported(AVX)) { 913 CpuFeatureScope scope(this, AVX); 914 vcvtsd2si(dst, src); 915 } else { 916 cvtsd2si(dst, src); 917 } 918 } 919 920 921 void MacroAssembler::Cvttsd2si(Register dst, XMMRegister src) { 922 if (CpuFeatures::IsSupported(AVX)) { 923 CpuFeatureScope scope(this, AVX); 924 vcvttsd2si(dst, src); 925 } else { 926 cvttsd2si(dst, src); 927 } 928 } 929 930 931 void MacroAssembler::Cvttsd2si(Register dst, const Operand& src) { 932 if (CpuFeatures::IsSupported(AVX)) { 933 CpuFeatureScope scope(this, AVX); 934 vcvttsd2si(dst, src); 935 } else { 936 cvttsd2si(dst, src); 937 } 938 } 939 940 941 void MacroAssembler::Cvttss2siq(Register dst, XMMRegister src) { 942 if (CpuFeatures::IsSupported(AVX)) { 943 CpuFeatureScope scope(this, AVX); 944 vcvttss2siq(dst, src); 945 } else { 946 cvttss2siq(dst, src); 947 } 948 } 949 950 951 void MacroAssembler::Cvttss2siq(Register dst, const Operand& src) { 952 if (CpuFeatures::IsSupported(AVX)) { 953 CpuFeatureScope scope(this, AVX); 954 vcvttss2siq(dst, src); 955 } else { 956 cvttss2siq(dst, src); 957 } 958 } 959 960 961 void MacroAssembler::Cvttsd2siq(Register dst, XMMRegister src) { 962 if (CpuFeatures::IsSupported(AVX)) { 963 CpuFeatureScope scope(this, AVX); 964 vcvttsd2siq(dst, src); 965 } else { 966 cvttsd2siq(dst, src); 967 } 968 } 969 970 971 void MacroAssembler::Cvttsd2siq(Register dst, const Operand& src) { 972 if (CpuFeatures::IsSupported(AVX)) { 973 CpuFeatureScope scope(this, AVX); 974 vcvttsd2siq(dst, src); 975 } else { 976 cvttsd2siq(dst, src); 977 } 978 } 979 980 981 void MacroAssembler::Load(Register dst, const Operand& src, Representation r) { 982 DCHECK(!r.IsDouble()); 983 if (r.IsInteger8()) { 984 movsxbq(dst, src); 985 } else if (r.IsUInteger8()) { 986 movzxbl(dst, src); 987 } else if (r.IsInteger16()) { 988 movsxwq(dst, src); 989 } else if (r.IsUInteger16()) { 990 movzxwl(dst, src); 991 } else if (r.IsInteger32()) { 992 movl(dst, src); 993 } else { 994 movp(dst, src); 995 } 996 } 997 998 999 void MacroAssembler::Store(const Operand& dst, Register src, Representation r) { 1000 DCHECK(!r.IsDouble()); 1001 if (r.IsInteger8() || r.IsUInteger8()) { 1002 movb(dst, src); 1003 } else if (r.IsInteger16() || r.IsUInteger16()) { 1004 movw(dst, src); 1005 } else if (r.IsInteger32()) { 1006 movl(dst, src); 1007 } else { 1008 if (r.IsHeapObject()) { 1009 AssertNotSmi(src); 1010 } else if (r.IsSmi()) { 1011 AssertSmi(src); 1012 } 1013 movp(dst, src); 1014 } 1015 } 1016 1017 1018 void MacroAssembler::Set(Register dst, int64_t x) { 1019 if (x == 0) { 1020 xorl(dst, dst); 1021 } else if (is_uint32(x)) { 1022 movl(dst, Immediate(static_cast<uint32_t>(x))); 1023 } else if (is_int32(x)) { 1024 movq(dst, Immediate(static_cast<int32_t>(x))); 1025 } else { 1026 movq(dst, x); 1027 } 1028 } 1029 1030 1031 void MacroAssembler::Set(const Operand& dst, intptr_t x) { 1032 if (kPointerSize == kInt64Size) { 1033 if (is_int32(x)) { 1034 movp(dst, Immediate(static_cast<int32_t>(x))); 1035 } else { 1036 Set(kScratchRegister, x); 1037 movp(dst, kScratchRegister); 1038 } 1039 } else { 1040 movp(dst, Immediate(static_cast<int32_t>(x))); 1041 } 1042 } 1043 1044 1045 // ---------------------------------------------------------------------------- 1046 // Smi tagging, untagging and tag detection. 1047 1048 bool MacroAssembler::IsUnsafeInt(const int32_t x) { 1049 static const int kMaxBits = 17; 1050 return !is_intn(x, kMaxBits); 1051 } 1052 1053 1054 void MacroAssembler::SafeMove(Register dst, Smi* src) { 1055 DCHECK(!dst.is(kScratchRegister)); 1056 if (IsUnsafeInt(src->value()) && jit_cookie() != 0) { 1057 if (SmiValuesAre32Bits()) { 1058 // JIT cookie can be converted to Smi. 1059 Move(dst, Smi::FromInt(src->value() ^ jit_cookie())); 1060 Move(kScratchRegister, Smi::FromInt(jit_cookie())); 1061 xorp(dst, kScratchRegister); 1062 } else { 1063 DCHECK(SmiValuesAre31Bits()); 1064 int32_t value = static_cast<int32_t>(reinterpret_cast<intptr_t>(src)); 1065 movp(dst, Immediate(value ^ jit_cookie())); 1066 xorp(dst, Immediate(jit_cookie())); 1067 } 1068 } else { 1069 Move(dst, src); 1070 } 1071 } 1072 1073 1074 void MacroAssembler::SafePush(Smi* src) { 1075 if (IsUnsafeInt(src->value()) && jit_cookie() != 0) { 1076 if (SmiValuesAre32Bits()) { 1077 // JIT cookie can be converted to Smi. 1078 Push(Smi::FromInt(src->value() ^ jit_cookie())); 1079 Move(kScratchRegister, Smi::FromInt(jit_cookie())); 1080 xorp(Operand(rsp, 0), kScratchRegister); 1081 } else { 1082 DCHECK(SmiValuesAre31Bits()); 1083 int32_t value = static_cast<int32_t>(reinterpret_cast<intptr_t>(src)); 1084 Push(Immediate(value ^ jit_cookie())); 1085 xorp(Operand(rsp, 0), Immediate(jit_cookie())); 1086 } 1087 } else { 1088 Push(src); 1089 } 1090 } 1091 1092 1093 Register MacroAssembler::GetSmiConstant(Smi* source) { 1094 STATIC_ASSERT(kSmiTag == 0); 1095 int value = source->value(); 1096 if (value == 0) { 1097 xorl(kScratchRegister, kScratchRegister); 1098 return kScratchRegister; 1099 } 1100 LoadSmiConstant(kScratchRegister, source); 1101 return kScratchRegister; 1102 } 1103 1104 1105 void MacroAssembler::LoadSmiConstant(Register dst, Smi* source) { 1106 STATIC_ASSERT(kSmiTag == 0); 1107 int value = source->value(); 1108 if (value == 0) { 1109 xorl(dst, dst); 1110 } else { 1111 Move(dst, source, Assembler::RelocInfoNone()); 1112 } 1113 } 1114 1115 1116 void MacroAssembler::Integer32ToSmi(Register dst, Register src) { 1117 STATIC_ASSERT(kSmiTag == 0); 1118 if (!dst.is(src)) { 1119 movl(dst, src); 1120 } 1121 shlp(dst, Immediate(kSmiShift)); 1122 } 1123 1124 1125 void MacroAssembler::Integer32ToSmiField(const Operand& dst, Register src) { 1126 if (emit_debug_code()) { 1127 testb(dst, Immediate(0x01)); 1128 Label ok; 1129 j(zero, &ok, Label::kNear); 1130 Abort(kInteger32ToSmiFieldWritingToNonSmiLocation); 1131 bind(&ok); 1132 } 1133 1134 if (SmiValuesAre32Bits()) { 1135 DCHECK(kSmiShift % kBitsPerByte == 0); 1136 movl(Operand(dst, kSmiShift / kBitsPerByte), src); 1137 } else { 1138 DCHECK(SmiValuesAre31Bits()); 1139 Integer32ToSmi(kScratchRegister, src); 1140 movp(dst, kScratchRegister); 1141 } 1142 } 1143 1144 1145 void MacroAssembler::Integer64PlusConstantToSmi(Register dst, 1146 Register src, 1147 int constant) { 1148 if (dst.is(src)) { 1149 addl(dst, Immediate(constant)); 1150 } else { 1151 leal(dst, Operand(src, constant)); 1152 } 1153 shlp(dst, Immediate(kSmiShift)); 1154 } 1155 1156 1157 void MacroAssembler::SmiToInteger32(Register dst, Register src) { 1158 STATIC_ASSERT(kSmiTag == 0); 1159 if (!dst.is(src)) { 1160 movp(dst, src); 1161 } 1162 1163 if (SmiValuesAre32Bits()) { 1164 shrp(dst, Immediate(kSmiShift)); 1165 } else { 1166 DCHECK(SmiValuesAre31Bits()); 1167 sarl(dst, Immediate(kSmiShift)); 1168 } 1169 } 1170 1171 1172 void MacroAssembler::SmiToInteger32(Register dst, const Operand& src) { 1173 if (SmiValuesAre32Bits()) { 1174 movl(dst, Operand(src, kSmiShift / kBitsPerByte)); 1175 } else { 1176 DCHECK(SmiValuesAre31Bits()); 1177 movl(dst, src); 1178 sarl(dst, Immediate(kSmiShift)); 1179 } 1180 } 1181 1182 1183 void MacroAssembler::SmiToInteger64(Register dst, Register src) { 1184 STATIC_ASSERT(kSmiTag == 0); 1185 if (!dst.is(src)) { 1186 movp(dst, src); 1187 } 1188 sarp(dst, Immediate(kSmiShift)); 1189 if (kPointerSize == kInt32Size) { 1190 // Sign extend to 64-bit. 1191 movsxlq(dst, dst); 1192 } 1193 } 1194 1195 1196 void MacroAssembler::SmiToInteger64(Register dst, const Operand& src) { 1197 if (SmiValuesAre32Bits()) { 1198 movsxlq(dst, Operand(src, kSmiShift / kBitsPerByte)); 1199 } else { 1200 DCHECK(SmiValuesAre31Bits()); 1201 movp(dst, src); 1202 SmiToInteger64(dst, dst); 1203 } 1204 } 1205 1206 1207 void MacroAssembler::SmiTest(Register src) { 1208 AssertSmi(src); 1209 testp(src, src); 1210 } 1211 1212 1213 void MacroAssembler::SmiCompare(Register smi1, Register smi2) { 1214 AssertSmi(smi1); 1215 AssertSmi(smi2); 1216 cmpp(smi1, smi2); 1217 } 1218 1219 1220 void MacroAssembler::SmiCompare(Register dst, Smi* src) { 1221 AssertSmi(dst); 1222 Cmp(dst, src); 1223 } 1224 1225 1226 void MacroAssembler::Cmp(Register dst, Smi* src) { 1227 DCHECK(!dst.is(kScratchRegister)); 1228 if (src->value() == 0) { 1229 testp(dst, dst); 1230 } else { 1231 Register constant_reg = GetSmiConstant(src); 1232 cmpp(dst, constant_reg); 1233 } 1234 } 1235 1236 1237 void MacroAssembler::SmiCompare(Register dst, const Operand& src) { 1238 AssertSmi(dst); 1239 AssertSmi(src); 1240 cmpp(dst, src); 1241 } 1242 1243 1244 void MacroAssembler::SmiCompare(const Operand& dst, Register src) { 1245 AssertSmi(dst); 1246 AssertSmi(src); 1247 cmpp(dst, src); 1248 } 1249 1250 1251 void MacroAssembler::SmiCompare(const Operand& dst, Smi* src) { 1252 AssertSmi(dst); 1253 if (SmiValuesAre32Bits()) { 1254 cmpl(Operand(dst, kSmiShift / kBitsPerByte), Immediate(src->value())); 1255 } else { 1256 DCHECK(SmiValuesAre31Bits()); 1257 cmpl(dst, Immediate(src)); 1258 } 1259 } 1260 1261 1262 void MacroAssembler::Cmp(const Operand& dst, Smi* src) { 1263 // The Operand cannot use the smi register. 1264 Register smi_reg = GetSmiConstant(src); 1265 DCHECK(!dst.AddressUsesRegister(smi_reg)); 1266 cmpp(dst, smi_reg); 1267 } 1268 1269 1270 void MacroAssembler::SmiCompareInteger32(const Operand& dst, Register src) { 1271 if (SmiValuesAre32Bits()) { 1272 cmpl(Operand(dst, kSmiShift / kBitsPerByte), src); 1273 } else { 1274 DCHECK(SmiValuesAre31Bits()); 1275 SmiToInteger32(kScratchRegister, dst); 1276 cmpl(kScratchRegister, src); 1277 } 1278 } 1279 1280 1281 void MacroAssembler::PositiveSmiTimesPowerOfTwoToInteger64(Register dst, 1282 Register src, 1283 int power) { 1284 DCHECK(power >= 0); 1285 DCHECK(power < 64); 1286 if (power == 0) { 1287 SmiToInteger64(dst, src); 1288 return; 1289 } 1290 if (!dst.is(src)) { 1291 movp(dst, src); 1292 } 1293 if (power < kSmiShift) { 1294 sarp(dst, Immediate(kSmiShift - power)); 1295 } else if (power > kSmiShift) { 1296 shlp(dst, Immediate(power - kSmiShift)); 1297 } 1298 } 1299 1300 1301 void MacroAssembler::PositiveSmiDivPowerOfTwoToInteger32(Register dst, 1302 Register src, 1303 int power) { 1304 DCHECK((0 <= power) && (power < 32)); 1305 if (dst.is(src)) { 1306 shrp(dst, Immediate(power + kSmiShift)); 1307 } else { 1308 UNIMPLEMENTED(); // Not used. 1309 } 1310 } 1311 1312 1313 void MacroAssembler::SmiOrIfSmis(Register dst, Register src1, Register src2, 1314 Label* on_not_smis, 1315 Label::Distance near_jump) { 1316 if (dst.is(src1) || dst.is(src2)) { 1317 DCHECK(!src1.is(kScratchRegister)); 1318 DCHECK(!src2.is(kScratchRegister)); 1319 movp(kScratchRegister, src1); 1320 orp(kScratchRegister, src2); 1321 JumpIfNotSmi(kScratchRegister, on_not_smis, near_jump); 1322 movp(dst, kScratchRegister); 1323 } else { 1324 movp(dst, src1); 1325 orp(dst, src2); 1326 JumpIfNotSmi(dst, on_not_smis, near_jump); 1327 } 1328 } 1329 1330 1331 Condition MacroAssembler::CheckSmi(Register src) { 1332 STATIC_ASSERT(kSmiTag == 0); 1333 testb(src, Immediate(kSmiTagMask)); 1334 return zero; 1335 } 1336 1337 1338 Condition MacroAssembler::CheckSmi(const Operand& src) { 1339 STATIC_ASSERT(kSmiTag == 0); 1340 testb(src, Immediate(kSmiTagMask)); 1341 return zero; 1342 } 1343 1344 1345 Condition MacroAssembler::CheckNonNegativeSmi(Register src) { 1346 STATIC_ASSERT(kSmiTag == 0); 1347 // Test that both bits of the mask 0x8000000000000001 are zero. 1348 movp(kScratchRegister, src); 1349 rolp(kScratchRegister, Immediate(1)); 1350 testb(kScratchRegister, Immediate(3)); 1351 return zero; 1352 } 1353 1354 1355 Condition MacroAssembler::CheckBothSmi(Register first, Register second) { 1356 if (first.is(second)) { 1357 return CheckSmi(first); 1358 } 1359 STATIC_ASSERT(kSmiTag == 0 && kHeapObjectTag == 1 && kHeapObjectTagMask == 3); 1360 if (SmiValuesAre32Bits()) { 1361 leal(kScratchRegister, Operand(first, second, times_1, 0)); 1362 testb(kScratchRegister, Immediate(0x03)); 1363 } else { 1364 DCHECK(SmiValuesAre31Bits()); 1365 movl(kScratchRegister, first); 1366 orl(kScratchRegister, second); 1367 testb(kScratchRegister, Immediate(kSmiTagMask)); 1368 } 1369 return zero; 1370 } 1371 1372 1373 Condition MacroAssembler::CheckBothNonNegativeSmi(Register first, 1374 Register second) { 1375 if (first.is(second)) { 1376 return CheckNonNegativeSmi(first); 1377 } 1378 movp(kScratchRegister, first); 1379 orp(kScratchRegister, second); 1380 rolp(kScratchRegister, Immediate(1)); 1381 testl(kScratchRegister, Immediate(3)); 1382 return zero; 1383 } 1384 1385 1386 Condition MacroAssembler::CheckEitherSmi(Register first, 1387 Register second, 1388 Register scratch) { 1389 if (first.is(second)) { 1390 return CheckSmi(first); 1391 } 1392 if (scratch.is(second)) { 1393 andl(scratch, first); 1394 } else { 1395 if (!scratch.is(first)) { 1396 movl(scratch, first); 1397 } 1398 andl(scratch, second); 1399 } 1400 testb(scratch, Immediate(kSmiTagMask)); 1401 return zero; 1402 } 1403 1404 1405 Condition MacroAssembler::CheckInteger32ValidSmiValue(Register src) { 1406 if (SmiValuesAre32Bits()) { 1407 // A 32-bit integer value can always be converted to a smi. 1408 return always; 1409 } else { 1410 DCHECK(SmiValuesAre31Bits()); 1411 cmpl(src, Immediate(0xc0000000)); 1412 return positive; 1413 } 1414 } 1415 1416 1417 Condition MacroAssembler::CheckUInteger32ValidSmiValue(Register src) { 1418 if (SmiValuesAre32Bits()) { 1419 // An unsigned 32-bit integer value is valid as long as the high bit 1420 // is not set. 1421 testl(src, src); 1422 return positive; 1423 } else { 1424 DCHECK(SmiValuesAre31Bits()); 1425 testl(src, Immediate(0xc0000000)); 1426 return zero; 1427 } 1428 } 1429 1430 1431 void MacroAssembler::CheckSmiToIndicator(Register dst, Register src) { 1432 if (dst.is(src)) { 1433 andl(dst, Immediate(kSmiTagMask)); 1434 } else { 1435 movl(dst, Immediate(kSmiTagMask)); 1436 andl(dst, src); 1437 } 1438 } 1439 1440 1441 void MacroAssembler::CheckSmiToIndicator(Register dst, const Operand& src) { 1442 if (!(src.AddressUsesRegister(dst))) { 1443 movl(dst, Immediate(kSmiTagMask)); 1444 andl(dst, src); 1445 } else { 1446 movl(dst, src); 1447 andl(dst, Immediate(kSmiTagMask)); 1448 } 1449 } 1450 1451 1452 void MacroAssembler::JumpIfValidSmiValue(Register src, 1453 Label* on_valid, 1454 Label::Distance near_jump) { 1455 Condition is_valid = CheckInteger32ValidSmiValue(src); 1456 j(is_valid, on_valid, near_jump); 1457 } 1458 1459 1460 void MacroAssembler::JumpIfNotValidSmiValue(Register src, 1461 Label* on_invalid, 1462 Label::Distance near_jump) { 1463 Condition is_valid = CheckInteger32ValidSmiValue(src); 1464 j(NegateCondition(is_valid), on_invalid, near_jump); 1465 } 1466 1467 1468 void MacroAssembler::JumpIfUIntValidSmiValue(Register src, 1469 Label* on_valid, 1470 Label::Distance near_jump) { 1471 Condition is_valid = CheckUInteger32ValidSmiValue(src); 1472 j(is_valid, on_valid, near_jump); 1473 } 1474 1475 1476 void MacroAssembler::JumpIfUIntNotValidSmiValue(Register src, 1477 Label* on_invalid, 1478 Label::Distance near_jump) { 1479 Condition is_valid = CheckUInteger32ValidSmiValue(src); 1480 j(NegateCondition(is_valid), on_invalid, near_jump); 1481 } 1482 1483 1484 void MacroAssembler::JumpIfSmi(Register src, 1485 Label* on_smi, 1486 Label::Distance near_jump) { 1487 Condition smi = CheckSmi(src); 1488 j(smi, on_smi, near_jump); 1489 } 1490 1491 1492 void MacroAssembler::JumpIfNotSmi(Register src, 1493 Label* on_not_smi, 1494 Label::Distance near_jump) { 1495 Condition smi = CheckSmi(src); 1496 j(NegateCondition(smi), on_not_smi, near_jump); 1497 } 1498 1499 1500 void MacroAssembler::JumpUnlessNonNegativeSmi( 1501 Register src, Label* on_not_smi_or_negative, 1502 Label::Distance near_jump) { 1503 Condition non_negative_smi = CheckNonNegativeSmi(src); 1504 j(NegateCondition(non_negative_smi), on_not_smi_or_negative, near_jump); 1505 } 1506 1507 1508 void MacroAssembler::JumpIfSmiEqualsConstant(Register src, 1509 Smi* constant, 1510 Label* on_equals, 1511 Label::Distance near_jump) { 1512 SmiCompare(src, constant); 1513 j(equal, on_equals, near_jump); 1514 } 1515 1516 1517 void MacroAssembler::JumpIfNotBothSmi(Register src1, 1518 Register src2, 1519 Label* on_not_both_smi, 1520 Label::Distance near_jump) { 1521 Condition both_smi = CheckBothSmi(src1, src2); 1522 j(NegateCondition(both_smi), on_not_both_smi, near_jump); 1523 } 1524 1525 1526 void MacroAssembler::JumpUnlessBothNonNegativeSmi(Register src1, 1527 Register src2, 1528 Label* on_not_both_smi, 1529 Label::Distance near_jump) { 1530 Condition both_smi = CheckBothNonNegativeSmi(src1, src2); 1531 j(NegateCondition(both_smi), on_not_both_smi, near_jump); 1532 } 1533 1534 1535 void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant) { 1536 if (constant->value() == 0) { 1537 if (!dst.is(src)) { 1538 movp(dst, src); 1539 } 1540 return; 1541 } else if (dst.is(src)) { 1542 DCHECK(!dst.is(kScratchRegister)); 1543 Register constant_reg = GetSmiConstant(constant); 1544 addp(dst, constant_reg); 1545 } else { 1546 LoadSmiConstant(dst, constant); 1547 addp(dst, src); 1548 } 1549 } 1550 1551 1552 void MacroAssembler::SmiAddConstant(const Operand& dst, Smi* constant) { 1553 if (constant->value() != 0) { 1554 if (SmiValuesAre32Bits()) { 1555 addl(Operand(dst, kSmiShift / kBitsPerByte), 1556 Immediate(constant->value())); 1557 } else { 1558 DCHECK(SmiValuesAre31Bits()); 1559 addp(dst, Immediate(constant)); 1560 } 1561 } 1562 } 1563 1564 1565 void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant, 1566 SmiOperationConstraints constraints, 1567 Label* bailout_label, 1568 Label::Distance near_jump) { 1569 if (constant->value() == 0) { 1570 if (!dst.is(src)) { 1571 movp(dst, src); 1572 } 1573 } else if (dst.is(src)) { 1574 DCHECK(!dst.is(kScratchRegister)); 1575 LoadSmiConstant(kScratchRegister, constant); 1576 addp(dst, kScratchRegister); 1577 if (constraints & SmiOperationConstraint::kBailoutOnNoOverflow) { 1578 j(no_overflow, bailout_label, near_jump); 1579 DCHECK(constraints & SmiOperationConstraint::kPreserveSourceRegister); 1580 subp(dst, kScratchRegister); 1581 } else if (constraints & SmiOperationConstraint::kBailoutOnOverflow) { 1582 if (constraints & SmiOperationConstraint::kPreserveSourceRegister) { 1583 Label done; 1584 j(no_overflow, &done, Label::kNear); 1585 subp(dst, kScratchRegister); 1586 jmp(bailout_label, near_jump); 1587 bind(&done); 1588 } else { 1589 // Bailout if overflow without reserving src. 1590 j(overflow, bailout_label, near_jump); 1591 } 1592 } else { 1593 UNREACHABLE(); 1594 } 1595 } else { 1596 DCHECK(constraints & SmiOperationConstraint::kPreserveSourceRegister); 1597 DCHECK(constraints & SmiOperationConstraint::kBailoutOnOverflow); 1598 LoadSmiConstant(dst, constant); 1599 addp(dst, src); 1600 j(overflow, bailout_label, near_jump); 1601 } 1602 } 1603 1604 1605 void MacroAssembler::SmiSubConstant(Register dst, Register src, Smi* constant) { 1606 if (constant->value() == 0) { 1607 if (!dst.is(src)) { 1608 movp(dst, src); 1609 } 1610 } else if (dst.is(src)) { 1611 DCHECK(!dst.is(kScratchRegister)); 1612 Register constant_reg = GetSmiConstant(constant); 1613 subp(dst, constant_reg); 1614 } else { 1615 if (constant->value() == Smi::kMinValue) { 1616 LoadSmiConstant(dst, constant); 1617 // Adding and subtracting the min-value gives the same result, it only 1618 // differs on the overflow bit, which we don't check here. 1619 addp(dst, src); 1620 } else { 1621 // Subtract by adding the negation. 1622 LoadSmiConstant(dst, Smi::FromInt(-constant->value())); 1623 addp(dst, src); 1624 } 1625 } 1626 } 1627 1628 1629 void MacroAssembler::SmiSubConstant(Register dst, Register src, Smi* constant, 1630 SmiOperationConstraints constraints, 1631 Label* bailout_label, 1632 Label::Distance near_jump) { 1633 if (constant->value() == 0) { 1634 if (!dst.is(src)) { 1635 movp(dst, src); 1636 } 1637 } else if (dst.is(src)) { 1638 DCHECK(!dst.is(kScratchRegister)); 1639 LoadSmiConstant(kScratchRegister, constant); 1640 subp(dst, kScratchRegister); 1641 if (constraints & SmiOperationConstraint::kBailoutOnNoOverflow) { 1642 j(no_overflow, bailout_label, near_jump); 1643 DCHECK(constraints & SmiOperationConstraint::kPreserveSourceRegister); 1644 addp(dst, kScratchRegister); 1645 } else if (constraints & SmiOperationConstraint::kBailoutOnOverflow) { 1646 if (constraints & SmiOperationConstraint::kPreserveSourceRegister) { 1647 Label done; 1648 j(no_overflow, &done, Label::kNear); 1649 addp(dst, kScratchRegister); 1650 jmp(bailout_label, near_jump); 1651 bind(&done); 1652 } else { 1653 // Bailout if overflow without reserving src. 1654 j(overflow, bailout_label, near_jump); 1655 } 1656 } else { 1657 UNREACHABLE(); 1658 } 1659 } else { 1660 DCHECK(constraints & SmiOperationConstraint::kPreserveSourceRegister); 1661 DCHECK(constraints & SmiOperationConstraint::kBailoutOnOverflow); 1662 if (constant->value() == Smi::kMinValue) { 1663 DCHECK(!dst.is(kScratchRegister)); 1664 movp(dst, src); 1665 LoadSmiConstant(kScratchRegister, constant); 1666 subp(dst, kScratchRegister); 1667 j(overflow, bailout_label, near_jump); 1668 } else { 1669 // Subtract by adding the negation. 1670 LoadSmiConstant(dst, Smi::FromInt(-(constant->value()))); 1671 addp(dst, src); 1672 j(overflow, bailout_label, near_jump); 1673 } 1674 } 1675 } 1676 1677 1678 void MacroAssembler::SmiNeg(Register dst, 1679 Register src, 1680 Label* on_smi_result, 1681 Label::Distance near_jump) { 1682 if (dst.is(src)) { 1683 DCHECK(!dst.is(kScratchRegister)); 1684 movp(kScratchRegister, src); 1685 negp(dst); // Low 32 bits are retained as zero by negation. 1686 // Test if result is zero or Smi::kMinValue. 1687 cmpp(dst, kScratchRegister); 1688 j(not_equal, on_smi_result, near_jump); 1689 movp(src, kScratchRegister); 1690 } else { 1691 movp(dst, src); 1692 negp(dst); 1693 cmpp(dst, src); 1694 // If the result is zero or Smi::kMinValue, negation failed to create a smi. 1695 j(not_equal, on_smi_result, near_jump); 1696 } 1697 } 1698 1699 1700 template<class T> 1701 static void SmiAddHelper(MacroAssembler* masm, 1702 Register dst, 1703 Register src1, 1704 T src2, 1705 Label* on_not_smi_result, 1706 Label::Distance near_jump) { 1707 if (dst.is(src1)) { 1708 Label done; 1709 masm->addp(dst, src2); 1710 masm->j(no_overflow, &done, Label::kNear); 1711 // Restore src1. 1712 masm->subp(dst, src2); 1713 masm->jmp(on_not_smi_result, near_jump); 1714 masm->bind(&done); 1715 } else { 1716 masm->movp(dst, src1); 1717 masm->addp(dst, src2); 1718 masm->j(overflow, on_not_smi_result, near_jump); 1719 } 1720 } 1721 1722 1723 void MacroAssembler::SmiAdd(Register dst, 1724 Register src1, 1725 Register src2, 1726 Label* on_not_smi_result, 1727 Label::Distance near_jump) { 1728 DCHECK_NOT_NULL(on_not_smi_result); 1729 DCHECK(!dst.is(src2)); 1730 SmiAddHelper<Register>(this, dst, src1, src2, on_not_smi_result, near_jump); 1731 } 1732 1733 1734 void MacroAssembler::SmiAdd(Register dst, 1735 Register src1, 1736 const Operand& src2, 1737 Label* on_not_smi_result, 1738 Label::Distance near_jump) { 1739 DCHECK_NOT_NULL(on_not_smi_result); 1740 DCHECK(!src2.AddressUsesRegister(dst)); 1741 SmiAddHelper<Operand>(this, dst, src1, src2, on_not_smi_result, near_jump); 1742 } 1743 1744 1745 void MacroAssembler::SmiAdd(Register dst, 1746 Register src1, 1747 Register src2) { 1748 // No overflow checking. Use only when it's known that 1749 // overflowing is impossible. 1750 if (!dst.is(src1)) { 1751 if (emit_debug_code()) { 1752 movp(kScratchRegister, src1); 1753 addp(kScratchRegister, src2); 1754 Check(no_overflow, kSmiAdditionOverflow); 1755 } 1756 leap(dst, Operand(src1, src2, times_1, 0)); 1757 } else { 1758 addp(dst, src2); 1759 Assert(no_overflow, kSmiAdditionOverflow); 1760 } 1761 } 1762 1763 1764 template<class T> 1765 static void SmiSubHelper(MacroAssembler* masm, 1766 Register dst, 1767 Register src1, 1768 T src2, 1769 Label* on_not_smi_result, 1770 Label::Distance near_jump) { 1771 if (dst.is(src1)) { 1772 Label done; 1773 masm->subp(dst, src2); 1774 masm->j(no_overflow, &done, Label::kNear); 1775 // Restore src1. 1776 masm->addp(dst, src2); 1777 masm->jmp(on_not_smi_result, near_jump); 1778 masm->bind(&done); 1779 } else { 1780 masm->movp(dst, src1); 1781 masm->subp(dst, src2); 1782 masm->j(overflow, on_not_smi_result, near_jump); 1783 } 1784 } 1785 1786 1787 void MacroAssembler::SmiSub(Register dst, 1788 Register src1, 1789 Register src2, 1790 Label* on_not_smi_result, 1791 Label::Distance near_jump) { 1792 DCHECK_NOT_NULL(on_not_smi_result); 1793 DCHECK(!dst.is(src2)); 1794 SmiSubHelper<Register>(this, dst, src1, src2, on_not_smi_result, near_jump); 1795 } 1796 1797 1798 void MacroAssembler::SmiSub(Register dst, 1799 Register src1, 1800 const Operand& src2, 1801 Label* on_not_smi_result, 1802 Label::Distance near_jump) { 1803 DCHECK_NOT_NULL(on_not_smi_result); 1804 DCHECK(!src2.AddressUsesRegister(dst)); 1805 SmiSubHelper<Operand>(this, dst, src1, src2, on_not_smi_result, near_jump); 1806 } 1807 1808 1809 template<class T> 1810 static void SmiSubNoOverflowHelper(MacroAssembler* masm, 1811 Register dst, 1812 Register src1, 1813 T src2) { 1814 // No overflow checking. Use only when it's known that 1815 // overflowing is impossible (e.g., subtracting two positive smis). 1816 if (!dst.is(src1)) { 1817 masm->movp(dst, src1); 1818 } 1819 masm->subp(dst, src2); 1820 masm->Assert(no_overflow, kSmiSubtractionOverflow); 1821 } 1822 1823 1824 void MacroAssembler::SmiSub(Register dst, Register src1, Register src2) { 1825 DCHECK(!dst.is(src2)); 1826 SmiSubNoOverflowHelper<Register>(this, dst, src1, src2); 1827 } 1828 1829 1830 void MacroAssembler::SmiSub(Register dst, 1831 Register src1, 1832 const Operand& src2) { 1833 SmiSubNoOverflowHelper<Operand>(this, dst, src1, src2); 1834 } 1835 1836 1837 void MacroAssembler::SmiMul(Register dst, 1838 Register src1, 1839 Register src2, 1840 Label* on_not_smi_result, 1841 Label::Distance near_jump) { 1842 DCHECK(!dst.is(src2)); 1843 DCHECK(!dst.is(kScratchRegister)); 1844 DCHECK(!src1.is(kScratchRegister)); 1845 DCHECK(!src2.is(kScratchRegister)); 1846 1847 if (dst.is(src1)) { 1848 Label failure, zero_correct_result; 1849 movp(kScratchRegister, src1); // Create backup for later testing. 1850 SmiToInteger64(dst, src1); 1851 imulp(dst, src2); 1852 j(overflow, &failure, Label::kNear); 1853 1854 // Check for negative zero result. If product is zero, and one 1855 // argument is negative, go to slow case. 1856 Label correct_result; 1857 testp(dst, dst); 1858 j(not_zero, &correct_result, Label::kNear); 1859 1860 movp(dst, kScratchRegister); 1861 xorp(dst, src2); 1862 // Result was positive zero. 1863 j(positive, &zero_correct_result, Label::kNear); 1864 1865 bind(&failure); // Reused failure exit, restores src1. 1866 movp(src1, kScratchRegister); 1867 jmp(on_not_smi_result, near_jump); 1868 1869 bind(&zero_correct_result); 1870 Set(dst, 0); 1871 1872 bind(&correct_result); 1873 } else { 1874 SmiToInteger64(dst, src1); 1875 imulp(dst, src2); 1876 j(overflow, on_not_smi_result, near_jump); 1877 // Check for negative zero result. If product is zero, and one 1878 // argument is negative, go to slow case. 1879 Label correct_result; 1880 testp(dst, dst); 1881 j(not_zero, &correct_result, Label::kNear); 1882 // One of src1 and src2 is zero, the check whether the other is 1883 // negative. 1884 movp(kScratchRegister, src1); 1885 xorp(kScratchRegister, src2); 1886 j(negative, on_not_smi_result, near_jump); 1887 bind(&correct_result); 1888 } 1889 } 1890 1891 1892 void MacroAssembler::SmiDiv(Register dst, 1893 Register src1, 1894 Register src2, 1895 Label* on_not_smi_result, 1896 Label::Distance near_jump) { 1897 DCHECK(!src1.is(kScratchRegister)); 1898 DCHECK(!src2.is(kScratchRegister)); 1899 DCHECK(!dst.is(kScratchRegister)); 1900 DCHECK(!src2.is(rax)); 1901 DCHECK(!src2.is(rdx)); 1902 DCHECK(!src1.is(rdx)); 1903 1904 // Check for 0 divisor (result is +/-Infinity). 1905 testp(src2, src2); 1906 j(zero, on_not_smi_result, near_jump); 1907 1908 if (src1.is(rax)) { 1909 movp(kScratchRegister, src1); 1910 } 1911 SmiToInteger32(rax, src1); 1912 // We need to rule out dividing Smi::kMinValue by -1, since that would 1913 // overflow in idiv and raise an exception. 1914 // We combine this with negative zero test (negative zero only happens 1915 // when dividing zero by a negative number). 1916 1917 // We overshoot a little and go to slow case if we divide min-value 1918 // by any negative value, not just -1. 1919 Label safe_div; 1920 testl(rax, Immediate(~Smi::kMinValue)); 1921 j(not_zero, &safe_div, Label::kNear); 1922 testp(src2, src2); 1923 if (src1.is(rax)) { 1924 j(positive, &safe_div, Label::kNear); 1925 movp(src1, kScratchRegister); 1926 jmp(on_not_smi_result, near_jump); 1927 } else { 1928 j(negative, on_not_smi_result, near_jump); 1929 } 1930 bind(&safe_div); 1931 1932 SmiToInteger32(src2, src2); 1933 // Sign extend src1 into edx:eax. 1934 cdq(); 1935 idivl(src2); 1936 Integer32ToSmi(src2, src2); 1937 // Check that the remainder is zero. 1938 testl(rdx, rdx); 1939 if (src1.is(rax)) { 1940 Label smi_result; 1941 j(zero, &smi_result, Label::kNear); 1942 movp(src1, kScratchRegister); 1943 jmp(on_not_smi_result, near_jump); 1944 bind(&smi_result); 1945 } else { 1946 j(not_zero, on_not_smi_result, near_jump); 1947 } 1948 if (!dst.is(src1) && src1.is(rax)) { 1949 movp(src1, kScratchRegister); 1950 } 1951 Integer32ToSmi(dst, rax); 1952 } 1953 1954 1955 void MacroAssembler::SmiMod(Register dst, 1956 Register src1, 1957 Register src2, 1958 Label* on_not_smi_result, 1959 Label::Distance near_jump) { 1960 DCHECK(!dst.is(kScratchRegister)); 1961 DCHECK(!src1.is(kScratchRegister)); 1962 DCHECK(!src2.is(kScratchRegister)); 1963 DCHECK(!src2.is(rax)); 1964 DCHECK(!src2.is(rdx)); 1965 DCHECK(!src1.is(rdx)); 1966 DCHECK(!src1.is(src2)); 1967 1968 testp(src2, src2); 1969 j(zero, on_not_smi_result, near_jump); 1970 1971 if (src1.is(rax)) { 1972 movp(kScratchRegister, src1); 1973 } 1974 SmiToInteger32(rax, src1); 1975 SmiToInteger32(src2, src2); 1976 1977 // Test for the edge case of dividing Smi::kMinValue by -1 (will overflow). 1978 Label safe_div; 1979 cmpl(rax, Immediate(Smi::kMinValue)); 1980 j(not_equal, &safe_div, Label::kNear); 1981 cmpl(src2, Immediate(-1)); 1982 j(not_equal, &safe_div, Label::kNear); 1983 // Retag inputs and go slow case. 1984 Integer32ToSmi(src2, src2); 1985 if (src1.is(rax)) { 1986 movp(src1, kScratchRegister); 1987 } 1988 jmp(on_not_smi_result, near_jump); 1989 bind(&safe_div); 1990 1991 // Sign extend eax into edx:eax. 1992 cdq(); 1993 idivl(src2); 1994 // Restore smi tags on inputs. 1995 Integer32ToSmi(src2, src2); 1996 if (src1.is(rax)) { 1997 movp(src1, kScratchRegister); 1998 } 1999 // Check for a negative zero result. If the result is zero, and the 2000 // dividend is negative, go slow to return a floating point negative zero. 2001 Label smi_result; 2002 testl(rdx, rdx); 2003 j(not_zero, &smi_result, Label::kNear); 2004 testp(src1, src1); 2005 j(negative, on_not_smi_result, near_jump); 2006 bind(&smi_result); 2007 Integer32ToSmi(dst, rdx); 2008 } 2009 2010 2011 void MacroAssembler::SmiNot(Register dst, Register src) { 2012 DCHECK(!dst.is(kScratchRegister)); 2013 DCHECK(!src.is(kScratchRegister)); 2014 if (SmiValuesAre32Bits()) { 2015 // Set tag and padding bits before negating, so that they are zero 2016 // afterwards. 2017 movl(kScratchRegister, Immediate(~0)); 2018 } else { 2019 DCHECK(SmiValuesAre31Bits()); 2020 movl(kScratchRegister, Immediate(1)); 2021 } 2022 if (dst.is(src)) { 2023 xorp(dst, kScratchRegister); 2024 } else { 2025 leap(dst, Operand(src, kScratchRegister, times_1, 0)); 2026 } 2027 notp(dst); 2028 } 2029 2030 2031 void MacroAssembler::SmiAnd(Register dst, Register src1, Register src2) { 2032 DCHECK(!dst.is(src2)); 2033 if (!dst.is(src1)) { 2034 movp(dst, src1); 2035 } 2036 andp(dst, src2); 2037 } 2038 2039 2040 void MacroAssembler::SmiAndConstant(Register dst, Register src, Smi* constant) { 2041 if (constant->value() == 0) { 2042 Set(dst, 0); 2043 } else if (dst.is(src)) { 2044 DCHECK(!dst.is(kScratchRegister)); 2045 Register constant_reg = GetSmiConstant(constant); 2046 andp(dst, constant_reg); 2047 } else { 2048 LoadSmiConstant(dst, constant); 2049 andp(dst, src); 2050 } 2051 } 2052 2053 2054 void MacroAssembler::SmiOr(Register dst, Register src1, Register src2) { 2055 if (!dst.is(src1)) { 2056 DCHECK(!src1.is(src2)); 2057 movp(dst, src1); 2058 } 2059 orp(dst, src2); 2060 } 2061 2062 2063 void MacroAssembler::SmiOrConstant(Register dst, Register src, Smi* constant) { 2064 if (dst.is(src)) { 2065 DCHECK(!dst.is(kScratchRegister)); 2066 Register constant_reg = GetSmiConstant(constant); 2067 orp(dst, constant_reg); 2068 } else { 2069 LoadSmiConstant(dst, constant); 2070 orp(dst, src); 2071 } 2072 } 2073 2074 2075 void MacroAssembler::SmiXor(Register dst, Register src1, Register src2) { 2076 if (!dst.is(src1)) { 2077 DCHECK(!src1.is(src2)); 2078 movp(dst, src1); 2079 } 2080 xorp(dst, src2); 2081 } 2082 2083 2084 void MacroAssembler::SmiXorConstant(Register dst, Register src, Smi* constant) { 2085 if (dst.is(src)) { 2086 DCHECK(!dst.is(kScratchRegister)); 2087 Register constant_reg = GetSmiConstant(constant); 2088 xorp(dst, constant_reg); 2089 } else { 2090 LoadSmiConstant(dst, constant); 2091 xorp(dst, src); 2092 } 2093 } 2094 2095 2096 void MacroAssembler::SmiShiftArithmeticRightConstant(Register dst, 2097 Register src, 2098 int shift_value) { 2099 DCHECK(is_uint5(shift_value)); 2100 if (shift_value > 0) { 2101 if (dst.is(src)) { 2102 sarp(dst, Immediate(shift_value + kSmiShift)); 2103 shlp(dst, Immediate(kSmiShift)); 2104 } else { 2105 UNIMPLEMENTED(); // Not used. 2106 } 2107 } 2108 } 2109 2110 2111 void MacroAssembler::SmiShiftLeftConstant(Register dst, 2112 Register src, 2113 int shift_value, 2114 Label* on_not_smi_result, 2115 Label::Distance near_jump) { 2116 if (SmiValuesAre32Bits()) { 2117 if (!dst.is(src)) { 2118 movp(dst, src); 2119 } 2120 if (shift_value > 0) { 2121 // Shift amount specified by lower 5 bits, not six as the shl opcode. 2122 shlq(dst, Immediate(shift_value & 0x1f)); 2123 } 2124 } else { 2125 DCHECK(SmiValuesAre31Bits()); 2126 if (dst.is(src)) { 2127 UNIMPLEMENTED(); // Not used. 2128 } else { 2129 SmiToInteger32(dst, src); 2130 shll(dst, Immediate(shift_value)); 2131 JumpIfNotValidSmiValue(dst, on_not_smi_result, near_jump); 2132 Integer32ToSmi(dst, dst); 2133 } 2134 } 2135 } 2136 2137 2138 void MacroAssembler::SmiShiftLogicalRightConstant( 2139 Register dst, Register src, int shift_value, 2140 Label* on_not_smi_result, Label::Distance near_jump) { 2141 // Logic right shift interprets its result as an *unsigned* number. 2142 if (dst.is(src)) { 2143 UNIMPLEMENTED(); // Not used. 2144 } else { 2145 if (shift_value == 0) { 2146 testp(src, src); 2147 j(negative, on_not_smi_result, near_jump); 2148 } 2149 if (SmiValuesAre32Bits()) { 2150 movp(dst, src); 2151 shrp(dst, Immediate(shift_value + kSmiShift)); 2152 shlp(dst, Immediate(kSmiShift)); 2153 } else { 2154 DCHECK(SmiValuesAre31Bits()); 2155 SmiToInteger32(dst, src); 2156 shrp(dst, Immediate(shift_value)); 2157 JumpIfUIntNotValidSmiValue(dst, on_not_smi_result, near_jump); 2158 Integer32ToSmi(dst, dst); 2159 } 2160 } 2161 } 2162 2163 2164 void MacroAssembler::SmiShiftLeft(Register dst, 2165 Register src1, 2166 Register src2, 2167 Label* on_not_smi_result, 2168 Label::Distance near_jump) { 2169 if (SmiValuesAre32Bits()) { 2170 DCHECK(!dst.is(rcx)); 2171 if (!dst.is(src1)) { 2172 movp(dst, src1); 2173 } 2174 // Untag shift amount. 2175 SmiToInteger32(rcx, src2); 2176 // Shift amount specified by lower 5 bits, not six as the shl opcode. 2177 andp(rcx, Immediate(0x1f)); 2178 shlq_cl(dst); 2179 } else { 2180 DCHECK(SmiValuesAre31Bits()); 2181 DCHECK(!dst.is(kScratchRegister)); 2182 DCHECK(!src1.is(kScratchRegister)); 2183 DCHECK(!src2.is(kScratchRegister)); 2184 DCHECK(!dst.is(src2)); 2185 DCHECK(!dst.is(rcx)); 2186 2187 if (src1.is(rcx) || src2.is(rcx)) { 2188 movq(kScratchRegister, rcx); 2189 } 2190 if (dst.is(src1)) { 2191 UNIMPLEMENTED(); // Not used. 2192 } else { 2193 Label valid_result; 2194 SmiToInteger32(dst, src1); 2195 SmiToInteger32(rcx, src2); 2196 shll_cl(dst); 2197 JumpIfValidSmiValue(dst, &valid_result, Label::kNear); 2198 // As src1 or src2 could not be dst, we do not need to restore them for 2199 // clobbering dst. 2200 if (src1.is(rcx) || src2.is(rcx)) { 2201 if (src1.is(rcx)) { 2202 movq(src1, kScratchRegister); 2203 } else { 2204 movq(src2, kScratchRegister); 2205 } 2206 } 2207 jmp(on_not_smi_result, near_jump); 2208 bind(&valid_result); 2209 Integer32ToSmi(dst, dst); 2210 } 2211 } 2212 } 2213 2214 2215 void MacroAssembler::SmiShiftLogicalRight(Register dst, 2216 Register src1, 2217 Register src2, 2218 Label* on_not_smi_result, 2219 Label::Distance near_jump) { 2220 DCHECK(!dst.is(kScratchRegister)); 2221 DCHECK(!src1.is(kScratchRegister)); 2222 DCHECK(!src2.is(kScratchRegister)); 2223 DCHECK(!dst.is(src2)); 2224 DCHECK(!dst.is(rcx)); 2225 if (src1.is(rcx) || src2.is(rcx)) { 2226 movq(kScratchRegister, rcx); 2227 } 2228 if (dst.is(src1)) { 2229 UNIMPLEMENTED(); // Not used. 2230 } else { 2231 Label valid_result; 2232 SmiToInteger32(dst, src1); 2233 SmiToInteger32(rcx, src2); 2234 shrl_cl(dst); 2235 JumpIfUIntValidSmiValue(dst, &valid_result, Label::kNear); 2236 // As src1 or src2 could not be dst, we do not need to restore them for 2237 // clobbering dst. 2238 if (src1.is(rcx) || src2.is(rcx)) { 2239 if (src1.is(rcx)) { 2240 movq(src1, kScratchRegister); 2241 } else { 2242 movq(src2, kScratchRegister); 2243 } 2244 } 2245 jmp(on_not_smi_result, near_jump); 2246 bind(&valid_result); 2247 Integer32ToSmi(dst, dst); 2248 } 2249 } 2250 2251 2252 void MacroAssembler::SmiShiftArithmeticRight(Register dst, 2253 Register src1, 2254 Register src2) { 2255 DCHECK(!dst.is(kScratchRegister)); 2256 DCHECK(!src1.is(kScratchRegister)); 2257 DCHECK(!src2.is(kScratchRegister)); 2258 DCHECK(!dst.is(rcx)); 2259 2260 SmiToInteger32(rcx, src2); 2261 if (!dst.is(src1)) { 2262 movp(dst, src1); 2263 } 2264 SmiToInteger32(dst, dst); 2265 sarl_cl(dst); 2266 Integer32ToSmi(dst, dst); 2267 } 2268 2269 2270 void MacroAssembler::SelectNonSmi(Register dst, 2271 Register src1, 2272 Register src2, 2273 Label* on_not_smis, 2274 Label::Distance near_jump) { 2275 DCHECK(!dst.is(kScratchRegister)); 2276 DCHECK(!src1.is(kScratchRegister)); 2277 DCHECK(!src2.is(kScratchRegister)); 2278 DCHECK(!dst.is(src1)); 2279 DCHECK(!dst.is(src2)); 2280 // Both operands must not be smis. 2281 #ifdef DEBUG 2282 Condition not_both_smis = NegateCondition(CheckBothSmi(src1, src2)); 2283 Check(not_both_smis, kBothRegistersWereSmisInSelectNonSmi); 2284 #endif 2285 STATIC_ASSERT(kSmiTag == 0); 2286 DCHECK_EQ(static_cast<Smi*>(0), Smi::FromInt(0)); 2287 movl(kScratchRegister, Immediate(kSmiTagMask)); 2288 andp(kScratchRegister, src1); 2289 testl(kScratchRegister, src2); 2290 // If non-zero then both are smis. 2291 j(not_zero, on_not_smis, near_jump); 2292 2293 // Exactly one operand is a smi. 2294 DCHECK_EQ(1, static_cast<int>(kSmiTagMask)); 2295 // kScratchRegister still holds src1 & kSmiTag, which is either zero or one. 2296 subp(kScratchRegister, Immediate(1)); 2297 // If src1 is a smi, then scratch register all 1s, else it is all 0s. 2298 movp(dst, src1); 2299 xorp(dst, src2); 2300 andp(dst, kScratchRegister); 2301 // If src1 is a smi, dst holds src1 ^ src2, else it is zero. 2302 xorp(dst, src1); 2303 // If src1 is a smi, dst is src2, else it is src1, i.e., the non-smi. 2304 } 2305 2306 2307 SmiIndex MacroAssembler::SmiToIndex(Register dst, 2308 Register src, 2309 int shift) { 2310 if (SmiValuesAre32Bits()) { 2311 DCHECK(is_uint6(shift)); 2312 // There is a possible optimization if shift is in the range 60-63, but that 2313 // will (and must) never happen. 2314 if (!dst.is(src)) { 2315 movp(dst, src); 2316 } 2317 if (shift < kSmiShift) { 2318 sarp(dst, Immediate(kSmiShift - shift)); 2319 } else { 2320 shlp(dst, Immediate(shift - kSmiShift)); 2321 } 2322 return SmiIndex(dst, times_1); 2323 } else { 2324 DCHECK(SmiValuesAre31Bits()); 2325 DCHECK(shift >= times_1 && shift <= (static_cast<int>(times_8) + 1)); 2326 if (!dst.is(src)) { 2327 movp(dst, src); 2328 } 2329 // We have to sign extend the index register to 64-bit as the SMI might 2330 // be negative. 2331 movsxlq(dst, dst); 2332 if (shift == times_1) { 2333 sarq(dst, Immediate(kSmiShift)); 2334 return SmiIndex(dst, times_1); 2335 } 2336 return SmiIndex(dst, static_cast<ScaleFactor>(shift - 1)); 2337 } 2338 } 2339 2340 2341 SmiIndex MacroAssembler::SmiToNegativeIndex(Register dst, 2342 Register src, 2343 int shift) { 2344 if (SmiValuesAre32Bits()) { 2345 // Register src holds a positive smi. 2346 DCHECK(is_uint6(shift)); 2347 if (!dst.is(src)) { 2348 movp(dst, src); 2349 } 2350 negp(dst); 2351 if (shift < kSmiShift) { 2352 sarp(dst, Immediate(kSmiShift - shift)); 2353 } else { 2354 shlp(dst, Immediate(shift - kSmiShift)); 2355 } 2356 return SmiIndex(dst, times_1); 2357 } else { 2358 DCHECK(SmiValuesAre31Bits()); 2359 DCHECK(shift >= times_1 && shift <= (static_cast<int>(times_8) + 1)); 2360 if (!dst.is(src)) { 2361 movp(dst, src); 2362 } 2363 negq(dst); 2364 if (shift == times_1) { 2365 sarq(dst, Immediate(kSmiShift)); 2366 return SmiIndex(dst, times_1); 2367 } 2368 return SmiIndex(dst, static_cast<ScaleFactor>(shift - 1)); 2369 } 2370 } 2371 2372 2373 void MacroAssembler::AddSmiField(Register dst, const Operand& src) { 2374 if (SmiValuesAre32Bits()) { 2375 DCHECK_EQ(0, kSmiShift % kBitsPerByte); 2376 addl(dst, Operand(src, kSmiShift / kBitsPerByte)); 2377 } else { 2378 DCHECK(SmiValuesAre31Bits()); 2379 SmiToInteger32(kScratchRegister, src); 2380 addl(dst, kScratchRegister); 2381 } 2382 } 2383 2384 2385 void MacroAssembler::Push(Smi* source) { 2386 intptr_t smi = reinterpret_cast<intptr_t>(source); 2387 if (is_int32(smi)) { 2388 Push(Immediate(static_cast<int32_t>(smi))); 2389 } else { 2390 Register constant = GetSmiConstant(source); 2391 Push(constant); 2392 } 2393 } 2394 2395 2396 void MacroAssembler::PushRegisterAsTwoSmis(Register src, Register scratch) { 2397 DCHECK(!src.is(scratch)); 2398 movp(scratch, src); 2399 // High bits. 2400 shrp(src, Immediate(kPointerSize * kBitsPerByte - kSmiShift)); 2401 shlp(src, Immediate(kSmiShift)); 2402 Push(src); 2403 // Low bits. 2404 shlp(scratch, Immediate(kSmiShift)); 2405 Push(scratch); 2406 } 2407 2408 2409 void MacroAssembler::PopRegisterAsTwoSmis(Register dst, Register scratch) { 2410 DCHECK(!dst.is(scratch)); 2411 Pop(scratch); 2412 // Low bits. 2413 shrp(scratch, Immediate(kSmiShift)); 2414 Pop(dst); 2415 shrp(dst, Immediate(kSmiShift)); 2416 // High bits. 2417 shlp(dst, Immediate(kPointerSize * kBitsPerByte - kSmiShift)); 2418 orp(dst, scratch); 2419 } 2420 2421 2422 void MacroAssembler::Test(const Operand& src, Smi* source) { 2423 if (SmiValuesAre32Bits()) { 2424 testl(Operand(src, kIntSize), Immediate(source->value())); 2425 } else { 2426 DCHECK(SmiValuesAre31Bits()); 2427 testl(src, Immediate(source)); 2428 } 2429 } 2430 2431 2432 // ---------------------------------------------------------------------------- 2433 2434 2435 void MacroAssembler::JumpIfNotString(Register object, 2436 Register object_map, 2437 Label* not_string, 2438 Label::Distance near_jump) { 2439 Condition is_smi = CheckSmi(object); 2440 j(is_smi, not_string, near_jump); 2441 CmpObjectType(object, FIRST_NONSTRING_TYPE, object_map); 2442 j(above_equal, not_string, near_jump); 2443 } 2444 2445 2446 void MacroAssembler::JumpIfNotBothSequentialOneByteStrings( 2447 Register first_object, Register second_object, Register scratch1, 2448 Register scratch2, Label* on_fail, Label::Distance near_jump) { 2449 // Check that both objects are not smis. 2450 Condition either_smi = CheckEitherSmi(first_object, second_object); 2451 j(either_smi, on_fail, near_jump); 2452 2453 // Load instance type for both strings. 2454 movp(scratch1, FieldOperand(first_object, HeapObject::kMapOffset)); 2455 movp(scratch2, FieldOperand(second_object, HeapObject::kMapOffset)); 2456 movzxbl(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset)); 2457 movzxbl(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); 2458 2459 // Check that both are flat one-byte strings. 2460 DCHECK(kNotStringTag != 0); 2461 const int kFlatOneByteStringMask = 2462 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; 2463 const int kFlatOneByteStringTag = 2464 kStringTag | kOneByteStringTag | kSeqStringTag; 2465 2466 andl(scratch1, Immediate(kFlatOneByteStringMask)); 2467 andl(scratch2, Immediate(kFlatOneByteStringMask)); 2468 // Interleave the bits to check both scratch1 and scratch2 in one test. 2469 DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << 3)); 2470 leap(scratch1, Operand(scratch1, scratch2, times_8, 0)); 2471 cmpl(scratch1, 2472 Immediate(kFlatOneByteStringTag + (kFlatOneByteStringTag << 3))); 2473 j(not_equal, on_fail, near_jump); 2474 } 2475 2476 2477 void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte( 2478 Register instance_type, Register scratch, Label* failure, 2479 Label::Distance near_jump) { 2480 if (!scratch.is(instance_type)) { 2481 movl(scratch, instance_type); 2482 } 2483 2484 const int kFlatOneByteStringMask = 2485 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; 2486 2487 andl(scratch, Immediate(kFlatOneByteStringMask)); 2488 cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kOneByteStringTag)); 2489 j(not_equal, failure, near_jump); 2490 } 2491 2492 2493 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte( 2494 Register first_object_instance_type, Register second_object_instance_type, 2495 Register scratch1, Register scratch2, Label* on_fail, 2496 Label::Distance near_jump) { 2497 // Load instance type for both strings. 2498 movp(scratch1, first_object_instance_type); 2499 movp(scratch2, second_object_instance_type); 2500 2501 // Check that both are flat one-byte strings. 2502 DCHECK(kNotStringTag != 0); 2503 const int kFlatOneByteStringMask = 2504 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; 2505 const int kFlatOneByteStringTag = 2506 kStringTag | kOneByteStringTag | kSeqStringTag; 2507 2508 andl(scratch1, Immediate(kFlatOneByteStringMask)); 2509 andl(scratch2, Immediate(kFlatOneByteStringMask)); 2510 // Interleave the bits to check both scratch1 and scratch2 in one test. 2511 DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << 3)); 2512 leap(scratch1, Operand(scratch1, scratch2, times_8, 0)); 2513 cmpl(scratch1, 2514 Immediate(kFlatOneByteStringTag + (kFlatOneByteStringTag << 3))); 2515 j(not_equal, on_fail, near_jump); 2516 } 2517 2518 2519 template<class T> 2520 static void JumpIfNotUniqueNameHelper(MacroAssembler* masm, 2521 T operand_or_register, 2522 Label* not_unique_name, 2523 Label::Distance distance) { 2524 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); 2525 Label succeed; 2526 masm->testb(operand_or_register, 2527 Immediate(kIsNotStringMask | kIsNotInternalizedMask)); 2528 masm->j(zero, &succeed, Label::kNear); 2529 masm->cmpb(operand_or_register, Immediate(static_cast<uint8_t>(SYMBOL_TYPE))); 2530 masm->j(not_equal, not_unique_name, distance); 2531 2532 masm->bind(&succeed); 2533 } 2534 2535 2536 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Operand operand, 2537 Label* not_unique_name, 2538 Label::Distance distance) { 2539 JumpIfNotUniqueNameHelper<Operand>(this, operand, not_unique_name, distance); 2540 } 2541 2542 2543 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg, 2544 Label* not_unique_name, 2545 Label::Distance distance) { 2546 JumpIfNotUniqueNameHelper<Register>(this, reg, not_unique_name, distance); 2547 } 2548 2549 2550 void MacroAssembler::Move(Register dst, Register src) { 2551 if (!dst.is(src)) { 2552 movp(dst, src); 2553 } 2554 } 2555 2556 2557 void MacroAssembler::Move(Register dst, Handle<Object> source) { 2558 AllowDeferredHandleDereference smi_check; 2559 if (source->IsSmi()) { 2560 Move(dst, Smi::cast(*source)); 2561 } else { 2562 MoveHeapObject(dst, source); 2563 } 2564 } 2565 2566 2567 void MacroAssembler::Move(const Operand& dst, Handle<Object> source) { 2568 AllowDeferredHandleDereference smi_check; 2569 if (source->IsSmi()) { 2570 Move(dst, Smi::cast(*source)); 2571 } else { 2572 MoveHeapObject(kScratchRegister, source); 2573 movp(dst, kScratchRegister); 2574 } 2575 } 2576 2577 2578 void MacroAssembler::Move(XMMRegister dst, uint32_t src) { 2579 if (src == 0) { 2580 Xorpd(dst, dst); 2581 } else { 2582 unsigned pop = base::bits::CountPopulation32(src); 2583 DCHECK_NE(0u, pop); 2584 if (pop == 32) { 2585 Pcmpeqd(dst, dst); 2586 } else { 2587 movl(kScratchRegister, Immediate(src)); 2588 Movq(dst, kScratchRegister); 2589 } 2590 } 2591 } 2592 2593 2594 void MacroAssembler::Move(XMMRegister dst, uint64_t src) { 2595 if (src == 0) { 2596 Xorpd(dst, dst); 2597 } else { 2598 unsigned nlz = base::bits::CountLeadingZeros64(src); 2599 unsigned ntz = base::bits::CountTrailingZeros64(src); 2600 unsigned pop = base::bits::CountPopulation64(src); 2601 DCHECK_NE(0u, pop); 2602 if (pop == 64) { 2603 Pcmpeqd(dst, dst); 2604 } else if (pop + ntz == 64) { 2605 Pcmpeqd(dst, dst); 2606 Psllq(dst, ntz); 2607 } else if (pop + nlz == 64) { 2608 Pcmpeqd(dst, dst); 2609 Psrlq(dst, nlz); 2610 } else { 2611 uint32_t lower = static_cast<uint32_t>(src); 2612 uint32_t upper = static_cast<uint32_t>(src >> 32); 2613 if (upper == 0) { 2614 Move(dst, lower); 2615 } else { 2616 movq(kScratchRegister, src); 2617 Movq(dst, kScratchRegister); 2618 } 2619 } 2620 } 2621 } 2622 2623 2624 void MacroAssembler::Movaps(XMMRegister dst, XMMRegister src) { 2625 if (CpuFeatures::IsSupported(AVX)) { 2626 CpuFeatureScope scope(this, AVX); 2627 vmovaps(dst, src); 2628 } else { 2629 movaps(dst, src); 2630 } 2631 } 2632 2633 2634 void MacroAssembler::Movapd(XMMRegister dst, XMMRegister src) { 2635 if (CpuFeatures::IsSupported(AVX)) { 2636 CpuFeatureScope scope(this, AVX); 2637 vmovapd(dst, src); 2638 } else { 2639 movapd(dst, src); 2640 } 2641 } 2642 2643 2644 void MacroAssembler::Movsd(XMMRegister dst, XMMRegister src) { 2645 if (CpuFeatures::IsSupported(AVX)) { 2646 CpuFeatureScope scope(this, AVX); 2647 vmovsd(dst, dst, src); 2648 } else { 2649 movsd(dst, src); 2650 } 2651 } 2652 2653 2654 void MacroAssembler::Movsd(XMMRegister dst, const Operand& src) { 2655 if (CpuFeatures::IsSupported(AVX)) { 2656 CpuFeatureScope scope(this, AVX); 2657 vmovsd(dst, src); 2658 } else { 2659 movsd(dst, src); 2660 } 2661 } 2662 2663 2664 void MacroAssembler::Movsd(const Operand& dst, XMMRegister src) { 2665 if (CpuFeatures::IsSupported(AVX)) { 2666 CpuFeatureScope scope(this, AVX); 2667 vmovsd(dst, src); 2668 } else { 2669 movsd(dst, src); 2670 } 2671 } 2672 2673 2674 void MacroAssembler::Movss(XMMRegister dst, XMMRegister src) { 2675 if (CpuFeatures::IsSupported(AVX)) { 2676 CpuFeatureScope scope(this, AVX); 2677 vmovss(dst, dst, src); 2678 } else { 2679 movss(dst, src); 2680 } 2681 } 2682 2683 2684 void MacroAssembler::Movss(XMMRegister dst, const Operand& src) { 2685 if (CpuFeatures::IsSupported(AVX)) { 2686 CpuFeatureScope scope(this, AVX); 2687 vmovss(dst, src); 2688 } else { 2689 movss(dst, src); 2690 } 2691 } 2692 2693 2694 void MacroAssembler::Movss(const Operand& dst, XMMRegister src) { 2695 if (CpuFeatures::IsSupported(AVX)) { 2696 CpuFeatureScope scope(this, AVX); 2697 vmovss(dst, src); 2698 } else { 2699 movss(dst, src); 2700 } 2701 } 2702 2703 2704 void MacroAssembler::Movd(XMMRegister dst, Register src) { 2705 if (CpuFeatures::IsSupported(AVX)) { 2706 CpuFeatureScope scope(this, AVX); 2707 vmovd(dst, src); 2708 } else { 2709 movd(dst, src); 2710 } 2711 } 2712 2713 2714 void MacroAssembler::Movd(XMMRegister dst, const Operand& src) { 2715 if (CpuFeatures::IsSupported(AVX)) { 2716 CpuFeatureScope scope(this, AVX); 2717 vmovd(dst, src); 2718 } else { 2719 movd(dst, src); 2720 } 2721 } 2722 2723 2724 void MacroAssembler::Movd(Register dst, XMMRegister src) { 2725 if (CpuFeatures::IsSupported(AVX)) { 2726 CpuFeatureScope scope(this, AVX); 2727 vmovd(dst, src); 2728 } else { 2729 movd(dst, src); 2730 } 2731 } 2732 2733 2734 void MacroAssembler::Movq(XMMRegister dst, Register src) { 2735 if (CpuFeatures::IsSupported(AVX)) { 2736 CpuFeatureScope scope(this, AVX); 2737 vmovq(dst, src); 2738 } else { 2739 movq(dst, src); 2740 } 2741 } 2742 2743 2744 void MacroAssembler::Movq(Register dst, XMMRegister src) { 2745 if (CpuFeatures::IsSupported(AVX)) { 2746 CpuFeatureScope scope(this, AVX); 2747 vmovq(dst, src); 2748 } else { 2749 movq(dst, src); 2750 } 2751 } 2752 2753 2754 void MacroAssembler::Movmskpd(Register dst, XMMRegister src) { 2755 if (CpuFeatures::IsSupported(AVX)) { 2756 CpuFeatureScope scope(this, AVX); 2757 vmovmskpd(dst, src); 2758 } else { 2759 movmskpd(dst, src); 2760 } 2761 } 2762 2763 2764 void MacroAssembler::Roundss(XMMRegister dst, XMMRegister src, 2765 RoundingMode mode) { 2766 if (CpuFeatures::IsSupported(AVX)) { 2767 CpuFeatureScope scope(this, AVX); 2768 vroundss(dst, dst, src, mode); 2769 } else { 2770 roundss(dst, src, mode); 2771 } 2772 } 2773 2774 2775 void MacroAssembler::Roundsd(XMMRegister dst, XMMRegister src, 2776 RoundingMode mode) { 2777 if (CpuFeatures::IsSupported(AVX)) { 2778 CpuFeatureScope scope(this, AVX); 2779 vroundsd(dst, dst, src, mode); 2780 } else { 2781 roundsd(dst, src, mode); 2782 } 2783 } 2784 2785 2786 void MacroAssembler::Sqrtsd(XMMRegister dst, XMMRegister src) { 2787 if (CpuFeatures::IsSupported(AVX)) { 2788 CpuFeatureScope scope(this, AVX); 2789 vsqrtsd(dst, dst, src); 2790 } else { 2791 sqrtsd(dst, src); 2792 } 2793 } 2794 2795 2796 void MacroAssembler::Sqrtsd(XMMRegister dst, const Operand& src) { 2797 if (CpuFeatures::IsSupported(AVX)) { 2798 CpuFeatureScope scope(this, AVX); 2799 vsqrtsd(dst, dst, src); 2800 } else { 2801 sqrtsd(dst, src); 2802 } 2803 } 2804 2805 2806 void MacroAssembler::Ucomiss(XMMRegister src1, XMMRegister src2) { 2807 if (CpuFeatures::IsSupported(AVX)) { 2808 CpuFeatureScope scope(this, AVX); 2809 vucomiss(src1, src2); 2810 } else { 2811 ucomiss(src1, src2); 2812 } 2813 } 2814 2815 2816 void MacroAssembler::Ucomiss(XMMRegister src1, const Operand& src2) { 2817 if (CpuFeatures::IsSupported(AVX)) { 2818 CpuFeatureScope scope(this, AVX); 2819 vucomiss(src1, src2); 2820 } else { 2821 ucomiss(src1, src2); 2822 } 2823 } 2824 2825 2826 void MacroAssembler::Ucomisd(XMMRegister src1, XMMRegister src2) { 2827 if (CpuFeatures::IsSupported(AVX)) { 2828 CpuFeatureScope scope(this, AVX); 2829 vucomisd(src1, src2); 2830 } else { 2831 ucomisd(src1, src2); 2832 } 2833 } 2834 2835 2836 void MacroAssembler::Ucomisd(XMMRegister src1, const Operand& src2) { 2837 if (CpuFeatures::IsSupported(AVX)) { 2838 CpuFeatureScope scope(this, AVX); 2839 vucomisd(src1, src2); 2840 } else { 2841 ucomisd(src1, src2); 2842 } 2843 } 2844 2845 2846 void MacroAssembler::Cmp(Register dst, Handle<Object> source) { 2847 AllowDeferredHandleDereference smi_check; 2848 if (source->IsSmi()) { 2849 Cmp(dst, Smi::cast(*source)); 2850 } else { 2851 MoveHeapObject(kScratchRegister, source); 2852 cmpp(dst, kScratchRegister); 2853 } 2854 } 2855 2856 2857 void MacroAssembler::Cmp(const Operand& dst, Handle<Object> source) { 2858 AllowDeferredHandleDereference smi_check; 2859 if (source->IsSmi()) { 2860 Cmp(dst, Smi::cast(*source)); 2861 } else { 2862 MoveHeapObject(kScratchRegister, source); 2863 cmpp(dst, kScratchRegister); 2864 } 2865 } 2866 2867 2868 void MacroAssembler::Push(Handle<Object> source) { 2869 AllowDeferredHandleDereference smi_check; 2870 if (source->IsSmi()) { 2871 Push(Smi::cast(*source)); 2872 } else { 2873 MoveHeapObject(kScratchRegister, source); 2874 Push(kScratchRegister); 2875 } 2876 } 2877 2878 2879 void MacroAssembler::MoveHeapObject(Register result, 2880 Handle<Object> object) { 2881 AllowDeferredHandleDereference using_raw_address; 2882 DCHECK(object->IsHeapObject()); 2883 if (isolate()->heap()->InNewSpace(*object)) { 2884 Handle<Cell> cell = isolate()->factory()->NewCell(object); 2885 Move(result, cell, RelocInfo::CELL); 2886 movp(result, Operand(result, 0)); 2887 } else { 2888 Move(result, object, RelocInfo::EMBEDDED_OBJECT); 2889 } 2890 } 2891 2892 2893 void MacroAssembler::LoadGlobalCell(Register dst, Handle<Cell> cell) { 2894 if (dst.is(rax)) { 2895 AllowDeferredHandleDereference embedding_raw_address; 2896 load_rax(cell.location(), RelocInfo::CELL); 2897 } else { 2898 Move(dst, cell, RelocInfo::CELL); 2899 movp(dst, Operand(dst, 0)); 2900 } 2901 } 2902 2903 2904 void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell, 2905 Register scratch) { 2906 Move(scratch, cell, RelocInfo::EMBEDDED_OBJECT); 2907 cmpp(value, FieldOperand(scratch, WeakCell::kValueOffset)); 2908 } 2909 2910 2911 void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) { 2912 Move(value, cell, RelocInfo::EMBEDDED_OBJECT); 2913 movp(value, FieldOperand(value, WeakCell::kValueOffset)); 2914 } 2915 2916 2917 void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell, 2918 Label* miss) { 2919 GetWeakValue(value, cell); 2920 JumpIfSmi(value, miss); 2921 } 2922 2923 2924 void MacroAssembler::Drop(int stack_elements) { 2925 if (stack_elements > 0) { 2926 addp(rsp, Immediate(stack_elements * kPointerSize)); 2927 } 2928 } 2929 2930 2931 void MacroAssembler::DropUnderReturnAddress(int stack_elements, 2932 Register scratch) { 2933 DCHECK(stack_elements > 0); 2934 if (kPointerSize == kInt64Size && stack_elements == 1) { 2935 popq(MemOperand(rsp, 0)); 2936 return; 2937 } 2938 2939 PopReturnAddressTo(scratch); 2940 Drop(stack_elements); 2941 PushReturnAddressFrom(scratch); 2942 } 2943 2944 2945 void MacroAssembler::Push(Register src) { 2946 if (kPointerSize == kInt64Size) { 2947 pushq(src); 2948 } else { 2949 // x32 uses 64-bit push for rbp in the prologue. 2950 DCHECK(src.code() != rbp.code()); 2951 leal(rsp, Operand(rsp, -4)); 2952 movp(Operand(rsp, 0), src); 2953 } 2954 } 2955 2956 2957 void MacroAssembler::Push(const Operand& src) { 2958 if (kPointerSize == kInt64Size) { 2959 pushq(src); 2960 } else { 2961 movp(kScratchRegister, src); 2962 leal(rsp, Operand(rsp, -4)); 2963 movp(Operand(rsp, 0), kScratchRegister); 2964 } 2965 } 2966 2967 2968 void MacroAssembler::PushQuad(const Operand& src) { 2969 if (kPointerSize == kInt64Size) { 2970 pushq(src); 2971 } else { 2972 movp(kScratchRegister, src); 2973 pushq(kScratchRegister); 2974 } 2975 } 2976 2977 2978 void MacroAssembler::Push(Immediate value) { 2979 if (kPointerSize == kInt64Size) { 2980 pushq(value); 2981 } else { 2982 leal(rsp, Operand(rsp, -4)); 2983 movp(Operand(rsp, 0), value); 2984 } 2985 } 2986 2987 2988 void MacroAssembler::PushImm32(int32_t imm32) { 2989 if (kPointerSize == kInt64Size) { 2990 pushq_imm32(imm32); 2991 } else { 2992 leal(rsp, Operand(rsp, -4)); 2993 movp(Operand(rsp, 0), Immediate(imm32)); 2994 } 2995 } 2996 2997 2998 void MacroAssembler::Pop(Register dst) { 2999 if (kPointerSize == kInt64Size) { 3000 popq(dst); 3001 } else { 3002 // x32 uses 64-bit pop for rbp in the epilogue. 3003 DCHECK(dst.code() != rbp.code()); 3004 movp(dst, Operand(rsp, 0)); 3005 leal(rsp, Operand(rsp, 4)); 3006 } 3007 } 3008 3009 3010 void MacroAssembler::Pop(const Operand& dst) { 3011 if (kPointerSize == kInt64Size) { 3012 popq(dst); 3013 } else { 3014 Register scratch = dst.AddressUsesRegister(kScratchRegister) 3015 ? kRootRegister : kScratchRegister; 3016 movp(scratch, Operand(rsp, 0)); 3017 movp(dst, scratch); 3018 leal(rsp, Operand(rsp, 4)); 3019 if (scratch.is(kRootRegister)) { 3020 // Restore kRootRegister. 3021 InitializeRootRegister(); 3022 } 3023 } 3024 } 3025 3026 3027 void MacroAssembler::PopQuad(const Operand& dst) { 3028 if (kPointerSize == kInt64Size) { 3029 popq(dst); 3030 } else { 3031 popq(kScratchRegister); 3032 movp(dst, kScratchRegister); 3033 } 3034 } 3035 3036 3037 void MacroAssembler::LoadSharedFunctionInfoSpecialField(Register dst, 3038 Register base, 3039 int offset) { 3040 DCHECK(offset > SharedFunctionInfo::kLengthOffset && 3041 offset <= SharedFunctionInfo::kSize && 3042 (((offset - SharedFunctionInfo::kLengthOffset) / kIntSize) % 2 == 1)); 3043 if (kPointerSize == kInt64Size) { 3044 movsxlq(dst, FieldOperand(base, offset)); 3045 } else { 3046 movp(dst, FieldOperand(base, offset)); 3047 SmiToInteger32(dst, dst); 3048 } 3049 } 3050 3051 3052 void MacroAssembler::TestBitSharedFunctionInfoSpecialField(Register base, 3053 int offset, 3054 int bits) { 3055 DCHECK(offset > SharedFunctionInfo::kLengthOffset && 3056 offset <= SharedFunctionInfo::kSize && 3057 (((offset - SharedFunctionInfo::kLengthOffset) / kIntSize) % 2 == 1)); 3058 if (kPointerSize == kInt32Size) { 3059 // On x32, this field is represented by SMI. 3060 bits += kSmiShift; 3061 } 3062 int byte_offset = bits / kBitsPerByte; 3063 int bit_in_byte = bits & (kBitsPerByte - 1); 3064 testb(FieldOperand(base, offset + byte_offset), Immediate(1 << bit_in_byte)); 3065 } 3066 3067 3068 void MacroAssembler::Jump(ExternalReference ext) { 3069 LoadAddress(kScratchRegister, ext); 3070 jmp(kScratchRegister); 3071 } 3072 3073 3074 void MacroAssembler::Jump(const Operand& op) { 3075 if (kPointerSize == kInt64Size) { 3076 jmp(op); 3077 } else { 3078 movp(kScratchRegister, op); 3079 jmp(kScratchRegister); 3080 } 3081 } 3082 3083 3084 void MacroAssembler::Jump(Address destination, RelocInfo::Mode rmode) { 3085 Move(kScratchRegister, destination, rmode); 3086 jmp(kScratchRegister); 3087 } 3088 3089 3090 void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) { 3091 // TODO(X64): Inline this 3092 jmp(code_object, rmode); 3093 } 3094 3095 3096 int MacroAssembler::CallSize(ExternalReference ext) { 3097 // Opcode for call kScratchRegister is: Rex.B FF D4 (three bytes). 3098 return LoadAddressSize(ext) + 3099 Assembler::kCallScratchRegisterInstructionLength; 3100 } 3101 3102 3103 void MacroAssembler::Call(ExternalReference ext) { 3104 #ifdef DEBUG 3105 int end_position = pc_offset() + CallSize(ext); 3106 #endif 3107 LoadAddress(kScratchRegister, ext); 3108 call(kScratchRegister); 3109 #ifdef DEBUG 3110 CHECK_EQ(end_position, pc_offset()); 3111 #endif 3112 } 3113 3114 3115 void MacroAssembler::Call(const Operand& op) { 3116 if (kPointerSize == kInt64Size && !CpuFeatures::IsSupported(ATOM)) { 3117 call(op); 3118 } else { 3119 movp(kScratchRegister, op); 3120 call(kScratchRegister); 3121 } 3122 } 3123 3124 3125 void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) { 3126 #ifdef DEBUG 3127 int end_position = pc_offset() + CallSize(destination); 3128 #endif 3129 Move(kScratchRegister, destination, rmode); 3130 call(kScratchRegister); 3131 #ifdef DEBUG 3132 CHECK_EQ(pc_offset(), end_position); 3133 #endif 3134 } 3135 3136 3137 void MacroAssembler::Call(Handle<Code> code_object, 3138 RelocInfo::Mode rmode, 3139 TypeFeedbackId ast_id) { 3140 #ifdef DEBUG 3141 int end_position = pc_offset() + CallSize(code_object); 3142 #endif 3143 DCHECK(RelocInfo::IsCodeTarget(rmode) || 3144 rmode == RelocInfo::CODE_AGE_SEQUENCE); 3145 call(code_object, rmode, ast_id); 3146 #ifdef DEBUG 3147 CHECK_EQ(end_position, pc_offset()); 3148 #endif 3149 } 3150 3151 3152 void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) { 3153 if (imm8 == 0) { 3154 Movd(dst, src); 3155 return; 3156 } 3157 DCHECK_EQ(1, imm8); 3158 if (CpuFeatures::IsSupported(SSE4_1)) { 3159 CpuFeatureScope sse_scope(this, SSE4_1); 3160 pextrd(dst, src, imm8); 3161 return; 3162 } 3163 movq(dst, src); 3164 shrq(dst, Immediate(32)); 3165 } 3166 3167 3168 void MacroAssembler::Pinsrd(XMMRegister dst, Register src, int8_t imm8) { 3169 if (CpuFeatures::IsSupported(SSE4_1)) { 3170 CpuFeatureScope sse_scope(this, SSE4_1); 3171 pinsrd(dst, src, imm8); 3172 return; 3173 } 3174 Movd(xmm0, src); 3175 if (imm8 == 1) { 3176 punpckldq(dst, xmm0); 3177 } else { 3178 DCHECK_EQ(0, imm8); 3179 Movss(dst, xmm0); 3180 } 3181 } 3182 3183 3184 void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) { 3185 DCHECK(imm8 == 0 || imm8 == 1); 3186 if (CpuFeatures::IsSupported(SSE4_1)) { 3187 CpuFeatureScope sse_scope(this, SSE4_1); 3188 pinsrd(dst, src, imm8); 3189 return; 3190 } 3191 Movd(xmm0, src); 3192 if (imm8 == 1) { 3193 punpckldq(dst, xmm0); 3194 } else { 3195 DCHECK_EQ(0, imm8); 3196 Movss(dst, xmm0); 3197 } 3198 } 3199 3200 3201 void MacroAssembler::Lzcntl(Register dst, Register src) { 3202 if (CpuFeatures::IsSupported(LZCNT)) { 3203 CpuFeatureScope scope(this, LZCNT); 3204 lzcntl(dst, src); 3205 return; 3206 } 3207 Label not_zero_src; 3208 bsrl(dst, src); 3209 j(not_zero, ¬_zero_src, Label::kNear); 3210 Set(dst, 63); // 63^31 == 32 3211 bind(¬_zero_src); 3212 xorl(dst, Immediate(31)); // for x in [0..31], 31^x == 31 - x 3213 } 3214 3215 3216 void MacroAssembler::Lzcntl(Register dst, const Operand& src) { 3217 if (CpuFeatures::IsSupported(LZCNT)) { 3218 CpuFeatureScope scope(this, LZCNT); 3219 lzcntl(dst, src); 3220 return; 3221 } 3222 Label not_zero_src; 3223 bsrl(dst, src); 3224 j(not_zero, ¬_zero_src, Label::kNear); 3225 Set(dst, 63); // 63^31 == 32 3226 bind(¬_zero_src); 3227 xorl(dst, Immediate(31)); // for x in [0..31], 31^x == 31 - x 3228 } 3229 3230 3231 void MacroAssembler::Lzcntq(Register dst, Register src) { 3232 if (CpuFeatures::IsSupported(LZCNT)) { 3233 CpuFeatureScope scope(this, LZCNT); 3234 lzcntq(dst, src); 3235 return; 3236 } 3237 Label not_zero_src; 3238 bsrq(dst, src); 3239 j(not_zero, ¬_zero_src, Label::kNear); 3240 Set(dst, 127); // 127^63 == 64 3241 bind(¬_zero_src); 3242 xorl(dst, Immediate(63)); // for x in [0..63], 63^x == 63 - x 3243 } 3244 3245 3246 void MacroAssembler::Lzcntq(Register dst, const Operand& src) { 3247 if (CpuFeatures::IsSupported(LZCNT)) { 3248 CpuFeatureScope scope(this, LZCNT); 3249 lzcntq(dst, src); 3250 return; 3251 } 3252 Label not_zero_src; 3253 bsrq(dst, src); 3254 j(not_zero, ¬_zero_src, Label::kNear); 3255 Set(dst, 127); // 127^63 == 64 3256 bind(¬_zero_src); 3257 xorl(dst, Immediate(63)); // for x in [0..63], 63^x == 63 - x 3258 } 3259 3260 3261 void MacroAssembler::Tzcntq(Register dst, Register src) { 3262 if (CpuFeatures::IsSupported(BMI1)) { 3263 CpuFeatureScope scope(this, BMI1); 3264 tzcntq(dst, src); 3265 return; 3266 } 3267 Label not_zero_src; 3268 bsfq(dst, src); 3269 j(not_zero, ¬_zero_src, Label::kNear); 3270 // Define the result of tzcnt(0) separately, because bsf(0) is undefined. 3271 Set(dst, 64); 3272 bind(¬_zero_src); 3273 } 3274 3275 3276 void MacroAssembler::Tzcntq(Register dst, const Operand& src) { 3277 if (CpuFeatures::IsSupported(BMI1)) { 3278 CpuFeatureScope scope(this, BMI1); 3279 tzcntq(dst, src); 3280 return; 3281 } 3282 Label not_zero_src; 3283 bsfq(dst, src); 3284 j(not_zero, ¬_zero_src, Label::kNear); 3285 // Define the result of tzcnt(0) separately, because bsf(0) is undefined. 3286 Set(dst, 64); 3287 bind(¬_zero_src); 3288 } 3289 3290 3291 void MacroAssembler::Tzcntl(Register dst, Register src) { 3292 if (CpuFeatures::IsSupported(BMI1)) { 3293 CpuFeatureScope scope(this, BMI1); 3294 tzcntl(dst, src); 3295 return; 3296 } 3297 Label not_zero_src; 3298 bsfl(dst, src); 3299 j(not_zero, ¬_zero_src, Label::kNear); 3300 Set(dst, 32); // The result of tzcnt is 32 if src = 0. 3301 bind(¬_zero_src); 3302 } 3303 3304 3305 void MacroAssembler::Tzcntl(Register dst, const Operand& src) { 3306 if (CpuFeatures::IsSupported(BMI1)) { 3307 CpuFeatureScope scope(this, BMI1); 3308 tzcntl(dst, src); 3309 return; 3310 } 3311 Label not_zero_src; 3312 bsfl(dst, src); 3313 j(not_zero, ¬_zero_src, Label::kNear); 3314 Set(dst, 32); // The result of tzcnt is 32 if src = 0. 3315 bind(¬_zero_src); 3316 } 3317 3318 3319 void MacroAssembler::Popcntl(Register dst, Register src) { 3320 if (CpuFeatures::IsSupported(POPCNT)) { 3321 CpuFeatureScope scope(this, POPCNT); 3322 popcntl(dst, src); 3323 return; 3324 } 3325 UNREACHABLE(); 3326 } 3327 3328 3329 void MacroAssembler::Popcntl(Register dst, const Operand& src) { 3330 if (CpuFeatures::IsSupported(POPCNT)) { 3331 CpuFeatureScope scope(this, POPCNT); 3332 popcntl(dst, src); 3333 return; 3334 } 3335 UNREACHABLE(); 3336 } 3337 3338 3339 void MacroAssembler::Popcntq(Register dst, Register src) { 3340 if (CpuFeatures::IsSupported(POPCNT)) { 3341 CpuFeatureScope scope(this, POPCNT); 3342 popcntq(dst, src); 3343 return; 3344 } 3345 UNREACHABLE(); 3346 } 3347 3348 3349 void MacroAssembler::Popcntq(Register dst, const Operand& src) { 3350 if (CpuFeatures::IsSupported(POPCNT)) { 3351 CpuFeatureScope scope(this, POPCNT); 3352 popcntq(dst, src); 3353 return; 3354 } 3355 UNREACHABLE(); 3356 } 3357 3358 3359 void MacroAssembler::Pushad() { 3360 Push(rax); 3361 Push(rcx); 3362 Push(rdx); 3363 Push(rbx); 3364 // Not pushing rsp or rbp. 3365 Push(rsi); 3366 Push(rdi); 3367 Push(r8); 3368 Push(r9); 3369 // r10 is kScratchRegister. 3370 Push(r11); 3371 Push(r12); 3372 // r13 is kRootRegister. 3373 Push(r14); 3374 Push(r15); 3375 STATIC_ASSERT(12 == kNumSafepointSavedRegisters); 3376 // Use lea for symmetry with Popad. 3377 int sp_delta = 3378 (kNumSafepointRegisters - kNumSafepointSavedRegisters) * kPointerSize; 3379 leap(rsp, Operand(rsp, -sp_delta)); 3380 } 3381 3382 3383 void MacroAssembler::Popad() { 3384 // Popad must not change the flags, so use lea instead of addq. 3385 int sp_delta = 3386 (kNumSafepointRegisters - kNumSafepointSavedRegisters) * kPointerSize; 3387 leap(rsp, Operand(rsp, sp_delta)); 3388 Pop(r15); 3389 Pop(r14); 3390 Pop(r12); 3391 Pop(r11); 3392 Pop(r9); 3393 Pop(r8); 3394 Pop(rdi); 3395 Pop(rsi); 3396 Pop(rbx); 3397 Pop(rdx); 3398 Pop(rcx); 3399 Pop(rax); 3400 } 3401 3402 3403 void MacroAssembler::Dropad() { 3404 addp(rsp, Immediate(kNumSafepointRegisters * kPointerSize)); 3405 } 3406 3407 3408 // Order general registers are pushed by Pushad: 3409 // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15. 3410 const int 3411 MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = { 3412 0, 3413 1, 3414 2, 3415 3, 3416 -1, 3417 -1, 3418 4, 3419 5, 3420 6, 3421 7, 3422 -1, 3423 8, 3424 9, 3425 -1, 3426 10, 3427 11 3428 }; 3429 3430 3431 void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, 3432 const Immediate& imm) { 3433 movp(SafepointRegisterSlot(dst), imm); 3434 } 3435 3436 3437 void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) { 3438 movp(SafepointRegisterSlot(dst), src); 3439 } 3440 3441 3442 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { 3443 movp(dst, SafepointRegisterSlot(src)); 3444 } 3445 3446 3447 Operand MacroAssembler::SafepointRegisterSlot(Register reg) { 3448 return Operand(rsp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); 3449 } 3450 3451 3452 void MacroAssembler::PushStackHandler() { 3453 // Adjust this code if not the case. 3454 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); 3455 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 3456 3457 // Link the current handler as the next handler. 3458 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); 3459 Push(ExternalOperand(handler_address)); 3460 3461 // Set this new handler as the current one. 3462 movp(ExternalOperand(handler_address), rsp); 3463 } 3464 3465 3466 void MacroAssembler::PopStackHandler() { 3467 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 3468 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); 3469 Pop(ExternalOperand(handler_address)); 3470 addp(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); 3471 } 3472 3473 3474 void MacroAssembler::Ret() { 3475 ret(0); 3476 } 3477 3478 3479 void MacroAssembler::Ret(int bytes_dropped, Register scratch) { 3480 if (is_uint16(bytes_dropped)) { 3481 ret(bytes_dropped); 3482 } else { 3483 PopReturnAddressTo(scratch); 3484 addp(rsp, Immediate(bytes_dropped)); 3485 PushReturnAddressFrom(scratch); 3486 ret(0); 3487 } 3488 } 3489 3490 3491 void MacroAssembler::FCmp() { 3492 fucomip(); 3493 fstp(0); 3494 } 3495 3496 3497 void MacroAssembler::CmpObjectType(Register heap_object, 3498 InstanceType type, 3499 Register map) { 3500 movp(map, FieldOperand(heap_object, HeapObject::kMapOffset)); 3501 CmpInstanceType(map, type); 3502 } 3503 3504 3505 void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { 3506 cmpb(FieldOperand(map, Map::kInstanceTypeOffset), 3507 Immediate(static_cast<int8_t>(type))); 3508 } 3509 3510 3511 void MacroAssembler::CheckFastElements(Register map, 3512 Label* fail, 3513 Label::Distance distance) { 3514 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 3515 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 3516 STATIC_ASSERT(FAST_ELEMENTS == 2); 3517 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); 3518 cmpb(FieldOperand(map, Map::kBitField2Offset), 3519 Immediate(Map::kMaximumBitField2FastHoleyElementValue)); 3520 j(above, fail, distance); 3521 } 3522 3523 3524 void MacroAssembler::CheckFastObjectElements(Register map, 3525 Label* fail, 3526 Label::Distance distance) { 3527 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 3528 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 3529 STATIC_ASSERT(FAST_ELEMENTS == 2); 3530 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); 3531 cmpb(FieldOperand(map, Map::kBitField2Offset), 3532 Immediate(Map::kMaximumBitField2FastHoleySmiElementValue)); 3533 j(below_equal, fail, distance); 3534 cmpb(FieldOperand(map, Map::kBitField2Offset), 3535 Immediate(Map::kMaximumBitField2FastHoleyElementValue)); 3536 j(above, fail, distance); 3537 } 3538 3539 3540 void MacroAssembler::CheckFastSmiElements(Register map, 3541 Label* fail, 3542 Label::Distance distance) { 3543 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 3544 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 3545 cmpb(FieldOperand(map, Map::kBitField2Offset), 3546 Immediate(Map::kMaximumBitField2FastHoleySmiElementValue)); 3547 j(above, fail, distance); 3548 } 3549 3550 3551 void MacroAssembler::StoreNumberToDoubleElements( 3552 Register maybe_number, 3553 Register elements, 3554 Register index, 3555 XMMRegister xmm_scratch, 3556 Label* fail, 3557 int elements_offset) { 3558 Label smi_value, done; 3559 3560 JumpIfSmi(maybe_number, &smi_value, Label::kNear); 3561 3562 CheckMap(maybe_number, 3563 isolate()->factory()->heap_number_map(), 3564 fail, 3565 DONT_DO_SMI_CHECK); 3566 3567 // Double value, turn potential sNaN into qNaN. 3568 Move(xmm_scratch, 1.0); 3569 mulsd(xmm_scratch, FieldOperand(maybe_number, HeapNumber::kValueOffset)); 3570 jmp(&done, Label::kNear); 3571 3572 bind(&smi_value); 3573 // Value is a smi. convert to a double and store. 3574 // Preserve original value. 3575 SmiToInteger32(kScratchRegister, maybe_number); 3576 Cvtlsi2sd(xmm_scratch, kScratchRegister); 3577 bind(&done); 3578 Movsd(FieldOperand(elements, index, times_8, 3579 FixedDoubleArray::kHeaderSize - elements_offset), 3580 xmm_scratch); 3581 } 3582 3583 3584 void MacroAssembler::CompareMap(Register obj, Handle<Map> map) { 3585 Cmp(FieldOperand(obj, HeapObject::kMapOffset), map); 3586 } 3587 3588 3589 void MacroAssembler::CheckMap(Register obj, 3590 Handle<Map> map, 3591 Label* fail, 3592 SmiCheckType smi_check_type) { 3593 if (smi_check_type == DO_SMI_CHECK) { 3594 JumpIfSmi(obj, fail); 3595 } 3596 3597 CompareMap(obj, map); 3598 j(not_equal, fail); 3599 } 3600 3601 3602 void MacroAssembler::ClampUint8(Register reg) { 3603 Label done; 3604 testl(reg, Immediate(0xFFFFFF00)); 3605 j(zero, &done, Label::kNear); 3606 setcc(negative, reg); // 1 if negative, 0 if positive. 3607 decb(reg); // 0 if negative, 255 if positive. 3608 bind(&done); 3609 } 3610 3611 3612 void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg, 3613 XMMRegister temp_xmm_reg, 3614 Register result_reg) { 3615 Label done; 3616 Label conv_failure; 3617 Xorpd(temp_xmm_reg, temp_xmm_reg); 3618 Cvtsd2si(result_reg, input_reg); 3619 testl(result_reg, Immediate(0xFFFFFF00)); 3620 j(zero, &done, Label::kNear); 3621 cmpl(result_reg, Immediate(1)); 3622 j(overflow, &conv_failure, Label::kNear); 3623 movl(result_reg, Immediate(0)); 3624 setcc(sign, result_reg); 3625 subl(result_reg, Immediate(1)); 3626 andl(result_reg, Immediate(255)); 3627 jmp(&done, Label::kNear); 3628 bind(&conv_failure); 3629 Set(result_reg, 0); 3630 Ucomisd(input_reg, temp_xmm_reg); 3631 j(below, &done, Label::kNear); 3632 Set(result_reg, 255); 3633 bind(&done); 3634 } 3635 3636 3637 void MacroAssembler::LoadUint32(XMMRegister dst, 3638 Register src) { 3639 if (FLAG_debug_code) { 3640 cmpq(src, Immediate(0xffffffff)); 3641 Assert(below_equal, kInputGPRIsExpectedToHaveUpper32Cleared); 3642 } 3643 Cvtqsi2sd(dst, src); 3644 } 3645 3646 3647 void MacroAssembler::SlowTruncateToI(Register result_reg, 3648 Register input_reg, 3649 int offset) { 3650 DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true); 3651 call(stub.GetCode(), RelocInfo::CODE_TARGET); 3652 } 3653 3654 3655 void MacroAssembler::TruncateHeapNumberToI(Register result_reg, 3656 Register input_reg) { 3657 Label done; 3658 Movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); 3659 Cvttsd2siq(result_reg, xmm0); 3660 cmpq(result_reg, Immediate(1)); 3661 j(no_overflow, &done, Label::kNear); 3662 3663 // Slow case. 3664 if (input_reg.is(result_reg)) { 3665 subp(rsp, Immediate(kDoubleSize)); 3666 Movsd(MemOperand(rsp, 0), xmm0); 3667 SlowTruncateToI(result_reg, rsp, 0); 3668 addp(rsp, Immediate(kDoubleSize)); 3669 } else { 3670 SlowTruncateToI(result_reg, input_reg); 3671 } 3672 3673 bind(&done); 3674 // Keep our invariant that the upper 32 bits are zero. 3675 movl(result_reg, result_reg); 3676 } 3677 3678 3679 void MacroAssembler::TruncateDoubleToI(Register result_reg, 3680 XMMRegister input_reg) { 3681 Label done; 3682 Cvttsd2siq(result_reg, input_reg); 3683 cmpq(result_reg, Immediate(1)); 3684 j(no_overflow, &done, Label::kNear); 3685 3686 subp(rsp, Immediate(kDoubleSize)); 3687 Movsd(MemOperand(rsp, 0), input_reg); 3688 SlowTruncateToI(result_reg, rsp, 0); 3689 addp(rsp, Immediate(kDoubleSize)); 3690 3691 bind(&done); 3692 // Keep our invariant that the upper 32 bits are zero. 3693 movl(result_reg, result_reg); 3694 } 3695 3696 3697 void MacroAssembler::DoubleToI(Register result_reg, XMMRegister input_reg, 3698 XMMRegister scratch, 3699 MinusZeroMode minus_zero_mode, 3700 Label* lost_precision, Label* is_nan, 3701 Label* minus_zero, Label::Distance dst) { 3702 Cvttsd2si(result_reg, input_reg); 3703 Cvtlsi2sd(xmm0, result_reg); 3704 Ucomisd(xmm0, input_reg); 3705 j(not_equal, lost_precision, dst); 3706 j(parity_even, is_nan, dst); // NaN. 3707 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { 3708 Label done; 3709 // The integer converted back is equal to the original. We 3710 // only have to test if we got -0 as an input. 3711 testl(result_reg, result_reg); 3712 j(not_zero, &done, Label::kNear); 3713 Movmskpd(result_reg, input_reg); 3714 // Bit 0 contains the sign of the double in input_reg. 3715 // If input was positive, we are ok and return 0, otherwise 3716 // jump to minus_zero. 3717 andl(result_reg, Immediate(1)); 3718 j(not_zero, minus_zero, dst); 3719 bind(&done); 3720 } 3721 } 3722 3723 3724 void MacroAssembler::LoadInstanceDescriptors(Register map, 3725 Register descriptors) { 3726 movp(descriptors, FieldOperand(map, Map::kDescriptorsOffset)); 3727 } 3728 3729 3730 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { 3731 movl(dst, FieldOperand(map, Map::kBitField3Offset)); 3732 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); 3733 } 3734 3735 3736 void MacroAssembler::EnumLength(Register dst, Register map) { 3737 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0); 3738 movl(dst, FieldOperand(map, Map::kBitField3Offset)); 3739 andl(dst, Immediate(Map::EnumLengthBits::kMask)); 3740 Integer32ToSmi(dst, dst); 3741 } 3742 3743 3744 void MacroAssembler::LoadAccessor(Register dst, Register holder, 3745 int accessor_index, 3746 AccessorComponent accessor) { 3747 movp(dst, FieldOperand(holder, HeapObject::kMapOffset)); 3748 LoadInstanceDescriptors(dst, dst); 3749 movp(dst, FieldOperand(dst, DescriptorArray::GetValueOffset(accessor_index))); 3750 int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset 3751 : AccessorPair::kSetterOffset; 3752 movp(dst, FieldOperand(dst, offset)); 3753 } 3754 3755 3756 void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1, 3757 Register scratch2, Handle<WeakCell> cell, 3758 Handle<Code> success, 3759 SmiCheckType smi_check_type) { 3760 Label fail; 3761 if (smi_check_type == DO_SMI_CHECK) { 3762 JumpIfSmi(obj, &fail); 3763 } 3764 movq(scratch1, FieldOperand(obj, HeapObject::kMapOffset)); 3765 CmpWeakValue(scratch1, cell, scratch2); 3766 j(equal, success, RelocInfo::CODE_TARGET); 3767 bind(&fail); 3768 } 3769 3770 3771 void MacroAssembler::AssertNumber(Register object) { 3772 if (emit_debug_code()) { 3773 Label ok; 3774 Condition is_smi = CheckSmi(object); 3775 j(is_smi, &ok, Label::kNear); 3776 Cmp(FieldOperand(object, HeapObject::kMapOffset), 3777 isolate()->factory()->heap_number_map()); 3778 Check(equal, kOperandIsNotANumber); 3779 bind(&ok); 3780 } 3781 } 3782 3783 3784 void MacroAssembler::AssertNotSmi(Register object) { 3785 if (emit_debug_code()) { 3786 Condition is_smi = CheckSmi(object); 3787 Check(NegateCondition(is_smi), kOperandIsASmi); 3788 } 3789 } 3790 3791 3792 void MacroAssembler::AssertSmi(Register object) { 3793 if (emit_debug_code()) { 3794 Condition is_smi = CheckSmi(object); 3795 Check(is_smi, kOperandIsNotASmi); 3796 } 3797 } 3798 3799 3800 void MacroAssembler::AssertSmi(const Operand& object) { 3801 if (emit_debug_code()) { 3802 Condition is_smi = CheckSmi(object); 3803 Check(is_smi, kOperandIsNotASmi); 3804 } 3805 } 3806 3807 3808 void MacroAssembler::AssertZeroExtended(Register int32_register) { 3809 if (emit_debug_code()) { 3810 DCHECK(!int32_register.is(kScratchRegister)); 3811 movq(kScratchRegister, V8_INT64_C(0x0000000100000000)); 3812 cmpq(kScratchRegister, int32_register); 3813 Check(above_equal, k32BitValueInRegisterIsNotZeroExtended); 3814 } 3815 } 3816 3817 3818 void MacroAssembler::AssertString(Register object) { 3819 if (emit_debug_code()) { 3820 testb(object, Immediate(kSmiTagMask)); 3821 Check(not_equal, kOperandIsASmiAndNotAString); 3822 Push(object); 3823 movp(object, FieldOperand(object, HeapObject::kMapOffset)); 3824 CmpInstanceType(object, FIRST_NONSTRING_TYPE); 3825 Pop(object); 3826 Check(below, kOperandIsNotAString); 3827 } 3828 } 3829 3830 3831 void MacroAssembler::AssertName(Register object) { 3832 if (emit_debug_code()) { 3833 testb(object, Immediate(kSmiTagMask)); 3834 Check(not_equal, kOperandIsASmiAndNotAName); 3835 Push(object); 3836 movp(object, FieldOperand(object, HeapObject::kMapOffset)); 3837 CmpInstanceType(object, LAST_NAME_TYPE); 3838 Pop(object); 3839 Check(below_equal, kOperandIsNotAName); 3840 } 3841 } 3842 3843 3844 void MacroAssembler::AssertFunction(Register object) { 3845 if (emit_debug_code()) { 3846 testb(object, Immediate(kSmiTagMask)); 3847 Check(not_equal, kOperandIsASmiAndNotAFunction); 3848 Push(object); 3849 CmpObjectType(object, JS_FUNCTION_TYPE, object); 3850 Pop(object); 3851 Check(equal, kOperandIsNotAFunction); 3852 } 3853 } 3854 3855 3856 void MacroAssembler::AssertBoundFunction(Register object) { 3857 if (emit_debug_code()) { 3858 testb(object, Immediate(kSmiTagMask)); 3859 Check(not_equal, kOperandIsASmiAndNotABoundFunction); 3860 Push(object); 3861 CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object); 3862 Pop(object); 3863 Check(equal, kOperandIsNotABoundFunction); 3864 } 3865 } 3866 3867 3868 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) { 3869 if (emit_debug_code()) { 3870 Label done_checking; 3871 AssertNotSmi(object); 3872 Cmp(object, isolate()->factory()->undefined_value()); 3873 j(equal, &done_checking); 3874 Cmp(FieldOperand(object, 0), isolate()->factory()->allocation_site_map()); 3875 Assert(equal, kExpectedUndefinedOrCell); 3876 bind(&done_checking); 3877 } 3878 } 3879 3880 3881 void MacroAssembler::AssertRootValue(Register src, 3882 Heap::RootListIndex root_value_index, 3883 BailoutReason reason) { 3884 if (emit_debug_code()) { 3885 DCHECK(!src.is(kScratchRegister)); 3886 LoadRoot(kScratchRegister, root_value_index); 3887 cmpp(src, kScratchRegister); 3888 Check(equal, reason); 3889 } 3890 } 3891 3892 3893 3894 Condition MacroAssembler::IsObjectStringType(Register heap_object, 3895 Register map, 3896 Register instance_type) { 3897 movp(map, FieldOperand(heap_object, HeapObject::kMapOffset)); 3898 movzxbl(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); 3899 STATIC_ASSERT(kNotStringTag != 0); 3900 testb(instance_type, Immediate(kIsNotStringMask)); 3901 return zero; 3902 } 3903 3904 3905 Condition MacroAssembler::IsObjectNameType(Register heap_object, 3906 Register map, 3907 Register instance_type) { 3908 movp(map, FieldOperand(heap_object, HeapObject::kMapOffset)); 3909 movzxbl(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); 3910 cmpb(instance_type, Immediate(static_cast<uint8_t>(LAST_NAME_TYPE))); 3911 return below_equal; 3912 } 3913 3914 3915 void MacroAssembler::GetMapConstructor(Register result, Register map, 3916 Register temp) { 3917 Label done, loop; 3918 movp(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); 3919 bind(&loop); 3920 JumpIfSmi(result, &done, Label::kNear); 3921 CmpObjectType(result, MAP_TYPE, temp); 3922 j(not_equal, &done, Label::kNear); 3923 movp(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); 3924 jmp(&loop); 3925 bind(&done); 3926 } 3927 3928 3929 void MacroAssembler::TryGetFunctionPrototype(Register function, Register result, 3930 Label* miss) { 3931 // Get the prototype or initial map from the function. 3932 movp(result, 3933 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 3934 3935 // If the prototype or initial map is the hole, don't return it and 3936 // simply miss the cache instead. This will allow us to allocate a 3937 // prototype object on-demand in the runtime system. 3938 CompareRoot(result, Heap::kTheHoleValueRootIndex); 3939 j(equal, miss); 3940 3941 // If the function does not have an initial map, we're done. 3942 Label done; 3943 CmpObjectType(result, MAP_TYPE, kScratchRegister); 3944 j(not_equal, &done, Label::kNear); 3945 3946 // Get the prototype from the initial map. 3947 movp(result, FieldOperand(result, Map::kPrototypeOffset)); 3948 3949 // All done. 3950 bind(&done); 3951 } 3952 3953 3954 void MacroAssembler::SetCounter(StatsCounter* counter, int value) { 3955 if (FLAG_native_code_counters && counter->Enabled()) { 3956 Operand counter_operand = ExternalOperand(ExternalReference(counter)); 3957 movl(counter_operand, Immediate(value)); 3958 } 3959 } 3960 3961 3962 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { 3963 DCHECK(value > 0); 3964 if (FLAG_native_code_counters && counter->Enabled()) { 3965 Operand counter_operand = ExternalOperand(ExternalReference(counter)); 3966 if (value == 1) { 3967 incl(counter_operand); 3968 } else { 3969 addl(counter_operand, Immediate(value)); 3970 } 3971 } 3972 } 3973 3974 3975 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) { 3976 DCHECK(value > 0); 3977 if (FLAG_native_code_counters && counter->Enabled()) { 3978 Operand counter_operand = ExternalOperand(ExternalReference(counter)); 3979 if (value == 1) { 3980 decl(counter_operand); 3981 } else { 3982 subl(counter_operand, Immediate(value)); 3983 } 3984 } 3985 } 3986 3987 3988 void MacroAssembler::DebugBreak() { 3989 Set(rax, 0); // No arguments. 3990 LoadAddress(rbx, 3991 ExternalReference(Runtime::kHandleDebuggerStatement, isolate())); 3992 CEntryStub ces(isolate(), 1); 3993 DCHECK(AllowThisStubCall(&ces)); 3994 Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); 3995 } 3996 3997 3998 void MacroAssembler::InvokeFunction(Register function, 3999 Register new_target, 4000 const ParameterCount& actual, 4001 InvokeFlag flag, 4002 const CallWrapper& call_wrapper) { 4003 movp(rbx, FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); 4004 LoadSharedFunctionInfoSpecialField( 4005 rbx, rbx, SharedFunctionInfo::kFormalParameterCountOffset); 4006 4007 ParameterCount expected(rbx); 4008 InvokeFunction(function, new_target, expected, actual, flag, call_wrapper); 4009 } 4010 4011 4012 void MacroAssembler::InvokeFunction(Handle<JSFunction> function, 4013 const ParameterCount& expected, 4014 const ParameterCount& actual, 4015 InvokeFlag flag, 4016 const CallWrapper& call_wrapper) { 4017 Move(rdi, function); 4018 InvokeFunction(rdi, no_reg, expected, actual, flag, call_wrapper); 4019 } 4020 4021 4022 void MacroAssembler::InvokeFunction(Register function, 4023 Register new_target, 4024 const ParameterCount& expected, 4025 const ParameterCount& actual, 4026 InvokeFlag flag, 4027 const CallWrapper& call_wrapper) { 4028 DCHECK(function.is(rdi)); 4029 movp(rsi, FieldOperand(function, JSFunction::kContextOffset)); 4030 InvokeFunctionCode(rdi, new_target, expected, actual, flag, call_wrapper); 4031 } 4032 4033 4034 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, 4035 const ParameterCount& expected, 4036 const ParameterCount& actual, 4037 InvokeFlag flag, 4038 const CallWrapper& call_wrapper) { 4039 // You can't call a function without a valid frame. 4040 DCHECK(flag == JUMP_FUNCTION || has_frame()); 4041 DCHECK(function.is(rdi)); 4042 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(rdx)); 4043 4044 if (call_wrapper.NeedsDebugStepCheck()) { 4045 FloodFunctionIfStepping(function, new_target, expected, actual); 4046 } 4047 4048 // Clear the new.target register if not given. 4049 if (!new_target.is_valid()) { 4050 LoadRoot(rdx, Heap::kUndefinedValueRootIndex); 4051 } 4052 4053 Label done; 4054 bool definitely_mismatches = false; 4055 InvokePrologue(expected, 4056 actual, 4057 &done, 4058 &definitely_mismatches, 4059 flag, 4060 Label::kNear, 4061 call_wrapper); 4062 if (!definitely_mismatches) { 4063 // We call indirectly through the code field in the function to 4064 // allow recompilation to take effect without changing any of the 4065 // call sites. 4066 Operand code = FieldOperand(function, JSFunction::kCodeEntryOffset); 4067 if (flag == CALL_FUNCTION) { 4068 call_wrapper.BeforeCall(CallSize(code)); 4069 call(code); 4070 call_wrapper.AfterCall(); 4071 } else { 4072 DCHECK(flag == JUMP_FUNCTION); 4073 jmp(code); 4074 } 4075 bind(&done); 4076 } 4077 } 4078 4079 4080 void MacroAssembler::InvokePrologue(const ParameterCount& expected, 4081 const ParameterCount& actual, 4082 Label* done, 4083 bool* definitely_mismatches, 4084 InvokeFlag flag, 4085 Label::Distance near_jump, 4086 const CallWrapper& call_wrapper) { 4087 bool definitely_matches = false; 4088 *definitely_mismatches = false; 4089 Label invoke; 4090 if (expected.is_immediate()) { 4091 DCHECK(actual.is_immediate()); 4092 Set(rax, actual.immediate()); 4093 if (expected.immediate() == actual.immediate()) { 4094 definitely_matches = true; 4095 } else { 4096 if (expected.immediate() == 4097 SharedFunctionInfo::kDontAdaptArgumentsSentinel) { 4098 // Don't worry about adapting arguments for built-ins that 4099 // don't want that done. Skip adaption code by making it look 4100 // like we have a match between expected and actual number of 4101 // arguments. 4102 definitely_matches = true; 4103 } else { 4104 *definitely_mismatches = true; 4105 Set(rbx, expected.immediate()); 4106 } 4107 } 4108 } else { 4109 if (actual.is_immediate()) { 4110 // Expected is in register, actual is immediate. This is the 4111 // case when we invoke function values without going through the 4112 // IC mechanism. 4113 Set(rax, actual.immediate()); 4114 cmpp(expected.reg(), Immediate(actual.immediate())); 4115 j(equal, &invoke, Label::kNear); 4116 DCHECK(expected.reg().is(rbx)); 4117 } else if (!expected.reg().is(actual.reg())) { 4118 // Both expected and actual are in (different) registers. This 4119 // is the case when we invoke functions using call and apply. 4120 cmpp(expected.reg(), actual.reg()); 4121 j(equal, &invoke, Label::kNear); 4122 DCHECK(actual.reg().is(rax)); 4123 DCHECK(expected.reg().is(rbx)); 4124 } else { 4125 Move(rax, actual.reg()); 4126 } 4127 } 4128 4129 if (!definitely_matches) { 4130 Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline(); 4131 if (flag == CALL_FUNCTION) { 4132 call_wrapper.BeforeCall(CallSize(adaptor)); 4133 Call(adaptor, RelocInfo::CODE_TARGET); 4134 call_wrapper.AfterCall(); 4135 if (!*definitely_mismatches) { 4136 jmp(done, near_jump); 4137 } 4138 } else { 4139 Jump(adaptor, RelocInfo::CODE_TARGET); 4140 } 4141 bind(&invoke); 4142 } 4143 } 4144 4145 4146 void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target, 4147 const ParameterCount& expected, 4148 const ParameterCount& actual) { 4149 Label skip_flooding; 4150 ExternalReference step_in_enabled = 4151 ExternalReference::debug_step_in_enabled_address(isolate()); 4152 Operand step_in_enabled_operand = ExternalOperand(step_in_enabled); 4153 cmpb(step_in_enabled_operand, Immediate(0)); 4154 j(equal, &skip_flooding); 4155 { 4156 FrameScope frame(this, 4157 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); 4158 if (expected.is_reg()) { 4159 Integer32ToSmi(expected.reg(), expected.reg()); 4160 Push(expected.reg()); 4161 } 4162 if (actual.is_reg()) { 4163 Integer32ToSmi(actual.reg(), actual.reg()); 4164 Push(actual.reg()); 4165 } 4166 if (new_target.is_valid()) { 4167 Push(new_target); 4168 } 4169 Push(fun); 4170 Push(fun); 4171 CallRuntime(Runtime::kDebugPrepareStepInIfStepping, 1); 4172 Pop(fun); 4173 if (new_target.is_valid()) { 4174 Pop(new_target); 4175 } 4176 if (actual.is_reg()) { 4177 Pop(actual.reg()); 4178 SmiToInteger64(actual.reg(), actual.reg()); 4179 } 4180 if (expected.is_reg()) { 4181 Pop(expected.reg()); 4182 SmiToInteger64(expected.reg(), expected.reg()); 4183 } 4184 } 4185 bind(&skip_flooding); 4186 } 4187 4188 4189 void MacroAssembler::StubPrologue() { 4190 pushq(rbp); // Caller's frame pointer. 4191 movp(rbp, rsp); 4192 Push(rsi); // Callee's context. 4193 Push(Smi::FromInt(StackFrame::STUB)); 4194 } 4195 4196 4197 void MacroAssembler::Prologue(bool code_pre_aging) { 4198 PredictableCodeSizeScope predictible_code_size_scope(this, 4199 kNoCodeAgeSequenceLength); 4200 if (code_pre_aging) { 4201 // Pre-age the code. 4202 Call(isolate()->builtins()->MarkCodeAsExecutedOnce(), 4203 RelocInfo::CODE_AGE_SEQUENCE); 4204 Nop(kNoCodeAgeSequenceLength - Assembler::kShortCallInstructionLength); 4205 } else { 4206 pushq(rbp); // Caller's frame pointer. 4207 movp(rbp, rsp); 4208 Push(rsi); // Callee's context. 4209 Push(rdi); // Callee's JS function. 4210 } 4211 } 4212 4213 4214 void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) { 4215 movp(vector, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 4216 movp(vector, FieldOperand(vector, JSFunction::kSharedFunctionInfoOffset)); 4217 movp(vector, FieldOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset)); 4218 } 4219 4220 4221 void MacroAssembler::EnterFrame(StackFrame::Type type, 4222 bool load_constant_pool_pointer_reg) { 4223 // Out-of-line constant pool not implemented on x64. 4224 UNREACHABLE(); 4225 } 4226 4227 4228 void MacroAssembler::EnterFrame(StackFrame::Type type) { 4229 pushq(rbp); 4230 movp(rbp, rsp); 4231 Push(rsi); // Context. 4232 Push(Smi::FromInt(type)); 4233 Move(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT); 4234 Push(kScratchRegister); 4235 if (emit_debug_code()) { 4236 Move(kScratchRegister, 4237 isolate()->factory()->undefined_value(), 4238 RelocInfo::EMBEDDED_OBJECT); 4239 cmpp(Operand(rsp, 0), kScratchRegister); 4240 Check(not_equal, kCodeObjectNotProperlyPatched); 4241 } 4242 } 4243 4244 4245 void MacroAssembler::LeaveFrame(StackFrame::Type type) { 4246 if (emit_debug_code()) { 4247 Move(kScratchRegister, Smi::FromInt(type)); 4248 cmpp(Operand(rbp, StandardFrameConstants::kMarkerOffset), kScratchRegister); 4249 Check(equal, kStackFrameTypesMustMatch); 4250 } 4251 movp(rsp, rbp); 4252 popq(rbp); 4253 } 4254 4255 4256 void MacroAssembler::EnterExitFramePrologue(bool save_rax) { 4257 // Set up the frame structure on the stack. 4258 // All constants are relative to the frame pointer of the exit frame. 4259 DCHECK(ExitFrameConstants::kCallerSPDisplacement == 4260 kFPOnStackSize + kPCOnStackSize); 4261 DCHECK(ExitFrameConstants::kCallerPCOffset == kFPOnStackSize); 4262 DCHECK(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize); 4263 pushq(rbp); 4264 movp(rbp, rsp); 4265 4266 // Reserve room for entry stack pointer and push the code object. 4267 DCHECK(ExitFrameConstants::kSPOffset == -1 * kPointerSize); 4268 Push(Immediate(0)); // Saved entry sp, patched before call. 4269 Move(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT); 4270 Push(kScratchRegister); // Accessed from EditFrame::code_slot. 4271 4272 // Save the frame pointer and the context in top. 4273 if (save_rax) { 4274 movp(r14, rax); // Backup rax in callee-save register. 4275 } 4276 4277 Store(ExternalReference(Isolate::kCEntryFPAddress, isolate()), rbp); 4278 Store(ExternalReference(Isolate::kContextAddress, isolate()), rsi); 4279 Store(ExternalReference(Isolate::kCFunctionAddress, isolate()), rbx); 4280 } 4281 4282 4283 void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space, 4284 bool save_doubles) { 4285 #ifdef _WIN64 4286 const int kShadowSpace = 4; 4287 arg_stack_space += kShadowSpace; 4288 #endif 4289 // Optionally save all XMM registers. 4290 if (save_doubles) { 4291 int space = XMMRegister::kMaxNumRegisters * kDoubleSize + 4292 arg_stack_space * kRegisterSize; 4293 subp(rsp, Immediate(space)); 4294 int offset = -2 * kPointerSize; 4295 const RegisterConfiguration* config = 4296 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT); 4297 for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { 4298 DoubleRegister reg = 4299 DoubleRegister::from_code(config->GetAllocatableDoubleCode(i)); 4300 Movsd(Operand(rbp, offset - ((i + 1) * kDoubleSize)), reg); 4301 } 4302 } else if (arg_stack_space > 0) { 4303 subp(rsp, Immediate(arg_stack_space * kRegisterSize)); 4304 } 4305 4306 // Get the required frame alignment for the OS. 4307 const int kFrameAlignment = base::OS::ActivationFrameAlignment(); 4308 if (kFrameAlignment > 0) { 4309 DCHECK(base::bits::IsPowerOfTwo32(kFrameAlignment)); 4310 DCHECK(is_int8(kFrameAlignment)); 4311 andp(rsp, Immediate(-kFrameAlignment)); 4312 } 4313 4314 // Patch the saved entry sp. 4315 movp(Operand(rbp, ExitFrameConstants::kSPOffset), rsp); 4316 } 4317 4318 4319 void MacroAssembler::EnterExitFrame(int arg_stack_space, bool save_doubles) { 4320 EnterExitFramePrologue(true); 4321 4322 // Set up argv in callee-saved register r15. It is reused in LeaveExitFrame, 4323 // so it must be retained across the C-call. 4324 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; 4325 leap(r15, Operand(rbp, r14, times_pointer_size, offset)); 4326 4327 EnterExitFrameEpilogue(arg_stack_space, save_doubles); 4328 } 4329 4330 4331 void MacroAssembler::EnterApiExitFrame(int arg_stack_space) { 4332 EnterExitFramePrologue(false); 4333 EnterExitFrameEpilogue(arg_stack_space, false); 4334 } 4335 4336 4337 void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) { 4338 // Registers: 4339 // r15 : argv 4340 if (save_doubles) { 4341 int offset = -2 * kPointerSize; 4342 const RegisterConfiguration* config = 4343 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT); 4344 for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { 4345 DoubleRegister reg = 4346 DoubleRegister::from_code(config->GetAllocatableDoubleCode(i)); 4347 Movsd(reg, Operand(rbp, offset - ((i + 1) * kDoubleSize))); 4348 } 4349 } 4350 4351 if (pop_arguments) { 4352 // Get the return address from the stack and restore the frame pointer. 4353 movp(rcx, Operand(rbp, kFPOnStackSize)); 4354 movp(rbp, Operand(rbp, 0 * kPointerSize)); 4355 4356 // Drop everything up to and including the arguments and the receiver 4357 // from the caller stack. 4358 leap(rsp, Operand(r15, 1 * kPointerSize)); 4359 4360 PushReturnAddressFrom(rcx); 4361 } else { 4362 // Otherwise just leave the exit frame. 4363 leave(); 4364 } 4365 4366 LeaveExitFrameEpilogue(true); 4367 } 4368 4369 4370 void MacroAssembler::LeaveApiExitFrame(bool restore_context) { 4371 movp(rsp, rbp); 4372 popq(rbp); 4373 4374 LeaveExitFrameEpilogue(restore_context); 4375 } 4376 4377 4378 void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) { 4379 // Restore current context from top and clear it in debug mode. 4380 ExternalReference context_address(Isolate::kContextAddress, isolate()); 4381 Operand context_operand = ExternalOperand(context_address); 4382 if (restore_context) { 4383 movp(rsi, context_operand); 4384 } 4385 #ifdef DEBUG 4386 movp(context_operand, Immediate(0)); 4387 #endif 4388 4389 // Clear the top frame. 4390 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, 4391 isolate()); 4392 Operand c_entry_fp_operand = ExternalOperand(c_entry_fp_address); 4393 movp(c_entry_fp_operand, Immediate(0)); 4394 } 4395 4396 4397 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, 4398 Register scratch, 4399 Label* miss) { 4400 Label same_contexts; 4401 4402 DCHECK(!holder_reg.is(scratch)); 4403 DCHECK(!scratch.is(kScratchRegister)); 4404 // Load current lexical context from the stack frame. 4405 movp(scratch, Operand(rbp, StandardFrameConstants::kContextOffset)); 4406 4407 // When generating debug code, make sure the lexical context is set. 4408 if (emit_debug_code()) { 4409 cmpp(scratch, Immediate(0)); 4410 Check(not_equal, kWeShouldNotHaveAnEmptyLexicalContext); 4411 } 4412 // Load the native context of the current context. 4413 movp(scratch, ContextOperand(scratch, Context::NATIVE_CONTEXT_INDEX)); 4414 4415 // Check the context is a native context. 4416 if (emit_debug_code()) { 4417 Cmp(FieldOperand(scratch, HeapObject::kMapOffset), 4418 isolate()->factory()->native_context_map()); 4419 Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext); 4420 } 4421 4422 // Check if both contexts are the same. 4423 cmpp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); 4424 j(equal, &same_contexts); 4425 4426 // Compare security tokens. 4427 // Check that the security token in the calling global object is 4428 // compatible with the security token in the receiving global 4429 // object. 4430 4431 // Check the context is a native context. 4432 if (emit_debug_code()) { 4433 // Preserve original value of holder_reg. 4434 Push(holder_reg); 4435 movp(holder_reg, 4436 FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); 4437 CompareRoot(holder_reg, Heap::kNullValueRootIndex); 4438 Check(not_equal, kJSGlobalProxyContextShouldNotBeNull); 4439 4440 // Read the first word and compare to native_context_map(), 4441 movp(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset)); 4442 CompareRoot(holder_reg, Heap::kNativeContextMapRootIndex); 4443 Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext); 4444 Pop(holder_reg); 4445 } 4446 4447 movp(kScratchRegister, 4448 FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); 4449 int token_offset = 4450 Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize; 4451 movp(scratch, FieldOperand(scratch, token_offset)); 4452 cmpp(scratch, FieldOperand(kScratchRegister, token_offset)); 4453 j(not_equal, miss); 4454 4455 bind(&same_contexts); 4456 } 4457 4458 4459 // Compute the hash code from the untagged key. This must be kept in sync with 4460 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in 4461 // code-stub-hydrogen.cc 4462 void MacroAssembler::GetNumberHash(Register r0, Register scratch) { 4463 // First of all we assign the hash seed to scratch. 4464 LoadRoot(scratch, Heap::kHashSeedRootIndex); 4465 SmiToInteger32(scratch, scratch); 4466 4467 // Xor original key with a seed. 4468 xorl(r0, scratch); 4469 4470 // Compute the hash code from the untagged key. This must be kept in sync 4471 // with ComputeIntegerHash in utils.h. 4472 // 4473 // hash = ~hash + (hash << 15); 4474 movl(scratch, r0); 4475 notl(r0); 4476 shll(scratch, Immediate(15)); 4477 addl(r0, scratch); 4478 // hash = hash ^ (hash >> 12); 4479 movl(scratch, r0); 4480 shrl(scratch, Immediate(12)); 4481 xorl(r0, scratch); 4482 // hash = hash + (hash << 2); 4483 leal(r0, Operand(r0, r0, times_4, 0)); 4484 // hash = hash ^ (hash >> 4); 4485 movl(scratch, r0); 4486 shrl(scratch, Immediate(4)); 4487 xorl(r0, scratch); 4488 // hash = hash * 2057; 4489 imull(r0, r0, Immediate(2057)); 4490 // hash = hash ^ (hash >> 16); 4491 movl(scratch, r0); 4492 shrl(scratch, Immediate(16)); 4493 xorl(r0, scratch); 4494 andl(r0, Immediate(0x3fffffff)); 4495 } 4496 4497 4498 4499 void MacroAssembler::LoadFromNumberDictionary(Label* miss, 4500 Register elements, 4501 Register key, 4502 Register r0, 4503 Register r1, 4504 Register r2, 4505 Register result) { 4506 // Register use: 4507 // 4508 // elements - holds the slow-case elements of the receiver on entry. 4509 // Unchanged unless 'result' is the same register. 4510 // 4511 // key - holds the smi key on entry. 4512 // Unchanged unless 'result' is the same register. 4513 // 4514 // Scratch registers: 4515 // 4516 // r0 - holds the untagged key on entry and holds the hash once computed. 4517 // 4518 // r1 - used to hold the capacity mask of the dictionary 4519 // 4520 // r2 - used for the index into the dictionary. 4521 // 4522 // result - holds the result on exit if the load succeeded. 4523 // Allowed to be the same as 'key' or 'result'. 4524 // Unchanged on bailout so 'key' or 'result' can be used 4525 // in further computation. 4526 4527 Label done; 4528 4529 GetNumberHash(r0, r1); 4530 4531 // Compute capacity mask. 4532 SmiToInteger32(r1, FieldOperand(elements, 4533 SeededNumberDictionary::kCapacityOffset)); 4534 decl(r1); 4535 4536 // Generate an unrolled loop that performs a few probes before giving up. 4537 for (int i = 0; i < kNumberDictionaryProbes; i++) { 4538 // Use r2 for index calculations and keep the hash intact in r0. 4539 movp(r2, r0); 4540 // Compute the masked index: (hash + i + i * i) & mask. 4541 if (i > 0) { 4542 addl(r2, Immediate(SeededNumberDictionary::GetProbeOffset(i))); 4543 } 4544 andp(r2, r1); 4545 4546 // Scale the index by multiplying by the entry size. 4547 DCHECK(SeededNumberDictionary::kEntrySize == 3); 4548 leap(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 4549 4550 // Check if the key matches. 4551 cmpp(key, FieldOperand(elements, 4552 r2, 4553 times_pointer_size, 4554 SeededNumberDictionary::kElementsStartOffset)); 4555 if (i != (kNumberDictionaryProbes - 1)) { 4556 j(equal, &done); 4557 } else { 4558 j(not_equal, miss); 4559 } 4560 } 4561 4562 bind(&done); 4563 // Check that the value is a field property. 4564 const int kDetailsOffset = 4565 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize; 4566 DCHECK_EQ(DATA, 0); 4567 Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), 4568 Smi::FromInt(PropertyDetails::TypeField::kMask)); 4569 j(not_zero, miss); 4570 4571 // Get the value at the masked, scaled index. 4572 const int kValueOffset = 4573 SeededNumberDictionary::kElementsStartOffset + kPointerSize; 4574 movp(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); 4575 } 4576 4577 4578 void MacroAssembler::LoadAllocationTopHelper(Register result, 4579 Register scratch, 4580 AllocationFlags flags) { 4581 ExternalReference allocation_top = 4582 AllocationUtils::GetAllocationTopReference(isolate(), flags); 4583 4584 // Just return if allocation top is already known. 4585 if ((flags & RESULT_CONTAINS_TOP) != 0) { 4586 // No use of scratch if allocation top is provided. 4587 DCHECK(!scratch.is_valid()); 4588 #ifdef DEBUG 4589 // Assert that result actually contains top on entry. 4590 Operand top_operand = ExternalOperand(allocation_top); 4591 cmpp(result, top_operand); 4592 Check(equal, kUnexpectedAllocationTop); 4593 #endif 4594 return; 4595 } 4596 4597 // Move address of new object to result. Use scratch register if available, 4598 // and keep address in scratch until call to UpdateAllocationTopHelper. 4599 if (scratch.is_valid()) { 4600 LoadAddress(scratch, allocation_top); 4601 movp(result, Operand(scratch, 0)); 4602 } else { 4603 Load(result, allocation_top); 4604 } 4605 } 4606 4607 4608 void MacroAssembler::MakeSureDoubleAlignedHelper(Register result, 4609 Register scratch, 4610 Label* gc_required, 4611 AllocationFlags flags) { 4612 if (kPointerSize == kDoubleSize) { 4613 if (FLAG_debug_code) { 4614 testl(result, Immediate(kDoubleAlignmentMask)); 4615 Check(zero, kAllocationIsNotDoubleAligned); 4616 } 4617 } else { 4618 // Align the next allocation. Storing the filler map without checking top 4619 // is safe in new-space because the limit of the heap is aligned there. 4620 DCHECK(kPointerSize * 2 == kDoubleSize); 4621 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 4622 // Make sure scratch is not clobbered by this function as it might be 4623 // used in UpdateAllocationTopHelper later. 4624 DCHECK(!scratch.is(kScratchRegister)); 4625 Label aligned; 4626 testl(result, Immediate(kDoubleAlignmentMask)); 4627 j(zero, &aligned, Label::kNear); 4628 if ((flags & PRETENURE) != 0) { 4629 ExternalReference allocation_limit = 4630 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 4631 cmpp(result, ExternalOperand(allocation_limit)); 4632 j(above_equal, gc_required); 4633 } 4634 LoadRoot(kScratchRegister, Heap::kOnePointerFillerMapRootIndex); 4635 movp(Operand(result, 0), kScratchRegister); 4636 addp(result, Immediate(kDoubleSize / 2)); 4637 bind(&aligned); 4638 } 4639 } 4640 4641 4642 void MacroAssembler::UpdateAllocationTopHelper(Register result_end, 4643 Register scratch, 4644 AllocationFlags flags) { 4645 if (emit_debug_code()) { 4646 testp(result_end, Immediate(kObjectAlignmentMask)); 4647 Check(zero, kUnalignedAllocationInNewSpace); 4648 } 4649 4650 ExternalReference allocation_top = 4651 AllocationUtils::GetAllocationTopReference(isolate(), flags); 4652 4653 // Update new top. 4654 if (scratch.is_valid()) { 4655 // Scratch already contains address of allocation top. 4656 movp(Operand(scratch, 0), result_end); 4657 } else { 4658 Store(allocation_top, result_end); 4659 } 4660 } 4661 4662 4663 void MacroAssembler::Allocate(int object_size, 4664 Register result, 4665 Register result_end, 4666 Register scratch, 4667 Label* gc_required, 4668 AllocationFlags flags) { 4669 DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0); 4670 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize); 4671 if (!FLAG_inline_new) { 4672 if (emit_debug_code()) { 4673 // Trash the registers to simulate an allocation failure. 4674 movl(result, Immediate(0x7091)); 4675 if (result_end.is_valid()) { 4676 movl(result_end, Immediate(0x7191)); 4677 } 4678 if (scratch.is_valid()) { 4679 movl(scratch, Immediate(0x7291)); 4680 } 4681 } 4682 jmp(gc_required); 4683 return; 4684 } 4685 DCHECK(!result.is(result_end)); 4686 4687 // Load address of new object into result. 4688 LoadAllocationTopHelper(result, scratch, flags); 4689 4690 if ((flags & DOUBLE_ALIGNMENT) != 0) { 4691 MakeSureDoubleAlignedHelper(result, scratch, gc_required, flags); 4692 } 4693 4694 // Calculate new top and bail out if new space is exhausted. 4695 ExternalReference allocation_limit = 4696 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 4697 4698 Register top_reg = result_end.is_valid() ? result_end : result; 4699 4700 if (!top_reg.is(result)) { 4701 movp(top_reg, result); 4702 } 4703 addp(top_reg, Immediate(object_size)); 4704 j(carry, gc_required); 4705 Operand limit_operand = ExternalOperand(allocation_limit); 4706 cmpp(top_reg, limit_operand); 4707 j(above, gc_required); 4708 4709 // Update allocation top. 4710 UpdateAllocationTopHelper(top_reg, scratch, flags); 4711 4712 bool tag_result = (flags & TAG_OBJECT) != 0; 4713 if (top_reg.is(result)) { 4714 if (tag_result) { 4715 subp(result, Immediate(object_size - kHeapObjectTag)); 4716 } else { 4717 subp(result, Immediate(object_size)); 4718 } 4719 } else if (tag_result) { 4720 // Tag the result if requested. 4721 DCHECK(kHeapObjectTag == 1); 4722 incp(result); 4723 } 4724 } 4725 4726 4727 void MacroAssembler::Allocate(int header_size, 4728 ScaleFactor element_size, 4729 Register element_count, 4730 Register result, 4731 Register result_end, 4732 Register scratch, 4733 Label* gc_required, 4734 AllocationFlags flags) { 4735 DCHECK((flags & SIZE_IN_WORDS) == 0); 4736 leap(result_end, Operand(element_count, element_size, header_size)); 4737 Allocate(result_end, result, result_end, scratch, gc_required, flags); 4738 } 4739 4740 4741 void MacroAssembler::Allocate(Register object_size, 4742 Register result, 4743 Register result_end, 4744 Register scratch, 4745 Label* gc_required, 4746 AllocationFlags flags) { 4747 DCHECK((flags & SIZE_IN_WORDS) == 0); 4748 if (!FLAG_inline_new) { 4749 if (emit_debug_code()) { 4750 // Trash the registers to simulate an allocation failure. 4751 movl(result, Immediate(0x7091)); 4752 movl(result_end, Immediate(0x7191)); 4753 if (scratch.is_valid()) { 4754 movl(scratch, Immediate(0x7291)); 4755 } 4756 // object_size is left unchanged by this function. 4757 } 4758 jmp(gc_required); 4759 return; 4760 } 4761 DCHECK(!result.is(result_end)); 4762 4763 // Load address of new object into result. 4764 LoadAllocationTopHelper(result, scratch, flags); 4765 4766 if ((flags & DOUBLE_ALIGNMENT) != 0) { 4767 MakeSureDoubleAlignedHelper(result, scratch, gc_required, flags); 4768 } 4769 4770 // Calculate new top and bail out if new space is exhausted. 4771 ExternalReference allocation_limit = 4772 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 4773 if (!object_size.is(result_end)) { 4774 movp(result_end, object_size); 4775 } 4776 addp(result_end, result); 4777 j(carry, gc_required); 4778 Operand limit_operand = ExternalOperand(allocation_limit); 4779 cmpp(result_end, limit_operand); 4780 j(above, gc_required); 4781 4782 // Update allocation top. 4783 UpdateAllocationTopHelper(result_end, scratch, flags); 4784 4785 // Tag the result if requested. 4786 if ((flags & TAG_OBJECT) != 0) { 4787 addp(result, Immediate(kHeapObjectTag)); 4788 } 4789 } 4790 4791 4792 void MacroAssembler::AllocateHeapNumber(Register result, 4793 Register scratch, 4794 Label* gc_required, 4795 MutableMode mode) { 4796 // Allocate heap number in new space. 4797 Allocate(HeapNumber::kSize, result, scratch, no_reg, gc_required, TAG_OBJECT); 4798 4799 Heap::RootListIndex map_index = mode == MUTABLE 4800 ? Heap::kMutableHeapNumberMapRootIndex 4801 : Heap::kHeapNumberMapRootIndex; 4802 4803 // Set the map. 4804 LoadRoot(kScratchRegister, map_index); 4805 movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); 4806 } 4807 4808 4809 void MacroAssembler::AllocateTwoByteString(Register result, 4810 Register length, 4811 Register scratch1, 4812 Register scratch2, 4813 Register scratch3, 4814 Label* gc_required) { 4815 // Calculate the number of bytes needed for the characters in the string while 4816 // observing object alignment. 4817 const int kHeaderAlignment = SeqTwoByteString::kHeaderSize & 4818 kObjectAlignmentMask; 4819 DCHECK(kShortSize == 2); 4820 // scratch1 = length * 2 + kObjectAlignmentMask. 4821 leap(scratch1, Operand(length, length, times_1, kObjectAlignmentMask + 4822 kHeaderAlignment)); 4823 andp(scratch1, Immediate(~kObjectAlignmentMask)); 4824 if (kHeaderAlignment > 0) { 4825 subp(scratch1, Immediate(kHeaderAlignment)); 4826 } 4827 4828 // Allocate two byte string in new space. 4829 Allocate(SeqTwoByteString::kHeaderSize, 4830 times_1, 4831 scratch1, 4832 result, 4833 scratch2, 4834 scratch3, 4835 gc_required, 4836 TAG_OBJECT); 4837 4838 // Set the map, length and hash field. 4839 LoadRoot(kScratchRegister, Heap::kStringMapRootIndex); 4840 movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); 4841 Integer32ToSmi(scratch1, length); 4842 movp(FieldOperand(result, String::kLengthOffset), scratch1); 4843 movp(FieldOperand(result, String::kHashFieldOffset), 4844 Immediate(String::kEmptyHashField)); 4845 } 4846 4847 4848 void MacroAssembler::AllocateOneByteString(Register result, Register length, 4849 Register scratch1, Register scratch2, 4850 Register scratch3, 4851 Label* gc_required) { 4852 // Calculate the number of bytes needed for the characters in the string while 4853 // observing object alignment. 4854 const int kHeaderAlignment = SeqOneByteString::kHeaderSize & 4855 kObjectAlignmentMask; 4856 movl(scratch1, length); 4857 DCHECK(kCharSize == 1); 4858 addp(scratch1, Immediate(kObjectAlignmentMask + kHeaderAlignment)); 4859 andp(scratch1, Immediate(~kObjectAlignmentMask)); 4860 if (kHeaderAlignment > 0) { 4861 subp(scratch1, Immediate(kHeaderAlignment)); 4862 } 4863 4864 // Allocate one-byte string in new space. 4865 Allocate(SeqOneByteString::kHeaderSize, 4866 times_1, 4867 scratch1, 4868 result, 4869 scratch2, 4870 scratch3, 4871 gc_required, 4872 TAG_OBJECT); 4873 4874 // Set the map, length and hash field. 4875 LoadRoot(kScratchRegister, Heap::kOneByteStringMapRootIndex); 4876 movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); 4877 Integer32ToSmi(scratch1, length); 4878 movp(FieldOperand(result, String::kLengthOffset), scratch1); 4879 movp(FieldOperand(result, String::kHashFieldOffset), 4880 Immediate(String::kEmptyHashField)); 4881 } 4882 4883 4884 void MacroAssembler::AllocateTwoByteConsString(Register result, 4885 Register scratch1, 4886 Register scratch2, 4887 Label* gc_required) { 4888 // Allocate heap number in new space. 4889 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, 4890 TAG_OBJECT); 4891 4892 // Set the map. The other fields are left uninitialized. 4893 LoadRoot(kScratchRegister, Heap::kConsStringMapRootIndex); 4894 movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); 4895 } 4896 4897 4898 void MacroAssembler::AllocateOneByteConsString(Register result, 4899 Register scratch1, 4900 Register scratch2, 4901 Label* gc_required) { 4902 Allocate(ConsString::kSize, 4903 result, 4904 scratch1, 4905 scratch2, 4906 gc_required, 4907 TAG_OBJECT); 4908 4909 // Set the map. The other fields are left uninitialized. 4910 LoadRoot(kScratchRegister, Heap::kConsOneByteStringMapRootIndex); 4911 movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); 4912 } 4913 4914 4915 void MacroAssembler::AllocateTwoByteSlicedString(Register result, 4916 Register scratch1, 4917 Register scratch2, 4918 Label* gc_required) { 4919 // Allocate heap number in new space. 4920 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, 4921 TAG_OBJECT); 4922 4923 // Set the map. The other fields are left uninitialized. 4924 LoadRoot(kScratchRegister, Heap::kSlicedStringMapRootIndex); 4925 movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); 4926 } 4927 4928 4929 void MacroAssembler::AllocateOneByteSlicedString(Register result, 4930 Register scratch1, 4931 Register scratch2, 4932 Label* gc_required) { 4933 // Allocate heap number in new space. 4934 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, 4935 TAG_OBJECT); 4936 4937 // Set the map. The other fields are left uninitialized. 4938 LoadRoot(kScratchRegister, Heap::kSlicedOneByteStringMapRootIndex); 4939 movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); 4940 } 4941 4942 4943 void MacroAssembler::AllocateJSValue(Register result, Register constructor, 4944 Register value, Register scratch, 4945 Label* gc_required) { 4946 DCHECK(!result.is(constructor)); 4947 DCHECK(!result.is(scratch)); 4948 DCHECK(!result.is(value)); 4949 4950 // Allocate JSValue in new space. 4951 Allocate(JSValue::kSize, result, scratch, no_reg, gc_required, TAG_OBJECT); 4952 4953 // Initialize the JSValue. 4954 LoadGlobalFunctionInitialMap(constructor, scratch); 4955 movp(FieldOperand(result, HeapObject::kMapOffset), scratch); 4956 LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); 4957 movp(FieldOperand(result, JSObject::kPropertiesOffset), scratch); 4958 movp(FieldOperand(result, JSObject::kElementsOffset), scratch); 4959 movp(FieldOperand(result, JSValue::kValueOffset), value); 4960 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); 4961 } 4962 4963 4964 // Copy memory, byte-by-byte, from source to destination. Not optimized for 4965 // long or aligned copies. The contents of scratch and length are destroyed. 4966 // Destination is incremented by length, source, length and scratch are 4967 // clobbered. 4968 // A simpler loop is faster on small copies, but slower on large ones. 4969 // The cld() instruction must have been emitted, to set the direction flag(), 4970 // before calling this function. 4971 void MacroAssembler::CopyBytes(Register destination, 4972 Register source, 4973 Register length, 4974 int min_length, 4975 Register scratch) { 4976 DCHECK(min_length >= 0); 4977 if (emit_debug_code()) { 4978 cmpl(length, Immediate(min_length)); 4979 Assert(greater_equal, kInvalidMinLength); 4980 } 4981 Label short_loop, len8, len16, len24, done, short_string; 4982 4983 const int kLongStringLimit = 4 * kPointerSize; 4984 if (min_length <= kLongStringLimit) { 4985 cmpl(length, Immediate(kPointerSize)); 4986 j(below, &short_string, Label::kNear); 4987 } 4988 4989 DCHECK(source.is(rsi)); 4990 DCHECK(destination.is(rdi)); 4991 DCHECK(length.is(rcx)); 4992 4993 if (min_length <= kLongStringLimit) { 4994 cmpl(length, Immediate(2 * kPointerSize)); 4995 j(below_equal, &len8, Label::kNear); 4996 cmpl(length, Immediate(3 * kPointerSize)); 4997 j(below_equal, &len16, Label::kNear); 4998 cmpl(length, Immediate(4 * kPointerSize)); 4999 j(below_equal, &len24, Label::kNear); 5000 } 5001 5002 // Because source is 8-byte aligned in our uses of this function, 5003 // we keep source aligned for the rep movs operation by copying the odd bytes 5004 // at the end of the ranges. 5005 movp(scratch, length); 5006 shrl(length, Immediate(kPointerSizeLog2)); 5007 repmovsp(); 5008 // Move remaining bytes of length. 5009 andl(scratch, Immediate(kPointerSize - 1)); 5010 movp(length, Operand(source, scratch, times_1, -kPointerSize)); 5011 movp(Operand(destination, scratch, times_1, -kPointerSize), length); 5012 addp(destination, scratch); 5013 5014 if (min_length <= kLongStringLimit) { 5015 jmp(&done, Label::kNear); 5016 bind(&len24); 5017 movp(scratch, Operand(source, 2 * kPointerSize)); 5018 movp(Operand(destination, 2 * kPointerSize), scratch); 5019 bind(&len16); 5020 movp(scratch, Operand(source, kPointerSize)); 5021 movp(Operand(destination, kPointerSize), scratch); 5022 bind(&len8); 5023 movp(scratch, Operand(source, 0)); 5024 movp(Operand(destination, 0), scratch); 5025 // Move remaining bytes of length. 5026 movp(scratch, Operand(source, length, times_1, -kPointerSize)); 5027 movp(Operand(destination, length, times_1, -kPointerSize), scratch); 5028 addp(destination, length); 5029 jmp(&done, Label::kNear); 5030 5031 bind(&short_string); 5032 if (min_length == 0) { 5033 testl(length, length); 5034 j(zero, &done, Label::kNear); 5035 } 5036 5037 bind(&short_loop); 5038 movb(scratch, Operand(source, 0)); 5039 movb(Operand(destination, 0), scratch); 5040 incp(source); 5041 incp(destination); 5042 decl(length); 5043 j(not_zero, &short_loop); 5044 } 5045 5046 bind(&done); 5047 } 5048 5049 5050 void MacroAssembler::InitializeFieldsWithFiller(Register current_address, 5051 Register end_address, 5052 Register filler) { 5053 Label loop, entry; 5054 jmp(&entry); 5055 bind(&loop); 5056 movp(Operand(current_address, 0), filler); 5057 addp(current_address, Immediate(kPointerSize)); 5058 bind(&entry); 5059 cmpp(current_address, end_address); 5060 j(below, &loop); 5061 } 5062 5063 5064 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { 5065 if (context_chain_length > 0) { 5066 // Move up the chain of contexts to the context containing the slot. 5067 movp(dst, Operand(rsi, Context::SlotOffset(Context::PREVIOUS_INDEX))); 5068 for (int i = 1; i < context_chain_length; i++) { 5069 movp(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); 5070 } 5071 } else { 5072 // Slot is in the current function context. Move it into the 5073 // destination register in case we store into it (the write barrier 5074 // cannot be allowed to destroy the context in rsi). 5075 movp(dst, rsi); 5076 } 5077 5078 // We should not have found a with context by walking the context 5079 // chain (i.e., the static scope chain and runtime context chain do 5080 // not agree). A variable occurring in such a scope should have 5081 // slot type LOOKUP and not CONTEXT. 5082 if (emit_debug_code()) { 5083 CompareRoot(FieldOperand(dst, HeapObject::kMapOffset), 5084 Heap::kWithContextMapRootIndex); 5085 Check(not_equal, kVariableResolvedToWithContext); 5086 } 5087 } 5088 5089 5090 void MacroAssembler::LoadTransitionedArrayMapConditional( 5091 ElementsKind expected_kind, 5092 ElementsKind transitioned_kind, 5093 Register map_in_out, 5094 Register scratch, 5095 Label* no_map_match) { 5096 DCHECK(IsFastElementsKind(expected_kind)); 5097 DCHECK(IsFastElementsKind(transitioned_kind)); 5098 5099 // Check that the function's map is the same as the expected cached map. 5100 movp(scratch, NativeContextOperand()); 5101 cmpp(map_in_out, 5102 ContextOperand(scratch, Context::ArrayMapIndex(expected_kind))); 5103 j(not_equal, no_map_match); 5104 5105 // Use the transitioned cached map. 5106 movp(map_in_out, 5107 ContextOperand(scratch, Context::ArrayMapIndex(transitioned_kind))); 5108 } 5109 5110 5111 #ifdef _WIN64 5112 static const int kRegisterPassedArguments = 4; 5113 #else 5114 static const int kRegisterPassedArguments = 6; 5115 #endif 5116 5117 5118 void MacroAssembler::LoadNativeContextSlot(int index, Register dst) { 5119 movp(dst, NativeContextOperand()); 5120 movp(dst, ContextOperand(dst, index)); 5121 } 5122 5123 5124 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, 5125 Register map) { 5126 // Load the initial map. The global functions all have initial maps. 5127 movp(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 5128 if (emit_debug_code()) { 5129 Label ok, fail; 5130 CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK); 5131 jmp(&ok); 5132 bind(&fail); 5133 Abort(kGlobalFunctionsMustHaveInitialMap); 5134 bind(&ok); 5135 } 5136 } 5137 5138 5139 int MacroAssembler::ArgumentStackSlotsForCFunctionCall(int num_arguments) { 5140 // On Windows 64 stack slots are reserved by the caller for all arguments 5141 // including the ones passed in registers, and space is always allocated for 5142 // the four register arguments even if the function takes fewer than four 5143 // arguments. 5144 // On AMD64 ABI (Linux/Mac) the first six arguments are passed in registers 5145 // and the caller does not reserve stack slots for them. 5146 DCHECK(num_arguments >= 0); 5147 #ifdef _WIN64 5148 const int kMinimumStackSlots = kRegisterPassedArguments; 5149 if (num_arguments < kMinimumStackSlots) return kMinimumStackSlots; 5150 return num_arguments; 5151 #else 5152 if (num_arguments < kRegisterPassedArguments) return 0; 5153 return num_arguments - kRegisterPassedArguments; 5154 #endif 5155 } 5156 5157 5158 void MacroAssembler::EmitSeqStringSetCharCheck(Register string, 5159 Register index, 5160 Register value, 5161 uint32_t encoding_mask) { 5162 Label is_object; 5163 JumpIfNotSmi(string, &is_object); 5164 Abort(kNonObject); 5165 bind(&is_object); 5166 5167 Push(value); 5168 movp(value, FieldOperand(string, HeapObject::kMapOffset)); 5169 movzxbp(value, FieldOperand(value, Map::kInstanceTypeOffset)); 5170 5171 andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask)); 5172 cmpp(value, Immediate(encoding_mask)); 5173 Pop(value); 5174 Check(equal, kUnexpectedStringType); 5175 5176 // The index is assumed to be untagged coming in, tag it to compare with the 5177 // string length without using a temp register, it is restored at the end of 5178 // this function. 5179 Integer32ToSmi(index, index); 5180 SmiCompare(index, FieldOperand(string, String::kLengthOffset)); 5181 Check(less, kIndexIsTooLarge); 5182 5183 SmiCompare(index, Smi::FromInt(0)); 5184 Check(greater_equal, kIndexIsNegative); 5185 5186 // Restore the index 5187 SmiToInteger32(index, index); 5188 } 5189 5190 5191 void MacroAssembler::PrepareCallCFunction(int num_arguments) { 5192 int frame_alignment = base::OS::ActivationFrameAlignment(); 5193 DCHECK(frame_alignment != 0); 5194 DCHECK(num_arguments >= 0); 5195 5196 // Make stack end at alignment and allocate space for arguments and old rsp. 5197 movp(kScratchRegister, rsp); 5198 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 5199 int argument_slots_on_stack = 5200 ArgumentStackSlotsForCFunctionCall(num_arguments); 5201 subp(rsp, Immediate((argument_slots_on_stack + 1) * kRegisterSize)); 5202 andp(rsp, Immediate(-frame_alignment)); 5203 movp(Operand(rsp, argument_slots_on_stack * kRegisterSize), kScratchRegister); 5204 } 5205 5206 5207 void MacroAssembler::CallCFunction(ExternalReference function, 5208 int num_arguments) { 5209 LoadAddress(rax, function); 5210 CallCFunction(rax, num_arguments); 5211 } 5212 5213 5214 void MacroAssembler::CallCFunction(Register function, int num_arguments) { 5215 DCHECK(has_frame()); 5216 // Check stack alignment. 5217 if (emit_debug_code()) { 5218 CheckStackAlignment(); 5219 } 5220 5221 call(function); 5222 DCHECK(base::OS::ActivationFrameAlignment() != 0); 5223 DCHECK(num_arguments >= 0); 5224 int argument_slots_on_stack = 5225 ArgumentStackSlotsForCFunctionCall(num_arguments); 5226 movp(rsp, Operand(rsp, argument_slots_on_stack * kRegisterSize)); 5227 } 5228 5229 5230 #ifdef DEBUG 5231 bool AreAliased(Register reg1, 5232 Register reg2, 5233 Register reg3, 5234 Register reg4, 5235 Register reg5, 5236 Register reg6, 5237 Register reg7, 5238 Register reg8) { 5239 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + 5240 reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() + 5241 reg7.is_valid() + reg8.is_valid(); 5242 5243 RegList regs = 0; 5244 if (reg1.is_valid()) regs |= reg1.bit(); 5245 if (reg2.is_valid()) regs |= reg2.bit(); 5246 if (reg3.is_valid()) regs |= reg3.bit(); 5247 if (reg4.is_valid()) regs |= reg4.bit(); 5248 if (reg5.is_valid()) regs |= reg5.bit(); 5249 if (reg6.is_valid()) regs |= reg6.bit(); 5250 if (reg7.is_valid()) regs |= reg7.bit(); 5251 if (reg8.is_valid()) regs |= reg8.bit(); 5252 int n_of_non_aliasing_regs = NumRegs(regs); 5253 5254 return n_of_valid_regs != n_of_non_aliasing_regs; 5255 } 5256 #endif 5257 5258 5259 CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size) 5260 : address_(address), 5261 size_(size), 5262 masm_(isolate, address, size + Assembler::kGap, CodeObjectRequired::kNo) { 5263 // Create a new macro assembler pointing to the address of the code to patch. 5264 // The size is adjusted with kGap on order for the assembler to generate size 5265 // bytes of instructions without failing with buffer size constraints. 5266 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 5267 } 5268 5269 5270 CodePatcher::~CodePatcher() { 5271 // Indicate that code has changed. 5272 Assembler::FlushICache(masm_.isolate(), address_, size_); 5273 5274 // Check that the code was patched as expected. 5275 DCHECK(masm_.pc_ == address_ + size_); 5276 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 5277 } 5278 5279 5280 void MacroAssembler::CheckPageFlag( 5281 Register object, 5282 Register scratch, 5283 int mask, 5284 Condition cc, 5285 Label* condition_met, 5286 Label::Distance condition_met_distance) { 5287 DCHECK(cc == zero || cc == not_zero); 5288 if (scratch.is(object)) { 5289 andp(scratch, Immediate(~Page::kPageAlignmentMask)); 5290 } else { 5291 movp(scratch, Immediate(~Page::kPageAlignmentMask)); 5292 andp(scratch, object); 5293 } 5294 if (mask < (1 << kBitsPerByte)) { 5295 testb(Operand(scratch, MemoryChunk::kFlagsOffset), 5296 Immediate(static_cast<uint8_t>(mask))); 5297 } else { 5298 testl(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask)); 5299 } 5300 j(cc, condition_met, condition_met_distance); 5301 } 5302 5303 5304 void MacroAssembler::JumpIfBlack(Register object, 5305 Register bitmap_scratch, 5306 Register mask_scratch, 5307 Label* on_black, 5308 Label::Distance on_black_distance) { 5309 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, rcx)); 5310 5311 GetMarkBits(object, bitmap_scratch, mask_scratch); 5312 5313 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 5314 // The mask_scratch register contains a 1 at the position of the first bit 5315 // and a 1 at a position of the second bit. All other positions are zero. 5316 movp(rcx, mask_scratch); 5317 andp(rcx, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); 5318 cmpp(mask_scratch, rcx); 5319 j(equal, on_black, on_black_distance); 5320 } 5321 5322 5323 void MacroAssembler::GetMarkBits(Register addr_reg, 5324 Register bitmap_reg, 5325 Register mask_reg) { 5326 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, rcx)); 5327 movp(bitmap_reg, addr_reg); 5328 // Sign extended 32 bit immediate. 5329 andp(bitmap_reg, Immediate(~Page::kPageAlignmentMask)); 5330 movp(rcx, addr_reg); 5331 int shift = 5332 Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2; 5333 shrl(rcx, Immediate(shift)); 5334 andp(rcx, 5335 Immediate((Page::kPageAlignmentMask >> shift) & 5336 ~(Bitmap::kBytesPerCell - 1))); 5337 5338 addp(bitmap_reg, rcx); 5339 movp(rcx, addr_reg); 5340 shrl(rcx, Immediate(kPointerSizeLog2)); 5341 andp(rcx, Immediate((1 << Bitmap::kBitsPerCellLog2) - 1)); 5342 movl(mask_reg, Immediate(3)); 5343 shlp_cl(mask_reg); 5344 } 5345 5346 5347 void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch, 5348 Register mask_scratch, Label* value_is_white, 5349 Label::Distance distance) { 5350 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, rcx)); 5351 GetMarkBits(value, bitmap_scratch, mask_scratch); 5352 5353 // If the value is black or grey we don't need to do anything. 5354 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); 5355 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 5356 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); 5357 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); 5358 5359 // Since both black and grey have a 1 in the first position and white does 5360 // not have a 1 there we only need to check one bit. 5361 testp(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch); 5362 j(zero, value_is_white, distance); 5363 } 5364 5365 5366 void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) { 5367 Label next, start; 5368 Register empty_fixed_array_value = r8; 5369 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); 5370 movp(rcx, rax); 5371 5372 // Check if the enum length field is properly initialized, indicating that 5373 // there is an enum cache. 5374 movp(rbx, FieldOperand(rcx, HeapObject::kMapOffset)); 5375 5376 EnumLength(rdx, rbx); 5377 Cmp(rdx, Smi::FromInt(kInvalidEnumCacheSentinel)); 5378 j(equal, call_runtime); 5379 5380 jmp(&start); 5381 5382 bind(&next); 5383 5384 movp(rbx, FieldOperand(rcx, HeapObject::kMapOffset)); 5385 5386 // For all objects but the receiver, check that the cache is empty. 5387 EnumLength(rdx, rbx); 5388 Cmp(rdx, Smi::FromInt(0)); 5389 j(not_equal, call_runtime); 5390 5391 bind(&start); 5392 5393 // Check that there are no elements. Register rcx contains the current JS 5394 // object we've reached through the prototype chain. 5395 Label no_elements; 5396 cmpp(empty_fixed_array_value, 5397 FieldOperand(rcx, JSObject::kElementsOffset)); 5398 j(equal, &no_elements); 5399 5400 // Second chance, the object may be using the empty slow element dictionary. 5401 LoadRoot(kScratchRegister, Heap::kEmptySlowElementDictionaryRootIndex); 5402 cmpp(kScratchRegister, FieldOperand(rcx, JSObject::kElementsOffset)); 5403 j(not_equal, call_runtime); 5404 5405 bind(&no_elements); 5406 movp(rcx, FieldOperand(rbx, Map::kPrototypeOffset)); 5407 cmpp(rcx, null_value); 5408 j(not_equal, &next); 5409 } 5410 5411 void MacroAssembler::TestJSArrayForAllocationMemento( 5412 Register receiver_reg, 5413 Register scratch_reg, 5414 Label* no_memento_found) { 5415 ExternalReference new_space_start = 5416 ExternalReference::new_space_start(isolate()); 5417 ExternalReference new_space_allocation_top = 5418 ExternalReference::new_space_allocation_top_address(isolate()); 5419 5420 leap(scratch_reg, Operand(receiver_reg, 5421 JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag)); 5422 Move(kScratchRegister, new_space_start); 5423 cmpp(scratch_reg, kScratchRegister); 5424 j(less, no_memento_found); 5425 cmpp(scratch_reg, ExternalOperand(new_space_allocation_top)); 5426 j(greater, no_memento_found); 5427 CompareRoot(MemOperand(scratch_reg, -AllocationMemento::kSize), 5428 Heap::kAllocationMementoMapRootIndex); 5429 } 5430 5431 5432 void MacroAssembler::JumpIfDictionaryInPrototypeChain( 5433 Register object, 5434 Register scratch0, 5435 Register scratch1, 5436 Label* found) { 5437 DCHECK(!(scratch0.is(kScratchRegister) && scratch1.is(kScratchRegister))); 5438 DCHECK(!scratch1.is(scratch0)); 5439 Register current = scratch0; 5440 Label loop_again, end; 5441 5442 movp(current, object); 5443 movp(current, FieldOperand(current, HeapObject::kMapOffset)); 5444 movp(current, FieldOperand(current, Map::kPrototypeOffset)); 5445 CompareRoot(current, Heap::kNullValueRootIndex); 5446 j(equal, &end); 5447 5448 // Loop based on the map going up the prototype chain. 5449 bind(&loop_again); 5450 movp(current, FieldOperand(current, HeapObject::kMapOffset)); 5451 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE); 5452 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE); 5453 CmpInstanceType(current, JS_OBJECT_TYPE); 5454 j(below, found); 5455 movp(scratch1, FieldOperand(current, Map::kBitField2Offset)); 5456 DecodeField<Map::ElementsKindBits>(scratch1); 5457 cmpp(scratch1, Immediate(DICTIONARY_ELEMENTS)); 5458 j(equal, found); 5459 movp(current, FieldOperand(current, Map::kPrototypeOffset)); 5460 CompareRoot(current, Heap::kNullValueRootIndex); 5461 j(not_equal, &loop_again); 5462 5463 bind(&end); 5464 } 5465 5466 5467 void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) { 5468 DCHECK(!dividend.is(rax)); 5469 DCHECK(!dividend.is(rdx)); 5470 base::MagicNumbersForDivision<uint32_t> mag = 5471 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor)); 5472 movl(rax, Immediate(mag.multiplier)); 5473 imull(dividend); 5474 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0; 5475 if (divisor > 0 && neg) addl(rdx, dividend); 5476 if (divisor < 0 && !neg && mag.multiplier > 0) subl(rdx, dividend); 5477 if (mag.shift > 0) sarl(rdx, Immediate(mag.shift)); 5478 movl(rax, dividend); 5479 shrl(rax, Immediate(31)); 5480 addl(rdx, rax); 5481 } 5482 5483 5484 } // namespace internal 5485 } // namespace v8 5486 5487 #endif // V8_TARGET_ARCH_X64 5488