1// Copyright 2012 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#if V8_TARGET_ARCH_IA32 6 7#include "src/base/bits.h" 8#include "src/base/division-by-constant.h" 9#include "src/bootstrapper.h" 10#include "src/codegen.h" 11#include "src/debug/debug.h" 12#include "src/ia32/frames-ia32.h" 13#include "src/ia32/macro-assembler-ia32.h" 14#include "src/runtime/runtime.h" 15 16namespace v8 { 17namespace internal { 18 19// ------------------------------------------------------------------------- 20// MacroAssembler implementation. 21 22MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size, 23 CodeObjectRequired create_code_object) 24 : Assembler(arg_isolate, buffer, size), 25 generating_stub_(false), 26 has_frame_(false) { 27 if (create_code_object == CodeObjectRequired::kYes) { 28 code_object_ = 29 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate()); 30 } 31} 32 33 34void MacroAssembler::Load(Register dst, const Operand& src, Representation r) { 35 DCHECK(!r.IsDouble()); 36 if (r.IsInteger8()) { 37 movsx_b(dst, src); 38 } else if (r.IsUInteger8()) { 39 movzx_b(dst, src); 40 } else if (r.IsInteger16()) { 41 movsx_w(dst, src); 42 } else if (r.IsUInteger16()) { 43 movzx_w(dst, src); 44 } else { 45 mov(dst, src); 46 } 47} 48 49 50void MacroAssembler::Store(Register src, const Operand& dst, Representation r) { 51 DCHECK(!r.IsDouble()); 52 if (r.IsInteger8() || r.IsUInteger8()) { 53 mov_b(dst, src); 54 } else if (r.IsInteger16() || r.IsUInteger16()) { 55 mov_w(dst, src); 56 } else { 57 if (r.IsHeapObject()) { 58 AssertNotSmi(src); 59 } else if (r.IsSmi()) { 60 AssertSmi(src); 61 } 62 mov(dst, src); 63 } 64} 65 66 67void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) { 68 if (isolate()->heap()->RootCanBeTreatedAsConstant(index)) { 69 mov(destination, isolate()->heap()->root_handle(index)); 70 return; 71 } 72 ExternalReference roots_array_start = 73 ExternalReference::roots_array_start(isolate()); 74 mov(destination, Immediate(index)); 75 mov(destination, Operand::StaticArray(destination, 76 times_pointer_size, 77 roots_array_start)); 78} 79 80 81void MacroAssembler::StoreRoot(Register source, 82 Register scratch, 83 Heap::RootListIndex index) { 84 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); 85 ExternalReference roots_array_start = 86 ExternalReference::roots_array_start(isolate()); 87 mov(scratch, Immediate(index)); 88 mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), 89 source); 90} 91 92 93void MacroAssembler::CompareRoot(Register with, 94 Register scratch, 95 Heap::RootListIndex index) { 96 ExternalReference roots_array_start = 97 ExternalReference::roots_array_start(isolate()); 98 mov(scratch, Immediate(index)); 99 cmp(with, Operand::StaticArray(scratch, 100 times_pointer_size, 101 roots_array_start)); 102} 103 104 105void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) { 106 DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index)); 107 cmp(with, isolate()->heap()->root_handle(index)); 108} 109 110 111void MacroAssembler::CompareRoot(const Operand& with, 112 Heap::RootListIndex index) { 113 DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index)); 114 cmp(with, isolate()->heap()->root_handle(index)); 115} 116 117 118void MacroAssembler::PushRoot(Heap::RootListIndex index) { 119 DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index)); 120 Push(isolate()->heap()->root_handle(index)); 121} 122 123#define REG(Name) \ 124 { Register::kCode_##Name } 125 126static const Register saved_regs[] = {REG(eax), REG(ecx), REG(edx)}; 127 128#undef REG 129 130static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register); 131 132void MacroAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, 133 Register exclusion1, Register exclusion2, 134 Register exclusion3) { 135 // We don't allow a GC during a store buffer overflow so there is no need to 136 // store the registers in any particular way, but we do have to store and 137 // restore them. 138 for (int i = 0; i < kNumberOfSavedRegs; i++) { 139 Register reg = saved_regs[i]; 140 if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { 141 push(reg); 142 } 143 } 144 if (fp_mode == kSaveFPRegs) { 145 sub(esp, Immediate(kDoubleSize * (XMMRegister::kMaxNumRegisters - 1))); 146 // Save all XMM registers except XMM0. 147 for (int i = XMMRegister::kMaxNumRegisters - 1; i > 0; i--) { 148 XMMRegister reg = XMMRegister::from_code(i); 149 movsd(Operand(esp, (i - 1) * kDoubleSize), reg); 150 } 151 } 152} 153 154void MacroAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1, 155 Register exclusion2, Register exclusion3) { 156 if (fp_mode == kSaveFPRegs) { 157 // Restore all XMM registers except XMM0. 158 for (int i = XMMRegister::kMaxNumRegisters - 1; i > 0; i--) { 159 XMMRegister reg = XMMRegister::from_code(i); 160 movsd(reg, Operand(esp, (i - 1) * kDoubleSize)); 161 } 162 add(esp, Immediate(kDoubleSize * (XMMRegister::kMaxNumRegisters - 1))); 163 } 164 165 for (int i = kNumberOfSavedRegs - 1; i >= 0; i--) { 166 Register reg = saved_regs[i]; 167 if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { 168 pop(reg); 169 } 170 } 171} 172 173void MacroAssembler::InNewSpace(Register object, Register scratch, Condition cc, 174 Label* condition_met, 175 Label::Distance distance) { 176 CheckPageFlag(object, scratch, MemoryChunk::kIsInNewSpaceMask, cc, 177 condition_met, distance); 178} 179 180 181void MacroAssembler::RememberedSetHelper( 182 Register object, // Only used for debug checks. 183 Register addr, 184 Register scratch, 185 SaveFPRegsMode save_fp, 186 MacroAssembler::RememberedSetFinalAction and_then) { 187 Label done; 188 if (emit_debug_code()) { 189 Label ok; 190 JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear); 191 int3(); 192 bind(&ok); 193 } 194 // Load store buffer top. 195 ExternalReference store_buffer = 196 ExternalReference::store_buffer_top(isolate()); 197 mov(scratch, Operand::StaticVariable(store_buffer)); 198 // Store pointer to buffer. 199 mov(Operand(scratch, 0), addr); 200 // Increment buffer top. 201 add(scratch, Immediate(kPointerSize)); 202 // Write back new top of buffer. 203 mov(Operand::StaticVariable(store_buffer), scratch); 204 // Call stub on end of buffer. 205 // Check for end of buffer. 206 test(scratch, Immediate(StoreBuffer::kStoreBufferMask)); 207 if (and_then == kReturnAtEnd) { 208 Label buffer_overflowed; 209 j(equal, &buffer_overflowed, Label::kNear); 210 ret(0); 211 bind(&buffer_overflowed); 212 } else { 213 DCHECK(and_then == kFallThroughAtEnd); 214 j(not_equal, &done, Label::kNear); 215 } 216 StoreBufferOverflowStub store_buffer_overflow(isolate(), save_fp); 217 CallStub(&store_buffer_overflow); 218 if (and_then == kReturnAtEnd) { 219 ret(0); 220 } else { 221 DCHECK(and_then == kFallThroughAtEnd); 222 bind(&done); 223 } 224} 225 226 227void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg, 228 XMMRegister scratch_reg, 229 Register result_reg) { 230 Label done; 231 Label conv_failure; 232 xorps(scratch_reg, scratch_reg); 233 cvtsd2si(result_reg, input_reg); 234 test(result_reg, Immediate(0xFFFFFF00)); 235 j(zero, &done, Label::kNear); 236 cmp(result_reg, Immediate(0x1)); 237 j(overflow, &conv_failure, Label::kNear); 238 mov(result_reg, Immediate(0)); 239 setcc(sign, result_reg); 240 sub(result_reg, Immediate(1)); 241 and_(result_reg, Immediate(255)); 242 jmp(&done, Label::kNear); 243 bind(&conv_failure); 244 Move(result_reg, Immediate(0)); 245 ucomisd(input_reg, scratch_reg); 246 j(below, &done, Label::kNear); 247 Move(result_reg, Immediate(255)); 248 bind(&done); 249} 250 251 252void MacroAssembler::ClampUint8(Register reg) { 253 Label done; 254 test(reg, Immediate(0xFFFFFF00)); 255 j(zero, &done, Label::kNear); 256 setcc(negative, reg); // 1 if negative, 0 if positive. 257 dec_b(reg); // 0 if negative, 255 if positive. 258 bind(&done); 259} 260 261 262void MacroAssembler::SlowTruncateToI(Register result_reg, 263 Register input_reg, 264 int offset) { 265 DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true); 266 call(stub.GetCode(), RelocInfo::CODE_TARGET); 267} 268 269 270void MacroAssembler::TruncateDoubleToI(Register result_reg, 271 XMMRegister input_reg) { 272 Label done; 273 cvttsd2si(result_reg, Operand(input_reg)); 274 cmp(result_reg, 0x1); 275 j(no_overflow, &done, Label::kNear); 276 277 sub(esp, Immediate(kDoubleSize)); 278 movsd(MemOperand(esp, 0), input_reg); 279 SlowTruncateToI(result_reg, esp, 0); 280 add(esp, Immediate(kDoubleSize)); 281 bind(&done); 282} 283 284 285void MacroAssembler::DoubleToI(Register result_reg, XMMRegister input_reg, 286 XMMRegister scratch, 287 MinusZeroMode minus_zero_mode, 288 Label* lost_precision, Label* is_nan, 289 Label* minus_zero, Label::Distance dst) { 290 DCHECK(!input_reg.is(scratch)); 291 cvttsd2si(result_reg, Operand(input_reg)); 292 Cvtsi2sd(scratch, Operand(result_reg)); 293 ucomisd(scratch, input_reg); 294 j(not_equal, lost_precision, dst); 295 j(parity_even, is_nan, dst); 296 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { 297 Label done; 298 // The integer converted back is equal to the original. We 299 // only have to test if we got -0 as an input. 300 test(result_reg, Operand(result_reg)); 301 j(not_zero, &done, Label::kNear); 302 movmskpd(result_reg, input_reg); 303 // Bit 0 contains the sign of the double in input_reg. 304 // If input was positive, we are ok and return 0, otherwise 305 // jump to minus_zero. 306 and_(result_reg, 1); 307 j(not_zero, minus_zero, dst); 308 bind(&done); 309 } 310} 311 312 313void MacroAssembler::TruncateHeapNumberToI(Register result_reg, 314 Register input_reg) { 315 Label done, slow_case; 316 317 if (CpuFeatures::IsSupported(SSE3)) { 318 CpuFeatureScope scope(this, SSE3); 319 Label convert; 320 // Use more powerful conversion when sse3 is available. 321 // Load x87 register with heap number. 322 fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); 323 // Get exponent alone and check for too-big exponent. 324 mov(result_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset)); 325 and_(result_reg, HeapNumber::kExponentMask); 326 const uint32_t kTooBigExponent = 327 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; 328 cmp(Operand(result_reg), Immediate(kTooBigExponent)); 329 j(greater_equal, &slow_case, Label::kNear); 330 331 // Reserve space for 64 bit answer. 332 sub(Operand(esp), Immediate(kDoubleSize)); 333 // Do conversion, which cannot fail because we checked the exponent. 334 fisttp_d(Operand(esp, 0)); 335 mov(result_reg, Operand(esp, 0)); // Low word of answer is the result. 336 add(Operand(esp), Immediate(kDoubleSize)); 337 jmp(&done, Label::kNear); 338 339 // Slow case. 340 bind(&slow_case); 341 if (input_reg.is(result_reg)) { 342 // Input is clobbered. Restore number from fpu stack 343 sub(Operand(esp), Immediate(kDoubleSize)); 344 fstp_d(Operand(esp, 0)); 345 SlowTruncateToI(result_reg, esp, 0); 346 add(esp, Immediate(kDoubleSize)); 347 } else { 348 fstp(0); 349 SlowTruncateToI(result_reg, input_reg); 350 } 351 } else { 352 movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); 353 cvttsd2si(result_reg, Operand(xmm0)); 354 cmp(result_reg, 0x1); 355 j(no_overflow, &done, Label::kNear); 356 // Check if the input was 0x8000000 (kMinInt). 357 // If no, then we got an overflow and we deoptimize. 358 ExternalReference min_int = ExternalReference::address_of_min_int(); 359 ucomisd(xmm0, Operand::StaticVariable(min_int)); 360 j(not_equal, &slow_case, Label::kNear); 361 j(parity_even, &slow_case, Label::kNear); // NaN. 362 jmp(&done, Label::kNear); 363 364 // Slow case. 365 bind(&slow_case); 366 if (input_reg.is(result_reg)) { 367 // Input is clobbered. Restore number from double scratch. 368 sub(esp, Immediate(kDoubleSize)); 369 movsd(MemOperand(esp, 0), xmm0); 370 SlowTruncateToI(result_reg, esp, 0); 371 add(esp, Immediate(kDoubleSize)); 372 } else { 373 SlowTruncateToI(result_reg, input_reg); 374 } 375 } 376 bind(&done); 377} 378 379 380void MacroAssembler::LoadUint32(XMMRegister dst, const Operand& src) { 381 Label done; 382 cmp(src, Immediate(0)); 383 ExternalReference uint32_bias = ExternalReference::address_of_uint32_bias(); 384 Cvtsi2sd(dst, src); 385 j(not_sign, &done, Label::kNear); 386 addsd(dst, Operand::StaticVariable(uint32_bias)); 387 bind(&done); 388} 389 390 391void MacroAssembler::RecordWriteArray( 392 Register object, 393 Register value, 394 Register index, 395 SaveFPRegsMode save_fp, 396 RememberedSetAction remembered_set_action, 397 SmiCheck smi_check, 398 PointersToHereCheck pointers_to_here_check_for_value) { 399 // First, check if a write barrier is even needed. The tests below 400 // catch stores of Smis. 401 Label done; 402 403 // Skip barrier if writing a smi. 404 if (smi_check == INLINE_SMI_CHECK) { 405 DCHECK_EQ(0, kSmiTag); 406 test(value, Immediate(kSmiTagMask)); 407 j(zero, &done); 408 } 409 410 // Array access: calculate the destination address in the same manner as 411 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset 412 // into an array of words. 413 Register dst = index; 414 lea(dst, Operand(object, index, times_half_pointer_size, 415 FixedArray::kHeaderSize - kHeapObjectTag)); 416 417 RecordWrite(object, dst, value, save_fp, remembered_set_action, 418 OMIT_SMI_CHECK, pointers_to_here_check_for_value); 419 420 bind(&done); 421 422 // Clobber clobbered input registers when running with the debug-code flag 423 // turned on to provoke errors. 424 if (emit_debug_code()) { 425 mov(value, Immediate(bit_cast<int32_t>(kZapValue))); 426 mov(index, Immediate(bit_cast<int32_t>(kZapValue))); 427 } 428} 429 430 431void MacroAssembler::RecordWriteField( 432 Register object, 433 int offset, 434 Register value, 435 Register dst, 436 SaveFPRegsMode save_fp, 437 RememberedSetAction remembered_set_action, 438 SmiCheck smi_check, 439 PointersToHereCheck pointers_to_here_check_for_value) { 440 // First, check if a write barrier is even needed. The tests below 441 // catch stores of Smis. 442 Label done; 443 444 // Skip barrier if writing a smi. 445 if (smi_check == INLINE_SMI_CHECK) { 446 JumpIfSmi(value, &done, Label::kNear); 447 } 448 449 // Although the object register is tagged, the offset is relative to the start 450 // of the object, so so offset must be a multiple of kPointerSize. 451 DCHECK(IsAligned(offset, kPointerSize)); 452 453 lea(dst, FieldOperand(object, offset)); 454 if (emit_debug_code()) { 455 Label ok; 456 test_b(dst, Immediate((1 << kPointerSizeLog2) - 1)); 457 j(zero, &ok, Label::kNear); 458 int3(); 459 bind(&ok); 460 } 461 462 RecordWrite(object, dst, value, save_fp, remembered_set_action, 463 OMIT_SMI_CHECK, pointers_to_here_check_for_value); 464 465 bind(&done); 466 467 // Clobber clobbered input registers when running with the debug-code flag 468 // turned on to provoke errors. 469 if (emit_debug_code()) { 470 mov(value, Immediate(bit_cast<int32_t>(kZapValue))); 471 mov(dst, Immediate(bit_cast<int32_t>(kZapValue))); 472 } 473} 474 475 476void MacroAssembler::RecordWriteForMap( 477 Register object, 478 Handle<Map> map, 479 Register scratch1, 480 Register scratch2, 481 SaveFPRegsMode save_fp) { 482 Label done; 483 484 Register address = scratch1; 485 Register value = scratch2; 486 if (emit_debug_code()) { 487 Label ok; 488 lea(address, FieldOperand(object, HeapObject::kMapOffset)); 489 test_b(address, Immediate((1 << kPointerSizeLog2) - 1)); 490 j(zero, &ok, Label::kNear); 491 int3(); 492 bind(&ok); 493 } 494 495 DCHECK(!object.is(value)); 496 DCHECK(!object.is(address)); 497 DCHECK(!value.is(address)); 498 AssertNotSmi(object); 499 500 if (!FLAG_incremental_marking) { 501 return; 502 } 503 504 // Compute the address. 505 lea(address, FieldOperand(object, HeapObject::kMapOffset)); 506 507 // A single check of the map's pages interesting flag suffices, since it is 508 // only set during incremental collection, and then it's also guaranteed that 509 // the from object's page's interesting flag is also set. This optimization 510 // relies on the fact that maps can never be in new space. 511 DCHECK(!isolate()->heap()->InNewSpace(*map)); 512 CheckPageFlagForMap(map, 513 MemoryChunk::kPointersToHereAreInterestingMask, 514 zero, 515 &done, 516 Label::kNear); 517 518 RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET, 519 save_fp); 520 CallStub(&stub); 521 522 bind(&done); 523 524 // Count number of write barriers in generated code. 525 isolate()->counters()->write_barriers_static()->Increment(); 526 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1); 527 528 // Clobber clobbered input registers when running with the debug-code flag 529 // turned on to provoke errors. 530 if (emit_debug_code()) { 531 mov(value, Immediate(bit_cast<int32_t>(kZapValue))); 532 mov(scratch1, Immediate(bit_cast<int32_t>(kZapValue))); 533 mov(scratch2, Immediate(bit_cast<int32_t>(kZapValue))); 534 } 535} 536 537 538void MacroAssembler::RecordWrite( 539 Register object, 540 Register address, 541 Register value, 542 SaveFPRegsMode fp_mode, 543 RememberedSetAction remembered_set_action, 544 SmiCheck smi_check, 545 PointersToHereCheck pointers_to_here_check_for_value) { 546 DCHECK(!object.is(value)); 547 DCHECK(!object.is(address)); 548 DCHECK(!value.is(address)); 549 AssertNotSmi(object); 550 551 if (remembered_set_action == OMIT_REMEMBERED_SET && 552 !FLAG_incremental_marking) { 553 return; 554 } 555 556 if (emit_debug_code()) { 557 Label ok; 558 cmp(value, Operand(address, 0)); 559 j(equal, &ok, Label::kNear); 560 int3(); 561 bind(&ok); 562 } 563 564 // First, check if a write barrier is even needed. The tests below 565 // catch stores of Smis and stores into young gen. 566 Label done; 567 568 if (smi_check == INLINE_SMI_CHECK) { 569 // Skip barrier if writing a smi. 570 JumpIfSmi(value, &done, Label::kNear); 571 } 572 573 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { 574 CheckPageFlag(value, 575 value, // Used as scratch. 576 MemoryChunk::kPointersToHereAreInterestingMask, 577 zero, 578 &done, 579 Label::kNear); 580 } 581 CheckPageFlag(object, 582 value, // Used as scratch. 583 MemoryChunk::kPointersFromHereAreInterestingMask, 584 zero, 585 &done, 586 Label::kNear); 587 588 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, 589 fp_mode); 590 CallStub(&stub); 591 592 bind(&done); 593 594 // Count number of write barriers in generated code. 595 isolate()->counters()->write_barriers_static()->Increment(); 596 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1); 597 598 // Clobber clobbered registers when running with the debug-code flag 599 // turned on to provoke errors. 600 if (emit_debug_code()) { 601 mov(address, Immediate(bit_cast<int32_t>(kZapValue))); 602 mov(value, Immediate(bit_cast<int32_t>(kZapValue))); 603 } 604} 605 606void MacroAssembler::RecordWriteCodeEntryField(Register js_function, 607 Register code_entry, 608 Register scratch) { 609 const int offset = JSFunction::kCodeEntryOffset; 610 611 // Since a code entry (value) is always in old space, we don't need to update 612 // remembered set. If incremental marking is off, there is nothing for us to 613 // do. 614 if (!FLAG_incremental_marking) return; 615 616 DCHECK(!js_function.is(code_entry)); 617 DCHECK(!js_function.is(scratch)); 618 DCHECK(!code_entry.is(scratch)); 619 AssertNotSmi(js_function); 620 621 if (emit_debug_code()) { 622 Label ok; 623 lea(scratch, FieldOperand(js_function, offset)); 624 cmp(code_entry, Operand(scratch, 0)); 625 j(equal, &ok, Label::kNear); 626 int3(); 627 bind(&ok); 628 } 629 630 // First, check if a write barrier is even needed. The tests below 631 // catch stores of Smis and stores into young gen. 632 Label done; 633 634 CheckPageFlag(code_entry, scratch, 635 MemoryChunk::kPointersToHereAreInterestingMask, zero, &done, 636 Label::kNear); 637 CheckPageFlag(js_function, scratch, 638 MemoryChunk::kPointersFromHereAreInterestingMask, zero, &done, 639 Label::kNear); 640 641 // Save input registers. 642 push(js_function); 643 push(code_entry); 644 645 const Register dst = scratch; 646 lea(dst, FieldOperand(js_function, offset)); 647 648 // Save caller-saved registers. 649 PushCallerSaved(kDontSaveFPRegs, js_function, code_entry); 650 651 int argument_count = 3; 652 PrepareCallCFunction(argument_count, code_entry); 653 mov(Operand(esp, 0 * kPointerSize), js_function); 654 mov(Operand(esp, 1 * kPointerSize), dst); // Slot. 655 mov(Operand(esp, 2 * kPointerSize), 656 Immediate(ExternalReference::isolate_address(isolate()))); 657 658 { 659 AllowExternalCallThatCantCauseGC scope(this); 660 CallCFunction( 661 ExternalReference::incremental_marking_record_write_code_entry_function( 662 isolate()), 663 argument_count); 664 } 665 666 // Restore caller-saved registers. 667 PopCallerSaved(kDontSaveFPRegs, js_function, code_entry); 668 669 // Restore input registers. 670 pop(code_entry); 671 pop(js_function); 672 673 bind(&done); 674} 675 676void MacroAssembler::DebugBreak() { 677 Move(eax, Immediate(0)); 678 mov(ebx, Immediate(ExternalReference(Runtime::kHandleDebuggerStatement, 679 isolate()))); 680 CEntryStub ces(isolate(), 1); 681 call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); 682} 683 684void MacroAssembler::Cvtsi2sd(XMMRegister dst, const Operand& src) { 685 xorps(dst, dst); 686 cvtsi2sd(dst, src); 687} 688 689 690void MacroAssembler::Cvtui2ss(XMMRegister dst, Register src, Register tmp) { 691 Label msb_set_src; 692 Label jmp_return; 693 test(src, src); 694 j(sign, &msb_set_src, Label::kNear); 695 cvtsi2ss(dst, src); 696 jmp(&jmp_return, Label::kNear); 697 bind(&msb_set_src); 698 mov(tmp, src); 699 shr(src, 1); 700 // Recover the least significant bit to avoid rounding errors. 701 and_(tmp, Immediate(1)); 702 or_(src, tmp); 703 cvtsi2ss(dst, src); 704 addss(dst, dst); 705 bind(&jmp_return); 706} 707 708void MacroAssembler::ShlPair(Register high, Register low, uint8_t shift) { 709 if (shift >= 32) { 710 mov(high, low); 711 shl(high, shift - 32); 712 xor_(low, low); 713 } else { 714 shld(high, low, shift); 715 shl(low, shift); 716 } 717} 718 719void MacroAssembler::ShlPair_cl(Register high, Register low) { 720 shld_cl(high, low); 721 shl_cl(low); 722 Label done; 723 test(ecx, Immediate(0x20)); 724 j(equal, &done, Label::kNear); 725 mov(high, low); 726 xor_(low, low); 727 bind(&done); 728} 729 730void MacroAssembler::ShrPair(Register high, Register low, uint8_t shift) { 731 if (shift >= 32) { 732 mov(low, high); 733 shr(low, shift - 32); 734 xor_(high, high); 735 } else { 736 shrd(high, low, shift); 737 shr(high, shift); 738 } 739} 740 741void MacroAssembler::ShrPair_cl(Register high, Register low) { 742 shrd_cl(low, high); 743 shr_cl(high); 744 Label done; 745 test(ecx, Immediate(0x20)); 746 j(equal, &done, Label::kNear); 747 mov(low, high); 748 xor_(high, high); 749 bind(&done); 750} 751 752void MacroAssembler::SarPair(Register high, Register low, uint8_t shift) { 753 if (shift >= 32) { 754 mov(low, high); 755 sar(low, shift - 32); 756 sar(high, 31); 757 } else { 758 shrd(high, low, shift); 759 sar(high, shift); 760 } 761} 762 763void MacroAssembler::SarPair_cl(Register high, Register low) { 764 shrd_cl(low, high); 765 sar_cl(high); 766 Label done; 767 test(ecx, Immediate(0x20)); 768 j(equal, &done, Label::kNear); 769 mov(low, high); 770 sar(high, 31); 771 bind(&done); 772} 773 774bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) { 775 static const int kMaxImmediateBits = 17; 776 if (!RelocInfo::IsNone(x.rmode_)) return false; 777 return !is_intn(x.x_, kMaxImmediateBits); 778} 779 780 781void MacroAssembler::SafeMove(Register dst, const Immediate& x) { 782 if (IsUnsafeImmediate(x) && jit_cookie() != 0) { 783 Move(dst, Immediate(x.x_ ^ jit_cookie())); 784 xor_(dst, jit_cookie()); 785 } else { 786 Move(dst, x); 787 } 788} 789 790 791void MacroAssembler::SafePush(const Immediate& x) { 792 if (IsUnsafeImmediate(x) && jit_cookie() != 0) { 793 push(Immediate(x.x_ ^ jit_cookie())); 794 xor_(Operand(esp, 0), Immediate(jit_cookie())); 795 } else { 796 push(x); 797 } 798} 799 800 801void MacroAssembler::CmpObjectType(Register heap_object, 802 InstanceType type, 803 Register map) { 804 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); 805 CmpInstanceType(map, type); 806} 807 808 809void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { 810 cmpb(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(type)); 811} 812 813void MacroAssembler::CheckFastObjectElements(Register map, 814 Label* fail, 815 Label::Distance distance) { 816 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 817 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 818 STATIC_ASSERT(FAST_ELEMENTS == 2); 819 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); 820 cmpb(FieldOperand(map, Map::kBitField2Offset), 821 Immediate(Map::kMaximumBitField2FastHoleySmiElementValue)); 822 j(below_equal, fail, distance); 823 cmpb(FieldOperand(map, Map::kBitField2Offset), 824 Immediate(Map::kMaximumBitField2FastHoleyElementValue)); 825 j(above, fail, distance); 826} 827 828 829void MacroAssembler::CheckFastSmiElements(Register map, 830 Label* fail, 831 Label::Distance distance) { 832 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 833 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 834 cmpb(FieldOperand(map, Map::kBitField2Offset), 835 Immediate(Map::kMaximumBitField2FastHoleySmiElementValue)); 836 j(above, fail, distance); 837} 838 839 840void MacroAssembler::StoreNumberToDoubleElements( 841 Register maybe_number, 842 Register elements, 843 Register key, 844 Register scratch1, 845 XMMRegister scratch2, 846 Label* fail, 847 int elements_offset) { 848 Label smi_value, done; 849 JumpIfSmi(maybe_number, &smi_value, Label::kNear); 850 851 CheckMap(maybe_number, 852 isolate()->factory()->heap_number_map(), 853 fail, 854 DONT_DO_SMI_CHECK); 855 856 // Double value, turn potential sNaN into qNaN. 857 Move(scratch2, 1.0); 858 mulsd(scratch2, FieldOperand(maybe_number, HeapNumber::kValueOffset)); 859 jmp(&done, Label::kNear); 860 861 bind(&smi_value); 862 // Value is a smi. Convert to a double and store. 863 // Preserve original value. 864 mov(scratch1, maybe_number); 865 SmiUntag(scratch1); 866 Cvtsi2sd(scratch2, scratch1); 867 bind(&done); 868 movsd(FieldOperand(elements, key, times_4, 869 FixedDoubleArray::kHeaderSize - elements_offset), 870 scratch2); 871} 872 873 874void MacroAssembler::CompareMap(Register obj, Handle<Map> map) { 875 cmp(FieldOperand(obj, HeapObject::kMapOffset), map); 876} 877 878 879void MacroAssembler::CheckMap(Register obj, 880 Handle<Map> map, 881 Label* fail, 882 SmiCheckType smi_check_type) { 883 if (smi_check_type == DO_SMI_CHECK) { 884 JumpIfSmi(obj, fail); 885 } 886 887 CompareMap(obj, map); 888 j(not_equal, fail); 889} 890 891 892void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1, 893 Register scratch2, Handle<WeakCell> cell, 894 Handle<Code> success, 895 SmiCheckType smi_check_type) { 896 Label fail; 897 if (smi_check_type == DO_SMI_CHECK) { 898 JumpIfSmi(obj, &fail); 899 } 900 mov(scratch1, FieldOperand(obj, HeapObject::kMapOffset)); 901 CmpWeakValue(scratch1, cell, scratch2); 902 j(equal, success); 903 904 bind(&fail); 905} 906 907 908Condition MacroAssembler::IsObjectStringType(Register heap_object, 909 Register map, 910 Register instance_type) { 911 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); 912 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); 913 STATIC_ASSERT(kNotStringTag != 0); 914 test(instance_type, Immediate(kIsNotStringMask)); 915 return zero; 916} 917 918 919Condition MacroAssembler::IsObjectNameType(Register heap_object, 920 Register map, 921 Register instance_type) { 922 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); 923 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); 924 cmpb(instance_type, Immediate(LAST_NAME_TYPE)); 925 return below_equal; 926} 927 928 929void MacroAssembler::FCmp() { 930 fucomip(); 931 fstp(0); 932} 933 934 935void MacroAssembler::AssertNumber(Register object) { 936 if (emit_debug_code()) { 937 Label ok; 938 JumpIfSmi(object, &ok); 939 cmp(FieldOperand(object, HeapObject::kMapOffset), 940 isolate()->factory()->heap_number_map()); 941 Check(equal, kOperandNotANumber); 942 bind(&ok); 943 } 944} 945 946void MacroAssembler::AssertNotNumber(Register object) { 947 if (emit_debug_code()) { 948 test(object, Immediate(kSmiTagMask)); 949 Check(not_equal, kOperandIsANumber); 950 cmp(FieldOperand(object, HeapObject::kMapOffset), 951 isolate()->factory()->heap_number_map()); 952 Check(not_equal, kOperandIsANumber); 953 } 954} 955 956void MacroAssembler::AssertSmi(Register object) { 957 if (emit_debug_code()) { 958 test(object, Immediate(kSmiTagMask)); 959 Check(equal, kOperandIsNotASmi); 960 } 961} 962 963 964void MacroAssembler::AssertString(Register object) { 965 if (emit_debug_code()) { 966 test(object, Immediate(kSmiTagMask)); 967 Check(not_equal, kOperandIsASmiAndNotAString); 968 push(object); 969 mov(object, FieldOperand(object, HeapObject::kMapOffset)); 970 CmpInstanceType(object, FIRST_NONSTRING_TYPE); 971 pop(object); 972 Check(below, kOperandIsNotAString); 973 } 974} 975 976 977void MacroAssembler::AssertName(Register object) { 978 if (emit_debug_code()) { 979 test(object, Immediate(kSmiTagMask)); 980 Check(not_equal, kOperandIsASmiAndNotAName); 981 push(object); 982 mov(object, FieldOperand(object, HeapObject::kMapOffset)); 983 CmpInstanceType(object, LAST_NAME_TYPE); 984 pop(object); 985 Check(below_equal, kOperandIsNotAName); 986 } 987} 988 989 990void MacroAssembler::AssertFunction(Register object) { 991 if (emit_debug_code()) { 992 test(object, Immediate(kSmiTagMask)); 993 Check(not_equal, kOperandIsASmiAndNotAFunction); 994 Push(object); 995 CmpObjectType(object, JS_FUNCTION_TYPE, object); 996 Pop(object); 997 Check(equal, kOperandIsNotAFunction); 998 } 999} 1000 1001 1002void MacroAssembler::AssertBoundFunction(Register object) { 1003 if (emit_debug_code()) { 1004 test(object, Immediate(kSmiTagMask)); 1005 Check(not_equal, kOperandIsASmiAndNotABoundFunction); 1006 Push(object); 1007 CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object); 1008 Pop(object); 1009 Check(equal, kOperandIsNotABoundFunction); 1010 } 1011} 1012 1013void MacroAssembler::AssertGeneratorObject(Register object) { 1014 if (emit_debug_code()) { 1015 test(object, Immediate(kSmiTagMask)); 1016 Check(not_equal, kOperandIsASmiAndNotAGeneratorObject); 1017 Push(object); 1018 CmpObjectType(object, JS_GENERATOR_OBJECT_TYPE, object); 1019 Pop(object); 1020 Check(equal, kOperandIsNotAGeneratorObject); 1021 } 1022} 1023 1024void MacroAssembler::AssertReceiver(Register object) { 1025 if (emit_debug_code()) { 1026 test(object, Immediate(kSmiTagMask)); 1027 Check(not_equal, kOperandIsASmiAndNotAReceiver); 1028 Push(object); 1029 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 1030 CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, object); 1031 Pop(object); 1032 Check(above_equal, kOperandIsNotAReceiver); 1033 } 1034} 1035 1036 1037void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) { 1038 if (emit_debug_code()) { 1039 Label done_checking; 1040 AssertNotSmi(object); 1041 cmp(object, isolate()->factory()->undefined_value()); 1042 j(equal, &done_checking); 1043 cmp(FieldOperand(object, 0), 1044 Immediate(isolate()->factory()->allocation_site_map())); 1045 Assert(equal, kExpectedUndefinedOrCell); 1046 bind(&done_checking); 1047 } 1048} 1049 1050 1051void MacroAssembler::AssertNotSmi(Register object) { 1052 if (emit_debug_code()) { 1053 test(object, Immediate(kSmiTagMask)); 1054 Check(not_equal, kOperandIsASmi); 1055 } 1056} 1057 1058void MacroAssembler::StubPrologue(StackFrame::Type type) { 1059 push(ebp); // Caller's frame pointer. 1060 mov(ebp, esp); 1061 push(Immediate(Smi::FromInt(type))); 1062} 1063 1064void MacroAssembler::Prologue(bool code_pre_aging) { 1065 PredictableCodeSizeScope predictible_code_size_scope(this, 1066 kNoCodeAgeSequenceLength); 1067 if (code_pre_aging) { 1068 // Pre-age the code. 1069 call(isolate()->builtins()->MarkCodeAsExecutedOnce(), 1070 RelocInfo::CODE_AGE_SEQUENCE); 1071 Nop(kNoCodeAgeSequenceLength - Assembler::kCallInstructionLength); 1072 } else { 1073 push(ebp); // Caller's frame pointer. 1074 mov(ebp, esp); 1075 push(esi); // Callee's context. 1076 push(edi); // Callee's JS function. 1077 } 1078} 1079 1080 1081void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) { 1082 mov(vector, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1083 mov(vector, FieldOperand(vector, JSFunction::kLiteralsOffset)); 1084 mov(vector, FieldOperand(vector, LiteralsArray::kFeedbackVectorOffset)); 1085} 1086 1087 1088void MacroAssembler::EnterFrame(StackFrame::Type type, 1089 bool load_constant_pool_pointer_reg) { 1090 // Out-of-line constant pool not implemented on ia32. 1091 UNREACHABLE(); 1092} 1093 1094 1095void MacroAssembler::EnterFrame(StackFrame::Type type) { 1096 push(ebp); 1097 mov(ebp, esp); 1098 push(Immediate(Smi::FromInt(type))); 1099 if (type == StackFrame::INTERNAL) { 1100 push(Immediate(CodeObject())); 1101 } 1102 if (emit_debug_code()) { 1103 cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value())); 1104 Check(not_equal, kCodeObjectNotProperlyPatched); 1105 } 1106} 1107 1108 1109void MacroAssembler::LeaveFrame(StackFrame::Type type) { 1110 if (emit_debug_code()) { 1111 cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset), 1112 Immediate(Smi::FromInt(type))); 1113 Check(equal, kStackFrameTypesMustMatch); 1114 } 1115 leave(); 1116} 1117 1118void MacroAssembler::EnterBuiltinFrame(Register context, Register target, 1119 Register argc) { 1120 Push(ebp); 1121 Move(ebp, esp); 1122 Push(context); 1123 Push(target); 1124 Push(argc); 1125} 1126 1127void MacroAssembler::LeaveBuiltinFrame(Register context, Register target, 1128 Register argc) { 1129 Pop(argc); 1130 Pop(target); 1131 Pop(context); 1132 leave(); 1133} 1134 1135void MacroAssembler::EnterExitFramePrologue(StackFrame::Type frame_type) { 1136 DCHECK(frame_type == StackFrame::EXIT || 1137 frame_type == StackFrame::BUILTIN_EXIT); 1138 1139 // Set up the frame structure on the stack. 1140 DCHECK_EQ(+2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); 1141 DCHECK_EQ(+1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); 1142 DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); 1143 push(ebp); 1144 mov(ebp, esp); 1145 1146 // Reserve room for entry stack pointer and push the code object. 1147 push(Immediate(Smi::FromInt(frame_type))); 1148 DCHECK_EQ(-2 * kPointerSize, ExitFrameConstants::kSPOffset); 1149 push(Immediate(0)); // Saved entry sp, patched before call. 1150 DCHECK_EQ(-3 * kPointerSize, ExitFrameConstants::kCodeOffset); 1151 push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot. 1152 1153 // Save the frame pointer and the context in top. 1154 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate()); 1155 ExternalReference context_address(Isolate::kContextAddress, isolate()); 1156 ExternalReference c_function_address(Isolate::kCFunctionAddress, isolate()); 1157 mov(Operand::StaticVariable(c_entry_fp_address), ebp); 1158 mov(Operand::StaticVariable(context_address), esi); 1159 mov(Operand::StaticVariable(c_function_address), ebx); 1160} 1161 1162 1163void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) { 1164 // Optionally save all XMM registers. 1165 if (save_doubles) { 1166 int space = XMMRegister::kMaxNumRegisters * kDoubleSize + 1167 argc * kPointerSize; 1168 sub(esp, Immediate(space)); 1169 const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp; 1170 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { 1171 XMMRegister reg = XMMRegister::from_code(i); 1172 movsd(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg); 1173 } 1174 } else { 1175 sub(esp, Immediate(argc * kPointerSize)); 1176 } 1177 1178 // Get the required frame alignment for the OS. 1179 const int kFrameAlignment = base::OS::ActivationFrameAlignment(); 1180 if (kFrameAlignment > 0) { 1181 DCHECK(base::bits::IsPowerOfTwo32(kFrameAlignment)); 1182 and_(esp, -kFrameAlignment); 1183 } 1184 1185 // Patch the saved entry sp. 1186 mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp); 1187} 1188 1189void MacroAssembler::EnterExitFrame(int argc, bool save_doubles, 1190 StackFrame::Type frame_type) { 1191 EnterExitFramePrologue(frame_type); 1192 1193 // Set up argc and argv in callee-saved registers. 1194 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; 1195 mov(edi, eax); 1196 lea(esi, Operand(ebp, eax, times_4, offset)); 1197 1198 // Reserve space for argc, argv and isolate. 1199 EnterExitFrameEpilogue(argc, save_doubles); 1200} 1201 1202 1203void MacroAssembler::EnterApiExitFrame(int argc) { 1204 EnterExitFramePrologue(StackFrame::EXIT); 1205 EnterExitFrameEpilogue(argc, false); 1206} 1207 1208 1209void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) { 1210 // Optionally restore all XMM registers. 1211 if (save_doubles) { 1212 const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp; 1213 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { 1214 XMMRegister reg = XMMRegister::from_code(i); 1215 movsd(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize))); 1216 } 1217 } 1218 1219 if (pop_arguments) { 1220 // Get the return address from the stack and restore the frame pointer. 1221 mov(ecx, Operand(ebp, 1 * kPointerSize)); 1222 mov(ebp, Operand(ebp, 0 * kPointerSize)); 1223 1224 // Pop the arguments and the receiver from the caller stack. 1225 lea(esp, Operand(esi, 1 * kPointerSize)); 1226 1227 // Push the return address to get ready to return. 1228 push(ecx); 1229 } else { 1230 // Otherwise just leave the exit frame. 1231 leave(); 1232 } 1233 1234 LeaveExitFrameEpilogue(true); 1235} 1236 1237 1238void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) { 1239 // Restore current context from top and clear it in debug mode. 1240 ExternalReference context_address(Isolate::kContextAddress, isolate()); 1241 if (restore_context) { 1242 mov(esi, Operand::StaticVariable(context_address)); 1243 } 1244#ifdef DEBUG 1245 mov(Operand::StaticVariable(context_address), Immediate(0)); 1246#endif 1247 1248 // Clear the top frame. 1249 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, 1250 isolate()); 1251 mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0)); 1252} 1253 1254 1255void MacroAssembler::LeaveApiExitFrame(bool restore_context) { 1256 mov(esp, ebp); 1257 pop(ebp); 1258 1259 LeaveExitFrameEpilogue(restore_context); 1260} 1261 1262 1263void MacroAssembler::PushStackHandler() { 1264 // Adjust this code if not the case. 1265 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); 1266 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 1267 1268 // Link the current handler as the next handler. 1269 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); 1270 push(Operand::StaticVariable(handler_address)); 1271 1272 // Set this new handler as the current one. 1273 mov(Operand::StaticVariable(handler_address), esp); 1274} 1275 1276 1277void MacroAssembler::PopStackHandler() { 1278 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 1279 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); 1280 pop(Operand::StaticVariable(handler_address)); 1281 add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize)); 1282} 1283 1284 1285// Compute the hash code from the untagged key. This must be kept in sync with 1286// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in 1287// code-stub-hydrogen.cc 1288// 1289// Note: r0 will contain hash code 1290void MacroAssembler::GetNumberHash(Register r0, Register scratch) { 1291 // Xor original key with a seed. 1292 if (serializer_enabled()) { 1293 ExternalReference roots_array_start = 1294 ExternalReference::roots_array_start(isolate()); 1295 mov(scratch, Immediate(Heap::kHashSeedRootIndex)); 1296 mov(scratch, 1297 Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); 1298 SmiUntag(scratch); 1299 xor_(r0, scratch); 1300 } else { 1301 int32_t seed = isolate()->heap()->HashSeed(); 1302 xor_(r0, Immediate(seed)); 1303 } 1304 1305 // hash = ~hash + (hash << 15); 1306 mov(scratch, r0); 1307 not_(r0); 1308 shl(scratch, 15); 1309 add(r0, scratch); 1310 // hash = hash ^ (hash >> 12); 1311 mov(scratch, r0); 1312 shr(scratch, 12); 1313 xor_(r0, scratch); 1314 // hash = hash + (hash << 2); 1315 lea(r0, Operand(r0, r0, times_4, 0)); 1316 // hash = hash ^ (hash >> 4); 1317 mov(scratch, r0); 1318 shr(scratch, 4); 1319 xor_(r0, scratch); 1320 // hash = hash * 2057; 1321 imul(r0, r0, 2057); 1322 // hash = hash ^ (hash >> 16); 1323 mov(scratch, r0); 1324 shr(scratch, 16); 1325 xor_(r0, scratch); 1326 and_(r0, 0x3fffffff); 1327} 1328 1329void MacroAssembler::LoadAllocationTopHelper(Register result, 1330 Register scratch, 1331 AllocationFlags flags) { 1332 ExternalReference allocation_top = 1333 AllocationUtils::GetAllocationTopReference(isolate(), flags); 1334 1335 // Just return if allocation top is already known. 1336 if ((flags & RESULT_CONTAINS_TOP) != 0) { 1337 // No use of scratch if allocation top is provided. 1338 DCHECK(scratch.is(no_reg)); 1339#ifdef DEBUG 1340 // Assert that result actually contains top on entry. 1341 cmp(result, Operand::StaticVariable(allocation_top)); 1342 Check(equal, kUnexpectedAllocationTop); 1343#endif 1344 return; 1345 } 1346 1347 // Move address of new object to result. Use scratch register if available. 1348 if (scratch.is(no_reg)) { 1349 mov(result, Operand::StaticVariable(allocation_top)); 1350 } else { 1351 mov(scratch, Immediate(allocation_top)); 1352 mov(result, Operand(scratch, 0)); 1353 } 1354} 1355 1356 1357void MacroAssembler::UpdateAllocationTopHelper(Register result_end, 1358 Register scratch, 1359 AllocationFlags flags) { 1360 if (emit_debug_code()) { 1361 test(result_end, Immediate(kObjectAlignmentMask)); 1362 Check(zero, kUnalignedAllocationInNewSpace); 1363 } 1364 1365 ExternalReference allocation_top = 1366 AllocationUtils::GetAllocationTopReference(isolate(), flags); 1367 1368 // Update new top. Use scratch if available. 1369 if (scratch.is(no_reg)) { 1370 mov(Operand::StaticVariable(allocation_top), result_end); 1371 } else { 1372 mov(Operand(scratch, 0), result_end); 1373 } 1374} 1375 1376 1377void MacroAssembler::Allocate(int object_size, 1378 Register result, 1379 Register result_end, 1380 Register scratch, 1381 Label* gc_required, 1382 AllocationFlags flags) { 1383 DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0); 1384 DCHECK(object_size <= kMaxRegularHeapObjectSize); 1385 DCHECK((flags & ALLOCATION_FOLDED) == 0); 1386 if (!FLAG_inline_new) { 1387 if (emit_debug_code()) { 1388 // Trash the registers to simulate an allocation failure. 1389 mov(result, Immediate(0x7091)); 1390 if (result_end.is_valid()) { 1391 mov(result_end, Immediate(0x7191)); 1392 } 1393 if (scratch.is_valid()) { 1394 mov(scratch, Immediate(0x7291)); 1395 } 1396 } 1397 jmp(gc_required); 1398 return; 1399 } 1400 DCHECK(!result.is(result_end)); 1401 1402 // Load address of new object into result. 1403 LoadAllocationTopHelper(result, scratch, flags); 1404 1405 ExternalReference allocation_limit = 1406 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 1407 1408 // Align the next allocation. Storing the filler map without checking top is 1409 // safe in new-space because the limit of the heap is aligned there. 1410 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1411 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1412 Label aligned; 1413 test(result, Immediate(kDoubleAlignmentMask)); 1414 j(zero, &aligned, Label::kNear); 1415 if ((flags & PRETENURE) != 0) { 1416 cmp(result, Operand::StaticVariable(allocation_limit)); 1417 j(above_equal, gc_required); 1418 } 1419 mov(Operand(result, 0), 1420 Immediate(isolate()->factory()->one_pointer_filler_map())); 1421 add(result, Immediate(kDoubleSize / 2)); 1422 bind(&aligned); 1423 } 1424 1425 // Calculate new top and bail out if space is exhausted. 1426 Register top_reg = result_end.is_valid() ? result_end : result; 1427 1428 if (!top_reg.is(result)) { 1429 mov(top_reg, result); 1430 } 1431 add(top_reg, Immediate(object_size)); 1432 cmp(top_reg, Operand::StaticVariable(allocation_limit)); 1433 j(above, gc_required); 1434 1435 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) { 1436 // The top pointer is not updated for allocation folding dominators. 1437 UpdateAllocationTopHelper(top_reg, scratch, flags); 1438 } 1439 1440 if (top_reg.is(result)) { 1441 sub(result, Immediate(object_size - kHeapObjectTag)); 1442 } else { 1443 // Tag the result. 1444 DCHECK(kHeapObjectTag == 1); 1445 inc(result); 1446 } 1447} 1448 1449 1450void MacroAssembler::Allocate(int header_size, 1451 ScaleFactor element_size, 1452 Register element_count, 1453 RegisterValueType element_count_type, 1454 Register result, 1455 Register result_end, 1456 Register scratch, 1457 Label* gc_required, 1458 AllocationFlags flags) { 1459 DCHECK((flags & SIZE_IN_WORDS) == 0); 1460 DCHECK((flags & ALLOCATION_FOLDING_DOMINATOR) == 0); 1461 DCHECK((flags & ALLOCATION_FOLDED) == 0); 1462 if (!FLAG_inline_new) { 1463 if (emit_debug_code()) { 1464 // Trash the registers to simulate an allocation failure. 1465 mov(result, Immediate(0x7091)); 1466 mov(result_end, Immediate(0x7191)); 1467 if (scratch.is_valid()) { 1468 mov(scratch, Immediate(0x7291)); 1469 } 1470 // Register element_count is not modified by the function. 1471 } 1472 jmp(gc_required); 1473 return; 1474 } 1475 DCHECK(!result.is(result_end)); 1476 1477 // Load address of new object into result. 1478 LoadAllocationTopHelper(result, scratch, flags); 1479 1480 ExternalReference allocation_limit = 1481 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 1482 1483 // Align the next allocation. Storing the filler map without checking top is 1484 // safe in new-space because the limit of the heap is aligned there. 1485 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1486 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1487 Label aligned; 1488 test(result, Immediate(kDoubleAlignmentMask)); 1489 j(zero, &aligned, Label::kNear); 1490 if ((flags & PRETENURE) != 0) { 1491 cmp(result, Operand::StaticVariable(allocation_limit)); 1492 j(above_equal, gc_required); 1493 } 1494 mov(Operand(result, 0), 1495 Immediate(isolate()->factory()->one_pointer_filler_map())); 1496 add(result, Immediate(kDoubleSize / 2)); 1497 bind(&aligned); 1498 } 1499 1500 // Calculate new top and bail out if space is exhausted. 1501 // We assume that element_count*element_size + header_size does not 1502 // overflow. 1503 if (element_count_type == REGISTER_VALUE_IS_SMI) { 1504 STATIC_ASSERT(static_cast<ScaleFactor>(times_2 - 1) == times_1); 1505 STATIC_ASSERT(static_cast<ScaleFactor>(times_4 - 1) == times_2); 1506 STATIC_ASSERT(static_cast<ScaleFactor>(times_8 - 1) == times_4); 1507 DCHECK(element_size >= times_2); 1508 DCHECK(kSmiTagSize == 1); 1509 element_size = static_cast<ScaleFactor>(element_size - 1); 1510 } else { 1511 DCHECK(element_count_type == REGISTER_VALUE_IS_INT32); 1512 } 1513 1514 lea(result_end, Operand(element_count, element_size, header_size)); 1515 add(result_end, result); 1516 cmp(result_end, Operand::StaticVariable(allocation_limit)); 1517 j(above, gc_required); 1518 1519 // Tag result. 1520 DCHECK(kHeapObjectTag == 1); 1521 inc(result); 1522 1523 UpdateAllocationTopHelper(result_end, scratch, flags); 1524} 1525 1526 1527void MacroAssembler::Allocate(Register object_size, 1528 Register result, 1529 Register result_end, 1530 Register scratch, 1531 Label* gc_required, 1532 AllocationFlags flags) { 1533 DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0); 1534 DCHECK((flags & ALLOCATION_FOLDED) == 0); 1535 if (!FLAG_inline_new) { 1536 if (emit_debug_code()) { 1537 // Trash the registers to simulate an allocation failure. 1538 mov(result, Immediate(0x7091)); 1539 mov(result_end, Immediate(0x7191)); 1540 if (scratch.is_valid()) { 1541 mov(scratch, Immediate(0x7291)); 1542 } 1543 // object_size is left unchanged by this function. 1544 } 1545 jmp(gc_required); 1546 return; 1547 } 1548 DCHECK(!result.is(result_end)); 1549 1550 // Load address of new object into result. 1551 LoadAllocationTopHelper(result, scratch, flags); 1552 1553 ExternalReference allocation_limit = 1554 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 1555 1556 // Align the next allocation. Storing the filler map without checking top is 1557 // safe in new-space because the limit of the heap is aligned there. 1558 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1559 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1560 Label aligned; 1561 test(result, Immediate(kDoubleAlignmentMask)); 1562 j(zero, &aligned, Label::kNear); 1563 if ((flags & PRETENURE) != 0) { 1564 cmp(result, Operand::StaticVariable(allocation_limit)); 1565 j(above_equal, gc_required); 1566 } 1567 mov(Operand(result, 0), 1568 Immediate(isolate()->factory()->one_pointer_filler_map())); 1569 add(result, Immediate(kDoubleSize / 2)); 1570 bind(&aligned); 1571 } 1572 1573 // Calculate new top and bail out if space is exhausted. 1574 if (!object_size.is(result_end)) { 1575 mov(result_end, object_size); 1576 } 1577 add(result_end, result); 1578 cmp(result_end, Operand::StaticVariable(allocation_limit)); 1579 j(above, gc_required); 1580 1581 // Tag result. 1582 DCHECK(kHeapObjectTag == 1); 1583 inc(result); 1584 1585 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) { 1586 // The top pointer is not updated for allocation folding dominators. 1587 UpdateAllocationTopHelper(result_end, scratch, flags); 1588 } 1589} 1590 1591void MacroAssembler::FastAllocate(int object_size, Register result, 1592 Register result_end, AllocationFlags flags) { 1593 DCHECK(!result.is(result_end)); 1594 // Load address of new object into result. 1595 LoadAllocationTopHelper(result, no_reg, flags); 1596 1597 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1598 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1599 Label aligned; 1600 test(result, Immediate(kDoubleAlignmentMask)); 1601 j(zero, &aligned, Label::kNear); 1602 mov(Operand(result, 0), 1603 Immediate(isolate()->factory()->one_pointer_filler_map())); 1604 add(result, Immediate(kDoubleSize / 2)); 1605 bind(&aligned); 1606 } 1607 1608 lea(result_end, Operand(result, object_size)); 1609 UpdateAllocationTopHelper(result_end, no_reg, flags); 1610 1611 DCHECK(kHeapObjectTag == 1); 1612 inc(result); 1613} 1614 1615void MacroAssembler::FastAllocate(Register object_size, Register result, 1616 Register result_end, AllocationFlags flags) { 1617 DCHECK(!result.is(result_end)); 1618 // Load address of new object into result. 1619 LoadAllocationTopHelper(result, no_reg, flags); 1620 1621 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1622 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1623 Label aligned; 1624 test(result, Immediate(kDoubleAlignmentMask)); 1625 j(zero, &aligned, Label::kNear); 1626 mov(Operand(result, 0), 1627 Immediate(isolate()->factory()->one_pointer_filler_map())); 1628 add(result, Immediate(kDoubleSize / 2)); 1629 bind(&aligned); 1630 } 1631 1632 lea(result_end, Operand(result, object_size, times_1, 0)); 1633 UpdateAllocationTopHelper(result_end, no_reg, flags); 1634 1635 DCHECK(kHeapObjectTag == 1); 1636 inc(result); 1637} 1638 1639 1640void MacroAssembler::AllocateHeapNumber(Register result, 1641 Register scratch1, 1642 Register scratch2, 1643 Label* gc_required, 1644 MutableMode mode) { 1645 // Allocate heap number in new space. 1646 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required, 1647 NO_ALLOCATION_FLAGS); 1648 1649 Handle<Map> map = mode == MUTABLE 1650 ? isolate()->factory()->mutable_heap_number_map() 1651 : isolate()->factory()->heap_number_map(); 1652 1653 // Set the map. 1654 mov(FieldOperand(result, HeapObject::kMapOffset), Immediate(map)); 1655} 1656 1657 1658void MacroAssembler::AllocateTwoByteString(Register result, 1659 Register length, 1660 Register scratch1, 1661 Register scratch2, 1662 Register scratch3, 1663 Label* gc_required) { 1664 // Calculate the number of bytes needed for the characters in the string while 1665 // observing object alignment. 1666 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); 1667 DCHECK(kShortSize == 2); 1668 // scratch1 = length * 2 + kObjectAlignmentMask. 1669 lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask)); 1670 and_(scratch1, Immediate(~kObjectAlignmentMask)); 1671 1672 // Allocate two byte string in new space. 1673 Allocate(SeqTwoByteString::kHeaderSize, times_1, scratch1, 1674 REGISTER_VALUE_IS_INT32, result, scratch2, scratch3, gc_required, 1675 NO_ALLOCATION_FLAGS); 1676 1677 // Set the map, length and hash field. 1678 mov(FieldOperand(result, HeapObject::kMapOffset), 1679 Immediate(isolate()->factory()->string_map())); 1680 mov(scratch1, length); 1681 SmiTag(scratch1); 1682 mov(FieldOperand(result, String::kLengthOffset), scratch1); 1683 mov(FieldOperand(result, String::kHashFieldOffset), 1684 Immediate(String::kEmptyHashField)); 1685} 1686 1687 1688void MacroAssembler::AllocateOneByteString(Register result, Register length, 1689 Register scratch1, Register scratch2, 1690 Register scratch3, 1691 Label* gc_required) { 1692 // Calculate the number of bytes needed for the characters in the string while 1693 // observing object alignment. 1694 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); 1695 mov(scratch1, length); 1696 DCHECK(kCharSize == 1); 1697 add(scratch1, Immediate(kObjectAlignmentMask)); 1698 and_(scratch1, Immediate(~kObjectAlignmentMask)); 1699 1700 // Allocate one-byte string in new space. 1701 Allocate(SeqOneByteString::kHeaderSize, times_1, scratch1, 1702 REGISTER_VALUE_IS_INT32, result, scratch2, scratch3, gc_required, 1703 NO_ALLOCATION_FLAGS); 1704 1705 // Set the map, length and hash field. 1706 mov(FieldOperand(result, HeapObject::kMapOffset), 1707 Immediate(isolate()->factory()->one_byte_string_map())); 1708 mov(scratch1, length); 1709 SmiTag(scratch1); 1710 mov(FieldOperand(result, String::kLengthOffset), scratch1); 1711 mov(FieldOperand(result, String::kHashFieldOffset), 1712 Immediate(String::kEmptyHashField)); 1713} 1714 1715 1716void MacroAssembler::AllocateOneByteString(Register result, int length, 1717 Register scratch1, Register scratch2, 1718 Label* gc_required) { 1719 DCHECK(length > 0); 1720 1721 // Allocate one-byte string in new space. 1722 Allocate(SeqOneByteString::SizeFor(length), result, scratch1, scratch2, 1723 gc_required, NO_ALLOCATION_FLAGS); 1724 1725 // Set the map, length and hash field. 1726 mov(FieldOperand(result, HeapObject::kMapOffset), 1727 Immediate(isolate()->factory()->one_byte_string_map())); 1728 mov(FieldOperand(result, String::kLengthOffset), 1729 Immediate(Smi::FromInt(length))); 1730 mov(FieldOperand(result, String::kHashFieldOffset), 1731 Immediate(String::kEmptyHashField)); 1732} 1733 1734 1735void MacroAssembler::AllocateTwoByteConsString(Register result, 1736 Register scratch1, 1737 Register scratch2, 1738 Label* gc_required) { 1739 // Allocate heap number in new space. 1740 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, 1741 NO_ALLOCATION_FLAGS); 1742 1743 // Set the map. The other fields are left uninitialized. 1744 mov(FieldOperand(result, HeapObject::kMapOffset), 1745 Immediate(isolate()->factory()->cons_string_map())); 1746} 1747 1748 1749void MacroAssembler::AllocateOneByteConsString(Register result, 1750 Register scratch1, 1751 Register scratch2, 1752 Label* gc_required) { 1753 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, 1754 NO_ALLOCATION_FLAGS); 1755 1756 // Set the map. The other fields are left uninitialized. 1757 mov(FieldOperand(result, HeapObject::kMapOffset), 1758 Immediate(isolate()->factory()->cons_one_byte_string_map())); 1759} 1760 1761 1762void MacroAssembler::AllocateTwoByteSlicedString(Register result, 1763 Register scratch1, 1764 Register scratch2, 1765 Label* gc_required) { 1766 // Allocate heap number in new space. 1767 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, 1768 NO_ALLOCATION_FLAGS); 1769 1770 // Set the map. The other fields are left uninitialized. 1771 mov(FieldOperand(result, HeapObject::kMapOffset), 1772 Immediate(isolate()->factory()->sliced_string_map())); 1773} 1774 1775 1776void MacroAssembler::AllocateOneByteSlicedString(Register result, 1777 Register scratch1, 1778 Register scratch2, 1779 Label* gc_required) { 1780 // Allocate heap number in new space. 1781 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, 1782 NO_ALLOCATION_FLAGS); 1783 1784 // Set the map. The other fields are left uninitialized. 1785 mov(FieldOperand(result, HeapObject::kMapOffset), 1786 Immediate(isolate()->factory()->sliced_one_byte_string_map())); 1787} 1788 1789 1790void MacroAssembler::AllocateJSValue(Register result, Register constructor, 1791 Register value, Register scratch, 1792 Label* gc_required) { 1793 DCHECK(!result.is(constructor)); 1794 DCHECK(!result.is(scratch)); 1795 DCHECK(!result.is(value)); 1796 1797 // Allocate JSValue in new space. 1798 Allocate(JSValue::kSize, result, scratch, no_reg, gc_required, 1799 NO_ALLOCATION_FLAGS); 1800 1801 // Initialize the JSValue. 1802 LoadGlobalFunctionInitialMap(constructor, scratch); 1803 mov(FieldOperand(result, HeapObject::kMapOffset), scratch); 1804 LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); 1805 mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch); 1806 mov(FieldOperand(result, JSObject::kElementsOffset), scratch); 1807 mov(FieldOperand(result, JSValue::kValueOffset), value); 1808 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); 1809} 1810 1811void MacroAssembler::InitializeFieldsWithFiller(Register current_address, 1812 Register end_address, 1813 Register filler) { 1814 Label loop, entry; 1815 jmp(&entry, Label::kNear); 1816 bind(&loop); 1817 mov(Operand(current_address, 0), filler); 1818 add(current_address, Immediate(kPointerSize)); 1819 bind(&entry); 1820 cmp(current_address, end_address); 1821 j(below, &loop, Label::kNear); 1822} 1823 1824 1825void MacroAssembler::BooleanBitTest(Register object, 1826 int field_offset, 1827 int bit_index) { 1828 bit_index += kSmiTagSize + kSmiShiftSize; 1829 DCHECK(base::bits::IsPowerOfTwo32(kBitsPerByte)); 1830 int byte_index = bit_index / kBitsPerByte; 1831 int byte_bit_index = bit_index & (kBitsPerByte - 1); 1832 test_b(FieldOperand(object, field_offset + byte_index), 1833 Immediate(1 << byte_bit_index)); 1834} 1835 1836 1837 1838void MacroAssembler::NegativeZeroTest(Register result, 1839 Register op, 1840 Label* then_label) { 1841 Label ok; 1842 test(result, result); 1843 j(not_zero, &ok, Label::kNear); 1844 test(op, op); 1845 j(sign, then_label, Label::kNear); 1846 bind(&ok); 1847} 1848 1849 1850void MacroAssembler::NegativeZeroTest(Register result, 1851 Register op1, 1852 Register op2, 1853 Register scratch, 1854 Label* then_label) { 1855 Label ok; 1856 test(result, result); 1857 j(not_zero, &ok, Label::kNear); 1858 mov(scratch, op1); 1859 or_(scratch, op2); 1860 j(sign, then_label, Label::kNear); 1861 bind(&ok); 1862} 1863 1864 1865void MacroAssembler::GetMapConstructor(Register result, Register map, 1866 Register temp) { 1867 Label done, loop; 1868 mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); 1869 bind(&loop); 1870 JumpIfSmi(result, &done, Label::kNear); 1871 CmpObjectType(result, MAP_TYPE, temp); 1872 j(not_equal, &done, Label::kNear); 1873 mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); 1874 jmp(&loop); 1875 bind(&done); 1876} 1877 1878 1879void MacroAssembler::TryGetFunctionPrototype(Register function, Register result, 1880 Register scratch, Label* miss) { 1881 // Get the prototype or initial map from the function. 1882 mov(result, 1883 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 1884 1885 // If the prototype or initial map is the hole, don't return it and 1886 // simply miss the cache instead. This will allow us to allocate a 1887 // prototype object on-demand in the runtime system. 1888 cmp(result, Immediate(isolate()->factory()->the_hole_value())); 1889 j(equal, miss); 1890 1891 // If the function does not have an initial map, we're done. 1892 Label done; 1893 CmpObjectType(result, MAP_TYPE, scratch); 1894 j(not_equal, &done, Label::kNear); 1895 1896 // Get the prototype from the initial map. 1897 mov(result, FieldOperand(result, Map::kPrototypeOffset)); 1898 1899 // All done. 1900 bind(&done); 1901} 1902 1903 1904void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) { 1905 DCHECK(AllowThisStubCall(stub)); // Calls are not allowed in some stubs. 1906 call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id); 1907} 1908 1909 1910void MacroAssembler::TailCallStub(CodeStub* stub) { 1911 jmp(stub->GetCode(), RelocInfo::CODE_TARGET); 1912} 1913 1914 1915void MacroAssembler::StubReturn(int argc) { 1916 DCHECK(argc >= 1 && generating_stub()); 1917 ret((argc - 1) * kPointerSize); 1918} 1919 1920 1921bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { 1922 return has_frame_ || !stub->SometimesSetsUpAFrame(); 1923} 1924 1925void MacroAssembler::CallRuntime(const Runtime::Function* f, 1926 int num_arguments, 1927 SaveFPRegsMode save_doubles) { 1928 // If the expected number of arguments of the runtime function is 1929 // constant, we check that the actual number of arguments match the 1930 // expectation. 1931 CHECK(f->nargs < 0 || f->nargs == num_arguments); 1932 1933 // TODO(1236192): Most runtime routines don't need the number of 1934 // arguments passed in because it is constant. At some point we 1935 // should remove this need and make the runtime routine entry code 1936 // smarter. 1937 Move(eax, Immediate(num_arguments)); 1938 mov(ebx, Immediate(ExternalReference(f, isolate()))); 1939 CEntryStub ces(isolate(), 1, save_doubles); 1940 CallStub(&ces); 1941} 1942 1943 1944void MacroAssembler::CallExternalReference(ExternalReference ref, 1945 int num_arguments) { 1946 mov(eax, Immediate(num_arguments)); 1947 mov(ebx, Immediate(ref)); 1948 1949 CEntryStub stub(isolate(), 1); 1950 CallStub(&stub); 1951} 1952 1953 1954void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { 1955 // ----------- S t a t e ------------- 1956 // -- esp[0] : return address 1957 // -- esp[8] : argument num_arguments - 1 1958 // ... 1959 // -- esp[8 * num_arguments] : argument 0 (receiver) 1960 // 1961 // For runtime functions with variable arguments: 1962 // -- eax : number of arguments 1963 // ----------------------------------- 1964 1965 const Runtime::Function* function = Runtime::FunctionForId(fid); 1966 DCHECK_EQ(1, function->result_size); 1967 if (function->nargs >= 0) { 1968 // TODO(1236192): Most runtime routines don't need the number of 1969 // arguments passed in because it is constant. At some point we 1970 // should remove this need and make the runtime routine entry code 1971 // smarter. 1972 mov(eax, Immediate(function->nargs)); 1973 } 1974 JumpToExternalReference(ExternalReference(fid, isolate())); 1975} 1976 1977void MacroAssembler::JumpToExternalReference(const ExternalReference& ext, 1978 bool builtin_exit_frame) { 1979 // Set the entry point and jump to the C entry runtime stub. 1980 mov(ebx, Immediate(ext)); 1981 CEntryStub ces(isolate(), 1, kDontSaveFPRegs, kArgvOnStack, 1982 builtin_exit_frame); 1983 jmp(ces.GetCode(), RelocInfo::CODE_TARGET); 1984} 1985 1986void MacroAssembler::PrepareForTailCall( 1987 const ParameterCount& callee_args_count, Register caller_args_count_reg, 1988 Register scratch0, Register scratch1, ReturnAddressState ra_state, 1989 int number_of_temp_values_after_return_address) { 1990#if DEBUG 1991 if (callee_args_count.is_reg()) { 1992 DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0, 1993 scratch1)); 1994 } else { 1995 DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1)); 1996 } 1997 DCHECK(ra_state != ReturnAddressState::kNotOnStack || 1998 number_of_temp_values_after_return_address == 0); 1999#endif 2000 2001 // Calculate the destination address where we will put the return address 2002 // after we drop current frame. 2003 Register new_sp_reg = scratch0; 2004 if (callee_args_count.is_reg()) { 2005 sub(caller_args_count_reg, callee_args_count.reg()); 2006 lea(new_sp_reg, 2007 Operand(ebp, caller_args_count_reg, times_pointer_size, 2008 StandardFrameConstants::kCallerPCOffset - 2009 number_of_temp_values_after_return_address * kPointerSize)); 2010 } else { 2011 lea(new_sp_reg, Operand(ebp, caller_args_count_reg, times_pointer_size, 2012 StandardFrameConstants::kCallerPCOffset - 2013 (callee_args_count.immediate() + 2014 number_of_temp_values_after_return_address) * 2015 kPointerSize)); 2016 } 2017 2018 if (FLAG_debug_code) { 2019 cmp(esp, new_sp_reg); 2020 Check(below, kStackAccessBelowStackPointer); 2021 } 2022 2023 // Copy return address from caller's frame to current frame's return address 2024 // to avoid its trashing and let the following loop copy it to the right 2025 // place. 2026 Register tmp_reg = scratch1; 2027 if (ra_state == ReturnAddressState::kOnStack) { 2028 mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset)); 2029 mov(Operand(esp, number_of_temp_values_after_return_address * kPointerSize), 2030 tmp_reg); 2031 } else { 2032 DCHECK(ReturnAddressState::kNotOnStack == ra_state); 2033 DCHECK_EQ(0, number_of_temp_values_after_return_address); 2034 Push(Operand(ebp, StandardFrameConstants::kCallerPCOffset)); 2035 } 2036 2037 // Restore caller's frame pointer now as it could be overwritten by 2038 // the copying loop. 2039 mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 2040 2041 // +2 here is to copy both receiver and return address. 2042 Register count_reg = caller_args_count_reg; 2043 if (callee_args_count.is_reg()) { 2044 lea(count_reg, Operand(callee_args_count.reg(), 2045 2 + number_of_temp_values_after_return_address)); 2046 } else { 2047 mov(count_reg, Immediate(callee_args_count.immediate() + 2 + 2048 number_of_temp_values_after_return_address)); 2049 // TODO(ishell): Unroll copying loop for small immediate values. 2050 } 2051 2052 // Now copy callee arguments to the caller frame going backwards to avoid 2053 // callee arguments corruption (source and destination areas could overlap). 2054 Label loop, entry; 2055 jmp(&entry, Label::kNear); 2056 bind(&loop); 2057 dec(count_reg); 2058 mov(tmp_reg, Operand(esp, count_reg, times_pointer_size, 0)); 2059 mov(Operand(new_sp_reg, count_reg, times_pointer_size, 0), tmp_reg); 2060 bind(&entry); 2061 cmp(count_reg, Immediate(0)); 2062 j(not_equal, &loop, Label::kNear); 2063 2064 // Leave current frame. 2065 mov(esp, new_sp_reg); 2066} 2067 2068void MacroAssembler::InvokePrologue(const ParameterCount& expected, 2069 const ParameterCount& actual, 2070 Label* done, 2071 bool* definitely_mismatches, 2072 InvokeFlag flag, 2073 Label::Distance done_near, 2074 const CallWrapper& call_wrapper) { 2075 bool definitely_matches = false; 2076 *definitely_mismatches = false; 2077 Label invoke; 2078 if (expected.is_immediate()) { 2079 DCHECK(actual.is_immediate()); 2080 mov(eax, actual.immediate()); 2081 if (expected.immediate() == actual.immediate()) { 2082 definitely_matches = true; 2083 } else { 2084 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel; 2085 if (expected.immediate() == sentinel) { 2086 // Don't worry about adapting arguments for builtins that 2087 // don't want that done. Skip adaption code by making it look 2088 // like we have a match between expected and actual number of 2089 // arguments. 2090 definitely_matches = true; 2091 } else { 2092 *definitely_mismatches = true; 2093 mov(ebx, expected.immediate()); 2094 } 2095 } 2096 } else { 2097 if (actual.is_immediate()) { 2098 // Expected is in register, actual is immediate. This is the 2099 // case when we invoke function values without going through the 2100 // IC mechanism. 2101 mov(eax, actual.immediate()); 2102 cmp(expected.reg(), actual.immediate()); 2103 j(equal, &invoke); 2104 DCHECK(expected.reg().is(ebx)); 2105 } else if (!expected.reg().is(actual.reg())) { 2106 // Both expected and actual are in (different) registers. This 2107 // is the case when we invoke functions using call and apply. 2108 cmp(expected.reg(), actual.reg()); 2109 j(equal, &invoke); 2110 DCHECK(actual.reg().is(eax)); 2111 DCHECK(expected.reg().is(ebx)); 2112 } else { 2113 Move(eax, actual.reg()); 2114 } 2115 } 2116 2117 if (!definitely_matches) { 2118 Handle<Code> adaptor = 2119 isolate()->builtins()->ArgumentsAdaptorTrampoline(); 2120 if (flag == CALL_FUNCTION) { 2121 call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET)); 2122 call(adaptor, RelocInfo::CODE_TARGET); 2123 call_wrapper.AfterCall(); 2124 if (!*definitely_mismatches) { 2125 jmp(done, done_near); 2126 } 2127 } else { 2128 jmp(adaptor, RelocInfo::CODE_TARGET); 2129 } 2130 bind(&invoke); 2131 } 2132} 2133 2134 2135void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target, 2136 const ParameterCount& expected, 2137 const ParameterCount& actual) { 2138 Label skip_flooding; 2139 ExternalReference last_step_action = 2140 ExternalReference::debug_last_step_action_address(isolate()); 2141 STATIC_ASSERT(StepFrame > StepIn); 2142 cmpb(Operand::StaticVariable(last_step_action), Immediate(StepIn)); 2143 j(less, &skip_flooding); 2144 { 2145 FrameScope frame(this, 2146 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); 2147 if (expected.is_reg()) { 2148 SmiTag(expected.reg()); 2149 Push(expected.reg()); 2150 } 2151 if (actual.is_reg()) { 2152 SmiTag(actual.reg()); 2153 Push(actual.reg()); 2154 } 2155 if (new_target.is_valid()) { 2156 Push(new_target); 2157 } 2158 Push(fun); 2159 Push(fun); 2160 CallRuntime(Runtime::kDebugPrepareStepInIfStepping); 2161 Pop(fun); 2162 if (new_target.is_valid()) { 2163 Pop(new_target); 2164 } 2165 if (actual.is_reg()) { 2166 Pop(actual.reg()); 2167 SmiUntag(actual.reg()); 2168 } 2169 if (expected.is_reg()) { 2170 Pop(expected.reg()); 2171 SmiUntag(expected.reg()); 2172 } 2173 } 2174 bind(&skip_flooding); 2175} 2176 2177 2178void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, 2179 const ParameterCount& expected, 2180 const ParameterCount& actual, 2181 InvokeFlag flag, 2182 const CallWrapper& call_wrapper) { 2183 // You can't call a function without a valid frame. 2184 DCHECK(flag == JUMP_FUNCTION || has_frame()); 2185 DCHECK(function.is(edi)); 2186 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(edx)); 2187 2188 if (call_wrapper.NeedsDebugStepCheck()) { 2189 FloodFunctionIfStepping(function, new_target, expected, actual); 2190 } 2191 2192 // Clear the new.target register if not given. 2193 if (!new_target.is_valid()) { 2194 mov(edx, isolate()->factory()->undefined_value()); 2195 } 2196 2197 Label done; 2198 bool definitely_mismatches = false; 2199 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag, 2200 Label::kNear, call_wrapper); 2201 if (!definitely_mismatches) { 2202 // We call indirectly through the code field in the function to 2203 // allow recompilation to take effect without changing any of the 2204 // call sites. 2205 Operand code = FieldOperand(function, JSFunction::kCodeEntryOffset); 2206 if (flag == CALL_FUNCTION) { 2207 call_wrapper.BeforeCall(CallSize(code)); 2208 call(code); 2209 call_wrapper.AfterCall(); 2210 } else { 2211 DCHECK(flag == JUMP_FUNCTION); 2212 jmp(code); 2213 } 2214 bind(&done); 2215 } 2216} 2217 2218 2219void MacroAssembler::InvokeFunction(Register fun, 2220 Register new_target, 2221 const ParameterCount& actual, 2222 InvokeFlag flag, 2223 const CallWrapper& call_wrapper) { 2224 // You can't call a function without a valid frame. 2225 DCHECK(flag == JUMP_FUNCTION || has_frame()); 2226 2227 DCHECK(fun.is(edi)); 2228 mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 2229 mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 2230 mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset)); 2231 SmiUntag(ebx); 2232 2233 ParameterCount expected(ebx); 2234 InvokeFunctionCode(edi, new_target, expected, actual, flag, call_wrapper); 2235} 2236 2237 2238void MacroAssembler::InvokeFunction(Register fun, 2239 const ParameterCount& expected, 2240 const ParameterCount& actual, 2241 InvokeFlag flag, 2242 const CallWrapper& call_wrapper) { 2243 // You can't call a function without a valid frame. 2244 DCHECK(flag == JUMP_FUNCTION || has_frame()); 2245 2246 DCHECK(fun.is(edi)); 2247 mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 2248 2249 InvokeFunctionCode(edi, no_reg, expected, actual, flag, call_wrapper); 2250} 2251 2252 2253void MacroAssembler::InvokeFunction(Handle<JSFunction> function, 2254 const ParameterCount& expected, 2255 const ParameterCount& actual, 2256 InvokeFlag flag, 2257 const CallWrapper& call_wrapper) { 2258 LoadHeapObject(edi, function); 2259 InvokeFunction(edi, expected, actual, flag, call_wrapper); 2260} 2261 2262 2263void MacroAssembler::LoadContext(Register dst, int context_chain_length) { 2264 if (context_chain_length > 0) { 2265 // Move up the chain of contexts to the context containing the slot. 2266 mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX))); 2267 for (int i = 1; i < context_chain_length; i++) { 2268 mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); 2269 } 2270 } else { 2271 // Slot is in the current function context. Move it into the 2272 // destination register in case we store into it (the write barrier 2273 // cannot be allowed to destroy the context in esi). 2274 mov(dst, esi); 2275 } 2276 2277 // We should not have found a with context by walking the context chain 2278 // (i.e., the static scope chain and runtime context chain do not agree). 2279 // A variable occurring in such a scope should have slot type LOOKUP and 2280 // not CONTEXT. 2281 if (emit_debug_code()) { 2282 cmp(FieldOperand(dst, HeapObject::kMapOffset), 2283 isolate()->factory()->with_context_map()); 2284 Check(not_equal, kVariableResolvedToWithContext); 2285 } 2286} 2287 2288 2289void MacroAssembler::LoadGlobalProxy(Register dst) { 2290 mov(dst, NativeContextOperand()); 2291 mov(dst, ContextOperand(dst, Context::GLOBAL_PROXY_INDEX)); 2292} 2293 2294 2295void MacroAssembler::LoadTransitionedArrayMapConditional( 2296 ElementsKind expected_kind, 2297 ElementsKind transitioned_kind, 2298 Register map_in_out, 2299 Register scratch, 2300 Label* no_map_match) { 2301 DCHECK(IsFastElementsKind(expected_kind)); 2302 DCHECK(IsFastElementsKind(transitioned_kind)); 2303 2304 // Check that the function's map is the same as the expected cached map. 2305 mov(scratch, NativeContextOperand()); 2306 cmp(map_in_out, 2307 ContextOperand(scratch, Context::ArrayMapIndex(expected_kind))); 2308 j(not_equal, no_map_match); 2309 2310 // Use the transitioned cached map. 2311 mov(map_in_out, 2312 ContextOperand(scratch, Context::ArrayMapIndex(transitioned_kind))); 2313} 2314 2315 2316void MacroAssembler::LoadGlobalFunction(int index, Register function) { 2317 // Load the native context from the current context. 2318 mov(function, NativeContextOperand()); 2319 // Load the function from the native context. 2320 mov(function, ContextOperand(function, index)); 2321} 2322 2323 2324void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, 2325 Register map) { 2326 // Load the initial map. The global functions all have initial maps. 2327 mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 2328 if (emit_debug_code()) { 2329 Label ok, fail; 2330 CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK); 2331 jmp(&ok); 2332 bind(&fail); 2333 Abort(kGlobalFunctionsMustHaveInitialMap); 2334 bind(&ok); 2335 } 2336} 2337 2338 2339// Store the value in register src in the safepoint register stack 2340// slot for register dst. 2341void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) { 2342 mov(SafepointRegisterSlot(dst), src); 2343} 2344 2345 2346void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Immediate src) { 2347 mov(SafepointRegisterSlot(dst), src); 2348} 2349 2350 2351void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { 2352 mov(dst, SafepointRegisterSlot(src)); 2353} 2354 2355 2356Operand MacroAssembler::SafepointRegisterSlot(Register reg) { 2357 return Operand(esp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); 2358} 2359 2360 2361int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { 2362 // The registers are pushed starting with the lowest encoding, 2363 // which means that lowest encodings are furthest away from 2364 // the stack pointer. 2365 DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters); 2366 return kNumSafepointRegisters - reg_code - 1; 2367} 2368 2369 2370void MacroAssembler::LoadHeapObject(Register result, 2371 Handle<HeapObject> object) { 2372 mov(result, object); 2373} 2374 2375 2376void MacroAssembler::CmpHeapObject(Register reg, Handle<HeapObject> object) { 2377 cmp(reg, object); 2378} 2379 2380void MacroAssembler::PushHeapObject(Handle<HeapObject> object) { Push(object); } 2381 2382void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell, 2383 Register scratch) { 2384 mov(scratch, cell); 2385 cmp(value, FieldOperand(scratch, WeakCell::kValueOffset)); 2386} 2387 2388 2389void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) { 2390 mov(value, cell); 2391 mov(value, FieldOperand(value, WeakCell::kValueOffset)); 2392} 2393 2394 2395void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell, 2396 Label* miss) { 2397 GetWeakValue(value, cell); 2398 JumpIfSmi(value, miss); 2399} 2400 2401 2402void MacroAssembler::Ret() { 2403 ret(0); 2404} 2405 2406 2407void MacroAssembler::Ret(int bytes_dropped, Register scratch) { 2408 if (is_uint16(bytes_dropped)) { 2409 ret(bytes_dropped); 2410 } else { 2411 pop(scratch); 2412 add(esp, Immediate(bytes_dropped)); 2413 push(scratch); 2414 ret(0); 2415 } 2416} 2417 2418 2419void MacroAssembler::Drop(int stack_elements) { 2420 if (stack_elements > 0) { 2421 add(esp, Immediate(stack_elements * kPointerSize)); 2422 } 2423} 2424 2425 2426void MacroAssembler::Move(Register dst, Register src) { 2427 if (!dst.is(src)) { 2428 mov(dst, src); 2429 } 2430} 2431 2432 2433void MacroAssembler::Move(Register dst, const Immediate& x) { 2434 if (x.is_zero() && RelocInfo::IsNone(x.rmode_)) { 2435 xor_(dst, dst); // Shorter than mov of 32-bit immediate 0. 2436 } else { 2437 mov(dst, x); 2438 } 2439} 2440 2441 2442void MacroAssembler::Move(const Operand& dst, const Immediate& x) { 2443 mov(dst, x); 2444} 2445 2446 2447void MacroAssembler::Move(XMMRegister dst, uint32_t src) { 2448 if (src == 0) { 2449 pxor(dst, dst); 2450 } else { 2451 unsigned cnt = base::bits::CountPopulation32(src); 2452 unsigned nlz = base::bits::CountLeadingZeros32(src); 2453 unsigned ntz = base::bits::CountTrailingZeros32(src); 2454 if (nlz + cnt + ntz == 32) { 2455 pcmpeqd(dst, dst); 2456 if (ntz == 0) { 2457 psrld(dst, 32 - cnt); 2458 } else { 2459 pslld(dst, 32 - cnt); 2460 if (nlz != 0) psrld(dst, nlz); 2461 } 2462 } else { 2463 push(eax); 2464 mov(eax, Immediate(src)); 2465 movd(dst, Operand(eax)); 2466 pop(eax); 2467 } 2468 } 2469} 2470 2471 2472void MacroAssembler::Move(XMMRegister dst, uint64_t src) { 2473 if (src == 0) { 2474 pxor(dst, dst); 2475 } else { 2476 uint32_t lower = static_cast<uint32_t>(src); 2477 uint32_t upper = static_cast<uint32_t>(src >> 32); 2478 unsigned cnt = base::bits::CountPopulation64(src); 2479 unsigned nlz = base::bits::CountLeadingZeros64(src); 2480 unsigned ntz = base::bits::CountTrailingZeros64(src); 2481 if (nlz + cnt + ntz == 64) { 2482 pcmpeqd(dst, dst); 2483 if (ntz == 0) { 2484 psrlq(dst, 64 - cnt); 2485 } else { 2486 psllq(dst, 64 - cnt); 2487 if (nlz != 0) psrlq(dst, nlz); 2488 } 2489 } else if (lower == 0) { 2490 Move(dst, upper); 2491 psllq(dst, 32); 2492 } else if (CpuFeatures::IsSupported(SSE4_1)) { 2493 CpuFeatureScope scope(this, SSE4_1); 2494 push(eax); 2495 Move(eax, Immediate(lower)); 2496 movd(dst, Operand(eax)); 2497 Move(eax, Immediate(upper)); 2498 pinsrd(dst, Operand(eax), 1); 2499 pop(eax); 2500 } else { 2501 push(Immediate(upper)); 2502 push(Immediate(lower)); 2503 movsd(dst, Operand(esp, 0)); 2504 add(esp, Immediate(kDoubleSize)); 2505 } 2506 } 2507} 2508 2509 2510void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) { 2511 if (imm8 == 0) { 2512 movd(dst, src); 2513 return; 2514 } 2515 DCHECK_EQ(1, imm8); 2516 if (CpuFeatures::IsSupported(SSE4_1)) { 2517 CpuFeatureScope sse_scope(this, SSE4_1); 2518 pextrd(dst, src, imm8); 2519 return; 2520 } 2521 pshufd(xmm0, src, 1); 2522 movd(dst, xmm0); 2523} 2524 2525 2526void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) { 2527 DCHECK(imm8 == 0 || imm8 == 1); 2528 if (CpuFeatures::IsSupported(SSE4_1)) { 2529 CpuFeatureScope sse_scope(this, SSE4_1); 2530 pinsrd(dst, src, imm8); 2531 return; 2532 } 2533 movd(xmm0, src); 2534 if (imm8 == 1) { 2535 punpckldq(dst, xmm0); 2536 } else { 2537 DCHECK_EQ(0, imm8); 2538 psrlq(dst, 32); 2539 punpckldq(xmm0, dst); 2540 movaps(dst, xmm0); 2541 } 2542} 2543 2544 2545void MacroAssembler::Lzcnt(Register dst, const Operand& src) { 2546 if (CpuFeatures::IsSupported(LZCNT)) { 2547 CpuFeatureScope scope(this, LZCNT); 2548 lzcnt(dst, src); 2549 return; 2550 } 2551 Label not_zero_src; 2552 bsr(dst, src); 2553 j(not_zero, ¬_zero_src, Label::kNear); 2554 Move(dst, Immediate(63)); // 63^31 == 32 2555 bind(¬_zero_src); 2556 xor_(dst, Immediate(31)); // for x in [0..31], 31^x == 31-x. 2557} 2558 2559 2560void MacroAssembler::Tzcnt(Register dst, const Operand& src) { 2561 if (CpuFeatures::IsSupported(BMI1)) { 2562 CpuFeatureScope scope(this, BMI1); 2563 tzcnt(dst, src); 2564 return; 2565 } 2566 Label not_zero_src; 2567 bsf(dst, src); 2568 j(not_zero, ¬_zero_src, Label::kNear); 2569 Move(dst, Immediate(32)); // The result of tzcnt is 32 if src = 0. 2570 bind(¬_zero_src); 2571} 2572 2573 2574void MacroAssembler::Popcnt(Register dst, const Operand& src) { 2575 if (CpuFeatures::IsSupported(POPCNT)) { 2576 CpuFeatureScope scope(this, POPCNT); 2577 popcnt(dst, src); 2578 return; 2579 } 2580 UNREACHABLE(); 2581} 2582 2583 2584void MacroAssembler::SetCounter(StatsCounter* counter, int value) { 2585 if (FLAG_native_code_counters && counter->Enabled()) { 2586 mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value)); 2587 } 2588} 2589 2590 2591void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { 2592 DCHECK(value > 0); 2593 if (FLAG_native_code_counters && counter->Enabled()) { 2594 Operand operand = Operand::StaticVariable(ExternalReference(counter)); 2595 if (value == 1) { 2596 inc(operand); 2597 } else { 2598 add(operand, Immediate(value)); 2599 } 2600 } 2601} 2602 2603 2604void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) { 2605 DCHECK(value > 0); 2606 if (FLAG_native_code_counters && counter->Enabled()) { 2607 Operand operand = Operand::StaticVariable(ExternalReference(counter)); 2608 if (value == 1) { 2609 dec(operand); 2610 } else { 2611 sub(operand, Immediate(value)); 2612 } 2613 } 2614} 2615 2616 2617void MacroAssembler::IncrementCounter(Condition cc, 2618 StatsCounter* counter, 2619 int value) { 2620 DCHECK(value > 0); 2621 if (FLAG_native_code_counters && counter->Enabled()) { 2622 Label skip; 2623 j(NegateCondition(cc), &skip); 2624 pushfd(); 2625 IncrementCounter(counter, value); 2626 popfd(); 2627 bind(&skip); 2628 } 2629} 2630 2631 2632void MacroAssembler::DecrementCounter(Condition cc, 2633 StatsCounter* counter, 2634 int value) { 2635 DCHECK(value > 0); 2636 if (FLAG_native_code_counters && counter->Enabled()) { 2637 Label skip; 2638 j(NegateCondition(cc), &skip); 2639 pushfd(); 2640 DecrementCounter(counter, value); 2641 popfd(); 2642 bind(&skip); 2643 } 2644} 2645 2646 2647void MacroAssembler::Assert(Condition cc, BailoutReason reason) { 2648 if (emit_debug_code()) Check(cc, reason); 2649} 2650 2651 2652void MacroAssembler::AssertFastElements(Register elements) { 2653 if (emit_debug_code()) { 2654 Factory* factory = isolate()->factory(); 2655 Label ok; 2656 cmp(FieldOperand(elements, HeapObject::kMapOffset), 2657 Immediate(factory->fixed_array_map())); 2658 j(equal, &ok); 2659 cmp(FieldOperand(elements, HeapObject::kMapOffset), 2660 Immediate(factory->fixed_double_array_map())); 2661 j(equal, &ok); 2662 cmp(FieldOperand(elements, HeapObject::kMapOffset), 2663 Immediate(factory->fixed_cow_array_map())); 2664 j(equal, &ok); 2665 Abort(kJSObjectWithFastElementsMapHasSlowElements); 2666 bind(&ok); 2667 } 2668} 2669 2670 2671void MacroAssembler::Check(Condition cc, BailoutReason reason) { 2672 Label L; 2673 j(cc, &L); 2674 Abort(reason); 2675 // will not return here 2676 bind(&L); 2677} 2678 2679 2680void MacroAssembler::CheckStackAlignment() { 2681 int frame_alignment = base::OS::ActivationFrameAlignment(); 2682 int frame_alignment_mask = frame_alignment - 1; 2683 if (frame_alignment > kPointerSize) { 2684 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 2685 Label alignment_as_expected; 2686 test(esp, Immediate(frame_alignment_mask)); 2687 j(zero, &alignment_as_expected); 2688 // Abort if stack is not aligned. 2689 int3(); 2690 bind(&alignment_as_expected); 2691 } 2692} 2693 2694 2695void MacroAssembler::Abort(BailoutReason reason) { 2696#ifdef DEBUG 2697 const char* msg = GetBailoutReason(reason); 2698 if (msg != NULL) { 2699 RecordComment("Abort message: "); 2700 RecordComment(msg); 2701 } 2702 2703 if (FLAG_trap_on_abort) { 2704 int3(); 2705 return; 2706 } 2707#endif 2708 2709 // Check if Abort() has already been initialized. 2710 DCHECK(isolate()->builtins()->Abort()->IsHeapObject()); 2711 2712 Move(edx, Smi::FromInt(static_cast<int>(reason))); 2713 2714 // Disable stub call restrictions to always allow calls to abort. 2715 if (!has_frame_) { 2716 // We don't actually want to generate a pile of code for this, so just 2717 // claim there is a stack frame, without generating one. 2718 FrameScope scope(this, StackFrame::NONE); 2719 Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET); 2720 } else { 2721 Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET); 2722 } 2723 // will not return here 2724 int3(); 2725} 2726 2727 2728void MacroAssembler::LoadInstanceDescriptors(Register map, 2729 Register descriptors) { 2730 mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset)); 2731} 2732 2733 2734void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { 2735 mov(dst, FieldOperand(map, Map::kBitField3Offset)); 2736 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); 2737} 2738 2739 2740void MacroAssembler::LoadAccessor(Register dst, Register holder, 2741 int accessor_index, 2742 AccessorComponent accessor) { 2743 mov(dst, FieldOperand(holder, HeapObject::kMapOffset)); 2744 LoadInstanceDescriptors(dst, dst); 2745 mov(dst, FieldOperand(dst, DescriptorArray::GetValueOffset(accessor_index))); 2746 int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset 2747 : AccessorPair::kSetterOffset; 2748 mov(dst, FieldOperand(dst, offset)); 2749} 2750 2751 2752void MacroAssembler::LoadPowerOf2(XMMRegister dst, 2753 Register scratch, 2754 int power) { 2755 DCHECK(is_uintn(power + HeapNumber::kExponentBias, 2756 HeapNumber::kExponentBits)); 2757 mov(scratch, Immediate(power + HeapNumber::kExponentBias)); 2758 movd(dst, scratch); 2759 psllq(dst, HeapNumber::kMantissaBits); 2760} 2761 2762 2763void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte( 2764 Register instance_type, Register scratch, Label* failure) { 2765 if (!scratch.is(instance_type)) { 2766 mov(scratch, instance_type); 2767 } 2768 and_(scratch, 2769 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); 2770 cmp(scratch, kStringTag | kSeqStringTag | kOneByteStringTag); 2771 j(not_equal, failure); 2772} 2773 2774 2775void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register object1, 2776 Register object2, 2777 Register scratch1, 2778 Register scratch2, 2779 Label* failure) { 2780 // Check that both objects are not smis. 2781 STATIC_ASSERT(kSmiTag == 0); 2782 mov(scratch1, object1); 2783 and_(scratch1, object2); 2784 JumpIfSmi(scratch1, failure); 2785 2786 // Load instance type for both strings. 2787 mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset)); 2788 mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset)); 2789 movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset)); 2790 movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); 2791 2792 // Check that both are flat one-byte strings. 2793 const int kFlatOneByteStringMask = 2794 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; 2795 const int kFlatOneByteStringTag = 2796 kStringTag | kOneByteStringTag | kSeqStringTag; 2797 // Interleave bits from both instance types and compare them in one check. 2798 DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << 3)); 2799 and_(scratch1, kFlatOneByteStringMask); 2800 and_(scratch2, kFlatOneByteStringMask); 2801 lea(scratch1, Operand(scratch1, scratch2, times_8, 0)); 2802 cmp(scratch1, kFlatOneByteStringTag | (kFlatOneByteStringTag << 3)); 2803 j(not_equal, failure); 2804} 2805 2806 2807void MacroAssembler::JumpIfNotUniqueNameInstanceType(Operand operand, 2808 Label* not_unique_name, 2809 Label::Distance distance) { 2810 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); 2811 Label succeed; 2812 test(operand, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); 2813 j(zero, &succeed); 2814 cmpb(operand, Immediate(SYMBOL_TYPE)); 2815 j(not_equal, not_unique_name, distance); 2816 2817 bind(&succeed); 2818} 2819 2820 2821void MacroAssembler::EmitSeqStringSetCharCheck(Register string, 2822 Register index, 2823 Register value, 2824 uint32_t encoding_mask) { 2825 Label is_object; 2826 JumpIfNotSmi(string, &is_object, Label::kNear); 2827 Abort(kNonObject); 2828 bind(&is_object); 2829 2830 push(value); 2831 mov(value, FieldOperand(string, HeapObject::kMapOffset)); 2832 movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset)); 2833 2834 and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask)); 2835 cmp(value, Immediate(encoding_mask)); 2836 pop(value); 2837 Check(equal, kUnexpectedStringType); 2838 2839 // The index is assumed to be untagged coming in, tag it to compare with the 2840 // string length without using a temp register, it is restored at the end of 2841 // this function. 2842 SmiTag(index); 2843 Check(no_overflow, kIndexIsTooLarge); 2844 2845 cmp(index, FieldOperand(string, String::kLengthOffset)); 2846 Check(less, kIndexIsTooLarge); 2847 2848 cmp(index, Immediate(Smi::kZero)); 2849 Check(greater_equal, kIndexIsNegative); 2850 2851 // Restore the index 2852 SmiUntag(index); 2853} 2854 2855 2856void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { 2857 int frame_alignment = base::OS::ActivationFrameAlignment(); 2858 if (frame_alignment != 0) { 2859 // Make stack end at alignment and make room for num_arguments words 2860 // and the original value of esp. 2861 mov(scratch, esp); 2862 sub(esp, Immediate((num_arguments + 1) * kPointerSize)); 2863 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 2864 and_(esp, -frame_alignment); 2865 mov(Operand(esp, num_arguments * kPointerSize), scratch); 2866 } else { 2867 sub(esp, Immediate(num_arguments * kPointerSize)); 2868 } 2869} 2870 2871 2872void MacroAssembler::CallCFunction(ExternalReference function, 2873 int num_arguments) { 2874 // Trashing eax is ok as it will be the return value. 2875 mov(eax, Immediate(function)); 2876 CallCFunction(eax, num_arguments); 2877} 2878 2879 2880void MacroAssembler::CallCFunction(Register function, 2881 int num_arguments) { 2882 DCHECK(has_frame()); 2883 // Check stack alignment. 2884 if (emit_debug_code()) { 2885 CheckStackAlignment(); 2886 } 2887 2888 call(function); 2889 if (base::OS::ActivationFrameAlignment() != 0) { 2890 mov(esp, Operand(esp, num_arguments * kPointerSize)); 2891 } else { 2892 add(esp, Immediate(num_arguments * kPointerSize)); 2893 } 2894} 2895 2896 2897#ifdef DEBUG 2898bool AreAliased(Register reg1, 2899 Register reg2, 2900 Register reg3, 2901 Register reg4, 2902 Register reg5, 2903 Register reg6, 2904 Register reg7, 2905 Register reg8) { 2906 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + 2907 reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() + 2908 reg7.is_valid() + reg8.is_valid(); 2909 2910 RegList regs = 0; 2911 if (reg1.is_valid()) regs |= reg1.bit(); 2912 if (reg2.is_valid()) regs |= reg2.bit(); 2913 if (reg3.is_valid()) regs |= reg3.bit(); 2914 if (reg4.is_valid()) regs |= reg4.bit(); 2915 if (reg5.is_valid()) regs |= reg5.bit(); 2916 if (reg6.is_valid()) regs |= reg6.bit(); 2917 if (reg7.is_valid()) regs |= reg7.bit(); 2918 if (reg8.is_valid()) regs |= reg8.bit(); 2919 int n_of_non_aliasing_regs = NumRegs(regs); 2920 2921 return n_of_valid_regs != n_of_non_aliasing_regs; 2922} 2923#endif 2924 2925 2926CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size) 2927 : address_(address), 2928 size_(size), 2929 masm_(isolate, address, size + Assembler::kGap, CodeObjectRequired::kNo) { 2930 // Create a new macro assembler pointing to the address of the code to patch. 2931 // The size is adjusted with kGap on order for the assembler to generate size 2932 // bytes of instructions without failing with buffer size constraints. 2933 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 2934} 2935 2936 2937CodePatcher::~CodePatcher() { 2938 // Indicate that code has changed. 2939 Assembler::FlushICache(masm_.isolate(), address_, size_); 2940 2941 // Check that the code was patched as expected. 2942 DCHECK(masm_.pc_ == address_ + size_); 2943 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 2944} 2945 2946 2947void MacroAssembler::CheckPageFlag( 2948 Register object, 2949 Register scratch, 2950 int mask, 2951 Condition cc, 2952 Label* condition_met, 2953 Label::Distance condition_met_distance) { 2954 DCHECK(cc == zero || cc == not_zero); 2955 if (scratch.is(object)) { 2956 and_(scratch, Immediate(~Page::kPageAlignmentMask)); 2957 } else { 2958 mov(scratch, Immediate(~Page::kPageAlignmentMask)); 2959 and_(scratch, object); 2960 } 2961 if (mask < (1 << kBitsPerByte)) { 2962 test_b(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask)); 2963 } else { 2964 test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask)); 2965 } 2966 j(cc, condition_met, condition_met_distance); 2967} 2968 2969 2970void MacroAssembler::CheckPageFlagForMap( 2971 Handle<Map> map, 2972 int mask, 2973 Condition cc, 2974 Label* condition_met, 2975 Label::Distance condition_met_distance) { 2976 DCHECK(cc == zero || cc == not_zero); 2977 Page* page = Page::FromAddress(map->address()); 2978 DCHECK(!serializer_enabled()); // Serializer cannot match page_flags. 2979 ExternalReference reference(ExternalReference::page_flags(page)); 2980 // The inlined static address check of the page's flags relies 2981 // on maps never being compacted. 2982 DCHECK(!isolate()->heap()->mark_compact_collector()-> 2983 IsOnEvacuationCandidate(*map)); 2984 if (mask < (1 << kBitsPerByte)) { 2985 test_b(Operand::StaticVariable(reference), Immediate(mask)); 2986 } else { 2987 test(Operand::StaticVariable(reference), Immediate(mask)); 2988 } 2989 j(cc, condition_met, condition_met_distance); 2990} 2991 2992 2993void MacroAssembler::JumpIfBlack(Register object, 2994 Register scratch0, 2995 Register scratch1, 2996 Label* on_black, 2997 Label::Distance on_black_near) { 2998 HasColor(object, scratch0, scratch1, on_black, on_black_near, 1, 2999 1); // kBlackBitPattern. 3000 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 3001} 3002 3003 3004void MacroAssembler::HasColor(Register object, 3005 Register bitmap_scratch, 3006 Register mask_scratch, 3007 Label* has_color, 3008 Label::Distance has_color_distance, 3009 int first_bit, 3010 int second_bit) { 3011 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, ecx)); 3012 3013 GetMarkBits(object, bitmap_scratch, mask_scratch); 3014 3015 Label other_color, word_boundary; 3016 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); 3017 j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear); 3018 add(mask_scratch, mask_scratch); // Shift left 1 by adding. 3019 j(zero, &word_boundary, Label::kNear); 3020 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); 3021 j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance); 3022 jmp(&other_color, Label::kNear); 3023 3024 bind(&word_boundary); 3025 test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize), 3026 Immediate(1)); 3027 3028 j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance); 3029 bind(&other_color); 3030} 3031 3032 3033void MacroAssembler::GetMarkBits(Register addr_reg, 3034 Register bitmap_reg, 3035 Register mask_reg) { 3036 DCHECK(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx)); 3037 mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask)); 3038 and_(bitmap_reg, addr_reg); 3039 mov(ecx, addr_reg); 3040 int shift = 3041 Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2; 3042 shr(ecx, shift); 3043 and_(ecx, 3044 (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1)); 3045 3046 add(bitmap_reg, ecx); 3047 mov(ecx, addr_reg); 3048 shr(ecx, kPointerSizeLog2); 3049 and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1); 3050 mov(mask_reg, Immediate(1)); 3051 shl_cl(mask_reg); 3052} 3053 3054 3055void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch, 3056 Register mask_scratch, Label* value_is_white, 3057 Label::Distance distance) { 3058 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ecx)); 3059 GetMarkBits(value, bitmap_scratch, mask_scratch); 3060 3061 // If the value is black or grey we don't need to do anything. 3062 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); 3063 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 3064 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); 3065 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); 3066 3067 // Since both black and grey have a 1 in the first position and white does 3068 // not have a 1 there we only need to check one bit. 3069 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); 3070 j(zero, value_is_white, Label::kNear); 3071} 3072 3073 3074void MacroAssembler::EnumLength(Register dst, Register map) { 3075 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0); 3076 mov(dst, FieldOperand(map, Map::kBitField3Offset)); 3077 and_(dst, Immediate(Map::EnumLengthBits::kMask)); 3078 SmiTag(dst); 3079} 3080 3081 3082void MacroAssembler::CheckEnumCache(Label* call_runtime) { 3083 Label next, start; 3084 mov(ecx, eax); 3085 3086 // Check if the enum length field is properly initialized, indicating that 3087 // there is an enum cache. 3088 mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); 3089 3090 EnumLength(edx, ebx); 3091 cmp(edx, Immediate(Smi::FromInt(kInvalidEnumCacheSentinel))); 3092 j(equal, call_runtime); 3093 3094 jmp(&start); 3095 3096 bind(&next); 3097 mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); 3098 3099 // For all objects but the receiver, check that the cache is empty. 3100 EnumLength(edx, ebx); 3101 cmp(edx, Immediate(Smi::kZero)); 3102 j(not_equal, call_runtime); 3103 3104 bind(&start); 3105 3106 // Check that there are no elements. Register rcx contains the current JS 3107 // object we've reached through the prototype chain. 3108 Label no_elements; 3109 mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); 3110 cmp(ecx, isolate()->factory()->empty_fixed_array()); 3111 j(equal, &no_elements); 3112 3113 // Second chance, the object may be using the empty slow element dictionary. 3114 cmp(ecx, isolate()->factory()->empty_slow_element_dictionary()); 3115 j(not_equal, call_runtime); 3116 3117 bind(&no_elements); 3118 mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); 3119 cmp(ecx, isolate()->factory()->null_value()); 3120 j(not_equal, &next); 3121} 3122 3123 3124void MacroAssembler::TestJSArrayForAllocationMemento( 3125 Register receiver_reg, 3126 Register scratch_reg, 3127 Label* no_memento_found) { 3128 Label map_check; 3129 Label top_check; 3130 ExternalReference new_space_allocation_top = 3131 ExternalReference::new_space_allocation_top_address(isolate()); 3132 const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag; 3133 const int kMementoLastWordOffset = 3134 kMementoMapOffset + AllocationMemento::kSize - kPointerSize; 3135 3136 // Bail out if the object is not in new space. 3137 JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found); 3138 // If the object is in new space, we need to check whether it is on the same 3139 // page as the current top. 3140 lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset)); 3141 xor_(scratch_reg, Operand::StaticVariable(new_space_allocation_top)); 3142 test(scratch_reg, Immediate(~Page::kPageAlignmentMask)); 3143 j(zero, &top_check); 3144 // The object is on a different page than allocation top. Bail out if the 3145 // object sits on the page boundary as no memento can follow and we cannot 3146 // touch the memory following it. 3147 lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset)); 3148 xor_(scratch_reg, receiver_reg); 3149 test(scratch_reg, Immediate(~Page::kPageAlignmentMask)); 3150 j(not_zero, no_memento_found); 3151 // Continue with the actual map check. 3152 jmp(&map_check); 3153 // If top is on the same page as the current object, we need to check whether 3154 // we are below top. 3155 bind(&top_check); 3156 lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset)); 3157 cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top)); 3158 j(greater_equal, no_memento_found); 3159 // Memento map check. 3160 bind(&map_check); 3161 mov(scratch_reg, Operand(receiver_reg, kMementoMapOffset)); 3162 cmp(scratch_reg, Immediate(isolate()->factory()->allocation_memento_map())); 3163} 3164 3165 3166void MacroAssembler::JumpIfDictionaryInPrototypeChain( 3167 Register object, 3168 Register scratch0, 3169 Register scratch1, 3170 Label* found) { 3171 DCHECK(!scratch1.is(scratch0)); 3172 Factory* factory = isolate()->factory(); 3173 Register current = scratch0; 3174 Label loop_again, end; 3175 3176 // scratch contained elements pointer. 3177 mov(current, object); 3178 mov(current, FieldOperand(current, HeapObject::kMapOffset)); 3179 mov(current, FieldOperand(current, Map::kPrototypeOffset)); 3180 cmp(current, Immediate(factory->null_value())); 3181 j(equal, &end); 3182 3183 // Loop based on the map going up the prototype chain. 3184 bind(&loop_again); 3185 mov(current, FieldOperand(current, HeapObject::kMapOffset)); 3186 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE); 3187 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE); 3188 CmpInstanceType(current, JS_OBJECT_TYPE); 3189 j(below, found); 3190 mov(scratch1, FieldOperand(current, Map::kBitField2Offset)); 3191 DecodeField<Map::ElementsKindBits>(scratch1); 3192 cmp(scratch1, Immediate(DICTIONARY_ELEMENTS)); 3193 j(equal, found); 3194 mov(current, FieldOperand(current, Map::kPrototypeOffset)); 3195 cmp(current, Immediate(factory->null_value())); 3196 j(not_equal, &loop_again); 3197 3198 bind(&end); 3199} 3200 3201 3202void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) { 3203 DCHECK(!dividend.is(eax)); 3204 DCHECK(!dividend.is(edx)); 3205 base::MagicNumbersForDivision<uint32_t> mag = 3206 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor)); 3207 mov(eax, Immediate(mag.multiplier)); 3208 imul(dividend); 3209 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0; 3210 if (divisor > 0 && neg) add(edx, dividend); 3211 if (divisor < 0 && !neg && mag.multiplier > 0) sub(edx, dividend); 3212 if (mag.shift > 0) sar(edx, mag.shift); 3213 mov(eax, dividend); 3214 shr(eax, 31); 3215 add(edx, eax); 3216} 3217 3218 3219} // namespace internal 3220} // namespace v8 3221 3222#endif // V8_TARGET_ARCH_IA32 3223