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