Home | History | Annotate | Download | only in ia32
      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 
     16 namespace v8 {
     17 namespace internal {
     18 
     19 // -------------------------------------------------------------------------
     20 // MacroAssembler implementation.
     21 
     22 MacroAssembler::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 
     34 void 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 
     50 void 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 
     67 void 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 
     81 void 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 
     93 void 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 
    105 void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
    106   DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
    107   cmp(with, isolate()->heap()->root_handle(index));
    108 }
    109 
    110 
    111 void 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 
    118 void 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 
    126 static const Register saved_regs[] = {REG(eax), REG(ecx), REG(edx)};
    127 
    128 #undef REG
    129 
    130 static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register);
    131 
    132 void 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 
    154 void 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 
    173 void 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 
    181 void 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 
    227 void 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 
    252 void 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 
    262 void 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 
    270 void 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 
    285 void 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 
    313 void 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 
    380 void 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 
    391 void 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 
    431 void 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 
    476 void 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 
    538 void 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 
    606 void 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 
    676 void MacroAssembler::MaybeDropFrames() {
    677   // Check whether we need to drop frames to restart a function on the stack.
    678   ExternalReference restart_fp =
    679       ExternalReference::debug_restart_fp_address(isolate());
    680   mov(ebx, Operand::StaticVariable(restart_fp));
    681   test(ebx, ebx);
    682   j(not_zero, isolate()->builtins()->FrameDropperTrampoline(),
    683     RelocInfo::CODE_TARGET);
    684 }
    685 
    686 void MacroAssembler::Cvtsi2sd(XMMRegister dst, const Operand& src) {
    687   xorps(dst, dst);
    688   cvtsi2sd(dst, src);
    689 }
    690 
    691 
    692 void MacroAssembler::Cvtui2ss(XMMRegister dst, Register src, Register tmp) {
    693   Label msb_set_src;
    694   Label jmp_return;
    695   test(src, src);
    696   j(sign, &msb_set_src, Label::kNear);
    697   cvtsi2ss(dst, src);
    698   jmp(&jmp_return, Label::kNear);
    699   bind(&msb_set_src);
    700   mov(tmp, src);
    701   shr(src, 1);
    702   // Recover the least significant bit to avoid rounding errors.
    703   and_(tmp, Immediate(1));
    704   or_(src, tmp);
    705   cvtsi2ss(dst, src);
    706   addss(dst, dst);
    707   bind(&jmp_return);
    708 }
    709 
    710 void MacroAssembler::ShlPair(Register high, Register low, uint8_t shift) {
    711   if (shift >= 32) {
    712     mov(high, low);
    713     shl(high, shift - 32);
    714     xor_(low, low);
    715   } else {
    716     shld(high, low, shift);
    717     shl(low, shift);
    718   }
    719 }
    720 
    721 void MacroAssembler::ShlPair_cl(Register high, Register low) {
    722   shld_cl(high, low);
    723   shl_cl(low);
    724   Label done;
    725   test(ecx, Immediate(0x20));
    726   j(equal, &done, Label::kNear);
    727   mov(high, low);
    728   xor_(low, low);
    729   bind(&done);
    730 }
    731 
    732 void MacroAssembler::ShrPair(Register high, Register low, uint8_t shift) {
    733   if (shift >= 32) {
    734     mov(low, high);
    735     shr(low, shift - 32);
    736     xor_(high, high);
    737   } else {
    738     shrd(high, low, shift);
    739     shr(high, shift);
    740   }
    741 }
    742 
    743 void MacroAssembler::ShrPair_cl(Register high, Register low) {
    744   shrd_cl(low, high);
    745   shr_cl(high);
    746   Label done;
    747   test(ecx, Immediate(0x20));
    748   j(equal, &done, Label::kNear);
    749   mov(low, high);
    750   xor_(high, high);
    751   bind(&done);
    752 }
    753 
    754 void MacroAssembler::SarPair(Register high, Register low, uint8_t shift) {
    755   if (shift >= 32) {
    756     mov(low, high);
    757     sar(low, shift - 32);
    758     sar(high, 31);
    759   } else {
    760     shrd(high, low, shift);
    761     sar(high, shift);
    762   }
    763 }
    764 
    765 void MacroAssembler::SarPair_cl(Register high, Register low) {
    766   shrd_cl(low, high);
    767   sar_cl(high);
    768   Label done;
    769   test(ecx, Immediate(0x20));
    770   j(equal, &done, Label::kNear);
    771   mov(low, high);
    772   sar(high, 31);
    773   bind(&done);
    774 }
    775 
    776 bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) {
    777   static const int kMaxImmediateBits = 17;
    778   if (!RelocInfo::IsNone(x.rmode_)) return false;
    779   return !is_intn(x.x_, kMaxImmediateBits);
    780 }
    781 
    782 
    783 void MacroAssembler::SafeMove(Register dst, const Immediate& x) {
    784   if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
    785     Move(dst, Immediate(x.x_ ^ jit_cookie()));
    786     xor_(dst, jit_cookie());
    787   } else {
    788     Move(dst, x);
    789   }
    790 }
    791 
    792 
    793 void MacroAssembler::SafePush(const Immediate& x) {
    794   if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
    795     push(Immediate(x.x_ ^ jit_cookie()));
    796     xor_(Operand(esp, 0), Immediate(jit_cookie()));
    797   } else {
    798     push(x);
    799   }
    800 }
    801 
    802 
    803 void MacroAssembler::CmpObjectType(Register heap_object,
    804                                    InstanceType type,
    805                                    Register map) {
    806   mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
    807   CmpInstanceType(map, type);
    808 }
    809 
    810 
    811 void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
    812   cmpb(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(type));
    813 }
    814 
    815 void MacroAssembler::CompareMap(Register obj, Handle<Map> map) {
    816   cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
    817 }
    818 
    819 
    820 void MacroAssembler::CheckMap(Register obj,
    821                               Handle<Map> map,
    822                               Label* fail,
    823                               SmiCheckType smi_check_type) {
    824   if (smi_check_type == DO_SMI_CHECK) {
    825     JumpIfSmi(obj, fail);
    826   }
    827 
    828   CompareMap(obj, map);
    829   j(not_equal, fail);
    830 }
    831 
    832 
    833 void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
    834                                      Register scratch2, Handle<WeakCell> cell,
    835                                      Handle<Code> success,
    836                                      SmiCheckType smi_check_type) {
    837   Label fail;
    838   if (smi_check_type == DO_SMI_CHECK) {
    839     JumpIfSmi(obj, &fail);
    840   }
    841   mov(scratch1, FieldOperand(obj, HeapObject::kMapOffset));
    842   CmpWeakValue(scratch1, cell, scratch2);
    843   j(equal, success);
    844 
    845   bind(&fail);
    846 }
    847 
    848 
    849 Condition MacroAssembler::IsObjectStringType(Register heap_object,
    850                                              Register map,
    851                                              Register instance_type) {
    852   mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
    853   movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
    854   STATIC_ASSERT(kNotStringTag != 0);
    855   test(instance_type, Immediate(kIsNotStringMask));
    856   return zero;
    857 }
    858 
    859 
    860 Condition MacroAssembler::IsObjectNameType(Register heap_object,
    861                                            Register map,
    862                                            Register instance_type) {
    863   mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
    864   movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
    865   cmpb(instance_type, Immediate(LAST_NAME_TYPE));
    866   return below_equal;
    867 }
    868 
    869 
    870 void MacroAssembler::FCmp() {
    871   fucomip();
    872   fstp(0);
    873 }
    874 
    875 
    876 void MacroAssembler::AssertNumber(Register object) {
    877   if (emit_debug_code()) {
    878     Label ok;
    879     JumpIfSmi(object, &ok);
    880     cmp(FieldOperand(object, HeapObject::kMapOffset),
    881         isolate()->factory()->heap_number_map());
    882     Check(equal, kOperandNotANumber);
    883     bind(&ok);
    884   }
    885 }
    886 
    887 void MacroAssembler::AssertNotNumber(Register object) {
    888   if (emit_debug_code()) {
    889     test(object, Immediate(kSmiTagMask));
    890     Check(not_equal, kOperandIsANumber);
    891     cmp(FieldOperand(object, HeapObject::kMapOffset),
    892         isolate()->factory()->heap_number_map());
    893     Check(not_equal, kOperandIsANumber);
    894   }
    895 }
    896 
    897 void MacroAssembler::AssertSmi(Register object) {
    898   if (emit_debug_code()) {
    899     test(object, Immediate(kSmiTagMask));
    900     Check(equal, kOperandIsNotASmi);
    901   }
    902 }
    903 
    904 
    905 void MacroAssembler::AssertString(Register object) {
    906   if (emit_debug_code()) {
    907     test(object, Immediate(kSmiTagMask));
    908     Check(not_equal, kOperandIsASmiAndNotAString);
    909     push(object);
    910     mov(object, FieldOperand(object, HeapObject::kMapOffset));
    911     CmpInstanceType(object, FIRST_NONSTRING_TYPE);
    912     pop(object);
    913     Check(below, kOperandIsNotAString);
    914   }
    915 }
    916 
    917 
    918 void MacroAssembler::AssertName(Register object) {
    919   if (emit_debug_code()) {
    920     test(object, Immediate(kSmiTagMask));
    921     Check(not_equal, kOperandIsASmiAndNotAName);
    922     push(object);
    923     mov(object, FieldOperand(object, HeapObject::kMapOffset));
    924     CmpInstanceType(object, LAST_NAME_TYPE);
    925     pop(object);
    926     Check(below_equal, kOperandIsNotAName);
    927   }
    928 }
    929 
    930 
    931 void MacroAssembler::AssertFunction(Register object) {
    932   if (emit_debug_code()) {
    933     test(object, Immediate(kSmiTagMask));
    934     Check(not_equal, kOperandIsASmiAndNotAFunction);
    935     Push(object);
    936     CmpObjectType(object, JS_FUNCTION_TYPE, object);
    937     Pop(object);
    938     Check(equal, kOperandIsNotAFunction);
    939   }
    940 }
    941 
    942 
    943 void MacroAssembler::AssertBoundFunction(Register object) {
    944   if (emit_debug_code()) {
    945     test(object, Immediate(kSmiTagMask));
    946     Check(not_equal, kOperandIsASmiAndNotABoundFunction);
    947     Push(object);
    948     CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object);
    949     Pop(object);
    950     Check(equal, kOperandIsNotABoundFunction);
    951   }
    952 }
    953 
    954 void MacroAssembler::AssertGeneratorObject(Register object) {
    955   if (emit_debug_code()) {
    956     test(object, Immediate(kSmiTagMask));
    957     Check(not_equal, kOperandIsASmiAndNotAGeneratorObject);
    958     Push(object);
    959     CmpObjectType(object, JS_GENERATOR_OBJECT_TYPE, object);
    960     Pop(object);
    961     Check(equal, kOperandIsNotAGeneratorObject);
    962   }
    963 }
    964 
    965 void MacroAssembler::AssertReceiver(Register object) {
    966   if (emit_debug_code()) {
    967     test(object, Immediate(kSmiTagMask));
    968     Check(not_equal, kOperandIsASmiAndNotAReceiver);
    969     Push(object);
    970     STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
    971     CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, object);
    972     Pop(object);
    973     Check(above_equal, kOperandIsNotAReceiver);
    974   }
    975 }
    976 
    977 
    978 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
    979   if (emit_debug_code()) {
    980     Label done_checking;
    981     AssertNotSmi(object);
    982     cmp(object, isolate()->factory()->undefined_value());
    983     j(equal, &done_checking);
    984     cmp(FieldOperand(object, 0),
    985         Immediate(isolate()->factory()->allocation_site_map()));
    986     Assert(equal, kExpectedUndefinedOrCell);
    987     bind(&done_checking);
    988   }
    989 }
    990 
    991 
    992 void MacroAssembler::AssertNotSmi(Register object) {
    993   if (emit_debug_code()) {
    994     test(object, Immediate(kSmiTagMask));
    995     Check(not_equal, kOperandIsASmi);
    996   }
    997 }
    998 
    999 void MacroAssembler::StubPrologue(StackFrame::Type type) {
   1000   push(ebp);  // Caller's frame pointer.
   1001   mov(ebp, esp);
   1002   push(Immediate(StackFrame::TypeToMarker(type)));
   1003 }
   1004 
   1005 void MacroAssembler::Prologue(bool code_pre_aging) {
   1006   PredictableCodeSizeScope predictible_code_size_scope(this,
   1007       kNoCodeAgeSequenceLength);
   1008   if (code_pre_aging) {
   1009       // Pre-age the code.
   1010     call(isolate()->builtins()->MarkCodeAsExecutedOnce(),
   1011         RelocInfo::CODE_AGE_SEQUENCE);
   1012     Nop(kNoCodeAgeSequenceLength - Assembler::kCallInstructionLength);
   1013   } else {
   1014     push(ebp);  // Caller's frame pointer.
   1015     mov(ebp, esp);
   1016     push(esi);  // Callee's context.
   1017     push(edi);  // Callee's JS function.
   1018   }
   1019 }
   1020 
   1021 void MacroAssembler::EmitLoadFeedbackVector(Register vector) {
   1022   mov(vector, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
   1023   mov(vector, FieldOperand(vector, JSFunction::kFeedbackVectorOffset));
   1024   mov(vector, FieldOperand(vector, Cell::kValueOffset));
   1025 }
   1026 
   1027 
   1028 void MacroAssembler::EnterFrame(StackFrame::Type type,
   1029                                 bool load_constant_pool_pointer_reg) {
   1030   // Out-of-line constant pool not implemented on ia32.
   1031   UNREACHABLE();
   1032 }
   1033 
   1034 
   1035 void MacroAssembler::EnterFrame(StackFrame::Type type) {
   1036   push(ebp);
   1037   mov(ebp, esp);
   1038   push(Immediate(StackFrame::TypeToMarker(type)));
   1039   if (type == StackFrame::INTERNAL) {
   1040     push(Immediate(CodeObject()));
   1041   }
   1042   if (emit_debug_code()) {
   1043     cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value()));
   1044     Check(not_equal, kCodeObjectNotProperlyPatched);
   1045   }
   1046 }
   1047 
   1048 
   1049 void MacroAssembler::LeaveFrame(StackFrame::Type type) {
   1050   if (emit_debug_code()) {
   1051     cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
   1052         Immediate(StackFrame::TypeToMarker(type)));
   1053     Check(equal, kStackFrameTypesMustMatch);
   1054   }
   1055   leave();
   1056 }
   1057 
   1058 void MacroAssembler::EnterBuiltinFrame(Register context, Register target,
   1059                                        Register argc) {
   1060   Push(ebp);
   1061   Move(ebp, esp);
   1062   Push(context);
   1063   Push(target);
   1064   Push(argc);
   1065 }
   1066 
   1067 void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
   1068                                        Register argc) {
   1069   Pop(argc);
   1070   Pop(target);
   1071   Pop(context);
   1072   leave();
   1073 }
   1074 
   1075 void MacroAssembler::EnterExitFramePrologue(StackFrame::Type frame_type) {
   1076   DCHECK(frame_type == StackFrame::EXIT ||
   1077          frame_type == StackFrame::BUILTIN_EXIT);
   1078 
   1079   // Set up the frame structure on the stack.
   1080   DCHECK_EQ(+2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
   1081   DCHECK_EQ(+1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
   1082   DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
   1083   push(ebp);
   1084   mov(ebp, esp);
   1085 
   1086   // Reserve room for entry stack pointer and push the code object.
   1087   push(Immediate(StackFrame::TypeToMarker(frame_type)));
   1088   DCHECK_EQ(-2 * kPointerSize, ExitFrameConstants::kSPOffset);
   1089   push(Immediate(0));  // Saved entry sp, patched before call.
   1090   DCHECK_EQ(-3 * kPointerSize, ExitFrameConstants::kCodeOffset);
   1091   push(Immediate(CodeObject()));  // Accessed from ExitFrame::code_slot.
   1092 
   1093   // Save the frame pointer and the context in top.
   1094   ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate());
   1095   ExternalReference context_address(Isolate::kContextAddress, isolate());
   1096   ExternalReference c_function_address(Isolate::kCFunctionAddress, isolate());
   1097   mov(Operand::StaticVariable(c_entry_fp_address), ebp);
   1098   mov(Operand::StaticVariable(context_address), esi);
   1099   mov(Operand::StaticVariable(c_function_address), ebx);
   1100 }
   1101 
   1102 
   1103 void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
   1104   // Optionally save all XMM registers.
   1105   if (save_doubles) {
   1106     int space = XMMRegister::kMaxNumRegisters * kDoubleSize +
   1107                 argc * kPointerSize;
   1108     sub(esp, Immediate(space));
   1109     const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
   1110     for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
   1111       XMMRegister reg = XMMRegister::from_code(i);
   1112       movsd(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg);
   1113     }
   1114   } else {
   1115     sub(esp, Immediate(argc * kPointerSize));
   1116   }
   1117 
   1118   // Get the required frame alignment for the OS.
   1119   const int kFrameAlignment = base::OS::ActivationFrameAlignment();
   1120   if (kFrameAlignment > 0) {
   1121     DCHECK(base::bits::IsPowerOfTwo32(kFrameAlignment));
   1122     and_(esp, -kFrameAlignment);
   1123   }
   1124 
   1125   // Patch the saved entry sp.
   1126   mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
   1127 }
   1128 
   1129 void MacroAssembler::EnterExitFrame(int argc, bool save_doubles,
   1130                                     StackFrame::Type frame_type) {
   1131   EnterExitFramePrologue(frame_type);
   1132 
   1133   // Set up argc and argv in callee-saved registers.
   1134   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
   1135   mov(edi, eax);
   1136   lea(esi, Operand(ebp, eax, times_4, offset));
   1137 
   1138   // Reserve space for argc, argv and isolate.
   1139   EnterExitFrameEpilogue(argc, save_doubles);
   1140 }
   1141 
   1142 
   1143 void MacroAssembler::EnterApiExitFrame(int argc) {
   1144   EnterExitFramePrologue(StackFrame::EXIT);
   1145   EnterExitFrameEpilogue(argc, false);
   1146 }
   1147 
   1148 
   1149 void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) {
   1150   // Optionally restore all XMM registers.
   1151   if (save_doubles) {
   1152     const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
   1153     for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
   1154       XMMRegister reg = XMMRegister::from_code(i);
   1155       movsd(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize)));
   1156     }
   1157   }
   1158 
   1159   if (pop_arguments) {
   1160     // Get the return address from the stack and restore the frame pointer.
   1161     mov(ecx, Operand(ebp, 1 * kPointerSize));
   1162     mov(ebp, Operand(ebp, 0 * kPointerSize));
   1163 
   1164     // Pop the arguments and the receiver from the caller stack.
   1165     lea(esp, Operand(esi, 1 * kPointerSize));
   1166 
   1167     // Push the return address to get ready to return.
   1168     push(ecx);
   1169   } else {
   1170     // Otherwise just leave the exit frame.
   1171     leave();
   1172   }
   1173 
   1174   LeaveExitFrameEpilogue(true);
   1175 }
   1176 
   1177 
   1178 void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) {
   1179   // Restore current context from top and clear it in debug mode.
   1180   ExternalReference context_address(Isolate::kContextAddress, isolate());
   1181   if (restore_context) {
   1182     mov(esi, Operand::StaticVariable(context_address));
   1183   }
   1184 #ifdef DEBUG
   1185   mov(Operand::StaticVariable(context_address), Immediate(0));
   1186 #endif
   1187 
   1188   // Clear the top frame.
   1189   ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
   1190                                        isolate());
   1191   mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
   1192 }
   1193 
   1194 
   1195 void MacroAssembler::LeaveApiExitFrame(bool restore_context) {
   1196   mov(esp, ebp);
   1197   pop(ebp);
   1198 
   1199   LeaveExitFrameEpilogue(restore_context);
   1200 }
   1201 
   1202 
   1203 void MacroAssembler::PushStackHandler() {
   1204   // Adjust this code if not the case.
   1205   STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
   1206   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   1207 
   1208   // Link the current handler as the next handler.
   1209   ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
   1210   push(Operand::StaticVariable(handler_address));
   1211 
   1212   // Set this new handler as the current one.
   1213   mov(Operand::StaticVariable(handler_address), esp);
   1214 }
   1215 
   1216 
   1217 void MacroAssembler::PopStackHandler() {
   1218   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   1219   ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
   1220   pop(Operand::StaticVariable(handler_address));
   1221   add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize));
   1222 }
   1223 
   1224 
   1225 // Compute the hash code from the untagged key.  This must be kept in sync with
   1226 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
   1227 // code-stub-hydrogen.cc
   1228 //
   1229 // Note: r0 will contain hash code
   1230 void MacroAssembler::GetNumberHash(Register r0, Register scratch) {
   1231   // Xor original key with a seed.
   1232   if (serializer_enabled()) {
   1233     ExternalReference roots_array_start =
   1234         ExternalReference::roots_array_start(isolate());
   1235     mov(scratch, Immediate(Heap::kHashSeedRootIndex));
   1236     mov(scratch,
   1237         Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
   1238     SmiUntag(scratch);
   1239     xor_(r0, scratch);
   1240   } else {
   1241     int32_t seed = isolate()->heap()->HashSeed();
   1242     xor_(r0, Immediate(seed));
   1243   }
   1244 
   1245   // hash = ~hash + (hash << 15);
   1246   mov(scratch, r0);
   1247   not_(r0);
   1248   shl(scratch, 15);
   1249   add(r0, scratch);
   1250   // hash = hash ^ (hash >> 12);
   1251   mov(scratch, r0);
   1252   shr(scratch, 12);
   1253   xor_(r0, scratch);
   1254   // hash = hash + (hash << 2);
   1255   lea(r0, Operand(r0, r0, times_4, 0));
   1256   // hash = hash ^ (hash >> 4);
   1257   mov(scratch, r0);
   1258   shr(scratch, 4);
   1259   xor_(r0, scratch);
   1260   // hash = hash * 2057;
   1261   imul(r0, r0, 2057);
   1262   // hash = hash ^ (hash >> 16);
   1263   mov(scratch, r0);
   1264   shr(scratch, 16);
   1265   xor_(r0, scratch);
   1266   and_(r0, 0x3fffffff);
   1267 }
   1268 
   1269 void MacroAssembler::LoadAllocationTopHelper(Register result,
   1270                                              Register scratch,
   1271                                              AllocationFlags flags) {
   1272   ExternalReference allocation_top =
   1273       AllocationUtils::GetAllocationTopReference(isolate(), flags);
   1274 
   1275   // Just return if allocation top is already known.
   1276   if ((flags & RESULT_CONTAINS_TOP) != 0) {
   1277     // No use of scratch if allocation top is provided.
   1278     DCHECK(scratch.is(no_reg));
   1279 #ifdef DEBUG
   1280     // Assert that result actually contains top on entry.
   1281     cmp(result, Operand::StaticVariable(allocation_top));
   1282     Check(equal, kUnexpectedAllocationTop);
   1283 #endif
   1284     return;
   1285   }
   1286 
   1287   // Move address of new object to result. Use scratch register if available.
   1288   if (scratch.is(no_reg)) {
   1289     mov(result, Operand::StaticVariable(allocation_top));
   1290   } else {
   1291     mov(scratch, Immediate(allocation_top));
   1292     mov(result, Operand(scratch, 0));
   1293   }
   1294 }
   1295 
   1296 
   1297 void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
   1298                                                Register scratch,
   1299                                                AllocationFlags flags) {
   1300   if (emit_debug_code()) {
   1301     test(result_end, Immediate(kObjectAlignmentMask));
   1302     Check(zero, kUnalignedAllocationInNewSpace);
   1303   }
   1304 
   1305   ExternalReference allocation_top =
   1306       AllocationUtils::GetAllocationTopReference(isolate(), flags);
   1307 
   1308   // Update new top. Use scratch if available.
   1309   if (scratch.is(no_reg)) {
   1310     mov(Operand::StaticVariable(allocation_top), result_end);
   1311   } else {
   1312     mov(Operand(scratch, 0), result_end);
   1313   }
   1314 }
   1315 
   1316 
   1317 void MacroAssembler::Allocate(int object_size,
   1318                               Register result,
   1319                               Register result_end,
   1320                               Register scratch,
   1321                               Label* gc_required,
   1322                               AllocationFlags flags) {
   1323   DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
   1324   DCHECK(object_size <= kMaxRegularHeapObjectSize);
   1325   DCHECK((flags & ALLOCATION_FOLDED) == 0);
   1326   if (!FLAG_inline_new) {
   1327     if (emit_debug_code()) {
   1328       // Trash the registers to simulate an allocation failure.
   1329       mov(result, Immediate(0x7091));
   1330       if (result_end.is_valid()) {
   1331         mov(result_end, Immediate(0x7191));
   1332       }
   1333       if (scratch.is_valid()) {
   1334         mov(scratch, Immediate(0x7291));
   1335       }
   1336     }
   1337     jmp(gc_required);
   1338     return;
   1339   }
   1340   DCHECK(!result.is(result_end));
   1341 
   1342   // Load address of new object into result.
   1343   LoadAllocationTopHelper(result, scratch, flags);
   1344 
   1345   ExternalReference allocation_limit =
   1346       AllocationUtils::GetAllocationLimitReference(isolate(), flags);
   1347 
   1348   // Align the next allocation. Storing the filler map without checking top is
   1349   // safe in new-space because the limit of the heap is aligned there.
   1350   if ((flags & DOUBLE_ALIGNMENT) != 0) {
   1351     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
   1352     Label aligned;
   1353     test(result, Immediate(kDoubleAlignmentMask));
   1354     j(zero, &aligned, Label::kNear);
   1355     if ((flags & PRETENURE) != 0) {
   1356       cmp(result, Operand::StaticVariable(allocation_limit));
   1357       j(above_equal, gc_required);
   1358     }
   1359     mov(Operand(result, 0),
   1360         Immediate(isolate()->factory()->one_pointer_filler_map()));
   1361     add(result, Immediate(kDoubleSize / 2));
   1362     bind(&aligned);
   1363   }
   1364 
   1365   // Calculate new top and bail out if space is exhausted.
   1366   Register top_reg = result_end.is_valid() ? result_end : result;
   1367 
   1368   if (!top_reg.is(result)) {
   1369     mov(top_reg, result);
   1370   }
   1371   add(top_reg, Immediate(object_size));
   1372   cmp(top_reg, Operand::StaticVariable(allocation_limit));
   1373   j(above, gc_required);
   1374 
   1375   if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
   1376     // The top pointer is not updated for allocation folding dominators.
   1377     UpdateAllocationTopHelper(top_reg, scratch, flags);
   1378   }
   1379 
   1380   if (top_reg.is(result)) {
   1381     sub(result, Immediate(object_size - kHeapObjectTag));
   1382   } else {
   1383     // Tag the result.
   1384     DCHECK(kHeapObjectTag == 1);
   1385     inc(result);
   1386   }
   1387 }
   1388 
   1389 
   1390 void MacroAssembler::Allocate(int header_size,
   1391                               ScaleFactor element_size,
   1392                               Register element_count,
   1393                               RegisterValueType element_count_type,
   1394                               Register result,
   1395                               Register result_end,
   1396                               Register scratch,
   1397                               Label* gc_required,
   1398                               AllocationFlags flags) {
   1399   DCHECK((flags & SIZE_IN_WORDS) == 0);
   1400   DCHECK((flags & ALLOCATION_FOLDING_DOMINATOR) == 0);
   1401   DCHECK((flags & ALLOCATION_FOLDED) == 0);
   1402   if (!FLAG_inline_new) {
   1403     if (emit_debug_code()) {
   1404       // Trash the registers to simulate an allocation failure.
   1405       mov(result, Immediate(0x7091));
   1406       mov(result_end, Immediate(0x7191));
   1407       if (scratch.is_valid()) {
   1408         mov(scratch, Immediate(0x7291));
   1409       }
   1410       // Register element_count is not modified by the function.
   1411     }
   1412     jmp(gc_required);
   1413     return;
   1414   }
   1415   DCHECK(!result.is(result_end));
   1416 
   1417   // Load address of new object into result.
   1418   LoadAllocationTopHelper(result, scratch, flags);
   1419 
   1420   ExternalReference allocation_limit =
   1421       AllocationUtils::GetAllocationLimitReference(isolate(), flags);
   1422 
   1423   // Align the next allocation. Storing the filler map without checking top is
   1424   // safe in new-space because the limit of the heap is aligned there.
   1425   if ((flags & DOUBLE_ALIGNMENT) != 0) {
   1426     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
   1427     Label aligned;
   1428     test(result, Immediate(kDoubleAlignmentMask));
   1429     j(zero, &aligned, Label::kNear);
   1430     if ((flags & PRETENURE) != 0) {
   1431       cmp(result, Operand::StaticVariable(allocation_limit));
   1432       j(above_equal, gc_required);
   1433     }
   1434     mov(Operand(result, 0),
   1435         Immediate(isolate()->factory()->one_pointer_filler_map()));
   1436     add(result, Immediate(kDoubleSize / 2));
   1437     bind(&aligned);
   1438   }
   1439 
   1440   // Calculate new top and bail out if space is exhausted.
   1441   // We assume that element_count*element_size + header_size does not
   1442   // overflow.
   1443   if (element_count_type == REGISTER_VALUE_IS_SMI) {
   1444     STATIC_ASSERT(static_cast<ScaleFactor>(times_2 - 1) == times_1);
   1445     STATIC_ASSERT(static_cast<ScaleFactor>(times_4 - 1) == times_2);
   1446     STATIC_ASSERT(static_cast<ScaleFactor>(times_8 - 1) == times_4);
   1447     DCHECK(element_size >= times_2);
   1448     DCHECK(kSmiTagSize == 1);
   1449     element_size = static_cast<ScaleFactor>(element_size - 1);
   1450   } else {
   1451     DCHECK(element_count_type == REGISTER_VALUE_IS_INT32);
   1452   }
   1453 
   1454   lea(result_end, Operand(element_count, element_size, header_size));
   1455   add(result_end, result);
   1456   cmp(result_end, Operand::StaticVariable(allocation_limit));
   1457   j(above, gc_required);
   1458 
   1459   // Tag result.
   1460   DCHECK(kHeapObjectTag == 1);
   1461   inc(result);
   1462 
   1463   UpdateAllocationTopHelper(result_end, scratch, flags);
   1464 }
   1465 
   1466 
   1467 void MacroAssembler::Allocate(Register object_size,
   1468                               Register result,
   1469                               Register result_end,
   1470                               Register scratch,
   1471                               Label* gc_required,
   1472                               AllocationFlags flags) {
   1473   DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
   1474   DCHECK((flags & ALLOCATION_FOLDED) == 0);
   1475   if (!FLAG_inline_new) {
   1476     if (emit_debug_code()) {
   1477       // Trash the registers to simulate an allocation failure.
   1478       mov(result, Immediate(0x7091));
   1479       mov(result_end, Immediate(0x7191));
   1480       if (scratch.is_valid()) {
   1481         mov(scratch, Immediate(0x7291));
   1482       }
   1483       // object_size is left unchanged by this function.
   1484     }
   1485     jmp(gc_required);
   1486     return;
   1487   }
   1488   DCHECK(!result.is(result_end));
   1489 
   1490   // Load address of new object into result.
   1491   LoadAllocationTopHelper(result, scratch, flags);
   1492 
   1493   ExternalReference allocation_limit =
   1494       AllocationUtils::GetAllocationLimitReference(isolate(), flags);
   1495 
   1496   // Align the next allocation. Storing the filler map without checking top is
   1497   // safe in new-space because the limit of the heap is aligned there.
   1498   if ((flags & DOUBLE_ALIGNMENT) != 0) {
   1499     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
   1500     Label aligned;
   1501     test(result, Immediate(kDoubleAlignmentMask));
   1502     j(zero, &aligned, Label::kNear);
   1503     if ((flags & PRETENURE) != 0) {
   1504       cmp(result, Operand::StaticVariable(allocation_limit));
   1505       j(above_equal, gc_required);
   1506     }
   1507     mov(Operand(result, 0),
   1508         Immediate(isolate()->factory()->one_pointer_filler_map()));
   1509     add(result, Immediate(kDoubleSize / 2));
   1510     bind(&aligned);
   1511   }
   1512 
   1513   // Calculate new top and bail out if space is exhausted.
   1514   if (!object_size.is(result_end)) {
   1515     mov(result_end, object_size);
   1516   }
   1517   add(result_end, result);
   1518   cmp(result_end, Operand::StaticVariable(allocation_limit));
   1519   j(above, gc_required);
   1520 
   1521   // Tag result.
   1522   DCHECK(kHeapObjectTag == 1);
   1523   inc(result);
   1524 
   1525   if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
   1526     // The top pointer is not updated for allocation folding dominators.
   1527     UpdateAllocationTopHelper(result_end, scratch, flags);
   1528   }
   1529 }
   1530 
   1531 void MacroAssembler::FastAllocate(int object_size, Register result,
   1532                                   Register result_end, AllocationFlags flags) {
   1533   DCHECK(!result.is(result_end));
   1534   // Load address of new object into result.
   1535   LoadAllocationTopHelper(result, no_reg, flags);
   1536 
   1537   if ((flags & DOUBLE_ALIGNMENT) != 0) {
   1538     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
   1539     Label aligned;
   1540     test(result, Immediate(kDoubleAlignmentMask));
   1541     j(zero, &aligned, Label::kNear);
   1542     mov(Operand(result, 0),
   1543         Immediate(isolate()->factory()->one_pointer_filler_map()));
   1544     add(result, Immediate(kDoubleSize / 2));
   1545     bind(&aligned);
   1546   }
   1547 
   1548   lea(result_end, Operand(result, object_size));
   1549   UpdateAllocationTopHelper(result_end, no_reg, flags);
   1550 
   1551   DCHECK(kHeapObjectTag == 1);
   1552   inc(result);
   1553 }
   1554 
   1555 void MacroAssembler::FastAllocate(Register object_size, Register result,
   1556                                   Register result_end, AllocationFlags flags) {
   1557   DCHECK(!result.is(result_end));
   1558   // Load address of new object into result.
   1559   LoadAllocationTopHelper(result, no_reg, flags);
   1560 
   1561   if ((flags & DOUBLE_ALIGNMENT) != 0) {
   1562     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
   1563     Label aligned;
   1564     test(result, Immediate(kDoubleAlignmentMask));
   1565     j(zero, &aligned, Label::kNear);
   1566     mov(Operand(result, 0),
   1567         Immediate(isolate()->factory()->one_pointer_filler_map()));
   1568     add(result, Immediate(kDoubleSize / 2));
   1569     bind(&aligned);
   1570   }
   1571 
   1572   lea(result_end, Operand(result, object_size, times_1, 0));
   1573   UpdateAllocationTopHelper(result_end, no_reg, flags);
   1574 
   1575   DCHECK(kHeapObjectTag == 1);
   1576   inc(result);
   1577 }
   1578 
   1579 
   1580 void MacroAssembler::AllocateHeapNumber(Register result,
   1581                                         Register scratch1,
   1582                                         Register scratch2,
   1583                                         Label* gc_required,
   1584                                         MutableMode mode) {
   1585   // Allocate heap number in new space.
   1586   Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
   1587            NO_ALLOCATION_FLAGS);
   1588 
   1589   Handle<Map> map = mode == MUTABLE
   1590       ? isolate()->factory()->mutable_heap_number_map()
   1591       : isolate()->factory()->heap_number_map();
   1592 
   1593   // Set the map.
   1594   mov(FieldOperand(result, HeapObject::kMapOffset), Immediate(map));
   1595 }
   1596 
   1597 void MacroAssembler::AllocateJSValue(Register result, Register constructor,
   1598                                      Register value, Register scratch,
   1599                                      Label* gc_required) {
   1600   DCHECK(!result.is(constructor));
   1601   DCHECK(!result.is(scratch));
   1602   DCHECK(!result.is(value));
   1603 
   1604   // Allocate JSValue in new space.
   1605   Allocate(JSValue::kSize, result, scratch, no_reg, gc_required,
   1606            NO_ALLOCATION_FLAGS);
   1607 
   1608   // Initialize the JSValue.
   1609   LoadGlobalFunctionInitialMap(constructor, scratch);
   1610   mov(FieldOperand(result, HeapObject::kMapOffset), scratch);
   1611   LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex);
   1612   mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
   1613   mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
   1614   mov(FieldOperand(result, JSValue::kValueOffset), value);
   1615   STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
   1616 }
   1617 
   1618 void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
   1619                                                 Register end_address,
   1620                                                 Register filler) {
   1621   Label loop, entry;
   1622   jmp(&entry, Label::kNear);
   1623   bind(&loop);
   1624   mov(Operand(current_address, 0), filler);
   1625   add(current_address, Immediate(kPointerSize));
   1626   bind(&entry);
   1627   cmp(current_address, end_address);
   1628   j(below, &loop, Label::kNear);
   1629 }
   1630 
   1631 
   1632 void MacroAssembler::BooleanBitTest(Register object,
   1633                                     int field_offset,
   1634                                     int bit_index) {
   1635   bit_index += kSmiTagSize + kSmiShiftSize;
   1636   DCHECK(base::bits::IsPowerOfTwo32(kBitsPerByte));
   1637   int byte_index = bit_index / kBitsPerByte;
   1638   int byte_bit_index = bit_index & (kBitsPerByte - 1);
   1639   test_b(FieldOperand(object, field_offset + byte_index),
   1640          Immediate(1 << byte_bit_index));
   1641 }
   1642 
   1643 
   1644 
   1645 void MacroAssembler::NegativeZeroTest(Register result,
   1646                                       Register op,
   1647                                       Label* then_label) {
   1648   Label ok;
   1649   test(result, result);
   1650   j(not_zero, &ok, Label::kNear);
   1651   test(op, op);
   1652   j(sign, then_label, Label::kNear);
   1653   bind(&ok);
   1654 }
   1655 
   1656 
   1657 void MacroAssembler::NegativeZeroTest(Register result,
   1658                                       Register op1,
   1659                                       Register op2,
   1660                                       Register scratch,
   1661                                       Label* then_label) {
   1662   Label ok;
   1663   test(result, result);
   1664   j(not_zero, &ok, Label::kNear);
   1665   mov(scratch, op1);
   1666   or_(scratch, op2);
   1667   j(sign, then_label, Label::kNear);
   1668   bind(&ok);
   1669 }
   1670 
   1671 
   1672 void MacroAssembler::GetMapConstructor(Register result, Register map,
   1673                                        Register temp) {
   1674   Label done, loop;
   1675   mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
   1676   bind(&loop);
   1677   JumpIfSmi(result, &done, Label::kNear);
   1678   CmpObjectType(result, MAP_TYPE, temp);
   1679   j(not_equal, &done, Label::kNear);
   1680   mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
   1681   jmp(&loop);
   1682   bind(&done);
   1683 }
   1684 
   1685 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) {
   1686   DCHECK(AllowThisStubCall(stub));  // Calls are not allowed in some stubs.
   1687   call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id);
   1688 }
   1689 
   1690 
   1691 void MacroAssembler::TailCallStub(CodeStub* stub) {
   1692   jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
   1693 }
   1694 
   1695 
   1696 void MacroAssembler::StubReturn(int argc) {
   1697   DCHECK(argc >= 1 && generating_stub());
   1698   ret((argc - 1) * kPointerSize);
   1699 }
   1700 
   1701 
   1702 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
   1703   return has_frame_ || !stub->SometimesSetsUpAFrame();
   1704 }
   1705 
   1706 void MacroAssembler::CallRuntime(const Runtime::Function* f,
   1707                                  int num_arguments,
   1708                                  SaveFPRegsMode save_doubles) {
   1709   // If the expected number of arguments of the runtime function is
   1710   // constant, we check that the actual number of arguments match the
   1711   // expectation.
   1712   CHECK(f->nargs < 0 || f->nargs == num_arguments);
   1713 
   1714   // TODO(1236192): Most runtime routines don't need the number of
   1715   // arguments passed in because it is constant. At some point we
   1716   // should remove this need and make the runtime routine entry code
   1717   // smarter.
   1718   Move(eax, Immediate(num_arguments));
   1719   mov(ebx, Immediate(ExternalReference(f, isolate())));
   1720   CEntryStub ces(isolate(), 1, save_doubles);
   1721   CallStub(&ces);
   1722 }
   1723 
   1724 
   1725 void MacroAssembler::CallExternalReference(ExternalReference ref,
   1726                                            int num_arguments) {
   1727   mov(eax, Immediate(num_arguments));
   1728   mov(ebx, Immediate(ref));
   1729 
   1730   CEntryStub stub(isolate(), 1);
   1731   CallStub(&stub);
   1732 }
   1733 
   1734 
   1735 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
   1736   // ----------- S t a t e -------------
   1737   //  -- esp[0]                 : return address
   1738   //  -- esp[8]                 : argument num_arguments - 1
   1739   //  ...
   1740   //  -- esp[8 * num_arguments] : argument 0 (receiver)
   1741   //
   1742   //  For runtime functions with variable arguments:
   1743   //  -- eax                    : number of  arguments
   1744   // -----------------------------------
   1745 
   1746   const Runtime::Function* function = Runtime::FunctionForId(fid);
   1747   DCHECK_EQ(1, function->result_size);
   1748   if (function->nargs >= 0) {
   1749     // TODO(1236192): Most runtime routines don't need the number of
   1750     // arguments passed in because it is constant. At some point we
   1751     // should remove this need and make the runtime routine entry code
   1752     // smarter.
   1753     mov(eax, Immediate(function->nargs));
   1754   }
   1755   JumpToExternalReference(ExternalReference(fid, isolate()));
   1756 }
   1757 
   1758 void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
   1759                                              bool builtin_exit_frame) {
   1760   // Set the entry point and jump to the C entry runtime stub.
   1761   mov(ebx, Immediate(ext));
   1762   CEntryStub ces(isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
   1763                  builtin_exit_frame);
   1764   jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
   1765 }
   1766 
   1767 void MacroAssembler::PrepareForTailCall(
   1768     const ParameterCount& callee_args_count, Register caller_args_count_reg,
   1769     Register scratch0, Register scratch1, ReturnAddressState ra_state,
   1770     int number_of_temp_values_after_return_address) {
   1771 #if DEBUG
   1772   if (callee_args_count.is_reg()) {
   1773     DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
   1774                        scratch1));
   1775   } else {
   1776     DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
   1777   }
   1778   DCHECK(ra_state != ReturnAddressState::kNotOnStack ||
   1779          number_of_temp_values_after_return_address == 0);
   1780 #endif
   1781 
   1782   // Calculate the destination address where we will put the return address
   1783   // after we drop current frame.
   1784   Register new_sp_reg = scratch0;
   1785   if (callee_args_count.is_reg()) {
   1786     sub(caller_args_count_reg, callee_args_count.reg());
   1787     lea(new_sp_reg,
   1788         Operand(ebp, caller_args_count_reg, times_pointer_size,
   1789                 StandardFrameConstants::kCallerPCOffset -
   1790                     number_of_temp_values_after_return_address * kPointerSize));
   1791   } else {
   1792     lea(new_sp_reg, Operand(ebp, caller_args_count_reg, times_pointer_size,
   1793                             StandardFrameConstants::kCallerPCOffset -
   1794                                 (callee_args_count.immediate() +
   1795                                  number_of_temp_values_after_return_address) *
   1796                                     kPointerSize));
   1797   }
   1798 
   1799   if (FLAG_debug_code) {
   1800     cmp(esp, new_sp_reg);
   1801     Check(below, kStackAccessBelowStackPointer);
   1802   }
   1803 
   1804   // Copy return address from caller's frame to current frame's return address
   1805   // to avoid its trashing and let the following loop copy it to the right
   1806   // place.
   1807   Register tmp_reg = scratch1;
   1808   if (ra_state == ReturnAddressState::kOnStack) {
   1809     mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset));
   1810     mov(Operand(esp, number_of_temp_values_after_return_address * kPointerSize),
   1811         tmp_reg);
   1812   } else {
   1813     DCHECK(ReturnAddressState::kNotOnStack == ra_state);
   1814     DCHECK_EQ(0, number_of_temp_values_after_return_address);
   1815     Push(Operand(ebp, StandardFrameConstants::kCallerPCOffset));
   1816   }
   1817 
   1818   // Restore caller's frame pointer now as it could be overwritten by
   1819   // the copying loop.
   1820   mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
   1821 
   1822   // +2 here is to copy both receiver and return address.
   1823   Register count_reg = caller_args_count_reg;
   1824   if (callee_args_count.is_reg()) {
   1825     lea(count_reg, Operand(callee_args_count.reg(),
   1826                            2 + number_of_temp_values_after_return_address));
   1827   } else {
   1828     mov(count_reg, Immediate(callee_args_count.immediate() + 2 +
   1829                              number_of_temp_values_after_return_address));
   1830     // TODO(ishell): Unroll copying loop for small immediate values.
   1831   }
   1832 
   1833   // Now copy callee arguments to the caller frame going backwards to avoid
   1834   // callee arguments corruption (source and destination areas could overlap).
   1835   Label loop, entry;
   1836   jmp(&entry, Label::kNear);
   1837   bind(&loop);
   1838   dec(count_reg);
   1839   mov(tmp_reg, Operand(esp, count_reg, times_pointer_size, 0));
   1840   mov(Operand(new_sp_reg, count_reg, times_pointer_size, 0), tmp_reg);
   1841   bind(&entry);
   1842   cmp(count_reg, Immediate(0));
   1843   j(not_equal, &loop, Label::kNear);
   1844 
   1845   // Leave current frame.
   1846   mov(esp, new_sp_reg);
   1847 }
   1848 
   1849 void MacroAssembler::InvokePrologue(const ParameterCount& expected,
   1850                                     const ParameterCount& actual,
   1851                                     Label* done,
   1852                                     bool* definitely_mismatches,
   1853                                     InvokeFlag flag,
   1854                                     Label::Distance done_near,
   1855                                     const CallWrapper& call_wrapper) {
   1856   bool definitely_matches = false;
   1857   *definitely_mismatches = false;
   1858   Label invoke;
   1859   if (expected.is_immediate()) {
   1860     DCHECK(actual.is_immediate());
   1861     mov(eax, actual.immediate());
   1862     if (expected.immediate() == actual.immediate()) {
   1863       definitely_matches = true;
   1864     } else {
   1865       const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
   1866       if (expected.immediate() == sentinel) {
   1867         // Don't worry about adapting arguments for builtins that
   1868         // don't want that done. Skip adaption code by making it look
   1869         // like we have a match between expected and actual number of
   1870         // arguments.
   1871         definitely_matches = true;
   1872       } else {
   1873         *definitely_mismatches = true;
   1874         mov(ebx, expected.immediate());
   1875       }
   1876     }
   1877   } else {
   1878     if (actual.is_immediate()) {
   1879       // Expected is in register, actual is immediate. This is the
   1880       // case when we invoke function values without going through the
   1881       // IC mechanism.
   1882       mov(eax, actual.immediate());
   1883       cmp(expected.reg(), actual.immediate());
   1884       j(equal, &invoke);
   1885       DCHECK(expected.reg().is(ebx));
   1886     } else if (!expected.reg().is(actual.reg())) {
   1887       // Both expected and actual are in (different) registers. This
   1888       // is the case when we invoke functions using call and apply.
   1889       cmp(expected.reg(), actual.reg());
   1890       j(equal, &invoke);
   1891       DCHECK(actual.reg().is(eax));
   1892       DCHECK(expected.reg().is(ebx));
   1893     } else {
   1894       definitely_matches = true;
   1895       Move(eax, actual.reg());
   1896     }
   1897   }
   1898 
   1899   if (!definitely_matches) {
   1900     Handle<Code> adaptor =
   1901         isolate()->builtins()->ArgumentsAdaptorTrampoline();
   1902     if (flag == CALL_FUNCTION) {
   1903       call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET));
   1904       call(adaptor, RelocInfo::CODE_TARGET);
   1905       call_wrapper.AfterCall();
   1906       if (!*definitely_mismatches) {
   1907         jmp(done, done_near);
   1908       }
   1909     } else {
   1910       jmp(adaptor, RelocInfo::CODE_TARGET);
   1911     }
   1912     bind(&invoke);
   1913   }
   1914 }
   1915 
   1916 void MacroAssembler::CheckDebugHook(Register fun, Register new_target,
   1917                                     const ParameterCount& expected,
   1918                                     const ParameterCount& actual) {
   1919   Label skip_hook;
   1920   ExternalReference debug_hook_active =
   1921       ExternalReference::debug_hook_on_function_call_address(isolate());
   1922   cmpb(Operand::StaticVariable(debug_hook_active), Immediate(0));
   1923   j(equal, &skip_hook);
   1924   {
   1925     FrameScope frame(this,
   1926                      has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
   1927     if (expected.is_reg()) {
   1928       SmiTag(expected.reg());
   1929       Push(expected.reg());
   1930     }
   1931     if (actual.is_reg()) {
   1932       SmiTag(actual.reg());
   1933       Push(actual.reg());
   1934     }
   1935     if (new_target.is_valid()) {
   1936       Push(new_target);
   1937     }
   1938     Push(fun);
   1939     Push(fun);
   1940     CallRuntime(Runtime::kDebugOnFunctionCall);
   1941     Pop(fun);
   1942     if (new_target.is_valid()) {
   1943       Pop(new_target);
   1944     }
   1945     if (actual.is_reg()) {
   1946       Pop(actual.reg());
   1947       SmiUntag(actual.reg());
   1948     }
   1949     if (expected.is_reg()) {
   1950       Pop(expected.reg());
   1951       SmiUntag(expected.reg());
   1952     }
   1953   }
   1954   bind(&skip_hook);
   1955 }
   1956 
   1957 
   1958 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
   1959                                         const ParameterCount& expected,
   1960                                         const ParameterCount& actual,
   1961                                         InvokeFlag flag,
   1962                                         const CallWrapper& call_wrapper) {
   1963   // You can't call a function without a valid frame.
   1964   DCHECK(flag == JUMP_FUNCTION || has_frame());
   1965   DCHECK(function.is(edi));
   1966   DCHECK_IMPLIES(new_target.is_valid(), new_target.is(edx));
   1967 
   1968   if (call_wrapper.NeedsDebugHookCheck()) {
   1969     CheckDebugHook(function, new_target, expected, actual);
   1970   }
   1971 
   1972   // Clear the new.target register if not given.
   1973   if (!new_target.is_valid()) {
   1974     mov(edx, isolate()->factory()->undefined_value());
   1975   }
   1976 
   1977   Label done;
   1978   bool definitely_mismatches = false;
   1979   InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
   1980                  Label::kNear, call_wrapper);
   1981   if (!definitely_mismatches) {
   1982     // We call indirectly through the code field in the function to
   1983     // allow recompilation to take effect without changing any of the
   1984     // call sites.
   1985     Operand code = FieldOperand(function, JSFunction::kCodeEntryOffset);
   1986     if (flag == CALL_FUNCTION) {
   1987       call_wrapper.BeforeCall(CallSize(code));
   1988       call(code);
   1989       call_wrapper.AfterCall();
   1990     } else {
   1991       DCHECK(flag == JUMP_FUNCTION);
   1992       jmp(code);
   1993     }
   1994     bind(&done);
   1995   }
   1996 }
   1997 
   1998 
   1999 void MacroAssembler::InvokeFunction(Register fun,
   2000                                     Register new_target,
   2001                                     const ParameterCount& actual,
   2002                                     InvokeFlag flag,
   2003                                     const CallWrapper& call_wrapper) {
   2004   // You can't call a function without a valid frame.
   2005   DCHECK(flag == JUMP_FUNCTION || has_frame());
   2006 
   2007   DCHECK(fun.is(edi));
   2008   mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
   2009   mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
   2010   mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset));
   2011   SmiUntag(ebx);
   2012 
   2013   ParameterCount expected(ebx);
   2014   InvokeFunctionCode(edi, new_target, expected, actual, flag, call_wrapper);
   2015 }
   2016 
   2017 
   2018 void MacroAssembler::InvokeFunction(Register fun,
   2019                                     const ParameterCount& expected,
   2020                                     const ParameterCount& actual,
   2021                                     InvokeFlag flag,
   2022                                     const CallWrapper& call_wrapper) {
   2023   // You can't call a function without a valid frame.
   2024   DCHECK(flag == JUMP_FUNCTION || has_frame());
   2025 
   2026   DCHECK(fun.is(edi));
   2027   mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
   2028 
   2029   InvokeFunctionCode(edi, no_reg, expected, actual, flag, call_wrapper);
   2030 }
   2031 
   2032 
   2033 void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
   2034                                     const ParameterCount& expected,
   2035                                     const ParameterCount& actual,
   2036                                     InvokeFlag flag,
   2037                                     const CallWrapper& call_wrapper) {
   2038   LoadHeapObject(edi, function);
   2039   InvokeFunction(edi, expected, actual, flag, call_wrapper);
   2040 }
   2041 
   2042 
   2043 void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
   2044   if (context_chain_length > 0) {
   2045     // Move up the chain of contexts to the context containing the slot.
   2046     mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX)));
   2047     for (int i = 1; i < context_chain_length; i++) {
   2048       mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
   2049     }
   2050   } else {
   2051     // Slot is in the current function context.  Move it into the
   2052     // destination register in case we store into it (the write barrier
   2053     // cannot be allowed to destroy the context in esi).
   2054     mov(dst, esi);
   2055   }
   2056 
   2057   // We should not have found a with context by walking the context chain
   2058   // (i.e., the static scope chain and runtime context chain do not agree).
   2059   // A variable occurring in such a scope should have slot type LOOKUP and
   2060   // not CONTEXT.
   2061   if (emit_debug_code()) {
   2062     cmp(FieldOperand(dst, HeapObject::kMapOffset),
   2063         isolate()->factory()->with_context_map());
   2064     Check(not_equal, kVariableResolvedToWithContext);
   2065   }
   2066 }
   2067 
   2068 
   2069 void MacroAssembler::LoadGlobalProxy(Register dst) {
   2070   mov(dst, NativeContextOperand());
   2071   mov(dst, ContextOperand(dst, Context::GLOBAL_PROXY_INDEX));
   2072 }
   2073 
   2074 void MacroAssembler::LoadGlobalFunction(int index, Register function) {
   2075   // Load the native context from the current context.
   2076   mov(function, NativeContextOperand());
   2077   // Load the function from the native context.
   2078   mov(function, ContextOperand(function, index));
   2079 }
   2080 
   2081 
   2082 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
   2083                                                   Register map) {
   2084   // Load the initial map.  The global functions all have initial maps.
   2085   mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
   2086   if (emit_debug_code()) {
   2087     Label ok, fail;
   2088     CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK);
   2089     jmp(&ok);
   2090     bind(&fail);
   2091     Abort(kGlobalFunctionsMustHaveInitialMap);
   2092     bind(&ok);
   2093   }
   2094 }
   2095 
   2096 
   2097 // Store the value in register src in the safepoint register stack
   2098 // slot for register dst.
   2099 void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) {
   2100   mov(SafepointRegisterSlot(dst), src);
   2101 }
   2102 
   2103 
   2104 void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Immediate src) {
   2105   mov(SafepointRegisterSlot(dst), src);
   2106 }
   2107 
   2108 
   2109 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
   2110   mov(dst, SafepointRegisterSlot(src));
   2111 }
   2112 
   2113 
   2114 Operand MacroAssembler::SafepointRegisterSlot(Register reg) {
   2115   return Operand(esp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
   2116 }
   2117 
   2118 
   2119 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
   2120   // The registers are pushed starting with the lowest encoding,
   2121   // which means that lowest encodings are furthest away from
   2122   // the stack pointer.
   2123   DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters);
   2124   return kNumSafepointRegisters - reg_code - 1;
   2125 }
   2126 
   2127 
   2128 void MacroAssembler::LoadHeapObject(Register result,
   2129                                     Handle<HeapObject> object) {
   2130   mov(result, object);
   2131 }
   2132 
   2133 
   2134 void MacroAssembler::CmpHeapObject(Register reg, Handle<HeapObject> object) {
   2135   cmp(reg, object);
   2136 }
   2137 
   2138 void MacroAssembler::PushHeapObject(Handle<HeapObject> object) { Push(object); }
   2139 
   2140 void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
   2141                                   Register scratch) {
   2142   mov(scratch, cell);
   2143   cmp(value, FieldOperand(scratch, WeakCell::kValueOffset));
   2144 }
   2145 
   2146 
   2147 void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
   2148   mov(value, cell);
   2149   mov(value, FieldOperand(value, WeakCell::kValueOffset));
   2150 }
   2151 
   2152 
   2153 void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
   2154                                    Label* miss) {
   2155   GetWeakValue(value, cell);
   2156   JumpIfSmi(value, miss);
   2157 }
   2158 
   2159 
   2160 void MacroAssembler::Ret() {
   2161   ret(0);
   2162 }
   2163 
   2164 
   2165 void MacroAssembler::Ret(int bytes_dropped, Register scratch) {
   2166   if (is_uint16(bytes_dropped)) {
   2167     ret(bytes_dropped);
   2168   } else {
   2169     pop(scratch);
   2170     add(esp, Immediate(bytes_dropped));
   2171     push(scratch);
   2172     ret(0);
   2173   }
   2174 }
   2175 
   2176 
   2177 void MacroAssembler::Drop(int stack_elements) {
   2178   if (stack_elements > 0) {
   2179     add(esp, Immediate(stack_elements * kPointerSize));
   2180   }
   2181 }
   2182 
   2183 
   2184 void MacroAssembler::Move(Register dst, Register src) {
   2185   if (!dst.is(src)) {
   2186     mov(dst, src);
   2187   }
   2188 }
   2189 
   2190 
   2191 void MacroAssembler::Move(Register dst, const Immediate& x) {
   2192   if (x.is_zero() && RelocInfo::IsNone(x.rmode_)) {
   2193     xor_(dst, dst);  // Shorter than mov of 32-bit immediate 0.
   2194   } else {
   2195     mov(dst, x);
   2196   }
   2197 }
   2198 
   2199 
   2200 void MacroAssembler::Move(const Operand& dst, const Immediate& x) {
   2201   mov(dst, x);
   2202 }
   2203 
   2204 
   2205 void MacroAssembler::Move(XMMRegister dst, uint32_t src) {
   2206   if (src == 0) {
   2207     pxor(dst, dst);
   2208   } else {
   2209     unsigned cnt = base::bits::CountPopulation32(src);
   2210     unsigned nlz = base::bits::CountLeadingZeros32(src);
   2211     unsigned ntz = base::bits::CountTrailingZeros32(src);
   2212     if (nlz + cnt + ntz == 32) {
   2213       pcmpeqd(dst, dst);
   2214       if (ntz == 0) {
   2215         psrld(dst, 32 - cnt);
   2216       } else {
   2217         pslld(dst, 32 - cnt);
   2218         if (nlz != 0) psrld(dst, nlz);
   2219       }
   2220     } else {
   2221       push(eax);
   2222       mov(eax, Immediate(src));
   2223       movd(dst, Operand(eax));
   2224       pop(eax);
   2225     }
   2226   }
   2227 }
   2228 
   2229 
   2230 void MacroAssembler::Move(XMMRegister dst, uint64_t src) {
   2231   if (src == 0) {
   2232     pxor(dst, dst);
   2233   } else {
   2234     uint32_t lower = static_cast<uint32_t>(src);
   2235     uint32_t upper = static_cast<uint32_t>(src >> 32);
   2236     unsigned cnt = base::bits::CountPopulation64(src);
   2237     unsigned nlz = base::bits::CountLeadingZeros64(src);
   2238     unsigned ntz = base::bits::CountTrailingZeros64(src);
   2239     if (nlz + cnt + ntz == 64) {
   2240       pcmpeqd(dst, dst);
   2241       if (ntz == 0) {
   2242         psrlq(dst, 64 - cnt);
   2243       } else {
   2244         psllq(dst, 64 - cnt);
   2245         if (nlz != 0) psrlq(dst, nlz);
   2246       }
   2247     } else if (lower == 0) {
   2248       Move(dst, upper);
   2249       psllq(dst, 32);
   2250     } else if (CpuFeatures::IsSupported(SSE4_1)) {
   2251       CpuFeatureScope scope(this, SSE4_1);
   2252       push(eax);
   2253       Move(eax, Immediate(lower));
   2254       movd(dst, Operand(eax));
   2255       Move(eax, Immediate(upper));
   2256       pinsrd(dst, Operand(eax), 1);
   2257       pop(eax);
   2258     } else {
   2259       push(Immediate(upper));
   2260       push(Immediate(lower));
   2261       movsd(dst, Operand(esp, 0));
   2262       add(esp, Immediate(kDoubleSize));
   2263     }
   2264   }
   2265 }
   2266 
   2267 
   2268 void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) {
   2269   if (imm8 == 0) {
   2270     movd(dst, src);
   2271     return;
   2272   }
   2273   DCHECK_EQ(1, imm8);
   2274   if (CpuFeatures::IsSupported(SSE4_1)) {
   2275     CpuFeatureScope sse_scope(this, SSE4_1);
   2276     pextrd(dst, src, imm8);
   2277     return;
   2278   }
   2279   pshufd(xmm0, src, 1);
   2280   movd(dst, xmm0);
   2281 }
   2282 
   2283 
   2284 void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) {
   2285   DCHECK(imm8 == 0 || imm8 == 1);
   2286   if (CpuFeatures::IsSupported(SSE4_1)) {
   2287     CpuFeatureScope sse_scope(this, SSE4_1);
   2288     pinsrd(dst, src, imm8);
   2289     return;
   2290   }
   2291   movd(xmm0, src);
   2292   if (imm8 == 1) {
   2293     punpckldq(dst, xmm0);
   2294   } else {
   2295     DCHECK_EQ(0, imm8);
   2296     psrlq(dst, 32);
   2297     punpckldq(xmm0, dst);
   2298     movaps(dst, xmm0);
   2299   }
   2300 }
   2301 
   2302 
   2303 void MacroAssembler::Lzcnt(Register dst, const Operand& src) {
   2304   if (CpuFeatures::IsSupported(LZCNT)) {
   2305     CpuFeatureScope scope(this, LZCNT);
   2306     lzcnt(dst, src);
   2307     return;
   2308   }
   2309   Label not_zero_src;
   2310   bsr(dst, src);
   2311   j(not_zero, &not_zero_src, Label::kNear);
   2312   Move(dst, Immediate(63));  // 63^31 == 32
   2313   bind(&not_zero_src);
   2314   xor_(dst, Immediate(31));  // for x in [0..31], 31^x == 31-x.
   2315 }
   2316 
   2317 
   2318 void MacroAssembler::Tzcnt(Register dst, const Operand& src) {
   2319   if (CpuFeatures::IsSupported(BMI1)) {
   2320     CpuFeatureScope scope(this, BMI1);
   2321     tzcnt(dst, src);
   2322     return;
   2323   }
   2324   Label not_zero_src;
   2325   bsf(dst, src);
   2326   j(not_zero, &not_zero_src, Label::kNear);
   2327   Move(dst, Immediate(32));  // The result of tzcnt is 32 if src = 0.
   2328   bind(&not_zero_src);
   2329 }
   2330 
   2331 
   2332 void MacroAssembler::Popcnt(Register dst, const Operand& src) {
   2333   if (CpuFeatures::IsSupported(POPCNT)) {
   2334     CpuFeatureScope scope(this, POPCNT);
   2335     popcnt(dst, src);
   2336     return;
   2337   }
   2338   UNREACHABLE();
   2339 }
   2340 
   2341 
   2342 void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
   2343   if (FLAG_native_code_counters && counter->Enabled()) {
   2344     mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
   2345   }
   2346 }
   2347 
   2348 
   2349 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
   2350   DCHECK(value > 0);
   2351   if (FLAG_native_code_counters && counter->Enabled()) {
   2352     Operand operand = Operand::StaticVariable(ExternalReference(counter));
   2353     if (value == 1) {
   2354       inc(operand);
   2355     } else {
   2356       add(operand, Immediate(value));
   2357     }
   2358   }
   2359 }
   2360 
   2361 
   2362 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
   2363   DCHECK(value > 0);
   2364   if (FLAG_native_code_counters && counter->Enabled()) {
   2365     Operand operand = Operand::StaticVariable(ExternalReference(counter));
   2366     if (value == 1) {
   2367       dec(operand);
   2368     } else {
   2369       sub(operand, Immediate(value));
   2370     }
   2371   }
   2372 }
   2373 
   2374 
   2375 void MacroAssembler::IncrementCounter(Condition cc,
   2376                                       StatsCounter* counter,
   2377                                       int value) {
   2378   DCHECK(value > 0);
   2379   if (FLAG_native_code_counters && counter->Enabled()) {
   2380     Label skip;
   2381     j(NegateCondition(cc), &skip);
   2382     pushfd();
   2383     IncrementCounter(counter, value);
   2384     popfd();
   2385     bind(&skip);
   2386   }
   2387 }
   2388 
   2389 
   2390 void MacroAssembler::DecrementCounter(Condition cc,
   2391                                       StatsCounter* counter,
   2392                                       int value) {
   2393   DCHECK(value > 0);
   2394   if (FLAG_native_code_counters && counter->Enabled()) {
   2395     Label skip;
   2396     j(NegateCondition(cc), &skip);
   2397     pushfd();
   2398     DecrementCounter(counter, value);
   2399     popfd();
   2400     bind(&skip);
   2401   }
   2402 }
   2403 
   2404 
   2405 void MacroAssembler::Assert(Condition cc, BailoutReason reason) {
   2406   if (emit_debug_code()) Check(cc, reason);
   2407 }
   2408 
   2409 
   2410 void MacroAssembler::AssertFastElements(Register elements) {
   2411   if (emit_debug_code()) {
   2412     Factory* factory = isolate()->factory();
   2413     Label ok;
   2414     cmp(FieldOperand(elements, HeapObject::kMapOffset),
   2415         Immediate(factory->fixed_array_map()));
   2416     j(equal, &ok);
   2417     cmp(FieldOperand(elements, HeapObject::kMapOffset),
   2418         Immediate(factory->fixed_double_array_map()));
   2419     j(equal, &ok);
   2420     cmp(FieldOperand(elements, HeapObject::kMapOffset),
   2421         Immediate(factory->fixed_cow_array_map()));
   2422     j(equal, &ok);
   2423     Abort(kJSObjectWithFastElementsMapHasSlowElements);
   2424     bind(&ok);
   2425   }
   2426 }
   2427 
   2428 
   2429 void MacroAssembler::Check(Condition cc, BailoutReason reason) {
   2430   Label L;
   2431   j(cc, &L);
   2432   Abort(reason);
   2433   // will not return here
   2434   bind(&L);
   2435 }
   2436 
   2437 
   2438 void MacroAssembler::CheckStackAlignment() {
   2439   int frame_alignment = base::OS::ActivationFrameAlignment();
   2440   int frame_alignment_mask = frame_alignment - 1;
   2441   if (frame_alignment > kPointerSize) {
   2442     DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
   2443     Label alignment_as_expected;
   2444     test(esp, Immediate(frame_alignment_mask));
   2445     j(zero, &alignment_as_expected);
   2446     // Abort if stack is not aligned.
   2447     int3();
   2448     bind(&alignment_as_expected);
   2449   }
   2450 }
   2451 
   2452 
   2453 void MacroAssembler::Abort(BailoutReason reason) {
   2454 #ifdef DEBUG
   2455   const char* msg = GetBailoutReason(reason);
   2456   if (msg != NULL) {
   2457     RecordComment("Abort message: ");
   2458     RecordComment(msg);
   2459   }
   2460 
   2461   if (FLAG_trap_on_abort) {
   2462     int3();
   2463     return;
   2464   }
   2465 #endif
   2466 
   2467   // Check if Abort() has already been initialized.
   2468   DCHECK(isolate()->builtins()->Abort()->IsHeapObject());
   2469 
   2470   Move(edx, Smi::FromInt(static_cast<int>(reason)));
   2471 
   2472   // Disable stub call restrictions to always allow calls to abort.
   2473   if (!has_frame_) {
   2474     // We don't actually want to generate a pile of code for this, so just
   2475     // claim there is a stack frame, without generating one.
   2476     FrameScope scope(this, StackFrame::NONE);
   2477     Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET);
   2478   } else {
   2479     Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET);
   2480   }
   2481   // will not return here
   2482   int3();
   2483 }
   2484 
   2485 
   2486 void MacroAssembler::LoadInstanceDescriptors(Register map,
   2487                                              Register descriptors) {
   2488   mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
   2489 }
   2490 
   2491 
   2492 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
   2493   mov(dst, FieldOperand(map, Map::kBitField3Offset));
   2494   DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
   2495 }
   2496 
   2497 
   2498 void MacroAssembler::LoadAccessor(Register dst, Register holder,
   2499                                   int accessor_index,
   2500                                   AccessorComponent accessor) {
   2501   mov(dst, FieldOperand(holder, HeapObject::kMapOffset));
   2502   LoadInstanceDescriptors(dst, dst);
   2503   mov(dst, FieldOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
   2504   int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset
   2505                                            : AccessorPair::kSetterOffset;
   2506   mov(dst, FieldOperand(dst, offset));
   2507 }
   2508 
   2509 
   2510 void MacroAssembler::LoadPowerOf2(XMMRegister dst,
   2511                                   Register scratch,
   2512                                   int power) {
   2513   DCHECK(is_uintn(power + HeapNumber::kExponentBias,
   2514                   HeapNumber::kExponentBits));
   2515   mov(scratch, Immediate(power + HeapNumber::kExponentBias));
   2516   movd(dst, scratch);
   2517   psllq(dst, HeapNumber::kMantissaBits);
   2518 }
   2519 
   2520 void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register object1,
   2521                                                            Register object2,
   2522                                                            Register scratch1,
   2523                                                            Register scratch2,
   2524                                                            Label* failure) {
   2525   // Check that both objects are not smis.
   2526   STATIC_ASSERT(kSmiTag == 0);
   2527   mov(scratch1, object1);
   2528   and_(scratch1, object2);
   2529   JumpIfSmi(scratch1, failure);
   2530 
   2531   // Load instance type for both strings.
   2532   mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
   2533   mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset));
   2534   movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
   2535   movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
   2536 
   2537   // Check that both are flat one-byte strings.
   2538   const int kFlatOneByteStringMask =
   2539       kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
   2540   const int kFlatOneByteStringTag =
   2541       kStringTag | kOneByteStringTag | kSeqStringTag;
   2542   // Interleave bits from both instance types and compare them in one check.
   2543   const int kShift = 8;
   2544   DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << kShift));
   2545   and_(scratch1, kFlatOneByteStringMask);
   2546   and_(scratch2, kFlatOneByteStringMask);
   2547   shl(scratch2, kShift);
   2548   or_(scratch1, scratch2);
   2549   cmp(scratch1, kFlatOneByteStringTag | (kFlatOneByteStringTag << kShift));
   2550   j(not_equal, failure);
   2551 }
   2552 
   2553 
   2554 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Operand operand,
   2555                                                      Label* not_unique_name,
   2556                                                      Label::Distance distance) {
   2557   STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
   2558   Label succeed;
   2559   test(operand, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
   2560   j(zero, &succeed);
   2561   cmpb(operand, Immediate(SYMBOL_TYPE));
   2562   j(not_equal, not_unique_name, distance);
   2563 
   2564   bind(&succeed);
   2565 }
   2566 
   2567 
   2568 void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
   2569                                                Register index,
   2570                                                Register value,
   2571                                                uint32_t encoding_mask) {
   2572   Label is_object;
   2573   JumpIfNotSmi(string, &is_object, Label::kNear);
   2574   Abort(kNonObject);
   2575   bind(&is_object);
   2576 
   2577   push(value);
   2578   mov(value, FieldOperand(string, HeapObject::kMapOffset));
   2579   movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
   2580 
   2581   and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
   2582   cmp(value, Immediate(encoding_mask));
   2583   pop(value);
   2584   Check(equal, kUnexpectedStringType);
   2585 
   2586   // The index is assumed to be untagged coming in, tag it to compare with the
   2587   // string length without using a temp register, it is restored at the end of
   2588   // this function.
   2589   SmiTag(index);
   2590   Check(no_overflow, kIndexIsTooLarge);
   2591 
   2592   cmp(index, FieldOperand(string, String::kLengthOffset));
   2593   Check(less, kIndexIsTooLarge);
   2594 
   2595   cmp(index, Immediate(Smi::kZero));
   2596   Check(greater_equal, kIndexIsNegative);
   2597 
   2598   // Restore the index
   2599   SmiUntag(index);
   2600 }
   2601 
   2602 
   2603 void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
   2604   int frame_alignment = base::OS::ActivationFrameAlignment();
   2605   if (frame_alignment != 0) {
   2606     // Make stack end at alignment and make room for num_arguments words
   2607     // and the original value of esp.
   2608     mov(scratch, esp);
   2609     sub(esp, Immediate((num_arguments + 1) * kPointerSize));
   2610     DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
   2611     and_(esp, -frame_alignment);
   2612     mov(Operand(esp, num_arguments * kPointerSize), scratch);
   2613   } else {
   2614     sub(esp, Immediate(num_arguments * kPointerSize));
   2615   }
   2616 }
   2617 
   2618 
   2619 void MacroAssembler::CallCFunction(ExternalReference function,
   2620                                    int num_arguments) {
   2621   // Trashing eax is ok as it will be the return value.
   2622   mov(eax, Immediate(function));
   2623   CallCFunction(eax, num_arguments);
   2624 }
   2625 
   2626 
   2627 void MacroAssembler::CallCFunction(Register function,
   2628                                    int num_arguments) {
   2629   DCHECK(has_frame());
   2630   // Check stack alignment.
   2631   if (emit_debug_code()) {
   2632     CheckStackAlignment();
   2633   }
   2634 
   2635   call(function);
   2636   if (base::OS::ActivationFrameAlignment() != 0) {
   2637     mov(esp, Operand(esp, num_arguments * kPointerSize));
   2638   } else {
   2639     add(esp, Immediate(num_arguments * kPointerSize));
   2640   }
   2641 }
   2642 
   2643 
   2644 #ifdef DEBUG
   2645 bool AreAliased(Register reg1,
   2646                 Register reg2,
   2647                 Register reg3,
   2648                 Register reg4,
   2649                 Register reg5,
   2650                 Register reg6,
   2651                 Register reg7,
   2652                 Register reg8) {
   2653   int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() +
   2654       reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
   2655       reg7.is_valid() + reg8.is_valid();
   2656 
   2657   RegList regs = 0;
   2658   if (reg1.is_valid()) regs |= reg1.bit();
   2659   if (reg2.is_valid()) regs |= reg2.bit();
   2660   if (reg3.is_valid()) regs |= reg3.bit();
   2661   if (reg4.is_valid()) regs |= reg4.bit();
   2662   if (reg5.is_valid()) regs |= reg5.bit();
   2663   if (reg6.is_valid()) regs |= reg6.bit();
   2664   if (reg7.is_valid()) regs |= reg7.bit();
   2665   if (reg8.is_valid()) regs |= reg8.bit();
   2666   int n_of_non_aliasing_regs = NumRegs(regs);
   2667 
   2668   return n_of_valid_regs != n_of_non_aliasing_regs;
   2669 }
   2670 #endif
   2671 
   2672 
   2673 CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size)
   2674     : address_(address),
   2675       size_(size),
   2676       masm_(isolate, address, size + Assembler::kGap, CodeObjectRequired::kNo) {
   2677   // Create a new macro assembler pointing to the address of the code to patch.
   2678   // The size is adjusted with kGap on order for the assembler to generate size
   2679   // bytes of instructions without failing with buffer size constraints.
   2680   DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
   2681 }
   2682 
   2683 
   2684 CodePatcher::~CodePatcher() {
   2685   // Indicate that code has changed.
   2686   Assembler::FlushICache(masm_.isolate(), address_, size_);
   2687 
   2688   // Check that the code was patched as expected.
   2689   DCHECK(masm_.pc_ == address_ + size_);
   2690   DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
   2691 }
   2692 
   2693 
   2694 void MacroAssembler::CheckPageFlag(
   2695     Register object,
   2696     Register scratch,
   2697     int mask,
   2698     Condition cc,
   2699     Label* condition_met,
   2700     Label::Distance condition_met_distance) {
   2701   DCHECK(cc == zero || cc == not_zero);
   2702   if (scratch.is(object)) {
   2703     and_(scratch, Immediate(~Page::kPageAlignmentMask));
   2704   } else {
   2705     mov(scratch, Immediate(~Page::kPageAlignmentMask));
   2706     and_(scratch, object);
   2707   }
   2708   if (mask < (1 << kBitsPerByte)) {
   2709     test_b(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
   2710   } else {
   2711     test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
   2712   }
   2713   j(cc, condition_met, condition_met_distance);
   2714 }
   2715 
   2716 
   2717 void MacroAssembler::CheckPageFlagForMap(
   2718     Handle<Map> map,
   2719     int mask,
   2720     Condition cc,
   2721     Label* condition_met,
   2722     Label::Distance condition_met_distance) {
   2723   DCHECK(cc == zero || cc == not_zero);
   2724   Page* page = Page::FromAddress(map->address());
   2725   DCHECK(!serializer_enabled());  // Serializer cannot match page_flags.
   2726   ExternalReference reference(ExternalReference::page_flags(page));
   2727   // The inlined static address check of the page's flags relies
   2728   // on maps never being compacted.
   2729   DCHECK(!isolate()->heap()->mark_compact_collector()->
   2730          IsOnEvacuationCandidate(*map));
   2731   if (mask < (1 << kBitsPerByte)) {
   2732     test_b(Operand::StaticVariable(reference), Immediate(mask));
   2733   } else {
   2734     test(Operand::StaticVariable(reference), Immediate(mask));
   2735   }
   2736   j(cc, condition_met, condition_met_distance);
   2737 }
   2738 
   2739 
   2740 void MacroAssembler::JumpIfBlack(Register object,
   2741                                  Register scratch0,
   2742                                  Register scratch1,
   2743                                  Label* on_black,
   2744                                  Label::Distance on_black_near) {
   2745   HasColor(object, scratch0, scratch1, on_black, on_black_near, 1,
   2746            1);  // kBlackBitPattern.
   2747   DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
   2748 }
   2749 
   2750 
   2751 void MacroAssembler::HasColor(Register object,
   2752                               Register bitmap_scratch,
   2753                               Register mask_scratch,
   2754                               Label* has_color,
   2755                               Label::Distance has_color_distance,
   2756                               int first_bit,
   2757                               int second_bit) {
   2758   DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, ecx));
   2759 
   2760   GetMarkBits(object, bitmap_scratch, mask_scratch);
   2761 
   2762   Label other_color, word_boundary;
   2763   test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
   2764   j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear);
   2765   add(mask_scratch, mask_scratch);  // Shift left 1 by adding.
   2766   j(zero, &word_boundary, Label::kNear);
   2767   test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
   2768   j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
   2769   jmp(&other_color, Label::kNear);
   2770 
   2771   bind(&word_boundary);
   2772   test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize),
   2773          Immediate(1));
   2774 
   2775   j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
   2776   bind(&other_color);
   2777 }
   2778 
   2779 
   2780 void MacroAssembler::GetMarkBits(Register addr_reg,
   2781                                  Register bitmap_reg,
   2782                                  Register mask_reg) {
   2783   DCHECK(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx));
   2784   mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask));
   2785   and_(bitmap_reg, addr_reg);
   2786   mov(ecx, addr_reg);
   2787   int shift =
   2788       Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2;
   2789   shr(ecx, shift);
   2790   and_(ecx,
   2791        (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1));
   2792 
   2793   add(bitmap_reg, ecx);
   2794   mov(ecx, addr_reg);
   2795   shr(ecx, kPointerSizeLog2);
   2796   and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1);
   2797   mov(mask_reg, Immediate(1));
   2798   shl_cl(mask_reg);
   2799 }
   2800 
   2801 
   2802 void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
   2803                                  Register mask_scratch, Label* value_is_white,
   2804                                  Label::Distance distance) {
   2805   DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ecx));
   2806   GetMarkBits(value, bitmap_scratch, mask_scratch);
   2807 
   2808   // If the value is black or grey we don't need to do anything.
   2809   DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
   2810   DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
   2811   DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
   2812   DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
   2813 
   2814   // Since both black and grey have a 1 in the first position and white does
   2815   // not have a 1 there we only need to check one bit.
   2816   test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
   2817   j(zero, value_is_white, Label::kNear);
   2818 }
   2819 
   2820 
   2821 void MacroAssembler::EnumLength(Register dst, Register map) {
   2822   STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
   2823   mov(dst, FieldOperand(map, Map::kBitField3Offset));
   2824   and_(dst, Immediate(Map::EnumLengthBits::kMask));
   2825   SmiTag(dst);
   2826 }
   2827 
   2828 
   2829 void MacroAssembler::CheckEnumCache(Label* call_runtime) {
   2830   Label next, start;
   2831   mov(ecx, eax);
   2832 
   2833   // Check if the enum length field is properly initialized, indicating that
   2834   // there is an enum cache.
   2835   mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
   2836 
   2837   EnumLength(edx, ebx);
   2838   cmp(edx, Immediate(Smi::FromInt(kInvalidEnumCacheSentinel)));
   2839   j(equal, call_runtime);
   2840 
   2841   jmp(&start);
   2842 
   2843   bind(&next);
   2844   mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
   2845 
   2846   // For all objects but the receiver, check that the cache is empty.
   2847   EnumLength(edx, ebx);
   2848   cmp(edx, Immediate(Smi::kZero));
   2849   j(not_equal, call_runtime);
   2850 
   2851   bind(&start);
   2852 
   2853   // Check that there are no elements. Register rcx contains the current JS
   2854   // object we've reached through the prototype chain.
   2855   Label no_elements;
   2856   mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
   2857   cmp(ecx, isolate()->factory()->empty_fixed_array());
   2858   j(equal, &no_elements);
   2859 
   2860   // Second chance, the object may be using the empty slow element dictionary.
   2861   cmp(ecx, isolate()->factory()->empty_slow_element_dictionary());
   2862   j(not_equal, call_runtime);
   2863 
   2864   bind(&no_elements);
   2865   mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
   2866   cmp(ecx, isolate()->factory()->null_value());
   2867   j(not_equal, &next);
   2868 }
   2869 
   2870 
   2871 void MacroAssembler::TestJSArrayForAllocationMemento(
   2872     Register receiver_reg,
   2873     Register scratch_reg,
   2874     Label* no_memento_found) {
   2875   Label map_check;
   2876   Label top_check;
   2877   ExternalReference new_space_allocation_top =
   2878       ExternalReference::new_space_allocation_top_address(isolate());
   2879   const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
   2880   const int kMementoLastWordOffset =
   2881       kMementoMapOffset + AllocationMemento::kSize - kPointerSize;
   2882 
   2883   // Bail out if the object is not in new space.
   2884   JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found);
   2885   // If the object is in new space, we need to check whether it is on the same
   2886   // page as the current top.
   2887   lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset));
   2888   xor_(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
   2889   test(scratch_reg, Immediate(~Page::kPageAlignmentMask));
   2890   j(zero, &top_check);
   2891   // The object is on a different page than allocation top. Bail out if the
   2892   // object sits on the page boundary as no memento can follow and we cannot
   2893   // touch the memory following it.
   2894   lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset));
   2895   xor_(scratch_reg, receiver_reg);
   2896   test(scratch_reg, Immediate(~Page::kPageAlignmentMask));
   2897   j(not_zero, no_memento_found);
   2898   // Continue with the actual map check.
   2899   jmp(&map_check);
   2900   // If top is on the same page as the current object, we need to check whether
   2901   // we are below top.
   2902   bind(&top_check);
   2903   lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset));
   2904   cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
   2905   j(greater_equal, no_memento_found);
   2906   // Memento map check.
   2907   bind(&map_check);
   2908   mov(scratch_reg, Operand(receiver_reg, kMementoMapOffset));
   2909   cmp(scratch_reg, Immediate(isolate()->factory()->allocation_memento_map()));
   2910 }
   2911 
   2912 void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) {
   2913   DCHECK(!dividend.is(eax));
   2914   DCHECK(!dividend.is(edx));
   2915   base::MagicNumbersForDivision<uint32_t> mag =
   2916       base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
   2917   mov(eax, Immediate(mag.multiplier));
   2918   imul(dividend);
   2919   bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
   2920   if (divisor > 0 && neg) add(edx, dividend);
   2921   if (divisor < 0 && !neg && mag.multiplier > 0) sub(edx, dividend);
   2922   if (mag.shift > 0) sar(edx, mag.shift);
   2923   mov(eax, dividend);
   2924   shr(eax, 31);
   2925   add(edx, eax);
   2926 }
   2927 
   2928 
   2929 }  // namespace internal
   2930 }  // namespace v8
   2931 
   2932 #endif  // V8_TARGET_ARCH_IA32
   2933