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