Home | History | Annotate | Download | only in arm
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <limits.h>  // For LONG_MIN, LONG_MAX.
      6 
      7 #if V8_TARGET_ARCH_ARM
      8 
      9 #include "src/base/bits.h"
     10 #include "src/base/division-by-constant.h"
     11 #include "src/bootstrapper.h"
     12 #include "src/codegen.h"
     13 #include "src/debug/debug.h"
     14 #include "src/register-configuration.h"
     15 #include "src/runtime/runtime.h"
     16 
     17 #include "src/arm/macro-assembler-arm.h"
     18 
     19 namespace v8 {
     20 namespace internal {
     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::Jump(Register target, Condition cond) {
     35   bx(target, cond);
     36 }
     37 
     38 
     39 void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
     40                           Condition cond) {
     41   DCHECK(RelocInfo::IsCodeTarget(rmode));
     42   mov(pc, Operand(target, rmode), LeaveCC, cond);
     43 }
     44 
     45 
     46 void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode,
     47                           Condition cond) {
     48   DCHECK(!RelocInfo::IsCodeTarget(rmode));
     49   Jump(reinterpret_cast<intptr_t>(target), rmode, cond);
     50 }
     51 
     52 
     53 void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
     54                           Condition cond) {
     55   DCHECK(RelocInfo::IsCodeTarget(rmode));
     56   // 'code' is always generated ARM code, never THUMB code
     57   AllowDeferredHandleDereference embedding_raw_address;
     58   Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
     59 }
     60 
     61 
     62 int MacroAssembler::CallSize(Register target, Condition cond) {
     63   return kInstrSize;
     64 }
     65 
     66 
     67 void MacroAssembler::Call(Register target, Condition cond) {
     68   // Block constant pool for the call instruction sequence.
     69   BlockConstPoolScope block_const_pool(this);
     70   Label start;
     71   bind(&start);
     72   blx(target, cond);
     73   DCHECK_EQ(CallSize(target, cond), SizeOfCodeGeneratedSince(&start));
     74 }
     75 
     76 
     77 int MacroAssembler::CallSize(
     78     Address target, RelocInfo::Mode rmode, Condition cond) {
     79   Instr mov_instr = cond | MOV | LeaveCC;
     80   Operand mov_operand = Operand(reinterpret_cast<intptr_t>(target), rmode);
     81   return kInstrSize +
     82          mov_operand.instructions_required(this, mov_instr) * kInstrSize;
     83 }
     84 
     85 
     86 int MacroAssembler::CallStubSize(
     87     CodeStub* stub, TypeFeedbackId ast_id, Condition cond) {
     88   return CallSize(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond);
     89 }
     90 
     91 
     92 int MacroAssembler::CallSizeNotPredictableCodeSize(Isolate* isolate,
     93                                                    Address target,
     94                                                    RelocInfo::Mode rmode,
     95                                                    Condition cond) {
     96   Instr mov_instr = cond | MOV | LeaveCC;
     97   Operand mov_operand = Operand(reinterpret_cast<intptr_t>(target), rmode);
     98   return kInstrSize +
     99          mov_operand.instructions_required(NULL, mov_instr) * kInstrSize;
    100 }
    101 
    102 
    103 void MacroAssembler::Call(Address target,
    104                           RelocInfo::Mode rmode,
    105                           Condition cond,
    106                           TargetAddressStorageMode mode) {
    107   // Block constant pool for the call instruction sequence.
    108   BlockConstPoolScope block_const_pool(this);
    109   Label start;
    110   bind(&start);
    111 
    112   bool old_predictable_code_size = predictable_code_size();
    113   if (mode == NEVER_INLINE_TARGET_ADDRESS) {
    114     set_predictable_code_size(true);
    115   }
    116 
    117 #ifdef DEBUG
    118   // Check the expected size before generating code to ensure we assume the same
    119   // constant pool availability (e.g., whether constant pool is full or not).
    120   int expected_size = CallSize(target, rmode, cond);
    121 #endif
    122 
    123   // Call sequence on V7 or later may be :
    124   //  movw  ip, #... @ call address low 16
    125   //  movt  ip, #... @ call address high 16
    126   //  blx   ip
    127   //                      @ return address
    128   // Or for pre-V7 or values that may be back-patched
    129   // to avoid ICache flushes:
    130   //  ldr   ip, [pc, #...] @ call address
    131   //  blx   ip
    132   //                      @ return address
    133 
    134   // Statement positions are expected to be recorded when the target
    135   // address is loaded. The mov method will automatically record
    136   // positions when pc is the target, since this is not the case here
    137   // we have to do it explicitly.
    138   positions_recorder()->WriteRecordedPositions();
    139 
    140   mov(ip, Operand(reinterpret_cast<int32_t>(target), rmode));
    141   blx(ip, cond);
    142 
    143   DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
    144   if (mode == NEVER_INLINE_TARGET_ADDRESS) {
    145     set_predictable_code_size(old_predictable_code_size);
    146   }
    147 }
    148 
    149 
    150 int MacroAssembler::CallSize(Handle<Code> code,
    151                              RelocInfo::Mode rmode,
    152                              TypeFeedbackId ast_id,
    153                              Condition cond) {
    154   AllowDeferredHandleDereference using_raw_address;
    155   return CallSize(reinterpret_cast<Address>(code.location()), rmode, cond);
    156 }
    157 
    158 
    159 void MacroAssembler::Call(Handle<Code> code,
    160                           RelocInfo::Mode rmode,
    161                           TypeFeedbackId ast_id,
    162                           Condition cond,
    163                           TargetAddressStorageMode mode) {
    164   Label start;
    165   bind(&start);
    166   DCHECK(RelocInfo::IsCodeTarget(rmode));
    167   if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) {
    168     SetRecordedAstId(ast_id);
    169     rmode = RelocInfo::CODE_TARGET_WITH_ID;
    170   }
    171   // 'code' is always generated ARM code, never THUMB code
    172   AllowDeferredHandleDereference embedding_raw_address;
    173   Call(reinterpret_cast<Address>(code.location()), rmode, cond, mode);
    174 }
    175 
    176 
    177 void MacroAssembler::Ret(Condition cond) {
    178   bx(lr, cond);
    179 }
    180 
    181 
    182 void MacroAssembler::Drop(int count, Condition cond) {
    183   if (count > 0) {
    184     add(sp, sp, Operand(count * kPointerSize), LeaveCC, cond);
    185   }
    186 }
    187 
    188 
    189 void MacroAssembler::Ret(int drop, Condition cond) {
    190   Drop(drop, cond);
    191   Ret(cond);
    192 }
    193 
    194 
    195 void MacroAssembler::Swap(Register reg1,
    196                           Register reg2,
    197                           Register scratch,
    198                           Condition cond) {
    199   if (scratch.is(no_reg)) {
    200     eor(reg1, reg1, Operand(reg2), LeaveCC, cond);
    201     eor(reg2, reg2, Operand(reg1), LeaveCC, cond);
    202     eor(reg1, reg1, Operand(reg2), LeaveCC, cond);
    203   } else {
    204     mov(scratch, reg1, LeaveCC, cond);
    205     mov(reg1, reg2, LeaveCC, cond);
    206     mov(reg2, scratch, LeaveCC, cond);
    207   }
    208 }
    209 
    210 
    211 void MacroAssembler::Call(Label* target) {
    212   bl(target);
    213 }
    214 
    215 
    216 void MacroAssembler::Push(Handle<Object> handle) {
    217   mov(ip, Operand(handle));
    218   push(ip);
    219 }
    220 
    221 
    222 void MacroAssembler::Move(Register dst, Handle<Object> value) {
    223   AllowDeferredHandleDereference smi_check;
    224   if (value->IsSmi()) {
    225     mov(dst, Operand(value));
    226   } else {
    227     DCHECK(value->IsHeapObject());
    228     if (isolate()->heap()->InNewSpace(*value)) {
    229       Handle<Cell> cell = isolate()->factory()->NewCell(value);
    230       mov(dst, Operand(cell));
    231       ldr(dst, FieldMemOperand(dst, Cell::kValueOffset));
    232     } else {
    233       mov(dst, Operand(value));
    234     }
    235   }
    236 }
    237 
    238 
    239 void MacroAssembler::Move(Register dst, Register src, Condition cond) {
    240   if (!dst.is(src)) {
    241     mov(dst, src, LeaveCC, cond);
    242   }
    243 }
    244 
    245 
    246 void MacroAssembler::Move(DwVfpRegister dst, DwVfpRegister src) {
    247   if (!dst.is(src)) {
    248     vmov(dst, src);
    249   }
    250 }
    251 
    252 
    253 void MacroAssembler::Mls(Register dst, Register src1, Register src2,
    254                          Register srcA, Condition cond) {
    255   if (CpuFeatures::IsSupported(MLS)) {
    256     CpuFeatureScope scope(this, MLS);
    257     mls(dst, src1, src2, srcA, cond);
    258   } else {
    259     DCHECK(!srcA.is(ip));
    260     mul(ip, src1, src2, LeaveCC, cond);
    261     sub(dst, srcA, ip, LeaveCC, cond);
    262   }
    263 }
    264 
    265 
    266 void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
    267                          Condition cond) {
    268   if (!src2.is_reg() &&
    269       !src2.must_output_reloc_info(this) &&
    270       src2.immediate() == 0) {
    271     mov(dst, Operand::Zero(), LeaveCC, cond);
    272   } else if (!(src2.instructions_required(this) == 1) &&
    273              !src2.must_output_reloc_info(this) &&
    274              CpuFeatures::IsSupported(ARMv7) &&
    275              base::bits::IsPowerOfTwo32(src2.immediate() + 1)) {
    276     ubfx(dst, src1, 0,
    277         WhichPowerOf2(static_cast<uint32_t>(src2.immediate()) + 1), cond);
    278   } else {
    279     and_(dst, src1, src2, LeaveCC, cond);
    280   }
    281 }
    282 
    283 
    284 void MacroAssembler::Ubfx(Register dst, Register src1, int lsb, int width,
    285                           Condition cond) {
    286   DCHECK(lsb < 32);
    287   if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) {
    288     int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
    289     and_(dst, src1, Operand(mask), LeaveCC, cond);
    290     if (lsb != 0) {
    291       mov(dst, Operand(dst, LSR, lsb), LeaveCC, cond);
    292     }
    293   } else {
    294     ubfx(dst, src1, lsb, width, cond);
    295   }
    296 }
    297 
    298 
    299 void MacroAssembler::Sbfx(Register dst, Register src1, int lsb, int width,
    300                           Condition cond) {
    301   DCHECK(lsb < 32);
    302   if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) {
    303     int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
    304     and_(dst, src1, Operand(mask), LeaveCC, cond);
    305     int shift_up = 32 - lsb - width;
    306     int shift_down = lsb + shift_up;
    307     if (shift_up != 0) {
    308       mov(dst, Operand(dst, LSL, shift_up), LeaveCC, cond);
    309     }
    310     if (shift_down != 0) {
    311       mov(dst, Operand(dst, ASR, shift_down), LeaveCC, cond);
    312     }
    313   } else {
    314     sbfx(dst, src1, lsb, width, cond);
    315   }
    316 }
    317 
    318 
    319 void MacroAssembler::Bfi(Register dst,
    320                          Register src,
    321                          Register scratch,
    322                          int lsb,
    323                          int width,
    324                          Condition cond) {
    325   DCHECK(0 <= lsb && lsb < 32);
    326   DCHECK(0 <= width && width < 32);
    327   DCHECK(lsb + width < 32);
    328   DCHECK(!scratch.is(dst));
    329   if (width == 0) return;
    330   if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) {
    331     int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
    332     bic(dst, dst, Operand(mask));
    333     and_(scratch, src, Operand((1 << width) - 1));
    334     mov(scratch, Operand(scratch, LSL, lsb));
    335     orr(dst, dst, scratch);
    336   } else {
    337     bfi(dst, src, lsb, width, cond);
    338   }
    339 }
    340 
    341 
    342 void MacroAssembler::Bfc(Register dst, Register src, int lsb, int width,
    343                          Condition cond) {
    344   DCHECK(lsb < 32);
    345   if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) {
    346     int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
    347     bic(dst, src, Operand(mask));
    348   } else {
    349     Move(dst, src, cond);
    350     bfc(dst, lsb, width, cond);
    351   }
    352 }
    353 
    354 
    355 void MacroAssembler::Usat(Register dst, int satpos, const Operand& src,
    356                           Condition cond) {
    357   if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) {
    358     DCHECK(!dst.is(pc) && !src.rm().is(pc));
    359     DCHECK((satpos >= 0) && (satpos <= 31));
    360 
    361     // These asserts are required to ensure compatibility with the ARMv7
    362     // implementation.
    363     DCHECK((src.shift_op() == ASR) || (src.shift_op() == LSL));
    364     DCHECK(src.rs().is(no_reg));
    365 
    366     Label done;
    367     int satval = (1 << satpos) - 1;
    368 
    369     if (cond != al) {
    370       b(NegateCondition(cond), &done);  // Skip saturate if !condition.
    371     }
    372     if (!(src.is_reg() && dst.is(src.rm()))) {
    373       mov(dst, src);
    374     }
    375     tst(dst, Operand(~satval));
    376     b(eq, &done);
    377     mov(dst, Operand::Zero(), LeaveCC, mi);  // 0 if negative.
    378     mov(dst, Operand(satval), LeaveCC, pl);  // satval if positive.
    379     bind(&done);
    380   } else {
    381     usat(dst, satpos, src, cond);
    382   }
    383 }
    384 
    385 
    386 void MacroAssembler::Load(Register dst,
    387                           const MemOperand& src,
    388                           Representation r) {
    389   DCHECK(!r.IsDouble());
    390   if (r.IsInteger8()) {
    391     ldrsb(dst, src);
    392   } else if (r.IsUInteger8()) {
    393     ldrb(dst, src);
    394   } else if (r.IsInteger16()) {
    395     ldrsh(dst, src);
    396   } else if (r.IsUInteger16()) {
    397     ldrh(dst, src);
    398   } else {
    399     ldr(dst, src);
    400   }
    401 }
    402 
    403 
    404 void MacroAssembler::Store(Register src,
    405                            const MemOperand& dst,
    406                            Representation r) {
    407   DCHECK(!r.IsDouble());
    408   if (r.IsInteger8() || r.IsUInteger8()) {
    409     strb(src, dst);
    410   } else if (r.IsInteger16() || r.IsUInteger16()) {
    411     strh(src, dst);
    412   } else {
    413     if (r.IsHeapObject()) {
    414       AssertNotSmi(src);
    415     } else if (r.IsSmi()) {
    416       AssertSmi(src);
    417     }
    418     str(src, dst);
    419   }
    420 }
    421 
    422 
    423 void MacroAssembler::LoadRoot(Register destination,
    424                               Heap::RootListIndex index,
    425                               Condition cond) {
    426   if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) &&
    427       isolate()->heap()->RootCanBeTreatedAsConstant(index) &&
    428       !predictable_code_size()) {
    429     // The CPU supports fast immediate values, and this root will never
    430     // change. We will load it as a relocatable immediate value.
    431     Handle<Object> root = isolate()->heap()->root_handle(index);
    432     mov(destination, Operand(root), LeaveCC, cond);
    433     return;
    434   }
    435   ldr(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), cond);
    436 }
    437 
    438 
    439 void MacroAssembler::StoreRoot(Register source,
    440                                Heap::RootListIndex index,
    441                                Condition cond) {
    442   DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
    443   str(source, MemOperand(kRootRegister, index << kPointerSizeLog2), cond);
    444 }
    445 
    446 
    447 void MacroAssembler::InNewSpace(Register object,
    448                                 Register scratch,
    449                                 Condition cond,
    450                                 Label* branch) {
    451   DCHECK(cond == eq || cond == ne);
    452   and_(scratch, object, Operand(ExternalReference::new_space_mask(isolate())));
    453   cmp(scratch, Operand(ExternalReference::new_space_start(isolate())));
    454   b(cond, branch);
    455 }
    456 
    457 
    458 void MacroAssembler::RecordWriteField(
    459     Register object,
    460     int offset,
    461     Register value,
    462     Register dst,
    463     LinkRegisterStatus lr_status,
    464     SaveFPRegsMode save_fp,
    465     RememberedSetAction remembered_set_action,
    466     SmiCheck smi_check,
    467     PointersToHereCheck pointers_to_here_check_for_value) {
    468   // First, check if a write barrier is even needed. The tests below
    469   // catch stores of Smis.
    470   Label done;
    471 
    472   // Skip barrier if writing a smi.
    473   if (smi_check == INLINE_SMI_CHECK) {
    474     JumpIfSmi(value, &done);
    475   }
    476 
    477   // Although the object register is tagged, the offset is relative to the start
    478   // of the object, so so offset must be a multiple of kPointerSize.
    479   DCHECK(IsAligned(offset, kPointerSize));
    480 
    481   add(dst, object, Operand(offset - kHeapObjectTag));
    482   if (emit_debug_code()) {
    483     Label ok;
    484     tst(dst, Operand((1 << kPointerSizeLog2) - 1));
    485     b(eq, &ok);
    486     stop("Unaligned cell in write barrier");
    487     bind(&ok);
    488   }
    489 
    490   RecordWrite(object,
    491               dst,
    492               value,
    493               lr_status,
    494               save_fp,
    495               remembered_set_action,
    496               OMIT_SMI_CHECK,
    497               pointers_to_here_check_for_value);
    498 
    499   bind(&done);
    500 
    501   // Clobber clobbered input registers when running with the debug-code flag
    502   // turned on to provoke errors.
    503   if (emit_debug_code()) {
    504     mov(value, Operand(bit_cast<int32_t>(kZapValue + 4)));
    505     mov(dst, Operand(bit_cast<int32_t>(kZapValue + 8)));
    506   }
    507 }
    508 
    509 
    510 // Will clobber 4 registers: object, map, dst, ip.  The
    511 // register 'object' contains a heap object pointer.
    512 void MacroAssembler::RecordWriteForMap(Register object,
    513                                        Register map,
    514                                        Register dst,
    515                                        LinkRegisterStatus lr_status,
    516                                        SaveFPRegsMode fp_mode) {
    517   if (emit_debug_code()) {
    518     ldr(dst, FieldMemOperand(map, HeapObject::kMapOffset));
    519     cmp(dst, Operand(isolate()->factory()->meta_map()));
    520     Check(eq, kWrongAddressOrValuePassedToRecordWrite);
    521   }
    522 
    523   if (!FLAG_incremental_marking) {
    524     return;
    525   }
    526 
    527   if (emit_debug_code()) {
    528     ldr(ip, FieldMemOperand(object, HeapObject::kMapOffset));
    529     cmp(ip, map);
    530     Check(eq, kWrongAddressOrValuePassedToRecordWrite);
    531   }
    532 
    533   Label done;
    534 
    535   // A single check of the map's pages interesting flag suffices, since it is
    536   // only set during incremental collection, and then it's also guaranteed that
    537   // the from object's page's interesting flag is also set.  This optimization
    538   // relies on the fact that maps can never be in new space.
    539   CheckPageFlag(map,
    540                 map,  // Used as scratch.
    541                 MemoryChunk::kPointersToHereAreInterestingMask,
    542                 eq,
    543                 &done);
    544 
    545   add(dst, object, Operand(HeapObject::kMapOffset - kHeapObjectTag));
    546   if (emit_debug_code()) {
    547     Label ok;
    548     tst(dst, Operand((1 << kPointerSizeLog2) - 1));
    549     b(eq, &ok);
    550     stop("Unaligned cell in write barrier");
    551     bind(&ok);
    552   }
    553 
    554   // Record the actual write.
    555   if (lr_status == kLRHasNotBeenSaved) {
    556     push(lr);
    557   }
    558   RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET,
    559                        fp_mode);
    560   CallStub(&stub);
    561   if (lr_status == kLRHasNotBeenSaved) {
    562     pop(lr);
    563   }
    564 
    565   bind(&done);
    566 
    567   // Count number of write barriers in generated code.
    568   isolate()->counters()->write_barriers_static()->Increment();
    569   IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, dst);
    570 
    571   // Clobber clobbered registers when running with the debug-code flag
    572   // turned on to provoke errors.
    573   if (emit_debug_code()) {
    574     mov(dst, Operand(bit_cast<int32_t>(kZapValue + 12)));
    575     mov(map, Operand(bit_cast<int32_t>(kZapValue + 16)));
    576   }
    577 }
    578 
    579 
    580 // Will clobber 4 registers: object, address, scratch, ip.  The
    581 // register 'object' contains a heap object pointer.  The heap object
    582 // tag is shifted away.
    583 void MacroAssembler::RecordWrite(
    584     Register object,
    585     Register address,
    586     Register value,
    587     LinkRegisterStatus lr_status,
    588     SaveFPRegsMode fp_mode,
    589     RememberedSetAction remembered_set_action,
    590     SmiCheck smi_check,
    591     PointersToHereCheck pointers_to_here_check_for_value) {
    592   DCHECK(!object.is(value));
    593   if (emit_debug_code()) {
    594     ldr(ip, MemOperand(address));
    595     cmp(ip, value);
    596     Check(eq, kWrongAddressOrValuePassedToRecordWrite);
    597   }
    598 
    599   if (remembered_set_action == OMIT_REMEMBERED_SET &&
    600       !FLAG_incremental_marking) {
    601     return;
    602   }
    603 
    604   // First, check if a write barrier is even needed. The tests below
    605   // catch stores of smis and stores into the young generation.
    606   Label done;
    607 
    608   if (smi_check == INLINE_SMI_CHECK) {
    609     JumpIfSmi(value, &done);
    610   }
    611 
    612   if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
    613     CheckPageFlag(value,
    614                   value,  // Used as scratch.
    615                   MemoryChunk::kPointersToHereAreInterestingMask,
    616                   eq,
    617                   &done);
    618   }
    619   CheckPageFlag(object,
    620                 value,  // Used as scratch.
    621                 MemoryChunk::kPointersFromHereAreInterestingMask,
    622                 eq,
    623                 &done);
    624 
    625   // Record the actual write.
    626   if (lr_status == kLRHasNotBeenSaved) {
    627     push(lr);
    628   }
    629   RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
    630                        fp_mode);
    631   CallStub(&stub);
    632   if (lr_status == kLRHasNotBeenSaved) {
    633     pop(lr);
    634   }
    635 
    636   bind(&done);
    637 
    638   // Count number of write barriers in generated code.
    639   isolate()->counters()->write_barriers_static()->Increment();
    640   IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip,
    641                    value);
    642 
    643   // Clobber clobbered registers when running with the debug-code flag
    644   // turned on to provoke errors.
    645   if (emit_debug_code()) {
    646     mov(address, Operand(bit_cast<int32_t>(kZapValue + 12)));
    647     mov(value, Operand(bit_cast<int32_t>(kZapValue + 16)));
    648   }
    649 }
    650 
    651 
    652 void MacroAssembler::RememberedSetHelper(Register object,  // For debug tests.
    653                                          Register address,
    654                                          Register scratch,
    655                                          SaveFPRegsMode fp_mode,
    656                                          RememberedSetFinalAction and_then) {
    657   Label done;
    658   if (emit_debug_code()) {
    659     Label ok;
    660     JumpIfNotInNewSpace(object, scratch, &ok);
    661     stop("Remembered set pointer is in new space");
    662     bind(&ok);
    663   }
    664   // Load store buffer top.
    665   ExternalReference store_buffer =
    666       ExternalReference::store_buffer_top(isolate());
    667   mov(ip, Operand(store_buffer));
    668   ldr(scratch, MemOperand(ip));
    669   // Store pointer to buffer and increment buffer top.
    670   str(address, MemOperand(scratch, kPointerSize, PostIndex));
    671   // Write back new top of buffer.
    672   str(scratch, MemOperand(ip));
    673   // Call stub on end of buffer.
    674   // Check for end of buffer.
    675   tst(scratch, Operand(StoreBuffer::kStoreBufferOverflowBit));
    676   if (and_then == kFallThroughAtEnd) {
    677     b(eq, &done);
    678   } else {
    679     DCHECK(and_then == kReturnAtEnd);
    680     Ret(eq);
    681   }
    682   push(lr);
    683   StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode);
    684   CallStub(&store_buffer_overflow);
    685   pop(lr);
    686   bind(&done);
    687   if (and_then == kReturnAtEnd) {
    688     Ret();
    689   }
    690 }
    691 
    692 
    693 void MacroAssembler::PushFixedFrame(Register marker_reg) {
    694   DCHECK(!marker_reg.is_valid() || marker_reg.code() < cp.code());
    695   stm(db_w, sp, (marker_reg.is_valid() ? marker_reg.bit() : 0) | cp.bit() |
    696                     (FLAG_enable_embedded_constant_pool ? pp.bit() : 0) |
    697                     fp.bit() | lr.bit());
    698 }
    699 
    700 
    701 void MacroAssembler::PopFixedFrame(Register marker_reg) {
    702   DCHECK(!marker_reg.is_valid() || marker_reg.code() < cp.code());
    703   ldm(ia_w, sp, (marker_reg.is_valid() ? marker_reg.bit() : 0) | cp.bit() |
    704                     (FLAG_enable_embedded_constant_pool ? pp.bit() : 0) |
    705                     fp.bit() | lr.bit());
    706 }
    707 
    708 
    709 // Push and pop all registers that can hold pointers.
    710 void MacroAssembler::PushSafepointRegisters() {
    711   // Safepoints expect a block of contiguous register values starting with r0.
    712   // except when FLAG_enable_embedded_constant_pool, which omits pp.
    713   DCHECK(kSafepointSavedRegisters ==
    714          (FLAG_enable_embedded_constant_pool
    715               ? ((1 << (kNumSafepointSavedRegisters + 1)) - 1) & ~pp.bit()
    716               : (1 << kNumSafepointSavedRegisters) - 1));
    717   // Safepoints expect a block of kNumSafepointRegisters values on the
    718   // stack, so adjust the stack for unsaved registers.
    719   const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
    720   DCHECK(num_unsaved >= 0);
    721   sub(sp, sp, Operand(num_unsaved * kPointerSize));
    722   stm(db_w, sp, kSafepointSavedRegisters);
    723 }
    724 
    725 
    726 void MacroAssembler::PopSafepointRegisters() {
    727   const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
    728   ldm(ia_w, sp, kSafepointSavedRegisters);
    729   add(sp, sp, Operand(num_unsaved * kPointerSize));
    730 }
    731 
    732 
    733 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
    734   str(src, SafepointRegisterSlot(dst));
    735 }
    736 
    737 
    738 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
    739   ldr(dst, SafepointRegisterSlot(src));
    740 }
    741 
    742 
    743 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
    744   // The registers are pushed starting with the highest encoding,
    745   // which means that lowest encodings are closest to the stack pointer.
    746   if (FLAG_enable_embedded_constant_pool && reg_code > pp.code()) {
    747     // RegList omits pp.
    748     reg_code -= 1;
    749   }
    750   DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters);
    751   return reg_code;
    752 }
    753 
    754 
    755 MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
    756   return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
    757 }
    758 
    759 
    760 MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
    761   // Number of d-regs not known at snapshot time.
    762   DCHECK(!serializer_enabled());
    763   // General purpose registers are pushed last on the stack.
    764   const RegisterConfiguration* config =
    765       RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
    766   int doubles_size = config->num_allocatable_double_registers() * kDoubleSize;
    767   int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
    768   return MemOperand(sp, doubles_size + register_offset);
    769 }
    770 
    771 
    772 void MacroAssembler::Ldrd(Register dst1, Register dst2,
    773                           const MemOperand& src, Condition cond) {
    774   DCHECK(src.rm().is(no_reg));
    775   DCHECK(!dst1.is(lr));  // r14.
    776 
    777   // V8 does not use this addressing mode, so the fallback code
    778   // below doesn't support it yet.
    779   DCHECK((src.am() != PreIndex) && (src.am() != NegPreIndex));
    780 
    781   // Generate two ldr instructions if ldrd is not available.
    782   if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size() &&
    783       (dst1.code() % 2 == 0) && (dst1.code() + 1 == dst2.code())) {
    784     CpuFeatureScope scope(this, ARMv7);
    785     ldrd(dst1, dst2, src, cond);
    786   } else {
    787     if ((src.am() == Offset) || (src.am() == NegOffset)) {
    788       MemOperand src2(src);
    789       src2.set_offset(src2.offset() + 4);
    790       if (dst1.is(src.rn())) {
    791         ldr(dst2, src2, cond);
    792         ldr(dst1, src, cond);
    793       } else {
    794         ldr(dst1, src, cond);
    795         ldr(dst2, src2, cond);
    796       }
    797     } else {  // PostIndex or NegPostIndex.
    798       DCHECK((src.am() == PostIndex) || (src.am() == NegPostIndex));
    799       if (dst1.is(src.rn())) {
    800         ldr(dst2, MemOperand(src.rn(), 4, Offset), cond);
    801         ldr(dst1, src, cond);
    802       } else {
    803         MemOperand src2(src);
    804         src2.set_offset(src2.offset() - 4);
    805         ldr(dst1, MemOperand(src.rn(), 4, PostIndex), cond);
    806         ldr(dst2, src2, cond);
    807       }
    808     }
    809   }
    810 }
    811 
    812 
    813 void MacroAssembler::Strd(Register src1, Register src2,
    814                           const MemOperand& dst, Condition cond) {
    815   DCHECK(dst.rm().is(no_reg));
    816   DCHECK(!src1.is(lr));  // r14.
    817 
    818   // V8 does not use this addressing mode, so the fallback code
    819   // below doesn't support it yet.
    820   DCHECK((dst.am() != PreIndex) && (dst.am() != NegPreIndex));
    821 
    822   // Generate two str instructions if strd is not available.
    823   if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size() &&
    824       (src1.code() % 2 == 0) && (src1.code() + 1 == src2.code())) {
    825     CpuFeatureScope scope(this, ARMv7);
    826     strd(src1, src2, dst, cond);
    827   } else {
    828     MemOperand dst2(dst);
    829     if ((dst.am() == Offset) || (dst.am() == NegOffset)) {
    830       dst2.set_offset(dst2.offset() + 4);
    831       str(src1, dst, cond);
    832       str(src2, dst2, cond);
    833     } else {  // PostIndex or NegPostIndex.
    834       DCHECK((dst.am() == PostIndex) || (dst.am() == NegPostIndex));
    835       dst2.set_offset(dst2.offset() - 4);
    836       str(src1, MemOperand(dst.rn(), 4, PostIndex), cond);
    837       str(src2, dst2, cond);
    838     }
    839   }
    840 }
    841 
    842 
    843 void MacroAssembler::VFPEnsureFPSCRState(Register scratch) {
    844   // If needed, restore wanted bits of FPSCR.
    845   Label fpscr_done;
    846   vmrs(scratch);
    847   if (emit_debug_code()) {
    848     Label rounding_mode_correct;
    849     tst(scratch, Operand(kVFPRoundingModeMask));
    850     b(eq, &rounding_mode_correct);
    851     // Don't call Assert here, since Runtime_Abort could re-enter here.
    852     stop("Default rounding mode not set");
    853     bind(&rounding_mode_correct);
    854   }
    855   tst(scratch, Operand(kVFPDefaultNaNModeControlBit));
    856   b(ne, &fpscr_done);
    857   orr(scratch, scratch, Operand(kVFPDefaultNaNModeControlBit));
    858   vmsr(scratch);
    859   bind(&fpscr_done);
    860 }
    861 
    862 
    863 void MacroAssembler::VFPCanonicalizeNaN(const DwVfpRegister dst,
    864                                         const DwVfpRegister src,
    865                                         const Condition cond) {
    866   vsub(dst, src, kDoubleRegZero, cond);
    867 }
    868 
    869 
    870 void MacroAssembler::VFPCompareAndSetFlags(const SwVfpRegister src1,
    871                                            const SwVfpRegister src2,
    872                                            const Condition cond) {
    873   // Compare and move FPSCR flags to the normal condition flags.
    874   VFPCompareAndLoadFlags(src1, src2, pc, cond);
    875 }
    876 
    877 void MacroAssembler::VFPCompareAndSetFlags(const SwVfpRegister src1,
    878                                            const float src2,
    879                                            const Condition cond) {
    880   // Compare and move FPSCR flags to the normal condition flags.
    881   VFPCompareAndLoadFlags(src1, src2, pc, cond);
    882 }
    883 
    884 
    885 void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1,
    886                                            const DwVfpRegister src2,
    887                                            const Condition cond) {
    888   // Compare and move FPSCR flags to the normal condition flags.
    889   VFPCompareAndLoadFlags(src1, src2, pc, cond);
    890 }
    891 
    892 void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1,
    893                                            const double src2,
    894                                            const Condition cond) {
    895   // Compare and move FPSCR flags to the normal condition flags.
    896   VFPCompareAndLoadFlags(src1, src2, pc, cond);
    897 }
    898 
    899 
    900 void MacroAssembler::VFPCompareAndLoadFlags(const SwVfpRegister src1,
    901                                             const SwVfpRegister src2,
    902                                             const Register fpscr_flags,
    903                                             const Condition cond) {
    904   // Compare and load FPSCR.
    905   vcmp(src1, src2, cond);
    906   vmrs(fpscr_flags, cond);
    907 }
    908 
    909 void MacroAssembler::VFPCompareAndLoadFlags(const SwVfpRegister src1,
    910                                             const float src2,
    911                                             const Register fpscr_flags,
    912                                             const Condition cond) {
    913   // Compare and load FPSCR.
    914   vcmp(src1, src2, cond);
    915   vmrs(fpscr_flags, cond);
    916 }
    917 
    918 
    919 void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1,
    920                                             const DwVfpRegister src2,
    921                                             const Register fpscr_flags,
    922                                             const Condition cond) {
    923   // Compare and load FPSCR.
    924   vcmp(src1, src2, cond);
    925   vmrs(fpscr_flags, cond);
    926 }
    927 
    928 void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1,
    929                                             const double src2,
    930                                             const Register fpscr_flags,
    931                                             const Condition cond) {
    932   // Compare and load FPSCR.
    933   vcmp(src1, src2, cond);
    934   vmrs(fpscr_flags, cond);
    935 }
    936 
    937 
    938 void MacroAssembler::Vmov(const DwVfpRegister dst,
    939                           const double imm,
    940                           const Register scratch) {
    941   static const DoubleRepresentation minus_zero(-0.0);
    942   static const DoubleRepresentation zero(0.0);
    943   DoubleRepresentation value_rep(imm);
    944   // Handle special values first.
    945   if (value_rep == zero) {
    946     vmov(dst, kDoubleRegZero);
    947   } else if (value_rep == minus_zero) {
    948     vneg(dst, kDoubleRegZero);
    949   } else {
    950     vmov(dst, imm, scratch);
    951   }
    952 }
    953 
    954 
    955 void MacroAssembler::VmovHigh(Register dst, DwVfpRegister src) {
    956   if (src.code() < 16) {
    957     const LowDwVfpRegister loc = LowDwVfpRegister::from_code(src.code());
    958     vmov(dst, loc.high());
    959   } else {
    960     vmov(dst, VmovIndexHi, src);
    961   }
    962 }
    963 
    964 
    965 void MacroAssembler::VmovHigh(DwVfpRegister dst, Register src) {
    966   if (dst.code() < 16) {
    967     const LowDwVfpRegister loc = LowDwVfpRegister::from_code(dst.code());
    968     vmov(loc.high(), src);
    969   } else {
    970     vmov(dst, VmovIndexHi, src);
    971   }
    972 }
    973 
    974 
    975 void MacroAssembler::VmovLow(Register dst, DwVfpRegister src) {
    976   if (src.code() < 16) {
    977     const LowDwVfpRegister loc = LowDwVfpRegister::from_code(src.code());
    978     vmov(dst, loc.low());
    979   } else {
    980     vmov(dst, VmovIndexLo, src);
    981   }
    982 }
    983 
    984 
    985 void MacroAssembler::VmovLow(DwVfpRegister dst, Register src) {
    986   if (dst.code() < 16) {
    987     const LowDwVfpRegister loc = LowDwVfpRegister::from_code(dst.code());
    988     vmov(loc.low(), src);
    989   } else {
    990     vmov(dst, VmovIndexLo, src);
    991   }
    992 }
    993 
    994 
    995 void MacroAssembler::LoadConstantPoolPointerRegisterFromCodeTargetAddress(
    996     Register code_target_address) {
    997   DCHECK(FLAG_enable_embedded_constant_pool);
    998   ldr(pp, MemOperand(code_target_address,
    999                      Code::kConstantPoolOffset - Code::kHeaderSize));
   1000   add(pp, pp, code_target_address);
   1001 }
   1002 
   1003 
   1004 void MacroAssembler::LoadConstantPoolPointerRegister() {
   1005   DCHECK(FLAG_enable_embedded_constant_pool);
   1006   int entry_offset = pc_offset() + Instruction::kPCReadOffset;
   1007   sub(ip, pc, Operand(entry_offset));
   1008   LoadConstantPoolPointerRegisterFromCodeTargetAddress(ip);
   1009 }
   1010 
   1011 
   1012 void MacroAssembler::StubPrologue() {
   1013   PushFixedFrame();
   1014   Push(Smi::FromInt(StackFrame::STUB));
   1015   // Adjust FP to point to saved FP.
   1016   add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
   1017   if (FLAG_enable_embedded_constant_pool) {
   1018     LoadConstantPoolPointerRegister();
   1019     set_constant_pool_available(true);
   1020   }
   1021 }
   1022 
   1023 
   1024 void MacroAssembler::Prologue(bool code_pre_aging) {
   1025   { PredictableCodeSizeScope predictible_code_size_scope(
   1026         this, kNoCodeAgeSequenceLength);
   1027     // The following three instructions must remain together and unmodified
   1028     // for code aging to work properly.
   1029     if (code_pre_aging) {
   1030       // Pre-age the code.
   1031       Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
   1032       add(r0, pc, Operand(-8));
   1033       ldr(pc, MemOperand(pc, -4));
   1034       emit_code_stub_address(stub);
   1035     } else {
   1036       PushFixedFrame(r1);
   1037       nop(ip.code());
   1038       // Adjust FP to point to saved FP.
   1039       add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
   1040     }
   1041   }
   1042   if (FLAG_enable_embedded_constant_pool) {
   1043     LoadConstantPoolPointerRegister();
   1044     set_constant_pool_available(true);
   1045   }
   1046 }
   1047 
   1048 
   1049 void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
   1050   ldr(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
   1051   ldr(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset));
   1052   ldr(vector,
   1053       FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset));
   1054 }
   1055 
   1056 
   1057 void MacroAssembler::EnterFrame(StackFrame::Type type,
   1058                                 bool load_constant_pool_pointer_reg) {
   1059   // r0-r3: preserved
   1060   PushFixedFrame();
   1061   if (FLAG_enable_embedded_constant_pool && load_constant_pool_pointer_reg) {
   1062     LoadConstantPoolPointerRegister();
   1063   }
   1064   mov(ip, Operand(Smi::FromInt(type)));
   1065   push(ip);
   1066   mov(ip, Operand(CodeObject()));
   1067   push(ip);
   1068   // Adjust FP to point to saved FP.
   1069   add(fp, sp,
   1070       Operand(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize));
   1071 }
   1072 
   1073 
   1074 int MacroAssembler::LeaveFrame(StackFrame::Type type) {
   1075   // r0: preserved
   1076   // r1: preserved
   1077   // r2: preserved
   1078 
   1079   // Drop the execution stack down to the frame pointer and restore
   1080   // the caller frame pointer, return address and constant pool pointer
   1081   // (if FLAG_enable_embedded_constant_pool).
   1082   int frame_ends;
   1083   if (FLAG_enable_embedded_constant_pool) {
   1084     add(sp, fp, Operand(StandardFrameConstants::kConstantPoolOffset));
   1085     frame_ends = pc_offset();
   1086     ldm(ia_w, sp, pp.bit() | fp.bit() | lr.bit());
   1087   } else {
   1088     mov(sp, fp);
   1089     frame_ends = pc_offset();
   1090     ldm(ia_w, sp, fp.bit() | lr.bit());
   1091   }
   1092   return frame_ends;
   1093 }
   1094 
   1095 
   1096 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
   1097   // Set up the frame structure on the stack.
   1098   DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
   1099   DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
   1100   DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
   1101   Push(lr, fp);
   1102   mov(fp, Operand(sp));  // Set up new frame pointer.
   1103   // Reserve room for saved entry sp and code object.
   1104   sub(sp, sp, Operand(ExitFrameConstants::kFrameSize));
   1105   if (emit_debug_code()) {
   1106     mov(ip, Operand::Zero());
   1107     str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset));
   1108   }
   1109   if (FLAG_enable_embedded_constant_pool) {
   1110     str(pp, MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
   1111   }
   1112   mov(ip, Operand(CodeObject()));
   1113   str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset));
   1114 
   1115   // Save the frame pointer and the context in top.
   1116   mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
   1117   str(fp, MemOperand(ip));
   1118   mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
   1119   str(cp, MemOperand(ip));
   1120 
   1121   // Optionally save all double registers.
   1122   if (save_doubles) {
   1123     SaveFPRegs(sp, ip);
   1124     // Note that d0 will be accessible at
   1125     //   fp - ExitFrameConstants::kFrameSize -
   1126     //   DwVfpRegister::kMaxNumRegisters * kDoubleSize,
   1127     // since the sp slot, code slot and constant pool slot (if
   1128     // FLAG_enable_embedded_constant_pool) were pushed after the fp.
   1129   }
   1130 
   1131   // Reserve place for the return address and stack space and align the frame
   1132   // preparing for calling the runtime function.
   1133   const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
   1134   sub(sp, sp, Operand((stack_space + 1) * kPointerSize));
   1135   if (frame_alignment > 0) {
   1136     DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
   1137     and_(sp, sp, Operand(-frame_alignment));
   1138   }
   1139 
   1140   // Set the exit frame sp value to point just before the return address
   1141   // location.
   1142   add(ip, sp, Operand(kPointerSize));
   1143   str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset));
   1144 }
   1145 
   1146 
   1147 void MacroAssembler::InitializeNewString(Register string,
   1148                                          Register length,
   1149                                          Heap::RootListIndex map_index,
   1150                                          Register scratch1,
   1151                                          Register scratch2) {
   1152   SmiTag(scratch1, length);
   1153   LoadRoot(scratch2, map_index);
   1154   str(scratch1, FieldMemOperand(string, String::kLengthOffset));
   1155   mov(scratch1, Operand(String::kEmptyHashField));
   1156   str(scratch2, FieldMemOperand(string, HeapObject::kMapOffset));
   1157   str(scratch1, FieldMemOperand(string, String::kHashFieldOffset));
   1158 }
   1159 
   1160 
   1161 int MacroAssembler::ActivationFrameAlignment() {
   1162 #if V8_HOST_ARCH_ARM
   1163   // Running on the real platform. Use the alignment as mandated by the local
   1164   // environment.
   1165   // Note: This will break if we ever start generating snapshots on one ARM
   1166   // platform for another ARM platform with a different alignment.
   1167   return base::OS::ActivationFrameAlignment();
   1168 #else  // V8_HOST_ARCH_ARM
   1169   // If we are using the simulator then we should always align to the expected
   1170   // alignment. As the simulator is used to generate snapshots we do not know
   1171   // if the target platform will need alignment, so this is controlled from a
   1172   // flag.
   1173   return FLAG_sim_stack_alignment;
   1174 #endif  // V8_HOST_ARCH_ARM
   1175 }
   1176 
   1177 
   1178 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
   1179                                     bool restore_context,
   1180                                     bool argument_count_is_length) {
   1181   ConstantPoolUnavailableScope constant_pool_unavailable(this);
   1182 
   1183   // Optionally restore all double registers.
   1184   if (save_doubles) {
   1185     // Calculate the stack location of the saved doubles and restore them.
   1186     const int offset = ExitFrameConstants::kFrameSize;
   1187     sub(r3, fp,
   1188         Operand(offset + DwVfpRegister::kMaxNumRegisters * kDoubleSize));
   1189     RestoreFPRegs(r3, ip);
   1190   }
   1191 
   1192   // Clear top frame.
   1193   mov(r3, Operand::Zero());
   1194   mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
   1195   str(r3, MemOperand(ip));
   1196 
   1197   // Restore current context from top and clear it in debug mode.
   1198   if (restore_context) {
   1199     mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
   1200     ldr(cp, MemOperand(ip));
   1201   }
   1202 #ifdef DEBUG
   1203   mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
   1204   str(r3, MemOperand(ip));
   1205 #endif
   1206 
   1207   // Tear down the exit frame, pop the arguments, and return.
   1208   if (FLAG_enable_embedded_constant_pool) {
   1209     ldr(pp, MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
   1210   }
   1211   mov(sp, Operand(fp));
   1212   ldm(ia_w, sp, fp.bit() | lr.bit());
   1213   if (argument_count.is_valid()) {
   1214     if (argument_count_is_length) {
   1215       add(sp, sp, argument_count);
   1216     } else {
   1217       add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2));
   1218     }
   1219   }
   1220 }
   1221 
   1222 
   1223 void MacroAssembler::MovFromFloatResult(const DwVfpRegister dst) {
   1224   if (use_eabi_hardfloat()) {
   1225     Move(dst, d0);
   1226   } else {
   1227     vmov(dst, r0, r1);
   1228   }
   1229 }
   1230 
   1231 
   1232 // On ARM this is just a synonym to make the purpose clear.
   1233 void MacroAssembler::MovFromFloatParameter(DwVfpRegister dst) {
   1234   MovFromFloatResult(dst);
   1235 }
   1236 
   1237 
   1238 void MacroAssembler::InvokePrologue(const ParameterCount& expected,
   1239                                     const ParameterCount& actual,
   1240                                     Label* done,
   1241                                     bool* definitely_mismatches,
   1242                                     InvokeFlag flag,
   1243                                     const CallWrapper& call_wrapper) {
   1244   bool definitely_matches = false;
   1245   *definitely_mismatches = false;
   1246   Label regular_invoke;
   1247 
   1248   // Check whether the expected and actual arguments count match. If not,
   1249   // setup registers according to contract with ArgumentsAdaptorTrampoline:
   1250   //  r0: actual arguments count
   1251   //  r1: function (passed through to callee)
   1252   //  r2: expected arguments count
   1253 
   1254   // The code below is made a lot easier because the calling code already sets
   1255   // up actual and expected registers according to the contract if values are
   1256   // passed in registers.
   1257   DCHECK(actual.is_immediate() || actual.reg().is(r0));
   1258   DCHECK(expected.is_immediate() || expected.reg().is(r2));
   1259 
   1260   if (expected.is_immediate()) {
   1261     DCHECK(actual.is_immediate());
   1262     mov(r0, Operand(actual.immediate()));
   1263     if (expected.immediate() == actual.immediate()) {
   1264       definitely_matches = true;
   1265     } else {
   1266       const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
   1267       if (expected.immediate() == sentinel) {
   1268         // Don't worry about adapting arguments for builtins that
   1269         // don't want that done. Skip adaption code by making it look
   1270         // like we have a match between expected and actual number of
   1271         // arguments.
   1272         definitely_matches = true;
   1273       } else {
   1274         *definitely_mismatches = true;
   1275         mov(r2, Operand(expected.immediate()));
   1276       }
   1277     }
   1278   } else {
   1279     if (actual.is_immediate()) {
   1280       mov(r0, Operand(actual.immediate()));
   1281       cmp(expected.reg(), Operand(actual.immediate()));
   1282       b(eq, &regular_invoke);
   1283     } else {
   1284       cmp(expected.reg(), Operand(actual.reg()));
   1285       b(eq, &regular_invoke);
   1286     }
   1287   }
   1288 
   1289   if (!definitely_matches) {
   1290     Handle<Code> adaptor =
   1291         isolate()->builtins()->ArgumentsAdaptorTrampoline();
   1292     if (flag == CALL_FUNCTION) {
   1293       call_wrapper.BeforeCall(CallSize(adaptor));
   1294       Call(adaptor);
   1295       call_wrapper.AfterCall();
   1296       if (!*definitely_mismatches) {
   1297         b(done);
   1298       }
   1299     } else {
   1300       Jump(adaptor, RelocInfo::CODE_TARGET);
   1301     }
   1302     bind(&regular_invoke);
   1303   }
   1304 }
   1305 
   1306 
   1307 void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
   1308                                              const ParameterCount& expected,
   1309                                              const ParameterCount& actual) {
   1310   Label skip_flooding;
   1311   ExternalReference step_in_enabled =
   1312       ExternalReference::debug_step_in_enabled_address(isolate());
   1313   mov(r4, Operand(step_in_enabled));
   1314   ldrb(r4, MemOperand(r4));
   1315   cmp(r4, Operand(0));
   1316   b(eq, &skip_flooding);
   1317   {
   1318     FrameScope frame(this,
   1319                      has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
   1320     if (expected.is_reg()) {
   1321       SmiTag(expected.reg());
   1322       Push(expected.reg());
   1323     }
   1324     if (actual.is_reg()) {
   1325       SmiTag(actual.reg());
   1326       Push(actual.reg());
   1327     }
   1328     if (new_target.is_valid()) {
   1329       Push(new_target);
   1330     }
   1331     Push(fun);
   1332     Push(fun);
   1333     CallRuntime(Runtime::kDebugPrepareStepInIfStepping, 1);
   1334     Pop(fun);
   1335     if (new_target.is_valid()) {
   1336       Pop(new_target);
   1337     }
   1338     if (actual.is_reg()) {
   1339       Pop(actual.reg());
   1340       SmiUntag(actual.reg());
   1341     }
   1342     if (expected.is_reg()) {
   1343       Pop(expected.reg());
   1344       SmiUntag(expected.reg());
   1345     }
   1346   }
   1347   bind(&skip_flooding);
   1348 }
   1349 
   1350 
   1351 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
   1352                                         const ParameterCount& expected,
   1353                                         const ParameterCount& actual,
   1354                                         InvokeFlag flag,
   1355                                         const CallWrapper& call_wrapper) {
   1356   // You can't call a function without a valid frame.
   1357   DCHECK(flag == JUMP_FUNCTION || has_frame());
   1358   DCHECK(function.is(r1));
   1359   DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r3));
   1360 
   1361   if (call_wrapper.NeedsDebugStepCheck()) {
   1362     FloodFunctionIfStepping(function, new_target, expected, actual);
   1363   }
   1364 
   1365   // Clear the new.target register if not given.
   1366   if (!new_target.is_valid()) {
   1367     LoadRoot(r3, Heap::kUndefinedValueRootIndex);
   1368   }
   1369 
   1370   Label done;
   1371   bool definitely_mismatches = false;
   1372   InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
   1373                  call_wrapper);
   1374   if (!definitely_mismatches) {
   1375     // We call indirectly through the code field in the function to
   1376     // allow recompilation to take effect without changing any of the
   1377     // call sites.
   1378     Register code = r4;
   1379     ldr(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
   1380     if (flag == CALL_FUNCTION) {
   1381       call_wrapper.BeforeCall(CallSize(code));
   1382       Call(code);
   1383       call_wrapper.AfterCall();
   1384     } else {
   1385       DCHECK(flag == JUMP_FUNCTION);
   1386       Jump(code);
   1387     }
   1388 
   1389     // Continue here if InvokePrologue does handle the invocation due to
   1390     // mismatched parameter counts.
   1391     bind(&done);
   1392   }
   1393 }
   1394 
   1395 
   1396 void MacroAssembler::InvokeFunction(Register fun,
   1397                                     Register new_target,
   1398                                     const ParameterCount& actual,
   1399                                     InvokeFlag flag,
   1400                                     const CallWrapper& call_wrapper) {
   1401   // You can't call a function without a valid frame.
   1402   DCHECK(flag == JUMP_FUNCTION || has_frame());
   1403 
   1404   // Contract with called JS functions requires that function is passed in r1.
   1405   DCHECK(fun.is(r1));
   1406 
   1407   Register expected_reg = r2;
   1408   Register temp_reg = r4;
   1409 
   1410   ldr(temp_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
   1411   ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
   1412   ldr(expected_reg,
   1413       FieldMemOperand(temp_reg,
   1414                       SharedFunctionInfo::kFormalParameterCountOffset));
   1415   SmiUntag(expected_reg);
   1416 
   1417   ParameterCount expected(expected_reg);
   1418   InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper);
   1419 }
   1420 
   1421 
   1422 void MacroAssembler::InvokeFunction(Register function,
   1423                                     const ParameterCount& expected,
   1424                                     const ParameterCount& actual,
   1425                                     InvokeFlag flag,
   1426                                     const CallWrapper& call_wrapper) {
   1427   // You can't call a function without a valid frame.
   1428   DCHECK(flag == JUMP_FUNCTION || has_frame());
   1429 
   1430   // Contract with called JS functions requires that function is passed in r1.
   1431   DCHECK(function.is(r1));
   1432 
   1433   // Get the function and setup the context.
   1434   ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
   1435 
   1436   InvokeFunctionCode(r1, no_reg, expected, actual, flag, call_wrapper);
   1437 }
   1438 
   1439 
   1440 void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
   1441                                     const ParameterCount& expected,
   1442                                     const ParameterCount& actual,
   1443                                     InvokeFlag flag,
   1444                                     const CallWrapper& call_wrapper) {
   1445   Move(r1, function);
   1446   InvokeFunction(r1, expected, actual, flag, call_wrapper);
   1447 }
   1448 
   1449 
   1450 void MacroAssembler::IsObjectJSStringType(Register object,
   1451                                           Register scratch,
   1452                                           Label* fail) {
   1453   DCHECK(kNotStringTag != 0);
   1454 
   1455   ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
   1456   ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
   1457   tst(scratch, Operand(kIsNotStringMask));
   1458   b(ne, fail);
   1459 }
   1460 
   1461 
   1462 void MacroAssembler::IsObjectNameType(Register object,
   1463                                       Register scratch,
   1464                                       Label* fail) {
   1465   ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
   1466   ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
   1467   cmp(scratch, Operand(LAST_NAME_TYPE));
   1468   b(hi, fail);
   1469 }
   1470 
   1471 
   1472 void MacroAssembler::DebugBreak() {
   1473   mov(r0, Operand::Zero());
   1474   mov(r1,
   1475       Operand(ExternalReference(Runtime::kHandleDebuggerStatement, isolate())));
   1476   CEntryStub ces(isolate(), 1);
   1477   DCHECK(AllowThisStubCall(&ces));
   1478   Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
   1479 }
   1480 
   1481 
   1482 void MacroAssembler::PushStackHandler() {
   1483   // Adjust this code if not the case.
   1484   STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
   1485   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
   1486 
   1487   // Link the current handler as the next handler.
   1488   mov(r6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
   1489   ldr(r5, MemOperand(r6));
   1490   push(r5);
   1491 
   1492   // Set this new handler as the current one.
   1493   str(sp, MemOperand(r6));
   1494 }
   1495 
   1496 
   1497 void MacroAssembler::PopStackHandler() {
   1498   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   1499   pop(r1);
   1500   mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
   1501   add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
   1502   str(r1, MemOperand(ip));
   1503 }
   1504 
   1505 
   1506 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
   1507                                             Register scratch,
   1508                                             Label* miss) {
   1509   Label same_contexts;
   1510 
   1511   DCHECK(!holder_reg.is(scratch));
   1512   DCHECK(!holder_reg.is(ip));
   1513   DCHECK(!scratch.is(ip));
   1514 
   1515   // Load current lexical context from the stack frame.
   1516   ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
   1517   // In debug mode, make sure the lexical context is set.
   1518 #ifdef DEBUG
   1519   cmp(scratch, Operand::Zero());
   1520   Check(ne, kWeShouldNotHaveAnEmptyLexicalContext);
   1521 #endif
   1522 
   1523   // Load the native context of the current context.
   1524   ldr(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX));
   1525 
   1526   // Check the context is a native context.
   1527   if (emit_debug_code()) {
   1528     // Cannot use ip as a temporary in this verification code. Due to the fact
   1529     // that ip is clobbered as part of cmp with an object Operand.
   1530     push(holder_reg);  // Temporarily save holder on the stack.
   1531     // Read the first word and compare to the native_context_map.
   1532     ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
   1533     LoadRoot(ip, Heap::kNativeContextMapRootIndex);
   1534     cmp(holder_reg, ip);
   1535     Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext);
   1536     pop(holder_reg);  // Restore holder.
   1537   }
   1538 
   1539   // Check if both contexts are the same.
   1540   ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
   1541   cmp(scratch, Operand(ip));
   1542   b(eq, &same_contexts);
   1543 
   1544   // Check the context is a native context.
   1545   if (emit_debug_code()) {
   1546     // Cannot use ip as a temporary in this verification code. Due to the fact
   1547     // that ip is clobbered as part of cmp with an object Operand.
   1548     push(holder_reg);  // Temporarily save holder on the stack.
   1549     mov(holder_reg, ip);  // Move ip to its holding place.
   1550     LoadRoot(ip, Heap::kNullValueRootIndex);
   1551     cmp(holder_reg, ip);
   1552     Check(ne, kJSGlobalProxyContextShouldNotBeNull);
   1553 
   1554     ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset));
   1555     LoadRoot(ip, Heap::kNativeContextMapRootIndex);
   1556     cmp(holder_reg, ip);
   1557     Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext);
   1558     // Restore ip is not needed. ip is reloaded below.
   1559     pop(holder_reg);  // Restore holder.
   1560     // Restore ip to holder's context.
   1561     ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
   1562   }
   1563 
   1564   // Check that the security token in the calling global object is
   1565   // compatible with the security token in the receiving global
   1566   // object.
   1567   int token_offset = Context::kHeaderSize +
   1568                      Context::SECURITY_TOKEN_INDEX * kPointerSize;
   1569 
   1570   ldr(scratch, FieldMemOperand(scratch, token_offset));
   1571   ldr(ip, FieldMemOperand(ip, token_offset));
   1572   cmp(scratch, Operand(ip));
   1573   b(ne, miss);
   1574 
   1575   bind(&same_contexts);
   1576 }
   1577 
   1578 
   1579 // Compute the hash code from the untagged key.  This must be kept in sync with
   1580 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
   1581 // code-stub-hydrogen.cc
   1582 void MacroAssembler::GetNumberHash(Register t0, Register scratch) {
   1583   // First of all we assign the hash seed to scratch.
   1584   LoadRoot(scratch, Heap::kHashSeedRootIndex);
   1585   SmiUntag(scratch);
   1586 
   1587   // Xor original key with a seed.
   1588   eor(t0, t0, Operand(scratch));
   1589 
   1590   // Compute the hash code from the untagged key.  This must be kept in sync
   1591   // with ComputeIntegerHash in utils.h.
   1592   //
   1593   // hash = ~hash + (hash << 15);
   1594   mvn(scratch, Operand(t0));
   1595   add(t0, scratch, Operand(t0, LSL, 15));
   1596   // hash = hash ^ (hash >> 12);
   1597   eor(t0, t0, Operand(t0, LSR, 12));
   1598   // hash = hash + (hash << 2);
   1599   add(t0, t0, Operand(t0, LSL, 2));
   1600   // hash = hash ^ (hash >> 4);
   1601   eor(t0, t0, Operand(t0, LSR, 4));
   1602   // hash = hash * 2057;
   1603   mov(scratch, Operand(t0, LSL, 11));
   1604   add(t0, t0, Operand(t0, LSL, 3));
   1605   add(t0, t0, scratch);
   1606   // hash = hash ^ (hash >> 16);
   1607   eor(t0, t0, Operand(t0, LSR, 16));
   1608   bic(t0, t0, Operand(0xc0000000u));
   1609 }
   1610 
   1611 
   1612 void MacroAssembler::LoadFromNumberDictionary(Label* miss,
   1613                                               Register elements,
   1614                                               Register key,
   1615                                               Register result,
   1616                                               Register t0,
   1617                                               Register t1,
   1618                                               Register t2) {
   1619   // Register use:
   1620   //
   1621   // elements - holds the slow-case elements of the receiver on entry.
   1622   //            Unchanged unless 'result' is the same register.
   1623   //
   1624   // key      - holds the smi key on entry.
   1625   //            Unchanged unless 'result' is the same register.
   1626   //
   1627   // result   - holds the result on exit if the load succeeded.
   1628   //            Allowed to be the same as 'key' or 'result'.
   1629   //            Unchanged on bailout so 'key' or 'result' can be used
   1630   //            in further computation.
   1631   //
   1632   // Scratch registers:
   1633   //
   1634   // t0 - holds the untagged key on entry and holds the hash once computed.
   1635   //
   1636   // t1 - used to hold the capacity mask of the dictionary
   1637   //
   1638   // t2 - used for the index into the dictionary.
   1639   Label done;
   1640 
   1641   GetNumberHash(t0, t1);
   1642 
   1643   // Compute the capacity mask.
   1644   ldr(t1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
   1645   SmiUntag(t1);
   1646   sub(t1, t1, Operand(1));
   1647 
   1648   // Generate an unrolled loop that performs a few probes before giving up.
   1649   for (int i = 0; i < kNumberDictionaryProbes; i++) {
   1650     // Use t2 for index calculations and keep the hash intact in t0.
   1651     mov(t2, t0);
   1652     // Compute the masked index: (hash + i + i * i) & mask.
   1653     if (i > 0) {
   1654       add(t2, t2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
   1655     }
   1656     and_(t2, t2, Operand(t1));
   1657 
   1658     // Scale the index by multiplying by the element size.
   1659     DCHECK(SeededNumberDictionary::kEntrySize == 3);
   1660     add(t2, t2, Operand(t2, LSL, 1));  // t2 = t2 * 3
   1661 
   1662     // Check if the key is identical to the name.
   1663     add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
   1664     ldr(ip, FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset));
   1665     cmp(key, Operand(ip));
   1666     if (i != kNumberDictionaryProbes - 1) {
   1667       b(eq, &done);
   1668     } else {
   1669       b(ne, miss);
   1670     }
   1671   }
   1672 
   1673   bind(&done);
   1674   // Check that the value is a field property.
   1675   // t2: elements + (index * kPointerSize)
   1676   const int kDetailsOffset =
   1677       SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
   1678   ldr(t1, FieldMemOperand(t2, kDetailsOffset));
   1679   DCHECK_EQ(DATA, 0);
   1680   tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
   1681   b(ne, miss);
   1682 
   1683   // Get the value at the masked, scaled index and return.
   1684   const int kValueOffset =
   1685       SeededNumberDictionary::kElementsStartOffset + kPointerSize;
   1686   ldr(result, FieldMemOperand(t2, kValueOffset));
   1687 }
   1688 
   1689 
   1690 void MacroAssembler::Allocate(int object_size,
   1691                               Register result,
   1692                               Register scratch1,
   1693                               Register scratch2,
   1694                               Label* gc_required,
   1695                               AllocationFlags flags) {
   1696   DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
   1697   if (!FLAG_inline_new) {
   1698     if (emit_debug_code()) {
   1699       // Trash the registers to simulate an allocation failure.
   1700       mov(result, Operand(0x7091));
   1701       mov(scratch1, Operand(0x7191));
   1702       mov(scratch2, Operand(0x7291));
   1703     }
   1704     jmp(gc_required);
   1705     return;
   1706   }
   1707 
   1708   DCHECK(!AreAliased(result, scratch1, scratch2, ip));
   1709 
   1710   // Make object size into bytes.
   1711   if ((flags & SIZE_IN_WORDS) != 0) {
   1712     object_size *= kPointerSize;
   1713   }
   1714   DCHECK_EQ(0, object_size & kObjectAlignmentMask);
   1715 
   1716   // Check relative positions of allocation top and limit addresses.
   1717   // The values must be adjacent in memory to allow the use of LDM.
   1718   // Also, assert that the registers are numbered such that the values
   1719   // are loaded in the correct order.
   1720   ExternalReference allocation_top =
   1721       AllocationUtils::GetAllocationTopReference(isolate(), flags);
   1722   ExternalReference allocation_limit =
   1723       AllocationUtils::GetAllocationLimitReference(isolate(), flags);
   1724 
   1725   intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
   1726   intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
   1727   DCHECK((limit - top) == kPointerSize);
   1728   DCHECK(result.code() < ip.code());
   1729 
   1730   // Set up allocation top address register.
   1731   Register top_address = scratch1;
   1732   // This code stores a temporary value in ip. This is OK, as the code below
   1733   // does not need ip for implicit literal generation.
   1734   Register alloc_limit = ip;
   1735   Register result_end = scratch2;
   1736   mov(top_address, Operand(allocation_top));
   1737 
   1738   if ((flags & RESULT_CONTAINS_TOP) == 0) {
   1739     // Load allocation top into result and allocation limit into alloc_limit.
   1740     ldm(ia, top_address, result.bit() | alloc_limit.bit());
   1741   } else {
   1742     if (emit_debug_code()) {
   1743       // Assert that result actually contains top on entry.
   1744       ldr(alloc_limit, MemOperand(top_address));
   1745       cmp(result, alloc_limit);
   1746       Check(eq, kUnexpectedAllocationTop);
   1747     }
   1748     // Load allocation limit. Result already contains allocation top.
   1749     ldr(alloc_limit, MemOperand(top_address, limit - top));
   1750   }
   1751 
   1752   if ((flags & DOUBLE_ALIGNMENT) != 0) {
   1753     // Align the next allocation. Storing the filler map without checking top is
   1754     // safe in new-space because the limit of the heap is aligned there.
   1755     STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
   1756     and_(result_end, result, Operand(kDoubleAlignmentMask), SetCC);
   1757     Label aligned;
   1758     b(eq, &aligned);
   1759     if ((flags & PRETENURE) != 0) {
   1760       cmp(result, Operand(alloc_limit));
   1761       b(hs, gc_required);
   1762     }
   1763     mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
   1764     str(result_end, MemOperand(result, kDoubleSize / 2, PostIndex));
   1765     bind(&aligned);
   1766   }
   1767 
   1768   // Calculate new top and bail out if new space is exhausted. Use result
   1769   // to calculate the new top. We must preserve the ip register at this
   1770   // point, so we cannot just use add().
   1771   DCHECK(object_size > 0);
   1772   Register source = result;
   1773   Condition cond = al;
   1774   int shift = 0;
   1775   while (object_size != 0) {
   1776     if (((object_size >> shift) & 0x03) == 0) {
   1777       shift += 2;
   1778     } else {
   1779       int bits = object_size & (0xff << shift);
   1780       object_size -= bits;
   1781       shift += 8;
   1782       Operand bits_operand(bits);
   1783       DCHECK(bits_operand.instructions_required(this) == 1);
   1784       add(result_end, source, bits_operand, SetCC, cond);
   1785       source = result_end;
   1786       cond = cc;
   1787     }
   1788   }
   1789   b(cs, gc_required);
   1790   cmp(result_end, Operand(alloc_limit));
   1791   b(hi, gc_required);
   1792   str(result_end, MemOperand(top_address));
   1793 
   1794   // Tag object if requested.
   1795   if ((flags & TAG_OBJECT) != 0) {
   1796     add(result, result, Operand(kHeapObjectTag));
   1797   }
   1798 }
   1799 
   1800 
   1801 void MacroAssembler::Allocate(Register object_size, Register result,
   1802                               Register result_end, Register scratch,
   1803                               Label* gc_required, AllocationFlags flags) {
   1804   if (!FLAG_inline_new) {
   1805     if (emit_debug_code()) {
   1806       // Trash the registers to simulate an allocation failure.
   1807       mov(result, Operand(0x7091));
   1808       mov(scratch, Operand(0x7191));
   1809       mov(result_end, Operand(0x7291));
   1810     }
   1811     jmp(gc_required);
   1812     return;
   1813   }
   1814 
   1815   // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag
   1816   // is not specified. Other registers must not overlap.
   1817   DCHECK(!AreAliased(object_size, result, scratch, ip));
   1818   DCHECK(!AreAliased(result_end, result, scratch, ip));
   1819   DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
   1820 
   1821   // Check relative positions of allocation top and limit addresses.
   1822   // The values must be adjacent in memory to allow the use of LDM.
   1823   // Also, assert that the registers are numbered such that the values
   1824   // are loaded in the correct order.
   1825   ExternalReference allocation_top =
   1826       AllocationUtils::GetAllocationTopReference(isolate(), flags);
   1827   ExternalReference allocation_limit =
   1828       AllocationUtils::GetAllocationLimitReference(isolate(), flags);
   1829   intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
   1830   intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
   1831   DCHECK((limit - top) == kPointerSize);
   1832   DCHECK(result.code() < ip.code());
   1833 
   1834   // Set up allocation top address and allocation limit registers.
   1835   Register top_address = scratch;
   1836   // This code stores a temporary value in ip. This is OK, as the code below
   1837   // does not need ip for implicit literal generation.
   1838   Register alloc_limit = ip;
   1839   mov(top_address, Operand(allocation_top));
   1840 
   1841   if ((flags & RESULT_CONTAINS_TOP) == 0) {
   1842     // Load allocation top into result and allocation limit into alloc_limit.
   1843     ldm(ia, top_address, result.bit() | alloc_limit.bit());
   1844   } else {
   1845     if (emit_debug_code()) {
   1846       // Assert that result actually contains top on entry.
   1847       ldr(alloc_limit, MemOperand(top_address));
   1848       cmp(result, alloc_limit);
   1849       Check(eq, kUnexpectedAllocationTop);
   1850     }
   1851     // Load allocation limit. Result already contains allocation top.
   1852     ldr(alloc_limit, MemOperand(top_address, limit - top));
   1853   }
   1854 
   1855   if ((flags & DOUBLE_ALIGNMENT) != 0) {
   1856     // Align the next allocation. Storing the filler map without checking top is
   1857     // safe in new-space because the limit of the heap is aligned there.
   1858     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
   1859     and_(result_end, result, Operand(kDoubleAlignmentMask), SetCC);
   1860     Label aligned;
   1861     b(eq, &aligned);
   1862     if ((flags & PRETENURE) != 0) {
   1863       cmp(result, Operand(alloc_limit));
   1864       b(hs, gc_required);
   1865     }
   1866     mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
   1867     str(result_end, MemOperand(result, kDoubleSize / 2, PostIndex));
   1868     bind(&aligned);
   1869   }
   1870 
   1871   // Calculate new top and bail out if new space is exhausted. Use result
   1872   // to calculate the new top. Object size may be in words so a shift is
   1873   // required to get the number of bytes.
   1874   if ((flags & SIZE_IN_WORDS) != 0) {
   1875     add(result_end, result, Operand(object_size, LSL, kPointerSizeLog2), SetCC);
   1876   } else {
   1877     add(result_end, result, Operand(object_size), SetCC);
   1878   }
   1879   b(cs, gc_required);
   1880   cmp(result_end, Operand(alloc_limit));
   1881   b(hi, gc_required);
   1882 
   1883   // Update allocation top. result temporarily holds the new top.
   1884   if (emit_debug_code()) {
   1885     tst(result_end, Operand(kObjectAlignmentMask));
   1886     Check(eq, kUnalignedAllocationInNewSpace);
   1887   }
   1888   str(result_end, MemOperand(top_address));
   1889 
   1890   // Tag object if requested.
   1891   if ((flags & TAG_OBJECT) != 0) {
   1892     add(result, result, Operand(kHeapObjectTag));
   1893   }
   1894 }
   1895 
   1896 
   1897 void MacroAssembler::AllocateTwoByteString(Register result,
   1898                                            Register length,
   1899                                            Register scratch1,
   1900                                            Register scratch2,
   1901                                            Register scratch3,
   1902                                            Label* gc_required) {
   1903   // Calculate the number of bytes needed for the characters in the string while
   1904   // observing object alignment.
   1905   DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
   1906   mov(scratch1, Operand(length, LSL, 1));  // Length in bytes, not chars.
   1907   add(scratch1, scratch1,
   1908       Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize));
   1909   and_(scratch1, scratch1, Operand(~kObjectAlignmentMask));
   1910 
   1911   // Allocate two-byte string in new space.
   1912   Allocate(scratch1,
   1913            result,
   1914            scratch2,
   1915            scratch3,
   1916            gc_required,
   1917            TAG_OBJECT);
   1918 
   1919   // Set the map, length and hash field.
   1920   InitializeNewString(result,
   1921                       length,
   1922                       Heap::kStringMapRootIndex,
   1923                       scratch1,
   1924                       scratch2);
   1925 }
   1926 
   1927 
   1928 void MacroAssembler::AllocateOneByteString(Register result, Register length,
   1929                                            Register scratch1, Register scratch2,
   1930                                            Register scratch3,
   1931                                            Label* gc_required) {
   1932   // Calculate the number of bytes needed for the characters in the string while
   1933   // observing object alignment.
   1934   DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
   1935   DCHECK(kCharSize == 1);
   1936   add(scratch1, length,
   1937       Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize));
   1938   and_(scratch1, scratch1, Operand(~kObjectAlignmentMask));
   1939 
   1940   // Allocate one-byte string in new space.
   1941   Allocate(scratch1,
   1942            result,
   1943            scratch2,
   1944            scratch3,
   1945            gc_required,
   1946            TAG_OBJECT);
   1947 
   1948   // Set the map, length and hash field.
   1949   InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex,
   1950                       scratch1, scratch2);
   1951 }
   1952 
   1953 
   1954 void MacroAssembler::AllocateTwoByteConsString(Register result,
   1955                                                Register length,
   1956                                                Register scratch1,
   1957                                                Register scratch2,
   1958                                                Label* gc_required) {
   1959   Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
   1960            TAG_OBJECT);
   1961 
   1962   InitializeNewString(result,
   1963                       length,
   1964                       Heap::kConsStringMapRootIndex,
   1965                       scratch1,
   1966                       scratch2);
   1967 }
   1968 
   1969 
   1970 void MacroAssembler::AllocateOneByteConsString(Register result, Register length,
   1971                                                Register scratch1,
   1972                                                Register scratch2,
   1973                                                Label* gc_required) {
   1974   Allocate(ConsString::kSize,
   1975            result,
   1976            scratch1,
   1977            scratch2,
   1978            gc_required,
   1979            TAG_OBJECT);
   1980 
   1981   InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex,
   1982                       scratch1, scratch2);
   1983 }
   1984 
   1985 
   1986 void MacroAssembler::AllocateTwoByteSlicedString(Register result,
   1987                                                  Register length,
   1988                                                  Register scratch1,
   1989                                                  Register scratch2,
   1990                                                  Label* gc_required) {
   1991   Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
   1992            TAG_OBJECT);
   1993 
   1994   InitializeNewString(result,
   1995                       length,
   1996                       Heap::kSlicedStringMapRootIndex,
   1997                       scratch1,
   1998                       scratch2);
   1999 }
   2000 
   2001 
   2002 void MacroAssembler::AllocateOneByteSlicedString(Register result,
   2003                                                  Register length,
   2004                                                  Register scratch1,
   2005                                                  Register scratch2,
   2006                                                  Label* gc_required) {
   2007   Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
   2008            TAG_OBJECT);
   2009 
   2010   InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex,
   2011                       scratch1, scratch2);
   2012 }
   2013 
   2014 
   2015 void MacroAssembler::CompareObjectType(Register object,
   2016                                        Register map,
   2017                                        Register type_reg,
   2018                                        InstanceType type) {
   2019   const Register temp = type_reg.is(no_reg) ? ip : type_reg;
   2020 
   2021   ldr(map, FieldMemOperand(object, HeapObject::kMapOffset));
   2022   CompareInstanceType(map, temp, type);
   2023 }
   2024 
   2025 
   2026 void MacroAssembler::CompareInstanceType(Register map,
   2027                                          Register type_reg,
   2028                                          InstanceType type) {
   2029   // Registers map and type_reg can be ip. These two lines assert
   2030   // that ip can be used with the two instructions (the constants
   2031   // will never need ip).
   2032   STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
   2033   STATIC_ASSERT(LAST_TYPE < 256);
   2034   ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
   2035   cmp(type_reg, Operand(type));
   2036 }
   2037 
   2038 
   2039 void MacroAssembler::CompareRoot(Register obj,
   2040                                  Heap::RootListIndex index) {
   2041   DCHECK(!obj.is(ip));
   2042   LoadRoot(ip, index);
   2043   cmp(obj, ip);
   2044 }
   2045 
   2046 
   2047 void MacroAssembler::CheckFastElements(Register map,
   2048                                        Register scratch,
   2049                                        Label* fail) {
   2050   STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
   2051   STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
   2052   STATIC_ASSERT(FAST_ELEMENTS == 2);
   2053   STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
   2054   ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
   2055   cmp(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue));
   2056   b(hi, fail);
   2057 }
   2058 
   2059 
   2060 void MacroAssembler::CheckFastObjectElements(Register map,
   2061                                              Register scratch,
   2062                                              Label* fail) {
   2063   STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
   2064   STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
   2065   STATIC_ASSERT(FAST_ELEMENTS == 2);
   2066   STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
   2067   ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
   2068   cmp(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
   2069   b(ls, fail);
   2070   cmp(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue));
   2071   b(hi, fail);
   2072 }
   2073 
   2074 
   2075 void MacroAssembler::CheckFastSmiElements(Register map,
   2076                                           Register scratch,
   2077                                           Label* fail) {
   2078   STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
   2079   STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
   2080   ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
   2081   cmp(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
   2082   b(hi, fail);
   2083 }
   2084 
   2085 
   2086 void MacroAssembler::StoreNumberToDoubleElements(
   2087                                       Register value_reg,
   2088                                       Register key_reg,
   2089                                       Register elements_reg,
   2090                                       Register scratch1,
   2091                                       LowDwVfpRegister double_scratch,
   2092                                       Label* fail,
   2093                                       int elements_offset) {
   2094   DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1));
   2095   Label smi_value, store;
   2096 
   2097   // Handle smi values specially.
   2098   JumpIfSmi(value_reg, &smi_value);
   2099 
   2100   // Ensure that the object is a heap number
   2101   CheckMap(value_reg,
   2102            scratch1,
   2103            isolate()->factory()->heap_number_map(),
   2104            fail,
   2105            DONT_DO_SMI_CHECK);
   2106 
   2107   vldr(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
   2108   // Force a canonical NaN.
   2109   if (emit_debug_code()) {
   2110     vmrs(ip);
   2111     tst(ip, Operand(kVFPDefaultNaNModeControlBit));
   2112     Assert(ne, kDefaultNaNModeNotSet);
   2113   }
   2114   VFPCanonicalizeNaN(double_scratch);
   2115   b(&store);
   2116 
   2117   bind(&smi_value);
   2118   SmiToDouble(double_scratch, value_reg);
   2119 
   2120   bind(&store);
   2121   add(scratch1, elements_reg, Operand::DoubleOffsetFromSmiKey(key_reg));
   2122   vstr(double_scratch,
   2123        FieldMemOperand(scratch1,
   2124                        FixedDoubleArray::kHeaderSize - elements_offset));
   2125 }
   2126 
   2127 
   2128 void MacroAssembler::CompareMap(Register obj,
   2129                                 Register scratch,
   2130                                 Handle<Map> map,
   2131                                 Label* early_success) {
   2132   ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
   2133   CompareMap(scratch, map, early_success);
   2134 }
   2135 
   2136 
   2137 void MacroAssembler::CompareMap(Register obj_map,
   2138                                 Handle<Map> map,
   2139                                 Label* early_success) {
   2140   cmp(obj_map, Operand(map));
   2141 }
   2142 
   2143 
   2144 void MacroAssembler::CheckMap(Register obj,
   2145                               Register scratch,
   2146                               Handle<Map> map,
   2147                               Label* fail,
   2148                               SmiCheckType smi_check_type) {
   2149   if (smi_check_type == DO_SMI_CHECK) {
   2150     JumpIfSmi(obj, fail);
   2151   }
   2152 
   2153   Label success;
   2154   CompareMap(obj, scratch, map, &success);
   2155   b(ne, fail);
   2156   bind(&success);
   2157 }
   2158 
   2159 
   2160 void MacroAssembler::CheckMap(Register obj,
   2161                               Register scratch,
   2162                               Heap::RootListIndex index,
   2163                               Label* fail,
   2164                               SmiCheckType smi_check_type) {
   2165   if (smi_check_type == DO_SMI_CHECK) {
   2166     JumpIfSmi(obj, fail);
   2167   }
   2168   ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
   2169   LoadRoot(ip, index);
   2170   cmp(scratch, ip);
   2171   b(ne, fail);
   2172 }
   2173 
   2174 
   2175 void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
   2176                                      Register scratch2, Handle<WeakCell> cell,
   2177                                      Handle<Code> success,
   2178                                      SmiCheckType smi_check_type) {
   2179   Label fail;
   2180   if (smi_check_type == DO_SMI_CHECK) {
   2181     JumpIfSmi(obj, &fail);
   2182   }
   2183   ldr(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
   2184   CmpWeakValue(scratch1, cell, scratch2);
   2185   Jump(success, RelocInfo::CODE_TARGET, eq);
   2186   bind(&fail);
   2187 }
   2188 
   2189 
   2190 void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
   2191                                   Register scratch) {
   2192   mov(scratch, Operand(cell));
   2193   ldr(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset));
   2194   cmp(value, scratch);
   2195 }
   2196 
   2197 
   2198 void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
   2199   mov(value, Operand(cell));
   2200   ldr(value, FieldMemOperand(value, WeakCell::kValueOffset));
   2201 }
   2202 
   2203 
   2204 void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
   2205                                    Label* miss) {
   2206   GetWeakValue(value, cell);
   2207   JumpIfSmi(value, miss);
   2208 }
   2209 
   2210 
   2211 void MacroAssembler::GetMapConstructor(Register result, Register map,
   2212                                        Register temp, Register temp2) {
   2213   Label done, loop;
   2214   ldr(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
   2215   bind(&loop);
   2216   JumpIfSmi(result, &done);
   2217   CompareObjectType(result, temp, temp2, MAP_TYPE);
   2218   b(ne, &done);
   2219   ldr(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
   2220   b(&loop);
   2221   bind(&done);
   2222 }
   2223 
   2224 
   2225 void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
   2226                                              Register scratch, Label* miss) {
   2227   // Get the prototype or initial map from the function.
   2228   ldr(result,
   2229       FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
   2230 
   2231   // If the prototype or initial map is the hole, don't return it and
   2232   // simply miss the cache instead. This will allow us to allocate a
   2233   // prototype object on-demand in the runtime system.
   2234   LoadRoot(ip, Heap::kTheHoleValueRootIndex);
   2235   cmp(result, ip);
   2236   b(eq, miss);
   2237 
   2238   // If the function does not have an initial map, we're done.
   2239   Label done;
   2240   CompareObjectType(result, scratch, scratch, MAP_TYPE);
   2241   b(ne, &done);
   2242 
   2243   // Get the prototype from the initial map.
   2244   ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
   2245 
   2246   // All done.
   2247   bind(&done);
   2248 }
   2249 
   2250 
   2251 void MacroAssembler::CallStub(CodeStub* stub,
   2252                               TypeFeedbackId ast_id,
   2253                               Condition cond) {
   2254   DCHECK(AllowThisStubCall(stub));  // Stub calls are not allowed in some stubs.
   2255   Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond);
   2256 }
   2257 
   2258 
   2259 void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
   2260   Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
   2261 }
   2262 
   2263 
   2264 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
   2265   return has_frame_ || !stub->SometimesSetsUpAFrame();
   2266 }
   2267 
   2268 
   2269 void MacroAssembler::IndexFromHash(Register hash, Register index) {
   2270   // If the hash field contains an array index pick it out. The assert checks
   2271   // that the constants for the maximum number of digits for an array index
   2272   // cached in the hash field and the number of bits reserved for it does not
   2273   // conflict.
   2274   DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
   2275          (1 << String::kArrayIndexValueBits));
   2276   DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash);
   2277 }
   2278 
   2279 
   2280 void MacroAssembler::SmiToDouble(LowDwVfpRegister value, Register smi) {
   2281   if (CpuFeatures::IsSupported(VFP3)) {
   2282     vmov(value.low(), smi);
   2283     vcvt_f64_s32(value, 1);
   2284   } else {
   2285     SmiUntag(ip, smi);
   2286     vmov(value.low(), ip);
   2287     vcvt_f64_s32(value, value.low());
   2288   }
   2289 }
   2290 
   2291 
   2292 void MacroAssembler::TestDoubleIsInt32(DwVfpRegister double_input,
   2293                                        LowDwVfpRegister double_scratch) {
   2294   DCHECK(!double_input.is(double_scratch));
   2295   vcvt_s32_f64(double_scratch.low(), double_input);
   2296   vcvt_f64_s32(double_scratch, double_scratch.low());
   2297   VFPCompareAndSetFlags(double_input, double_scratch);
   2298 }
   2299 
   2300 
   2301 void MacroAssembler::TryDoubleToInt32Exact(Register result,
   2302                                            DwVfpRegister double_input,
   2303                                            LowDwVfpRegister double_scratch) {
   2304   DCHECK(!double_input.is(double_scratch));
   2305   vcvt_s32_f64(double_scratch.low(), double_input);
   2306   vmov(result, double_scratch.low());
   2307   vcvt_f64_s32(double_scratch, double_scratch.low());
   2308   VFPCompareAndSetFlags(double_input, double_scratch);
   2309 }
   2310 
   2311 
   2312 void MacroAssembler::TryInt32Floor(Register result,
   2313                                    DwVfpRegister double_input,
   2314                                    Register input_high,
   2315                                    LowDwVfpRegister double_scratch,
   2316                                    Label* done,
   2317                                    Label* exact) {
   2318   DCHECK(!result.is(input_high));
   2319   DCHECK(!double_input.is(double_scratch));
   2320   Label negative, exception;
   2321 
   2322   VmovHigh(input_high, double_input);
   2323 
   2324   // Test for NaN and infinities.
   2325   Sbfx(result, input_high,
   2326        HeapNumber::kExponentShift, HeapNumber::kExponentBits);
   2327   cmp(result, Operand(-1));
   2328   b(eq, &exception);
   2329   // Test for values that can be exactly represented as a
   2330   // signed 32-bit integer.
   2331   TryDoubleToInt32Exact(result, double_input, double_scratch);
   2332   // If exact, return (result already fetched).
   2333   b(eq, exact);
   2334   cmp(input_high, Operand::Zero());
   2335   b(mi, &negative);
   2336 
   2337   // Input is in ]+0, +inf[.
   2338   // If result equals 0x7fffffff input was out of range or
   2339   // in ]0x7fffffff, 0x80000000[. We ignore this last case which
   2340   // could fits into an int32, that means we always think input was
   2341   // out of range and always go to exception.
   2342   // If result < 0x7fffffff, go to done, result fetched.
   2343   cmn(result, Operand(1));
   2344   b(mi, &exception);
   2345   b(done);
   2346 
   2347   // Input is in ]-inf, -0[.
   2348   // If x is a non integer negative number,
   2349   // floor(x) <=> round_to_zero(x) - 1.
   2350   bind(&negative);
   2351   sub(result, result, Operand(1), SetCC);
   2352   // If result is still negative, go to done, result fetched.
   2353   // Else, we had an overflow and we fall through exception.
   2354   b(mi, done);
   2355   bind(&exception);
   2356 }
   2357 
   2358 void MacroAssembler::TryInlineTruncateDoubleToI(Register result,
   2359                                                 DwVfpRegister double_input,
   2360                                                 Label* done) {
   2361   LowDwVfpRegister double_scratch = kScratchDoubleReg;
   2362   vcvt_s32_f64(double_scratch.low(), double_input);
   2363   vmov(result, double_scratch.low());
   2364 
   2365   // If result is not saturated (0x7fffffff or 0x80000000), we are done.
   2366   sub(ip, result, Operand(1));
   2367   cmp(ip, Operand(0x7ffffffe));
   2368   b(lt, done);
   2369 }
   2370 
   2371 
   2372 void MacroAssembler::TruncateDoubleToI(Register result,
   2373                                        DwVfpRegister double_input) {
   2374   Label done;
   2375 
   2376   TryInlineTruncateDoubleToI(result, double_input, &done);
   2377 
   2378   // If we fell through then inline version didn't succeed - call stub instead.
   2379   push(lr);
   2380   sub(sp, sp, Operand(kDoubleSize));  // Put input on stack.
   2381   vstr(double_input, MemOperand(sp, 0));
   2382 
   2383   DoubleToIStub stub(isolate(), sp, result, 0, true, true);
   2384   CallStub(&stub);
   2385 
   2386   add(sp, sp, Operand(kDoubleSize));
   2387   pop(lr);
   2388 
   2389   bind(&done);
   2390 }
   2391 
   2392 
   2393 void MacroAssembler::TruncateHeapNumberToI(Register result,
   2394                                            Register object) {
   2395   Label done;
   2396   LowDwVfpRegister double_scratch = kScratchDoubleReg;
   2397   DCHECK(!result.is(object));
   2398 
   2399   vldr(double_scratch,
   2400        MemOperand(object, HeapNumber::kValueOffset - kHeapObjectTag));
   2401   TryInlineTruncateDoubleToI(result, double_scratch, &done);
   2402 
   2403   // If we fell through then inline version didn't succeed - call stub instead.
   2404   push(lr);
   2405   DoubleToIStub stub(isolate(),
   2406                      object,
   2407                      result,
   2408                      HeapNumber::kValueOffset - kHeapObjectTag,
   2409                      true,
   2410                      true);
   2411   CallStub(&stub);
   2412   pop(lr);
   2413 
   2414   bind(&done);
   2415 }
   2416 
   2417 
   2418 void MacroAssembler::TruncateNumberToI(Register object,
   2419                                        Register result,
   2420                                        Register heap_number_map,
   2421                                        Register scratch1,
   2422                                        Label* not_number) {
   2423   Label done;
   2424   DCHECK(!result.is(object));
   2425 
   2426   UntagAndJumpIfSmi(result, object, &done);
   2427   JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
   2428   TruncateHeapNumberToI(result, object);
   2429 
   2430   bind(&done);
   2431 }
   2432 
   2433 
   2434 void MacroAssembler::GetLeastBitsFromSmi(Register dst,
   2435                                          Register src,
   2436                                          int num_least_bits) {
   2437   if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size()) {
   2438     ubfx(dst, src, kSmiTagSize, num_least_bits);
   2439   } else {
   2440     SmiUntag(dst, src);
   2441     and_(dst, dst, Operand((1 << num_least_bits) - 1));
   2442   }
   2443 }
   2444 
   2445 
   2446 void MacroAssembler::GetLeastBitsFromInt32(Register dst,
   2447                                            Register src,
   2448                                            int num_least_bits) {
   2449   and_(dst, src, Operand((1 << num_least_bits) - 1));
   2450 }
   2451 
   2452 
   2453 void MacroAssembler::CallRuntime(const Runtime::Function* f,
   2454                                  int num_arguments,
   2455                                  SaveFPRegsMode save_doubles) {
   2456   // All parameters are on the stack.  r0 has the return value after call.
   2457 
   2458   // If the expected number of arguments of the runtime function is
   2459   // constant, we check that the actual number of arguments match the
   2460   // expectation.
   2461   CHECK(f->nargs < 0 || f->nargs == num_arguments);
   2462 
   2463   // TODO(1236192): Most runtime routines don't need the number of
   2464   // arguments passed in because it is constant. At some point we
   2465   // should remove this need and make the runtime routine entry code
   2466   // smarter.
   2467   mov(r0, Operand(num_arguments));
   2468   mov(r1, Operand(ExternalReference(f, isolate())));
   2469   CEntryStub stub(isolate(), 1, save_doubles);
   2470   CallStub(&stub);
   2471 }
   2472 
   2473 
   2474 void MacroAssembler::CallExternalReference(const ExternalReference& ext,
   2475                                            int num_arguments) {
   2476   mov(r0, Operand(num_arguments));
   2477   mov(r1, Operand(ext));
   2478 
   2479   CEntryStub stub(isolate(), 1);
   2480   CallStub(&stub);
   2481 }
   2482 
   2483 
   2484 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
   2485   const Runtime::Function* function = Runtime::FunctionForId(fid);
   2486   DCHECK_EQ(1, function->result_size);
   2487   if (function->nargs >= 0) {
   2488     // TODO(1236192): Most runtime routines don't need the number of
   2489     // arguments passed in because it is constant. At some point we
   2490     // should remove this need and make the runtime routine entry code
   2491     // smarter.
   2492     mov(r0, Operand(function->nargs));
   2493   }
   2494   JumpToExternalReference(ExternalReference(fid, isolate()));
   2495 }
   2496 
   2497 
   2498 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
   2499 #if defined(__thumb__)
   2500   // Thumb mode builtin.
   2501   DCHECK((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1);
   2502 #endif
   2503   mov(r1, Operand(builtin));
   2504   CEntryStub stub(isolate(), 1);
   2505   Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
   2506 }
   2507 
   2508 
   2509 void MacroAssembler::InvokeBuiltin(int native_context_index, InvokeFlag flag,
   2510                                    const CallWrapper& call_wrapper) {
   2511   // You can't call a builtin without a valid frame.
   2512   DCHECK(flag == JUMP_FUNCTION || has_frame());
   2513 
   2514   // Fake a parameter count to avoid emitting code to do the check.
   2515   ParameterCount expected(0);
   2516   LoadNativeContextSlot(native_context_index, r1);
   2517   InvokeFunctionCode(r1, no_reg, expected, expected, flag, call_wrapper);
   2518 }
   2519 
   2520 
   2521 void MacroAssembler::SetCounter(StatsCounter* counter, int value,
   2522                                 Register scratch1, Register scratch2) {
   2523   if (FLAG_native_code_counters && counter->Enabled()) {
   2524     mov(scratch1, Operand(value));
   2525     mov(scratch2, Operand(ExternalReference(counter)));
   2526     str(scratch1, MemOperand(scratch2));
   2527   }
   2528 }
   2529 
   2530 
   2531 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
   2532                                       Register scratch1, Register scratch2) {
   2533   DCHECK(value > 0);
   2534   if (FLAG_native_code_counters && counter->Enabled()) {
   2535     mov(scratch2, Operand(ExternalReference(counter)));
   2536     ldr(scratch1, MemOperand(scratch2));
   2537     add(scratch1, scratch1, Operand(value));
   2538     str(scratch1, MemOperand(scratch2));
   2539   }
   2540 }
   2541 
   2542 
   2543 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
   2544                                       Register scratch1, Register scratch2) {
   2545   DCHECK(value > 0);
   2546   if (FLAG_native_code_counters && counter->Enabled()) {
   2547     mov(scratch2, Operand(ExternalReference(counter)));
   2548     ldr(scratch1, MemOperand(scratch2));
   2549     sub(scratch1, scratch1, Operand(value));
   2550     str(scratch1, MemOperand(scratch2));
   2551   }
   2552 }
   2553 
   2554 
   2555 void MacroAssembler::Assert(Condition cond, BailoutReason reason) {
   2556   if (emit_debug_code())
   2557     Check(cond, reason);
   2558 }
   2559 
   2560 
   2561 void MacroAssembler::AssertFastElements(Register elements) {
   2562   if (emit_debug_code()) {
   2563     DCHECK(!elements.is(ip));
   2564     Label ok;
   2565     push(elements);
   2566     ldr(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
   2567     LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
   2568     cmp(elements, ip);
   2569     b(eq, &ok);
   2570     LoadRoot(ip, Heap::kFixedDoubleArrayMapRootIndex);
   2571     cmp(elements, ip);
   2572     b(eq, &ok);
   2573     LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
   2574     cmp(elements, ip);
   2575     b(eq, &ok);
   2576     Abort(kJSObjectWithFastElementsMapHasSlowElements);
   2577     bind(&ok);
   2578     pop(elements);
   2579   }
   2580 }
   2581 
   2582 
   2583 void MacroAssembler::Check(Condition cond, BailoutReason reason) {
   2584   Label L;
   2585   b(cond, &L);
   2586   Abort(reason);
   2587   // will not return here
   2588   bind(&L);
   2589 }
   2590 
   2591 
   2592 void MacroAssembler::Abort(BailoutReason reason) {
   2593   Label abort_start;
   2594   bind(&abort_start);
   2595 #ifdef DEBUG
   2596   const char* msg = GetBailoutReason(reason);
   2597   if (msg != NULL) {
   2598     RecordComment("Abort message: ");
   2599     RecordComment(msg);
   2600   }
   2601 
   2602   if (FLAG_trap_on_abort) {
   2603     stop(msg);
   2604     return;
   2605   }
   2606 #endif
   2607 
   2608   mov(r0, Operand(Smi::FromInt(reason)));
   2609   push(r0);
   2610 
   2611   // Disable stub call restrictions to always allow calls to abort.
   2612   if (!has_frame_) {
   2613     // We don't actually want to generate a pile of code for this, so just
   2614     // claim there is a stack frame, without generating one.
   2615     FrameScope scope(this, StackFrame::NONE);
   2616     CallRuntime(Runtime::kAbort, 1);
   2617   } else {
   2618     CallRuntime(Runtime::kAbort, 1);
   2619   }
   2620   // will not return here
   2621   if (is_const_pool_blocked()) {
   2622     // If the calling code cares about the exact number of
   2623     // instructions generated, we insert padding here to keep the size
   2624     // of the Abort macro constant.
   2625     static const int kExpectedAbortInstructions = 7;
   2626     int abort_instructions = InstructionsGeneratedSince(&abort_start);
   2627     DCHECK(abort_instructions <= kExpectedAbortInstructions);
   2628     while (abort_instructions++ < kExpectedAbortInstructions) {
   2629       nop();
   2630     }
   2631   }
   2632 }
   2633 
   2634 
   2635 void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
   2636   if (context_chain_length > 0) {
   2637     // Move up the chain of contexts to the context containing the slot.
   2638     ldr(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
   2639     for (int i = 1; i < context_chain_length; i++) {
   2640       ldr(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
   2641     }
   2642   } else {
   2643     // Slot is in the current function context.  Move it into the
   2644     // destination register in case we store into it (the write barrier
   2645     // cannot be allowed to destroy the context in esi).
   2646     mov(dst, cp);
   2647   }
   2648 }
   2649 
   2650 
   2651 void MacroAssembler::LoadTransitionedArrayMapConditional(
   2652     ElementsKind expected_kind,
   2653     ElementsKind transitioned_kind,
   2654     Register map_in_out,
   2655     Register scratch,
   2656     Label* no_map_match) {
   2657   DCHECK(IsFastElementsKind(expected_kind));
   2658   DCHECK(IsFastElementsKind(transitioned_kind));
   2659 
   2660   // Check that the function's map is the same as the expected cached map.
   2661   ldr(scratch, NativeContextMemOperand());
   2662   ldr(ip, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind)));
   2663   cmp(map_in_out, ip);
   2664   b(ne, no_map_match);
   2665 
   2666   // Use the transitioned cached map.
   2667   ldr(map_in_out,
   2668       ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
   2669 }
   2670 
   2671 
   2672 void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
   2673   ldr(dst, NativeContextMemOperand());
   2674   ldr(dst, ContextMemOperand(dst, index));
   2675 }
   2676 
   2677 
   2678 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
   2679                                                   Register map,
   2680                                                   Register scratch) {
   2681   // Load the initial map. The global functions all have initial maps.
   2682   ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
   2683   if (emit_debug_code()) {
   2684     Label ok, fail;
   2685     CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
   2686     b(&ok);
   2687     bind(&fail);
   2688     Abort(kGlobalFunctionsMustHaveInitialMap);
   2689     bind(&ok);
   2690   }
   2691 }
   2692 
   2693 
   2694 void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
   2695     Register reg,
   2696     Register scratch,
   2697     Label* not_power_of_two_or_zero) {
   2698   sub(scratch, reg, Operand(1), SetCC);
   2699   b(mi, not_power_of_two_or_zero);
   2700   tst(scratch, reg);
   2701   b(ne, not_power_of_two_or_zero);
   2702 }
   2703 
   2704 
   2705 void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(
   2706     Register reg,
   2707     Register scratch,
   2708     Label* zero_and_neg,
   2709     Label* not_power_of_two) {
   2710   sub(scratch, reg, Operand(1), SetCC);
   2711   b(mi, zero_and_neg);
   2712   tst(scratch, reg);
   2713   b(ne, not_power_of_two);
   2714 }
   2715 
   2716 
   2717 void MacroAssembler::JumpIfNotBothSmi(Register reg1,
   2718                                       Register reg2,
   2719                                       Label* on_not_both_smi) {
   2720   STATIC_ASSERT(kSmiTag == 0);
   2721   tst(reg1, Operand(kSmiTagMask));
   2722   tst(reg2, Operand(kSmiTagMask), eq);
   2723   b(ne, on_not_both_smi);
   2724 }
   2725 
   2726 
   2727 void MacroAssembler::UntagAndJumpIfSmi(
   2728     Register dst, Register src, Label* smi_case) {
   2729   STATIC_ASSERT(kSmiTag == 0);
   2730   SmiUntag(dst, src, SetCC);
   2731   b(cc, smi_case);  // Shifter carry is not set for a smi.
   2732 }
   2733 
   2734 
   2735 void MacroAssembler::UntagAndJumpIfNotSmi(
   2736     Register dst, Register src, Label* non_smi_case) {
   2737   STATIC_ASSERT(kSmiTag == 0);
   2738   SmiUntag(dst, src, SetCC);
   2739   b(cs, non_smi_case);  // Shifter carry is set for a non-smi.
   2740 }
   2741 
   2742 
   2743 void MacroAssembler::JumpIfEitherSmi(Register reg1,
   2744                                      Register reg2,
   2745                                      Label* on_either_smi) {
   2746   STATIC_ASSERT(kSmiTag == 0);
   2747   tst(reg1, Operand(kSmiTagMask));
   2748   tst(reg2, Operand(kSmiTagMask), ne);
   2749   b(eq, on_either_smi);
   2750 }
   2751 
   2752 
   2753 void MacroAssembler::AssertNotSmi(Register object) {
   2754   if (emit_debug_code()) {
   2755     STATIC_ASSERT(kSmiTag == 0);
   2756     tst(object, Operand(kSmiTagMask));
   2757     Check(ne, kOperandIsASmi);
   2758   }
   2759 }
   2760 
   2761 
   2762 void MacroAssembler::AssertSmi(Register object) {
   2763   if (emit_debug_code()) {
   2764     STATIC_ASSERT(kSmiTag == 0);
   2765     tst(object, Operand(kSmiTagMask));
   2766     Check(eq, kOperandIsNotSmi);
   2767   }
   2768 }
   2769 
   2770 
   2771 void MacroAssembler::AssertString(Register object) {
   2772   if (emit_debug_code()) {
   2773     STATIC_ASSERT(kSmiTag == 0);
   2774     tst(object, Operand(kSmiTagMask));
   2775     Check(ne, kOperandIsASmiAndNotAString);
   2776     push(object);
   2777     ldr(object, FieldMemOperand(object, HeapObject::kMapOffset));
   2778     CompareInstanceType(object, object, FIRST_NONSTRING_TYPE);
   2779     pop(object);
   2780     Check(lo, kOperandIsNotAString);
   2781   }
   2782 }
   2783 
   2784 
   2785 void MacroAssembler::AssertName(Register object) {
   2786   if (emit_debug_code()) {
   2787     STATIC_ASSERT(kSmiTag == 0);
   2788     tst(object, Operand(kSmiTagMask));
   2789     Check(ne, kOperandIsASmiAndNotAName);
   2790     push(object);
   2791     ldr(object, FieldMemOperand(object, HeapObject::kMapOffset));
   2792     CompareInstanceType(object, object, LAST_NAME_TYPE);
   2793     pop(object);
   2794     Check(le, kOperandIsNotAName);
   2795   }
   2796 }
   2797 
   2798 
   2799 void MacroAssembler::AssertFunction(Register object) {
   2800   if (emit_debug_code()) {
   2801     STATIC_ASSERT(kSmiTag == 0);
   2802     tst(object, Operand(kSmiTagMask));
   2803     Check(ne, kOperandIsASmiAndNotAFunction);
   2804     push(object);
   2805     CompareObjectType(object, object, object, JS_FUNCTION_TYPE);
   2806     pop(object);
   2807     Check(eq, kOperandIsNotAFunction);
   2808   }
   2809 }
   2810 
   2811 
   2812 void MacroAssembler::AssertBoundFunction(Register object) {
   2813   if (emit_debug_code()) {
   2814     STATIC_ASSERT(kSmiTag == 0);
   2815     tst(object, Operand(kSmiTagMask));
   2816     Check(ne, kOperandIsASmiAndNotABoundFunction);
   2817     push(object);
   2818     CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE);
   2819     pop(object);
   2820     Check(eq, kOperandIsNotABoundFunction);
   2821   }
   2822 }
   2823 
   2824 
   2825 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
   2826                                                      Register scratch) {
   2827   if (emit_debug_code()) {
   2828     Label done_checking;
   2829     AssertNotSmi(object);
   2830     CompareRoot(object, Heap::kUndefinedValueRootIndex);
   2831     b(eq, &done_checking);
   2832     ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
   2833     CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex);
   2834     Assert(eq, kExpectedUndefinedOrCell);
   2835     bind(&done_checking);
   2836   }
   2837 }
   2838 
   2839 
   2840 void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) {
   2841   if (emit_debug_code()) {
   2842     CompareRoot(reg, index);
   2843     Check(eq, kHeapNumberMapRegisterClobbered);
   2844   }
   2845 }
   2846 
   2847 
   2848 void MacroAssembler::JumpIfNotHeapNumber(Register object,
   2849                                          Register heap_number_map,
   2850                                          Register scratch,
   2851                                          Label* on_not_heap_number) {
   2852   ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
   2853   AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
   2854   cmp(scratch, heap_number_map);
   2855   b(ne, on_not_heap_number);
   2856 }
   2857 
   2858 
   2859 void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
   2860     Register first, Register second, Register scratch1, Register scratch2,
   2861     Label* failure) {
   2862   // Test that both first and second are sequential one-byte strings.
   2863   // Assume that they are non-smis.
   2864   ldr(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
   2865   ldr(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
   2866   ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
   2867   ldrb(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
   2868 
   2869   JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1,
   2870                                                  scratch2, failure);
   2871 }
   2872 
   2873 void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first,
   2874                                                            Register second,
   2875                                                            Register scratch1,
   2876                                                            Register scratch2,
   2877                                                            Label* failure) {
   2878   // Check that neither is a smi.
   2879   and_(scratch1, first, Operand(second));
   2880   JumpIfSmi(scratch1, failure);
   2881   JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1,
   2882                                                scratch2, failure);
   2883 }
   2884 
   2885 
   2886 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg,
   2887                                                      Label* not_unique_name) {
   2888   STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
   2889   Label succeed;
   2890   tst(reg, Operand(kIsNotStringMask | kIsNotInternalizedMask));
   2891   b(eq, &succeed);
   2892   cmp(reg, Operand(SYMBOL_TYPE));
   2893   b(ne, not_unique_name);
   2894 
   2895   bind(&succeed);
   2896 }
   2897 
   2898 
   2899 // Allocates a heap number or jumps to the need_gc label if the young space
   2900 // is full and a scavenge is needed.
   2901 void MacroAssembler::AllocateHeapNumber(Register result,
   2902                                         Register scratch1,
   2903                                         Register scratch2,
   2904                                         Register heap_number_map,
   2905                                         Label* gc_required,
   2906                                         TaggingMode tagging_mode,
   2907                                         MutableMode mode) {
   2908   // Allocate an object in the heap for the heap number and tag it as a heap
   2909   // object.
   2910   Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
   2911            tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS);
   2912 
   2913   Heap::RootListIndex map_index = mode == MUTABLE
   2914       ? Heap::kMutableHeapNumberMapRootIndex
   2915       : Heap::kHeapNumberMapRootIndex;
   2916   AssertIsRoot(heap_number_map, map_index);
   2917 
   2918   // Store heap number map in the allocated object.
   2919   if (tagging_mode == TAG_RESULT) {
   2920     str(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
   2921   } else {
   2922     str(heap_number_map, MemOperand(result, HeapObject::kMapOffset));
   2923   }
   2924 }
   2925 
   2926 
   2927 void MacroAssembler::AllocateHeapNumberWithValue(Register result,
   2928                                                  DwVfpRegister value,
   2929                                                  Register scratch1,
   2930                                                  Register scratch2,
   2931                                                  Register heap_number_map,
   2932                                                  Label* gc_required) {
   2933   AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required);
   2934   sub(scratch1, result, Operand(kHeapObjectTag));
   2935   vstr(value, scratch1, HeapNumber::kValueOffset);
   2936 }
   2937 
   2938 
   2939 void MacroAssembler::AllocateJSValue(Register result, Register constructor,
   2940                                      Register value, Register scratch1,
   2941                                      Register scratch2, Label* gc_required) {
   2942   DCHECK(!result.is(constructor));
   2943   DCHECK(!result.is(scratch1));
   2944   DCHECK(!result.is(scratch2));
   2945   DCHECK(!result.is(value));
   2946 
   2947   // Allocate JSValue in new space.
   2948   Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
   2949 
   2950   // Initialize the JSValue.
   2951   LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
   2952   str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
   2953   LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
   2954   str(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset));
   2955   str(scratch1, FieldMemOperand(result, JSObject::kElementsOffset));
   2956   str(value, FieldMemOperand(result, JSValue::kValueOffset));
   2957   STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
   2958 }
   2959 
   2960 
   2961 void MacroAssembler::CopyBytes(Register src,
   2962                                Register dst,
   2963                                Register length,
   2964                                Register scratch) {
   2965   Label align_loop_1, word_loop, byte_loop, byte_loop_1, done;
   2966 
   2967   // Align src before copying in word size chunks.
   2968   cmp(length, Operand(kPointerSize));
   2969   b(le, &byte_loop);
   2970 
   2971   bind(&align_loop_1);
   2972   tst(src, Operand(kPointerSize - 1));
   2973   b(eq, &word_loop);
   2974   ldrb(scratch, MemOperand(src, 1, PostIndex));
   2975   strb(scratch, MemOperand(dst, 1, PostIndex));
   2976   sub(length, length, Operand(1), SetCC);
   2977   b(&align_loop_1);
   2978   // Copy bytes in word size chunks.
   2979   bind(&word_loop);
   2980   if (emit_debug_code()) {
   2981     tst(src, Operand(kPointerSize - 1));
   2982     Assert(eq, kExpectingAlignmentForCopyBytes);
   2983   }
   2984   cmp(length, Operand(kPointerSize));
   2985   b(lt, &byte_loop);
   2986   ldr(scratch, MemOperand(src, kPointerSize, PostIndex));
   2987   if (CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) {
   2988     str(scratch, MemOperand(dst, kPointerSize, PostIndex));
   2989   } else {
   2990     strb(scratch, MemOperand(dst, 1, PostIndex));
   2991     mov(scratch, Operand(scratch, LSR, 8));
   2992     strb(scratch, MemOperand(dst, 1, PostIndex));
   2993     mov(scratch, Operand(scratch, LSR, 8));
   2994     strb(scratch, MemOperand(dst, 1, PostIndex));
   2995     mov(scratch, Operand(scratch, LSR, 8));
   2996     strb(scratch, MemOperand(dst, 1, PostIndex));
   2997   }
   2998   sub(length, length, Operand(kPointerSize));
   2999   b(&word_loop);
   3000 
   3001   // Copy the last bytes if any left.
   3002   bind(&byte_loop);
   3003   cmp(length, Operand::Zero());
   3004   b(eq, &done);
   3005   bind(&byte_loop_1);
   3006   ldrb(scratch, MemOperand(src, 1, PostIndex));
   3007   strb(scratch, MemOperand(dst, 1, PostIndex));
   3008   sub(length, length, Operand(1), SetCC);
   3009   b(ne, &byte_loop_1);
   3010   bind(&done);
   3011 }
   3012 
   3013 
   3014 void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
   3015                                                 Register end_address,
   3016                                                 Register filler) {
   3017   Label loop, entry;
   3018   b(&entry);
   3019   bind(&loop);
   3020   str(filler, MemOperand(current_address, kPointerSize, PostIndex));
   3021   bind(&entry);
   3022   cmp(current_address, end_address);
   3023   b(lo, &loop);
   3024 }
   3025 
   3026 
   3027 void MacroAssembler::CheckFor32DRegs(Register scratch) {
   3028   mov(scratch, Operand(ExternalReference::cpu_features()));
   3029   ldr(scratch, MemOperand(scratch));
   3030   tst(scratch, Operand(1u << VFP32DREGS));
   3031 }
   3032 
   3033 
   3034 void MacroAssembler::SaveFPRegs(Register location, Register scratch) {
   3035   CheckFor32DRegs(scratch);
   3036   vstm(db_w, location, d16, d31, ne);
   3037   sub(location, location, Operand(16 * kDoubleSize), LeaveCC, eq);
   3038   vstm(db_w, location, d0, d15);
   3039 }
   3040 
   3041 
   3042 void MacroAssembler::RestoreFPRegs(Register location, Register scratch) {
   3043   CheckFor32DRegs(scratch);
   3044   vldm(ia_w, location, d0, d15);
   3045   vldm(ia_w, location, d16, d31, ne);
   3046   add(location, location, Operand(16 * kDoubleSize), LeaveCC, eq);
   3047 }
   3048 
   3049 
   3050 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
   3051     Register first, Register second, Register scratch1, Register scratch2,
   3052     Label* failure) {
   3053   const int kFlatOneByteStringMask =
   3054       kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
   3055   const int kFlatOneByteStringTag =
   3056       kStringTag | kOneByteStringTag | kSeqStringTag;
   3057   and_(scratch1, first, Operand(kFlatOneByteStringMask));
   3058   and_(scratch2, second, Operand(kFlatOneByteStringMask));
   3059   cmp(scratch1, Operand(kFlatOneByteStringTag));
   3060   // Ignore second test if first test failed.
   3061   cmp(scratch2, Operand(kFlatOneByteStringTag), eq);
   3062   b(ne, failure);
   3063 }
   3064 
   3065 
   3066 void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type,
   3067                                                               Register scratch,
   3068                                                               Label* failure) {
   3069   const int kFlatOneByteStringMask =
   3070       kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
   3071   const int kFlatOneByteStringTag =
   3072       kStringTag | kOneByteStringTag | kSeqStringTag;
   3073   and_(scratch, type, Operand(kFlatOneByteStringMask));
   3074   cmp(scratch, Operand(kFlatOneByteStringTag));
   3075   b(ne, failure);
   3076 }
   3077 
   3078 static const int kRegisterPassedArguments = 4;
   3079 
   3080 
   3081 int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments,
   3082                                               int num_double_arguments) {
   3083   int stack_passed_words = 0;
   3084   if (use_eabi_hardfloat()) {
   3085     // In the hard floating point calling convention, we can use
   3086     // all double registers to pass doubles.
   3087     if (num_double_arguments > DoubleRegister::NumRegisters()) {
   3088       stack_passed_words +=
   3089           2 * (num_double_arguments - DoubleRegister::NumRegisters());
   3090     }
   3091   } else {
   3092     // In the soft floating point calling convention, every double
   3093     // argument is passed using two registers.
   3094     num_reg_arguments += 2 * num_double_arguments;
   3095   }
   3096   // Up to four simple arguments are passed in registers r0..r3.
   3097   if (num_reg_arguments > kRegisterPassedArguments) {
   3098     stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
   3099   }
   3100   return stack_passed_words;
   3101 }
   3102 
   3103 
   3104 void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
   3105                                                Register index,
   3106                                                Register value,
   3107                                                uint32_t encoding_mask) {
   3108   Label is_object;
   3109   SmiTst(string);
   3110   Check(ne, kNonObject);
   3111 
   3112   ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset));
   3113   ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
   3114 
   3115   and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
   3116   cmp(ip, Operand(encoding_mask));
   3117   Check(eq, kUnexpectedStringType);
   3118 
   3119   // The index is assumed to be untagged coming in, tag it to compare with the
   3120   // string length without using a temp register, it is restored at the end of
   3121   // this function.
   3122   Label index_tag_ok, index_tag_bad;
   3123   TrySmiTag(index, index, &index_tag_bad);
   3124   b(&index_tag_ok);
   3125   bind(&index_tag_bad);
   3126   Abort(kIndexIsTooLarge);
   3127   bind(&index_tag_ok);
   3128 
   3129   ldr(ip, FieldMemOperand(string, String::kLengthOffset));
   3130   cmp(index, ip);
   3131   Check(lt, kIndexIsTooLarge);
   3132 
   3133   cmp(index, Operand(Smi::FromInt(0)));
   3134   Check(ge, kIndexIsNegative);
   3135 
   3136   SmiUntag(index, index);
   3137 }
   3138 
   3139 
   3140 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
   3141                                           int num_double_arguments,
   3142                                           Register scratch) {
   3143   int frame_alignment = ActivationFrameAlignment();
   3144   int stack_passed_arguments = CalculateStackPassedWords(
   3145       num_reg_arguments, num_double_arguments);
   3146   if (frame_alignment > kPointerSize) {
   3147     // Make stack end at alignment and make room for num_arguments - 4 words
   3148     // and the original value of sp.
   3149     mov(scratch, sp);
   3150     sub(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
   3151     DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
   3152     and_(sp, sp, Operand(-frame_alignment));
   3153     str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
   3154   } else {
   3155     sub(sp, sp, Operand(stack_passed_arguments * kPointerSize));
   3156   }
   3157 }
   3158 
   3159 
   3160 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
   3161                                           Register scratch) {
   3162   PrepareCallCFunction(num_reg_arguments, 0, scratch);
   3163 }
   3164 
   3165 
   3166 void MacroAssembler::MovToFloatParameter(DwVfpRegister src) {
   3167   DCHECK(src.is(d0));
   3168   if (!use_eabi_hardfloat()) {
   3169     vmov(r0, r1, src);
   3170   }
   3171 }
   3172 
   3173 
   3174 // On ARM this is just a synonym to make the purpose clear.
   3175 void MacroAssembler::MovToFloatResult(DwVfpRegister src) {
   3176   MovToFloatParameter(src);
   3177 }
   3178 
   3179 
   3180 void MacroAssembler::MovToFloatParameters(DwVfpRegister src1,
   3181                                           DwVfpRegister src2) {
   3182   DCHECK(src1.is(d0));
   3183   DCHECK(src2.is(d1));
   3184   if (!use_eabi_hardfloat()) {
   3185     vmov(r0, r1, src1);
   3186     vmov(r2, r3, src2);
   3187   }
   3188 }
   3189 
   3190 
   3191 void MacroAssembler::CallCFunction(ExternalReference function,
   3192                                    int num_reg_arguments,
   3193                                    int num_double_arguments) {
   3194   mov(ip, Operand(function));
   3195   CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments);
   3196 }
   3197 
   3198 
   3199 void MacroAssembler::CallCFunction(Register function,
   3200                                    int num_reg_arguments,
   3201                                    int num_double_arguments) {
   3202   CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
   3203 }
   3204 
   3205 
   3206 void MacroAssembler::CallCFunction(ExternalReference function,
   3207                                    int num_arguments) {
   3208   CallCFunction(function, num_arguments, 0);
   3209 }
   3210 
   3211 
   3212 void MacroAssembler::CallCFunction(Register function,
   3213                                    int num_arguments) {
   3214   CallCFunction(function, num_arguments, 0);
   3215 }
   3216 
   3217 
   3218 void MacroAssembler::CallCFunctionHelper(Register function,
   3219                                          int num_reg_arguments,
   3220                                          int num_double_arguments) {
   3221   DCHECK(has_frame());
   3222   // Make sure that the stack is aligned before calling a C function unless
   3223   // running in the simulator. The simulator has its own alignment check which
   3224   // provides more information.
   3225 #if V8_HOST_ARCH_ARM
   3226   if (emit_debug_code()) {
   3227     int frame_alignment = base::OS::ActivationFrameAlignment();
   3228     int frame_alignment_mask = frame_alignment - 1;
   3229     if (frame_alignment > kPointerSize) {
   3230       DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
   3231       Label alignment_as_expected;
   3232       tst(sp, Operand(frame_alignment_mask));
   3233       b(eq, &alignment_as_expected);
   3234       // Don't use Check here, as it will call Runtime_Abort possibly
   3235       // re-entering here.
   3236       stop("Unexpected alignment");
   3237       bind(&alignment_as_expected);
   3238     }
   3239   }
   3240 #endif
   3241 
   3242   // Just call directly. The function called cannot cause a GC, or
   3243   // allow preemption, so the return address in the link register
   3244   // stays correct.
   3245   Call(function);
   3246   int stack_passed_arguments = CalculateStackPassedWords(
   3247       num_reg_arguments, num_double_arguments);
   3248   if (ActivationFrameAlignment() > kPointerSize) {
   3249     ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
   3250   } else {
   3251     add(sp, sp, Operand(stack_passed_arguments * kPointerSize));
   3252   }
   3253 }
   3254 
   3255 
   3256 void MacroAssembler::CheckPageFlag(
   3257     Register object,
   3258     Register scratch,
   3259     int mask,
   3260     Condition cc,
   3261     Label* condition_met) {
   3262   Bfc(scratch, object, 0, kPageSizeBits);
   3263   ldr(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
   3264   tst(scratch, Operand(mask));
   3265   b(cc, condition_met);
   3266 }
   3267 
   3268 
   3269 void MacroAssembler::JumpIfBlack(Register object,
   3270                                  Register scratch0,
   3271                                  Register scratch1,
   3272                                  Label* on_black) {
   3273   HasColor(object, scratch0, scratch1, on_black, 1, 1);  // kBlackBitPattern.
   3274   DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
   3275 }
   3276 
   3277 
   3278 void MacroAssembler::HasColor(Register object,
   3279                               Register bitmap_scratch,
   3280                               Register mask_scratch,
   3281                               Label* has_color,
   3282                               int first_bit,
   3283                               int second_bit) {
   3284   DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, no_reg));
   3285 
   3286   GetMarkBits(object, bitmap_scratch, mask_scratch);
   3287 
   3288   Label other_color, word_boundary;
   3289   ldr(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
   3290   tst(ip, Operand(mask_scratch));
   3291   b(first_bit == 1 ? eq : ne, &other_color);
   3292   // Shift left 1 by adding.
   3293   add(mask_scratch, mask_scratch, Operand(mask_scratch), SetCC);
   3294   b(eq, &word_boundary);
   3295   tst(ip, Operand(mask_scratch));
   3296   b(second_bit == 1 ? ne : eq, has_color);
   3297   jmp(&other_color);
   3298 
   3299   bind(&word_boundary);
   3300   ldr(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize));
   3301   tst(ip, Operand(1));
   3302   b(second_bit == 1 ? ne : eq, has_color);
   3303   bind(&other_color);
   3304 }
   3305 
   3306 
   3307 void MacroAssembler::GetMarkBits(Register addr_reg,
   3308                                  Register bitmap_reg,
   3309                                  Register mask_reg) {
   3310   DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg));
   3311   and_(bitmap_reg, addr_reg, Operand(~Page::kPageAlignmentMask));
   3312   Ubfx(mask_reg, addr_reg, kPointerSizeLog2, Bitmap::kBitsPerCellLog2);
   3313   const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2;
   3314   Ubfx(ip, addr_reg, kLowBits, kPageSizeBits - kLowBits);
   3315   add(bitmap_reg, bitmap_reg, Operand(ip, LSL, kPointerSizeLog2));
   3316   mov(ip, Operand(1));
   3317   mov(mask_reg, Operand(ip, LSL, mask_reg));
   3318 }
   3319 
   3320 
   3321 void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
   3322                                  Register mask_scratch, Register load_scratch,
   3323                                  Label* value_is_white) {
   3324   DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip));
   3325   GetMarkBits(value, bitmap_scratch, mask_scratch);
   3326 
   3327   // If the value is black or grey we don't need to do anything.
   3328   DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
   3329   DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
   3330   DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
   3331   DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
   3332 
   3333   // Since both black and grey have a 1 in the first position and white does
   3334   // not have a 1 there we only need to check one bit.
   3335   ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
   3336   tst(mask_scratch, load_scratch);
   3337   b(eq, value_is_white);
   3338 }
   3339 
   3340 
   3341 void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
   3342   Usat(output_reg, 8, Operand(input_reg));
   3343 }
   3344 
   3345 
   3346 void MacroAssembler::ClampDoubleToUint8(Register result_reg,
   3347                                         DwVfpRegister input_reg,
   3348                                         LowDwVfpRegister double_scratch) {
   3349   Label done;
   3350 
   3351   // Handle inputs >= 255 (including +infinity).
   3352   Vmov(double_scratch, 255.0, result_reg);
   3353   mov(result_reg, Operand(255));
   3354   VFPCompareAndSetFlags(input_reg, double_scratch);
   3355   b(ge, &done);
   3356 
   3357   // For inputs < 255 (including negative) vcvt_u32_f64 with round-to-nearest
   3358   // rounding mode will provide the correct result.
   3359   vcvt_u32_f64(double_scratch.low(), input_reg, kFPSCRRounding);
   3360   vmov(result_reg, double_scratch.low());
   3361 
   3362   bind(&done);
   3363 }
   3364 
   3365 
   3366 void MacroAssembler::LoadInstanceDescriptors(Register map,
   3367                                              Register descriptors) {
   3368   ldr(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
   3369 }
   3370 
   3371 
   3372 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
   3373   ldr(dst, FieldMemOperand(map, Map::kBitField3Offset));
   3374   DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
   3375 }
   3376 
   3377 
   3378 void MacroAssembler::EnumLength(Register dst, Register map) {
   3379   STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
   3380   ldr(dst, FieldMemOperand(map, Map::kBitField3Offset));
   3381   and_(dst, dst, Operand(Map::EnumLengthBits::kMask));
   3382   SmiTag(dst);
   3383 }
   3384 
   3385 
   3386 void MacroAssembler::LoadAccessor(Register dst, Register holder,
   3387                                   int accessor_index,
   3388                                   AccessorComponent accessor) {
   3389   ldr(dst, FieldMemOperand(holder, HeapObject::kMapOffset));
   3390   LoadInstanceDescriptors(dst, dst);
   3391   ldr(dst,
   3392       FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
   3393   int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset
   3394                                            : AccessorPair::kSetterOffset;
   3395   ldr(dst, FieldMemOperand(dst, offset));
   3396 }
   3397 
   3398 
   3399 void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
   3400   Register  empty_fixed_array_value = r6;
   3401   LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
   3402   Label next, start;
   3403   mov(r2, r0);
   3404 
   3405   // Check if the enum length field is properly initialized, indicating that
   3406   // there is an enum cache.
   3407   ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
   3408 
   3409   EnumLength(r3, r1);
   3410   cmp(r3, Operand(Smi::FromInt(kInvalidEnumCacheSentinel)));
   3411   b(eq, call_runtime);
   3412 
   3413   jmp(&start);
   3414 
   3415   bind(&next);
   3416   ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
   3417 
   3418   // For all objects but the receiver, check that the cache is empty.
   3419   EnumLength(r3, r1);
   3420   cmp(r3, Operand(Smi::FromInt(0)));
   3421   b(ne, call_runtime);
   3422 
   3423   bind(&start);
   3424 
   3425   // Check that there are no elements. Register r2 contains the current JS
   3426   // object we've reached through the prototype chain.
   3427   Label no_elements;
   3428   ldr(r2, FieldMemOperand(r2, JSObject::kElementsOffset));
   3429   cmp(r2, empty_fixed_array_value);
   3430   b(eq, &no_elements);
   3431 
   3432   // Second chance, the object may be using the empty slow element dictionary.
   3433   CompareRoot(r2, Heap::kEmptySlowElementDictionaryRootIndex);
   3434   b(ne, call_runtime);
   3435 
   3436   bind(&no_elements);
   3437   ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset));
   3438   cmp(r2, null_value);
   3439   b(ne, &next);
   3440 }
   3441 
   3442 
   3443 void MacroAssembler::TestJSArrayForAllocationMemento(
   3444     Register receiver_reg,
   3445     Register scratch_reg,
   3446     Label* no_memento_found) {
   3447   ExternalReference new_space_start =
   3448       ExternalReference::new_space_start(isolate());
   3449   ExternalReference new_space_allocation_top =
   3450       ExternalReference::new_space_allocation_top_address(isolate());
   3451   add(scratch_reg, receiver_reg,
   3452       Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag));
   3453   cmp(scratch_reg, Operand(new_space_start));
   3454   b(lt, no_memento_found);
   3455   mov(ip, Operand(new_space_allocation_top));
   3456   ldr(ip, MemOperand(ip));
   3457   cmp(scratch_reg, ip);
   3458   b(gt, no_memento_found);
   3459   ldr(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize));
   3460   cmp(scratch_reg,
   3461       Operand(isolate()->factory()->allocation_memento_map()));
   3462 }
   3463 
   3464 
   3465 Register GetRegisterThatIsNotOneOf(Register reg1,
   3466                                    Register reg2,
   3467                                    Register reg3,
   3468                                    Register reg4,
   3469                                    Register reg5,
   3470                                    Register reg6) {
   3471   RegList regs = 0;
   3472   if (reg1.is_valid()) regs |= reg1.bit();
   3473   if (reg2.is_valid()) regs |= reg2.bit();
   3474   if (reg3.is_valid()) regs |= reg3.bit();
   3475   if (reg4.is_valid()) regs |= reg4.bit();
   3476   if (reg5.is_valid()) regs |= reg5.bit();
   3477   if (reg6.is_valid()) regs |= reg6.bit();
   3478 
   3479   const RegisterConfiguration* config =
   3480       RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
   3481   for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
   3482     int code = config->GetAllocatableGeneralCode(i);
   3483     Register candidate = Register::from_code(code);
   3484     if (regs & candidate.bit()) continue;
   3485     return candidate;
   3486   }
   3487   UNREACHABLE();
   3488   return no_reg;
   3489 }
   3490 
   3491 
   3492 void MacroAssembler::JumpIfDictionaryInPrototypeChain(
   3493     Register object,
   3494     Register scratch0,
   3495     Register scratch1,
   3496     Label* found) {
   3497   DCHECK(!scratch1.is(scratch0));
   3498   Register current = scratch0;
   3499   Label loop_again, end;
   3500 
   3501   // scratch contained elements pointer.
   3502   mov(current, object);
   3503   ldr(current, FieldMemOperand(current, HeapObject::kMapOffset));
   3504   ldr(current, FieldMemOperand(current, Map::kPrototypeOffset));
   3505   CompareRoot(current, Heap::kNullValueRootIndex);
   3506   b(eq, &end);
   3507 
   3508   // Loop based on the map going up the prototype chain.
   3509   bind(&loop_again);
   3510   ldr(current, FieldMemOperand(current, HeapObject::kMapOffset));
   3511 
   3512   STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
   3513   STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
   3514   ldrb(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset));
   3515   cmp(scratch1, Operand(JS_OBJECT_TYPE));
   3516   b(lo, found);
   3517 
   3518   ldr(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
   3519   DecodeField<Map::ElementsKindBits>(scratch1);
   3520   cmp(scratch1, Operand(DICTIONARY_ELEMENTS));
   3521   b(eq, found);
   3522   ldr(current, FieldMemOperand(current, Map::kPrototypeOffset));
   3523   CompareRoot(current, Heap::kNullValueRootIndex);
   3524   b(ne, &loop_again);
   3525 
   3526   bind(&end);
   3527 }
   3528 
   3529 
   3530 #ifdef DEBUG
   3531 bool AreAliased(Register reg1,
   3532                 Register reg2,
   3533                 Register reg3,
   3534                 Register reg4,
   3535                 Register reg5,
   3536                 Register reg6,
   3537                 Register reg7,
   3538                 Register reg8) {
   3539   int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() +
   3540       reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
   3541       reg7.is_valid() + reg8.is_valid();
   3542 
   3543   RegList regs = 0;
   3544   if (reg1.is_valid()) regs |= reg1.bit();
   3545   if (reg2.is_valid()) regs |= reg2.bit();
   3546   if (reg3.is_valid()) regs |= reg3.bit();
   3547   if (reg4.is_valid()) regs |= reg4.bit();
   3548   if (reg5.is_valid()) regs |= reg5.bit();
   3549   if (reg6.is_valid()) regs |= reg6.bit();
   3550   if (reg7.is_valid()) regs |= reg7.bit();
   3551   if (reg8.is_valid()) regs |= reg8.bit();
   3552   int n_of_non_aliasing_regs = NumRegs(regs);
   3553 
   3554   return n_of_valid_regs != n_of_non_aliasing_regs;
   3555 }
   3556 #endif
   3557 
   3558 
   3559 CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions,
   3560                          FlushICache flush_cache)
   3561     : address_(address),
   3562       size_(instructions * Assembler::kInstrSize),
   3563       masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo),
   3564       flush_cache_(flush_cache) {
   3565   // Create a new macro assembler pointing to the address of the code to patch.
   3566   // The size is adjusted with kGap on order for the assembler to generate size
   3567   // bytes of instructions without failing with buffer size constraints.
   3568   DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
   3569 }
   3570 
   3571 
   3572 CodePatcher::~CodePatcher() {
   3573   // Indicate that code has changed.
   3574   if (flush_cache_ == FLUSH) {
   3575     Assembler::FlushICache(masm_.isolate(), address_, size_);
   3576   }
   3577 
   3578   // Check that the code was patched as expected.
   3579   DCHECK(masm_.pc_ == address_ + size_);
   3580   DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
   3581 }
   3582 
   3583 
   3584 void CodePatcher::Emit(Instr instr) {
   3585   masm()->emit(instr);
   3586 }
   3587 
   3588 
   3589 void CodePatcher::Emit(Address addr) {
   3590   masm()->emit(reinterpret_cast<Instr>(addr));
   3591 }
   3592 
   3593 
   3594 void CodePatcher::EmitCondition(Condition cond) {
   3595   Instr instr = Assembler::instr_at(masm_.pc_);
   3596   instr = (instr & ~kCondMask) | cond;
   3597   masm_.emit(instr);
   3598 }
   3599 
   3600 
   3601 void MacroAssembler::TruncatingDiv(Register result,
   3602                                    Register dividend,
   3603                                    int32_t divisor) {
   3604   DCHECK(!dividend.is(result));
   3605   DCHECK(!dividend.is(ip));
   3606   DCHECK(!result.is(ip));
   3607   base::MagicNumbersForDivision<uint32_t> mag =
   3608       base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
   3609   mov(ip, Operand(mag.multiplier));
   3610   bool neg = (mag.multiplier & (1U << 31)) != 0;
   3611   if (divisor > 0 && neg) {
   3612     smmla(result, dividend, ip, dividend);
   3613   } else {
   3614     smmul(result, dividend, ip);
   3615     if (divisor < 0 && !neg && mag.multiplier > 0) {
   3616       sub(result, result, Operand(dividend));
   3617     }
   3618   }
   3619   if (mag.shift > 0) mov(result, Operand(result, ASR, mag.shift));
   3620   add(result, result, Operand(dividend, LSR, 31));
   3621 }
   3622 
   3623 }  // namespace internal
   3624 }  // namespace v8
   3625 
   3626 #endif  // V8_TARGET_ARCH_ARM
   3627