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