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