Home | History | Annotate | Download | only in arm64
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/v8.h"
      6 
      7 #if V8_TARGET_ARCH_ARM64
      8 
      9 #include "src/bootstrapper.h"
     10 #include "src/code-stubs.h"
     11 #include "src/codegen.h"
     12 #include "src/ic/handler-compiler.h"
     13 #include "src/ic/ic.h"
     14 #include "src/isolate.h"
     15 #include "src/jsregexp.h"
     16 #include "src/regexp-macro-assembler.h"
     17 #include "src/runtime.h"
     18 
     19 namespace v8 {
     20 namespace internal {
     21 
     22 
     23 static void InitializeArrayConstructorDescriptor(
     24     Isolate* isolate, CodeStubDescriptor* descriptor,
     25     int constant_stack_parameter_count) {
     26   // cp: context
     27   // x1: function
     28   // x2: allocation site with elements kind
     29   // x0: number of arguments to the constructor function
     30   Address deopt_handler = Runtime::FunctionForId(
     31       Runtime::kArrayConstructor)->entry;
     32 
     33   if (constant_stack_parameter_count == 0) {
     34     descriptor->Initialize(deopt_handler, constant_stack_parameter_count,
     35                            JS_FUNCTION_STUB_MODE);
     36   } else {
     37     descriptor->Initialize(x0, deopt_handler, constant_stack_parameter_count,
     38                            JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS);
     39   }
     40 }
     41 
     42 
     43 void ArrayNoArgumentConstructorStub::InitializeDescriptor(
     44     CodeStubDescriptor* descriptor) {
     45   InitializeArrayConstructorDescriptor(isolate(), descriptor, 0);
     46 }
     47 
     48 
     49 void ArraySingleArgumentConstructorStub::InitializeDescriptor(
     50     CodeStubDescriptor* descriptor) {
     51   InitializeArrayConstructorDescriptor(isolate(), descriptor, 1);
     52 }
     53 
     54 
     55 void ArrayNArgumentsConstructorStub::InitializeDescriptor(
     56     CodeStubDescriptor* descriptor) {
     57   InitializeArrayConstructorDescriptor(isolate(), descriptor, -1);
     58 }
     59 
     60 
     61 static void InitializeInternalArrayConstructorDescriptor(
     62     Isolate* isolate, CodeStubDescriptor* descriptor,
     63     int constant_stack_parameter_count) {
     64   Address deopt_handler = Runtime::FunctionForId(
     65       Runtime::kInternalArrayConstructor)->entry;
     66 
     67   if (constant_stack_parameter_count == 0) {
     68     descriptor->Initialize(deopt_handler, constant_stack_parameter_count,
     69                            JS_FUNCTION_STUB_MODE);
     70   } else {
     71     descriptor->Initialize(x0, deopt_handler, constant_stack_parameter_count,
     72                            JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS);
     73   }
     74 }
     75 
     76 
     77 void InternalArrayNoArgumentConstructorStub::InitializeDescriptor(
     78     CodeStubDescriptor* descriptor) {
     79   InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 0);
     80 }
     81 
     82 
     83 void InternalArraySingleArgumentConstructorStub::InitializeDescriptor(
     84     CodeStubDescriptor* descriptor) {
     85   InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 1);
     86 }
     87 
     88 
     89 void InternalArrayNArgumentsConstructorStub::InitializeDescriptor(
     90     CodeStubDescriptor* descriptor) {
     91   InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, -1);
     92 }
     93 
     94 
     95 #define __ ACCESS_MASM(masm)
     96 
     97 
     98 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm,
     99                                                ExternalReference miss) {
    100   // Update the static counter each time a new code stub is generated.
    101   isolate()->counters()->code_stubs()->Increment();
    102 
    103   CallInterfaceDescriptor descriptor = GetCallInterfaceDescriptor();
    104   int param_count = descriptor.GetEnvironmentParameterCount();
    105   {
    106     // Call the runtime system in a fresh internal frame.
    107     FrameScope scope(masm, StackFrame::INTERNAL);
    108     DCHECK((param_count == 0) ||
    109            x0.Is(descriptor.GetEnvironmentParameterRegister(param_count - 1)));
    110 
    111     // Push arguments
    112     MacroAssembler::PushPopQueue queue(masm);
    113     for (int i = 0; i < param_count; ++i) {
    114       queue.Queue(descriptor.GetEnvironmentParameterRegister(i));
    115     }
    116     queue.PushQueued();
    117 
    118     __ CallExternalReference(miss, param_count);
    119   }
    120 
    121   __ Ret();
    122 }
    123 
    124 
    125 void DoubleToIStub::Generate(MacroAssembler* masm) {
    126   Label done;
    127   Register input = source();
    128   Register result = destination();
    129   DCHECK(is_truncating());
    130 
    131   DCHECK(result.Is64Bits());
    132   DCHECK(jssp.Is(masm->StackPointer()));
    133 
    134   int double_offset = offset();
    135 
    136   DoubleRegister double_scratch = d0;  // only used if !skip_fastpath()
    137   Register scratch1 = GetAllocatableRegisterThatIsNotOneOf(input, result);
    138   Register scratch2 =
    139       GetAllocatableRegisterThatIsNotOneOf(input, result, scratch1);
    140 
    141   __ Push(scratch1, scratch2);
    142   // Account for saved regs if input is jssp.
    143   if (input.is(jssp)) double_offset += 2 * kPointerSize;
    144 
    145   if (!skip_fastpath()) {
    146     __ Push(double_scratch);
    147     if (input.is(jssp)) double_offset += 1 * kDoubleSize;
    148     __ Ldr(double_scratch, MemOperand(input, double_offset));
    149     // Try to convert with a FPU convert instruction.  This handles all
    150     // non-saturating cases.
    151     __ TryConvertDoubleToInt64(result, double_scratch, &done);
    152     __ Fmov(result, double_scratch);
    153   } else {
    154     __ Ldr(result, MemOperand(input, double_offset));
    155   }
    156 
    157   // If we reach here we need to manually convert the input to an int32.
    158 
    159   // Extract the exponent.
    160   Register exponent = scratch1;
    161   __ Ubfx(exponent, result, HeapNumber::kMantissaBits,
    162           HeapNumber::kExponentBits);
    163 
    164   // It the exponent is >= 84 (kMantissaBits + 32), the result is always 0 since
    165   // the mantissa gets shifted completely out of the int32_t result.
    166   __ Cmp(exponent, HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 32);
    167   __ CzeroX(result, ge);
    168   __ B(ge, &done);
    169 
    170   // The Fcvtzs sequence handles all cases except where the conversion causes
    171   // signed overflow in the int64_t target. Since we've already handled
    172   // exponents >= 84, we can guarantee that 63 <= exponent < 84.
    173 
    174   if (masm->emit_debug_code()) {
    175     __ Cmp(exponent, HeapNumber::kExponentBias + 63);
    176     // Exponents less than this should have been handled by the Fcvt case.
    177     __ Check(ge, kUnexpectedValue);
    178   }
    179 
    180   // Isolate the mantissa bits, and set the implicit '1'.
    181   Register mantissa = scratch2;
    182   __ Ubfx(mantissa, result, 0, HeapNumber::kMantissaBits);
    183   __ Orr(mantissa, mantissa, 1UL << HeapNumber::kMantissaBits);
    184 
    185   // Negate the mantissa if necessary.
    186   __ Tst(result, kXSignMask);
    187   __ Cneg(mantissa, mantissa, ne);
    188 
    189   // Shift the mantissa bits in the correct place. We know that we have to shift
    190   // it left here, because exponent >= 63 >= kMantissaBits.
    191   __ Sub(exponent, exponent,
    192          HeapNumber::kExponentBias + HeapNumber::kMantissaBits);
    193   __ Lsl(result, mantissa, exponent);
    194 
    195   __ Bind(&done);
    196   if (!skip_fastpath()) {
    197     __ Pop(double_scratch);
    198   }
    199   __ Pop(scratch2, scratch1);
    200   __ Ret();
    201 }
    202 
    203 
    204 // See call site for description.
    205 static void EmitIdenticalObjectComparison(MacroAssembler* masm,
    206                                           Register left,
    207                                           Register right,
    208                                           Register scratch,
    209                                           FPRegister double_scratch,
    210                                           Label* slow,
    211                                           Condition cond) {
    212   DCHECK(!AreAliased(left, right, scratch));
    213   Label not_identical, return_equal, heap_number;
    214   Register result = x0;
    215 
    216   __ Cmp(right, left);
    217   __ B(ne, &not_identical);
    218 
    219   // Test for NaN. Sadly, we can't just compare to factory::nan_value(),
    220   // so we do the second best thing - test it ourselves.
    221   // They are both equal and they are not both Smis so both of them are not
    222   // Smis.  If it's not a heap number, then return equal.
    223   if ((cond == lt) || (cond == gt)) {
    224     __ JumpIfObjectType(right, scratch, scratch, FIRST_SPEC_OBJECT_TYPE, slow,
    225                         ge);
    226   } else if (cond == eq) {
    227     __ JumpIfHeapNumber(right, &heap_number);
    228   } else {
    229     Register right_type = scratch;
    230     __ JumpIfObjectType(right, right_type, right_type, HEAP_NUMBER_TYPE,
    231                         &heap_number);
    232     // Comparing JS objects with <=, >= is complicated.
    233     __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE);
    234     __ B(ge, slow);
    235     // Normally here we fall through to return_equal, but undefined is
    236     // special: (undefined == undefined) == true, but
    237     // (undefined <= undefined) == false!  See ECMAScript 11.8.5.
    238     if ((cond == le) || (cond == ge)) {
    239       __ Cmp(right_type, ODDBALL_TYPE);
    240       __ B(ne, &return_equal);
    241       __ JumpIfNotRoot(right, Heap::kUndefinedValueRootIndex, &return_equal);
    242       if (cond == le) {
    243         // undefined <= undefined should fail.
    244         __ Mov(result, GREATER);
    245       } else {
    246         // undefined >= undefined should fail.
    247         __ Mov(result, LESS);
    248       }
    249       __ Ret();
    250     }
    251   }
    252 
    253   __ Bind(&return_equal);
    254   if (cond == lt) {
    255     __ Mov(result, GREATER);  // Things aren't less than themselves.
    256   } else if (cond == gt) {
    257     __ Mov(result, LESS);     // Things aren't greater than themselves.
    258   } else {
    259     __ Mov(result, EQUAL);    // Things are <=, >=, ==, === themselves.
    260   }
    261   __ Ret();
    262 
    263   // Cases lt and gt have been handled earlier, and case ne is never seen, as
    264   // it is handled in the parser (see Parser::ParseBinaryExpression). We are
    265   // only concerned with cases ge, le and eq here.
    266   if ((cond != lt) && (cond != gt)) {
    267     DCHECK((cond == ge) || (cond == le) || (cond == eq));
    268     __ Bind(&heap_number);
    269     // Left and right are identical pointers to a heap number object. Return
    270     // non-equal if the heap number is a NaN, and equal otherwise. Comparing
    271     // the number to itself will set the overflow flag iff the number is NaN.
    272     __ Ldr(double_scratch, FieldMemOperand(right, HeapNumber::kValueOffset));
    273     __ Fcmp(double_scratch, double_scratch);
    274     __ B(vc, &return_equal);  // Not NaN, so treat as normal heap number.
    275 
    276     if (cond == le) {
    277       __ Mov(result, GREATER);
    278     } else {
    279       __ Mov(result, LESS);
    280     }
    281     __ Ret();
    282   }
    283 
    284   // No fall through here.
    285   if (FLAG_debug_code) {
    286     __ Unreachable();
    287   }
    288 
    289   __ Bind(&not_identical);
    290 }
    291 
    292 
    293 // See call site for description.
    294 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
    295                                            Register left,
    296                                            Register right,
    297                                            Register left_type,
    298                                            Register right_type,
    299                                            Register scratch) {
    300   DCHECK(!AreAliased(left, right, left_type, right_type, scratch));
    301 
    302   if (masm->emit_debug_code()) {
    303     // We assume that the arguments are not identical.
    304     __ Cmp(left, right);
    305     __ Assert(ne, kExpectedNonIdenticalObjects);
    306   }
    307 
    308   // If either operand is a JS object or an oddball value, then they are not
    309   // equal since their pointers are different.
    310   // There is no test for undetectability in strict equality.
    311   STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
    312   Label right_non_object;
    313 
    314   __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE);
    315   __ B(lt, &right_non_object);
    316 
    317   // Return non-zero - x0 already contains a non-zero pointer.
    318   DCHECK(left.is(x0) || right.is(x0));
    319   Label return_not_equal;
    320   __ Bind(&return_not_equal);
    321   __ Ret();
    322 
    323   __ Bind(&right_non_object);
    324 
    325   // Check for oddballs: true, false, null, undefined.
    326   __ Cmp(right_type, ODDBALL_TYPE);
    327 
    328   // If right is not ODDBALL, test left. Otherwise, set eq condition.
    329   __ Ccmp(left_type, ODDBALL_TYPE, ZFlag, ne);
    330 
    331   // If right or left is not ODDBALL, test left >= FIRST_SPEC_OBJECT_TYPE.
    332   // Otherwise, right or left is ODDBALL, so set a ge condition.
    333   __ Ccmp(left_type, FIRST_SPEC_OBJECT_TYPE, NVFlag, ne);
    334 
    335   __ B(ge, &return_not_equal);
    336 
    337   // Internalized strings are unique, so they can only be equal if they are the
    338   // same object. We have already tested that case, so if left and right are
    339   // both internalized strings, they cannot be equal.
    340   STATIC_ASSERT((kInternalizedTag == 0) && (kStringTag == 0));
    341   __ Orr(scratch, left_type, right_type);
    342   __ TestAndBranchIfAllClear(
    343       scratch, kIsNotStringMask | kIsNotInternalizedMask, &return_not_equal);
    344 }
    345 
    346 
    347 // See call site for description.
    348 static void EmitSmiNonsmiComparison(MacroAssembler* masm,
    349                                     Register left,
    350                                     Register right,
    351                                     FPRegister left_d,
    352                                     FPRegister right_d,
    353                                     Label* slow,
    354                                     bool strict) {
    355   DCHECK(!AreAliased(left_d, right_d));
    356   DCHECK((left.is(x0) && right.is(x1)) ||
    357          (right.is(x0) && left.is(x1)));
    358   Register result = x0;
    359 
    360   Label right_is_smi, done;
    361   __ JumpIfSmi(right, &right_is_smi);
    362 
    363   // Left is the smi. Check whether right is a heap number.
    364   if (strict) {
    365     // If right is not a number and left is a smi, then strict equality cannot
    366     // succeed. Return non-equal.
    367     Label is_heap_number;
    368     __ JumpIfHeapNumber(right, &is_heap_number);
    369     // Register right is a non-zero pointer, which is a valid NOT_EQUAL result.
    370     if (!right.is(result)) {
    371       __ Mov(result, NOT_EQUAL);
    372     }
    373     __ Ret();
    374     __ Bind(&is_heap_number);
    375   } else {
    376     // Smi compared non-strictly with a non-smi, non-heap-number. Call the
    377     // runtime.
    378     __ JumpIfNotHeapNumber(right, slow);
    379   }
    380 
    381   // Left is the smi. Right is a heap number. Load right value into right_d, and
    382   // convert left smi into double in left_d.
    383   __ Ldr(right_d, FieldMemOperand(right, HeapNumber::kValueOffset));
    384   __ SmiUntagToDouble(left_d, left);
    385   __ B(&done);
    386 
    387   __ Bind(&right_is_smi);
    388   // Right is a smi. Check whether the non-smi left is a heap number.
    389   if (strict) {
    390     // If left is not a number and right is a smi then strict equality cannot
    391     // succeed. Return non-equal.
    392     Label is_heap_number;
    393     __ JumpIfHeapNumber(left, &is_heap_number);
    394     // Register left is a non-zero pointer, which is a valid NOT_EQUAL result.
    395     if (!left.is(result)) {
    396       __ Mov(result, NOT_EQUAL);
    397     }
    398     __ Ret();
    399     __ Bind(&is_heap_number);
    400   } else {
    401     // Smi compared non-strictly with a non-smi, non-heap-number. Call the
    402     // runtime.
    403     __ JumpIfNotHeapNumber(left, slow);
    404   }
    405 
    406   // Right is the smi. Left is a heap number. Load left value into left_d, and
    407   // convert right smi into double in right_d.
    408   __ Ldr(left_d, FieldMemOperand(left, HeapNumber::kValueOffset));
    409   __ SmiUntagToDouble(right_d, right);
    410 
    411   // Fall through to both_loaded_as_doubles.
    412   __ Bind(&done);
    413 }
    414 
    415 
    416 // Fast negative check for internalized-to-internalized equality.
    417 // See call site for description.
    418 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
    419                                                      Register left,
    420                                                      Register right,
    421                                                      Register left_map,
    422                                                      Register right_map,
    423                                                      Register left_type,
    424                                                      Register right_type,
    425                                                      Label* possible_strings,
    426                                                      Label* not_both_strings) {
    427   DCHECK(!AreAliased(left, right, left_map, right_map, left_type, right_type));
    428   Register result = x0;
    429 
    430   Label object_test;
    431   STATIC_ASSERT((kInternalizedTag == 0) && (kStringTag == 0));
    432   // TODO(all): reexamine this branch sequence for optimisation wrt branch
    433   // prediction.
    434   __ Tbnz(right_type, MaskToBit(kIsNotStringMask), &object_test);
    435   __ Tbnz(right_type, MaskToBit(kIsNotInternalizedMask), possible_strings);
    436   __ Tbnz(left_type, MaskToBit(kIsNotStringMask), not_both_strings);
    437   __ Tbnz(left_type, MaskToBit(kIsNotInternalizedMask), possible_strings);
    438 
    439   // Both are internalized. We already checked that they weren't the same
    440   // pointer, so they are not equal.
    441   __ Mov(result, NOT_EQUAL);
    442   __ Ret();
    443 
    444   __ Bind(&object_test);
    445 
    446   __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE);
    447 
    448   // If right >= FIRST_SPEC_OBJECT_TYPE, test left.
    449   // Otherwise, right < FIRST_SPEC_OBJECT_TYPE, so set lt condition.
    450   __ Ccmp(left_type, FIRST_SPEC_OBJECT_TYPE, NFlag, ge);
    451 
    452   __ B(lt, not_both_strings);
    453 
    454   // If both objects are undetectable, they are equal. Otherwise, they are not
    455   // equal, since they are different objects and an object is not equal to
    456   // undefined.
    457 
    458   // Returning here, so we can corrupt right_type and left_type.
    459   Register right_bitfield = right_type;
    460   Register left_bitfield = left_type;
    461   __ Ldrb(right_bitfield, FieldMemOperand(right_map, Map::kBitFieldOffset));
    462   __ Ldrb(left_bitfield, FieldMemOperand(left_map, Map::kBitFieldOffset));
    463   __ And(result, right_bitfield, left_bitfield);
    464   __ And(result, result, 1 << Map::kIsUndetectable);
    465   __ Eor(result, result, 1 << Map::kIsUndetectable);
    466   __ Ret();
    467 }
    468 
    469 
    470 static void CompareICStub_CheckInputType(MacroAssembler* masm, Register input,
    471                                          CompareICState::State expected,
    472                                          Label* fail) {
    473   Label ok;
    474   if (expected == CompareICState::SMI) {
    475     __ JumpIfNotSmi(input, fail);
    476   } else if (expected == CompareICState::NUMBER) {
    477     __ JumpIfSmi(input, &ok);
    478     __ JumpIfNotHeapNumber(input, fail);
    479   }
    480   // We could be strict about internalized/non-internalized here, but as long as
    481   // hydrogen doesn't care, the stub doesn't have to care either.
    482   __ Bind(&ok);
    483 }
    484 
    485 
    486 void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
    487   Register lhs = x1;
    488   Register rhs = x0;
    489   Register result = x0;
    490   Condition cond = GetCondition();
    491 
    492   Label miss;
    493   CompareICStub_CheckInputType(masm, lhs, left(), &miss);
    494   CompareICStub_CheckInputType(masm, rhs, right(), &miss);
    495 
    496   Label slow;  // Call builtin.
    497   Label not_smis, both_loaded_as_doubles;
    498   Label not_two_smis, smi_done;
    499   __ JumpIfEitherNotSmi(lhs, rhs, &not_two_smis);
    500   __ SmiUntag(lhs);
    501   __ Sub(result, lhs, Operand::UntagSmi(rhs));
    502   __ Ret();
    503 
    504   __ Bind(&not_two_smis);
    505 
    506   // NOTICE! This code is only reached after a smi-fast-case check, so it is
    507   // certain that at least one operand isn't a smi.
    508 
    509   // Handle the case where the objects are identical. Either returns the answer
    510   // or goes to slow. Only falls through if the objects were not identical.
    511   EmitIdenticalObjectComparison(masm, lhs, rhs, x10, d0, &slow, cond);
    512 
    513   // If either is a smi (we know that at least one is not a smi), then they can
    514   // only be strictly equal if the other is a HeapNumber.
    515   __ JumpIfBothNotSmi(lhs, rhs, &not_smis);
    516 
    517   // Exactly one operand is a smi. EmitSmiNonsmiComparison generates code that
    518   // can:
    519   //  1) Return the answer.
    520   //  2) Branch to the slow case.
    521   //  3) Fall through to both_loaded_as_doubles.
    522   // In case 3, we have found out that we were dealing with a number-number
    523   // comparison. The double values of the numbers have been loaded, right into
    524   // rhs_d, left into lhs_d.
    525   FPRegister rhs_d = d0;
    526   FPRegister lhs_d = d1;
    527   EmitSmiNonsmiComparison(masm, lhs, rhs, lhs_d, rhs_d, &slow, strict());
    528 
    529   __ Bind(&both_loaded_as_doubles);
    530   // The arguments have been converted to doubles and stored in rhs_d and
    531   // lhs_d.
    532   Label nan;
    533   __ Fcmp(lhs_d, rhs_d);
    534   __ B(vs, &nan);  // Overflow flag set if either is NaN.
    535   STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1));
    536   __ Cset(result, gt);  // gt => 1, otherwise (lt, eq) => 0 (EQUAL).
    537   __ Csinv(result, result, xzr, ge);  // lt => -1, gt => 1, eq => 0.
    538   __ Ret();
    539 
    540   __ Bind(&nan);
    541   // Left and/or right is a NaN. Load the result register with whatever makes
    542   // the comparison fail, since comparisons with NaN always fail (except ne,
    543   // which is filtered out at a higher level.)
    544   DCHECK(cond != ne);
    545   if ((cond == lt) || (cond == le)) {
    546     __ Mov(result, GREATER);
    547   } else {
    548     __ Mov(result, LESS);
    549   }
    550   __ Ret();
    551 
    552   __ Bind(&not_smis);
    553   // At this point we know we are dealing with two different objects, and
    554   // neither of them is a smi. The objects are in rhs_ and lhs_.
    555 
    556   // Load the maps and types of the objects.
    557   Register rhs_map = x10;
    558   Register rhs_type = x11;
    559   Register lhs_map = x12;
    560   Register lhs_type = x13;
    561   __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset));
    562   __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset));
    563   __ Ldrb(rhs_type, FieldMemOperand(rhs_map, Map::kInstanceTypeOffset));
    564   __ Ldrb(lhs_type, FieldMemOperand(lhs_map, Map::kInstanceTypeOffset));
    565 
    566   if (strict()) {
    567     // This emits a non-equal return sequence for some object types, or falls
    568     // through if it was not lucky.
    569     EmitStrictTwoHeapObjectCompare(masm, lhs, rhs, lhs_type, rhs_type, x14);
    570   }
    571 
    572   Label check_for_internalized_strings;
    573   Label flat_string_check;
    574   // Check for heap number comparison. Branch to earlier double comparison code
    575   // if they are heap numbers, otherwise, branch to internalized string check.
    576   __ Cmp(rhs_type, HEAP_NUMBER_TYPE);
    577   __ B(ne, &check_for_internalized_strings);
    578   __ Cmp(lhs_map, rhs_map);
    579 
    580   // If maps aren't equal, lhs_ and rhs_ are not heap numbers. Branch to flat
    581   // string check.
    582   __ B(ne, &flat_string_check);
    583 
    584   // Both lhs_ and rhs_ are heap numbers. Load them and branch to the double
    585   // comparison code.
    586   __ Ldr(lhs_d, FieldMemOperand(lhs, HeapNumber::kValueOffset));
    587   __ Ldr(rhs_d, FieldMemOperand(rhs, HeapNumber::kValueOffset));
    588   __ B(&both_loaded_as_doubles);
    589 
    590   __ Bind(&check_for_internalized_strings);
    591   // In the strict case, the EmitStrictTwoHeapObjectCompare already took care
    592   // of internalized strings.
    593   if ((cond == eq) && !strict()) {
    594     // Returns an answer for two internalized strings or two detectable objects.
    595     // Otherwise branches to the string case or not both strings case.
    596     EmitCheckForInternalizedStringsOrObjects(masm, lhs, rhs, lhs_map, rhs_map,
    597                                              lhs_type, rhs_type,
    598                                              &flat_string_check, &slow);
    599   }
    600 
    601   // Check for both being sequential one-byte strings,
    602   // and inline if that is the case.
    603   __ Bind(&flat_string_check);
    604   __ JumpIfBothInstanceTypesAreNotSequentialOneByte(lhs_type, rhs_type, x14,
    605                                                     x15, &slow);
    606 
    607   __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, x10,
    608                       x11);
    609   if (cond == eq) {
    610     StringHelper::GenerateFlatOneByteStringEquals(masm, lhs, rhs, x10, x11,
    611                                                   x12);
    612   } else {
    613     StringHelper::GenerateCompareFlatOneByteStrings(masm, lhs, rhs, x10, x11,
    614                                                     x12, x13);
    615   }
    616 
    617   // Never fall through to here.
    618   if (FLAG_debug_code) {
    619     __ Unreachable();
    620   }
    621 
    622   __ Bind(&slow);
    623 
    624   __ Push(lhs, rhs);
    625   // Figure out which native to call and setup the arguments.
    626   Builtins::JavaScript native;
    627   if (cond == eq) {
    628     native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
    629   } else {
    630     native = Builtins::COMPARE;
    631     int ncr;  // NaN compare result
    632     if ((cond == lt) || (cond == le)) {
    633       ncr = GREATER;
    634     } else {
    635       DCHECK((cond == gt) || (cond == ge));  // remaining cases
    636       ncr = LESS;
    637     }
    638     __ Mov(x10, Smi::FromInt(ncr));
    639     __ Push(x10);
    640   }
    641 
    642   // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
    643   // tagged as a small integer.
    644   __ InvokeBuiltin(native, JUMP_FUNCTION);
    645 
    646   __ Bind(&miss);
    647   GenerateMiss(masm);
    648 }
    649 
    650 
    651 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
    652   CPURegList saved_regs = kCallerSaved;
    653   CPURegList saved_fp_regs = kCallerSavedFP;
    654 
    655   // We don't allow a GC during a store buffer overflow so there is no need to
    656   // store the registers in any particular way, but we do have to store and
    657   // restore them.
    658 
    659   // We don't care if MacroAssembler scratch registers are corrupted.
    660   saved_regs.Remove(*(masm->TmpList()));
    661   saved_fp_regs.Remove(*(masm->FPTmpList()));
    662 
    663   __ PushCPURegList(saved_regs);
    664   if (save_doubles()) {
    665     __ PushCPURegList(saved_fp_regs);
    666   }
    667 
    668   AllowExternalCallThatCantCauseGC scope(masm);
    669   __ Mov(x0, ExternalReference::isolate_address(isolate()));
    670   __ CallCFunction(
    671       ExternalReference::store_buffer_overflow_function(isolate()), 1, 0);
    672 
    673   if (save_doubles()) {
    674     __ PopCPURegList(saved_fp_regs);
    675   }
    676   __ PopCPURegList(saved_regs);
    677   __ Ret();
    678 }
    679 
    680 
    681 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
    682     Isolate* isolate) {
    683   StoreBufferOverflowStub stub1(isolate, kDontSaveFPRegs);
    684   stub1.GetCode();
    685   StoreBufferOverflowStub stub2(isolate, kSaveFPRegs);
    686   stub2.GetCode();
    687 }
    688 
    689 
    690 void StoreRegistersStateStub::Generate(MacroAssembler* masm) {
    691   MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm);
    692   UseScratchRegisterScope temps(masm);
    693   Register saved_lr = temps.UnsafeAcquire(to_be_pushed_lr());
    694   Register return_address = temps.AcquireX();
    695   __ Mov(return_address, lr);
    696   // Restore lr with the value it had before the call to this stub (the value
    697   // which must be pushed).
    698   __ Mov(lr, saved_lr);
    699   __ PushSafepointRegisters();
    700   __ Ret(return_address);
    701 }
    702 
    703 
    704 void RestoreRegistersStateStub::Generate(MacroAssembler* masm) {
    705   MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm);
    706   UseScratchRegisterScope temps(masm);
    707   Register return_address = temps.AcquireX();
    708   // Preserve the return address (lr will be clobbered by the pop).
    709   __ Mov(return_address, lr);
    710   __ PopSafepointRegisters();
    711   __ Ret(return_address);
    712 }
    713 
    714 
    715 void MathPowStub::Generate(MacroAssembler* masm) {
    716   // Stack on entry:
    717   // jssp[0]: Exponent (as a tagged value).
    718   // jssp[1]: Base (as a tagged value).
    719   //
    720   // The (tagged) result will be returned in x0, as a heap number.
    721 
    722   Register result_tagged = x0;
    723   Register base_tagged = x10;
    724   Register exponent_tagged = MathPowTaggedDescriptor::exponent();
    725   DCHECK(exponent_tagged.is(x11));
    726   Register exponent_integer = MathPowIntegerDescriptor::exponent();
    727   DCHECK(exponent_integer.is(x12));
    728   Register scratch1 = x14;
    729   Register scratch0 = x15;
    730   Register saved_lr = x19;
    731   FPRegister result_double = d0;
    732   FPRegister base_double = d0;
    733   FPRegister exponent_double = d1;
    734   FPRegister base_double_copy = d2;
    735   FPRegister scratch1_double = d6;
    736   FPRegister scratch0_double = d7;
    737 
    738   // A fast-path for integer exponents.
    739   Label exponent_is_smi, exponent_is_integer;
    740   // Bail out to runtime.
    741   Label call_runtime;
    742   // Allocate a heap number for the result, and return it.
    743   Label done;
    744 
    745   // Unpack the inputs.
    746   if (exponent_type() == ON_STACK) {
    747     Label base_is_smi;
    748     Label unpack_exponent;
    749 
    750     __ Pop(exponent_tagged, base_tagged);
    751 
    752     __ JumpIfSmi(base_tagged, &base_is_smi);
    753     __ JumpIfNotHeapNumber(base_tagged, &call_runtime);
    754     // base_tagged is a heap number, so load its double value.
    755     __ Ldr(base_double, FieldMemOperand(base_tagged, HeapNumber::kValueOffset));
    756     __ B(&unpack_exponent);
    757     __ Bind(&base_is_smi);
    758     // base_tagged is a SMI, so untag it and convert it to a double.
    759     __ SmiUntagToDouble(base_double, base_tagged);
    760 
    761     __ Bind(&unpack_exponent);
    762     //  x10   base_tagged       The tagged base (input).
    763     //  x11   exponent_tagged   The tagged exponent (input).
    764     //  d1    base_double       The base as a double.
    765     __ JumpIfSmi(exponent_tagged, &exponent_is_smi);
    766     __ JumpIfNotHeapNumber(exponent_tagged, &call_runtime);
    767     // exponent_tagged is a heap number, so load its double value.
    768     __ Ldr(exponent_double,
    769            FieldMemOperand(exponent_tagged, HeapNumber::kValueOffset));
    770   } else if (exponent_type() == TAGGED) {
    771     __ JumpIfSmi(exponent_tagged, &exponent_is_smi);
    772     __ Ldr(exponent_double,
    773            FieldMemOperand(exponent_tagged, HeapNumber::kValueOffset));
    774   }
    775 
    776   // Handle double (heap number) exponents.
    777   if (exponent_type() != INTEGER) {
    778     // Detect integer exponents stored as doubles and handle those in the
    779     // integer fast-path.
    780     __ TryRepresentDoubleAsInt64(exponent_integer, exponent_double,
    781                                  scratch0_double, &exponent_is_integer);
    782 
    783     if (exponent_type() == ON_STACK) {
    784       FPRegister  half_double = d3;
    785       FPRegister  minus_half_double = d4;
    786       // Detect square root case. Crankshaft detects constant +/-0.5 at compile
    787       // time and uses DoMathPowHalf instead. We then skip this check for
    788       // non-constant cases of +/-0.5 as these hardly occur.
    789 
    790       __ Fmov(minus_half_double, -0.5);
    791       __ Fmov(half_double, 0.5);
    792       __ Fcmp(minus_half_double, exponent_double);
    793       __ Fccmp(half_double, exponent_double, NZFlag, ne);
    794       // Condition flags at this point:
    795       //    0.5;  nZCv    // Identified by eq && pl
    796       //   -0.5:  NZcv    // Identified by eq && mi
    797       //  other:  ?z??    // Identified by ne
    798       __ B(ne, &call_runtime);
    799 
    800       // The exponent is 0.5 or -0.5.
    801 
    802       // Given that exponent is known to be either 0.5 or -0.5, the following
    803       // special cases could apply (according to ECMA-262 15.8.2.13):
    804       //
    805       //  base.isNaN():                   The result is NaN.
    806       //  (base == +INFINITY) || (base == -INFINITY)
    807       //    exponent == 0.5:              The result is +INFINITY.
    808       //    exponent == -0.5:             The result is +0.
    809       //  (base == +0) || (base == -0)
    810       //    exponent == 0.5:              The result is +0.
    811       //    exponent == -0.5:             The result is +INFINITY.
    812       //  (base < 0) && base.isFinite():  The result is NaN.
    813       //
    814       // Fsqrt (and Fdiv for the -0.5 case) can handle all of those except
    815       // where base is -INFINITY or -0.
    816 
    817       // Add +0 to base. This has no effect other than turning -0 into +0.
    818       __ Fadd(base_double, base_double, fp_zero);
    819       // The operation -0+0 results in +0 in all cases except where the
    820       // FPCR rounding mode is 'round towards minus infinity' (RM). The
    821       // ARM64 simulator does not currently simulate FPCR (where the rounding
    822       // mode is set), so test the operation with some debug code.
    823       if (masm->emit_debug_code()) {
    824         UseScratchRegisterScope temps(masm);
    825         Register temp = temps.AcquireX();
    826         __ Fneg(scratch0_double, fp_zero);
    827         // Verify that we correctly generated +0.0 and -0.0.
    828         //  bits(+0.0) = 0x0000000000000000
    829         //  bits(-0.0) = 0x8000000000000000
    830         __ Fmov(temp, fp_zero);
    831         __ CheckRegisterIsClear(temp, kCouldNotGenerateZero);
    832         __ Fmov(temp, scratch0_double);
    833         __ Eor(temp, temp, kDSignMask);
    834         __ CheckRegisterIsClear(temp, kCouldNotGenerateNegativeZero);
    835         // Check that -0.0 + 0.0 == +0.0.
    836         __ Fadd(scratch0_double, scratch0_double, fp_zero);
    837         __ Fmov(temp, scratch0_double);
    838         __ CheckRegisterIsClear(temp, kExpectedPositiveZero);
    839       }
    840 
    841       // If base is -INFINITY, make it +INFINITY.
    842       //  * Calculate base - base: All infinities will become NaNs since both
    843       //    -INFINITY+INFINITY and +INFINITY-INFINITY are NaN in ARM64.
    844       //  * If the result is NaN, calculate abs(base).
    845       __ Fsub(scratch0_double, base_double, base_double);
    846       __ Fcmp(scratch0_double, 0.0);
    847       __ Fabs(scratch1_double, base_double);
    848       __ Fcsel(base_double, scratch1_double, base_double, vs);
    849 
    850       // Calculate the square root of base.
    851       __ Fsqrt(result_double, base_double);
    852       __ Fcmp(exponent_double, 0.0);
    853       __ B(ge, &done);  // Finish now for exponents of 0.5.
    854       // Find the inverse for exponents of -0.5.
    855       __ Fmov(scratch0_double, 1.0);
    856       __ Fdiv(result_double, scratch0_double, result_double);
    857       __ B(&done);
    858     }
    859 
    860     {
    861       AllowExternalCallThatCantCauseGC scope(masm);
    862       __ Mov(saved_lr, lr);
    863       __ CallCFunction(
    864           ExternalReference::power_double_double_function(isolate()),
    865           0, 2);
    866       __ Mov(lr, saved_lr);
    867       __ B(&done);
    868     }
    869 
    870     // Handle SMI exponents.
    871     __ Bind(&exponent_is_smi);
    872     //  x10   base_tagged       The tagged base (input).
    873     //  x11   exponent_tagged   The tagged exponent (input).
    874     //  d1    base_double       The base as a double.
    875     __ SmiUntag(exponent_integer, exponent_tagged);
    876   }
    877 
    878   __ Bind(&exponent_is_integer);
    879   //  x10   base_tagged       The tagged base (input).
    880   //  x11   exponent_tagged   The tagged exponent (input).
    881   //  x12   exponent_integer  The exponent as an integer.
    882   //  d1    base_double       The base as a double.
    883 
    884   // Find abs(exponent). For negative exponents, we can find the inverse later.
    885   Register exponent_abs = x13;
    886   __ Cmp(exponent_integer, 0);
    887   __ Cneg(exponent_abs, exponent_integer, mi);
    888   //  x13   exponent_abs      The value of abs(exponent_integer).
    889 
    890   // Repeatedly multiply to calculate the power.
    891   //  result = 1.0;
    892   //  For each bit n (exponent_integer{n}) {
    893   //    if (exponent_integer{n}) {
    894   //      result *= base;
    895   //    }
    896   //    base *= base;
    897   //    if (remaining bits in exponent_integer are all zero) {
    898   //      break;
    899   //    }
    900   //  }
    901   Label power_loop, power_loop_entry, power_loop_exit;
    902   __ Fmov(scratch1_double, base_double);
    903   __ Fmov(base_double_copy, base_double);
    904   __ Fmov(result_double, 1.0);
    905   __ B(&power_loop_entry);
    906 
    907   __ Bind(&power_loop);
    908   __ Fmul(scratch1_double, scratch1_double, scratch1_double);
    909   __ Lsr(exponent_abs, exponent_abs, 1);
    910   __ Cbz(exponent_abs, &power_loop_exit);
    911 
    912   __ Bind(&power_loop_entry);
    913   __ Tbz(exponent_abs, 0, &power_loop);
    914   __ Fmul(result_double, result_double, scratch1_double);
    915   __ B(&power_loop);
    916 
    917   __ Bind(&power_loop_exit);
    918 
    919   // If the exponent was positive, result_double holds the result.
    920   __ Tbz(exponent_integer, kXSignBit, &done);
    921 
    922   // The exponent was negative, so find the inverse.
    923   __ Fmov(scratch0_double, 1.0);
    924   __ Fdiv(result_double, scratch0_double, result_double);
    925   // ECMA-262 only requires Math.pow to return an 'implementation-dependent
    926   // approximation' of base^exponent. However, mjsunit/math-pow uses Math.pow
    927   // to calculate the subnormal value 2^-1074. This method of calculating
    928   // negative powers doesn't work because 2^1074 overflows to infinity. To
    929   // catch this corner-case, we bail out if the result was 0. (This can only
    930   // occur if the divisor is infinity or the base is zero.)
    931   __ Fcmp(result_double, 0.0);
    932   __ B(&done, ne);
    933 
    934   if (exponent_type() == ON_STACK) {
    935     // Bail out to runtime code.
    936     __ Bind(&call_runtime);
    937     // Put the arguments back on the stack.
    938     __ Push(base_tagged, exponent_tagged);
    939     __ TailCallRuntime(Runtime::kMathPowRT, 2, 1);
    940 
    941     // Return.
    942     __ Bind(&done);
    943     __ AllocateHeapNumber(result_tagged, &call_runtime, scratch0, scratch1,
    944                           result_double);
    945     DCHECK(result_tagged.is(x0));
    946     __ IncrementCounter(
    947         isolate()->counters()->math_pow(), 1, scratch0, scratch1);
    948     __ Ret();
    949   } else {
    950     AllowExternalCallThatCantCauseGC scope(masm);
    951     __ Mov(saved_lr, lr);
    952     __ Fmov(base_double, base_double_copy);
    953     __ Scvtf(exponent_double, exponent_integer);
    954     __ CallCFunction(
    955         ExternalReference::power_double_double_function(isolate()),
    956         0, 2);
    957     __ Mov(lr, saved_lr);
    958     __ Bind(&done);
    959     __ IncrementCounter(
    960         isolate()->counters()->math_pow(), 1, scratch0, scratch1);
    961     __ Ret();
    962   }
    963 }
    964 
    965 
    966 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
    967   // It is important that the following stubs are generated in this order
    968   // because pregenerated stubs can only call other pregenerated stubs.
    969   // RecordWriteStub uses StoreBufferOverflowStub, which in turn uses
    970   // CEntryStub.
    971   CEntryStub::GenerateAheadOfTime(isolate);
    972   StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
    973   StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
    974   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
    975   CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
    976   BinaryOpICStub::GenerateAheadOfTime(isolate);
    977   StoreRegistersStateStub::GenerateAheadOfTime(isolate);
    978   RestoreRegistersStateStub::GenerateAheadOfTime(isolate);
    979   BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
    980 }
    981 
    982 
    983 void StoreRegistersStateStub::GenerateAheadOfTime(Isolate* isolate) {
    984   StoreRegistersStateStub stub(isolate);
    985   stub.GetCode();
    986 }
    987 
    988 
    989 void RestoreRegistersStateStub::GenerateAheadOfTime(Isolate* isolate) {
    990   RestoreRegistersStateStub stub(isolate);
    991   stub.GetCode();
    992 }
    993 
    994 
    995 void CodeStub::GenerateFPStubs(Isolate* isolate) {
    996   // Floating-point code doesn't get special handling in ARM64, so there's
    997   // nothing to do here.
    998   USE(isolate);
    999 }
   1000 
   1001 
   1002 bool CEntryStub::NeedsImmovableCode() {
   1003   // CEntryStub stores the return address on the stack before calling into
   1004   // C++ code. In some cases, the VM accesses this address, but it is not used
   1005   // when the C++ code returns to the stub because LR holds the return address
   1006   // in AAPCS64. If the stub is moved (perhaps during a GC), we could end up
   1007   // returning to dead code.
   1008   // TODO(jbramley): Whilst this is the only analysis that makes sense, I can't
   1009   // find any comment to confirm this, and I don't hit any crashes whatever
   1010   // this function returns. The anaylsis should be properly confirmed.
   1011   return true;
   1012 }
   1013 
   1014 
   1015 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
   1016   CEntryStub stub(isolate, 1, kDontSaveFPRegs);
   1017   stub.GetCode();
   1018   CEntryStub stub_fp(isolate, 1, kSaveFPRegs);
   1019   stub_fp.GetCode();
   1020 }
   1021 
   1022 
   1023 void CEntryStub::Generate(MacroAssembler* masm) {
   1024   // The Abort mechanism relies on CallRuntime, which in turn relies on
   1025   // CEntryStub, so until this stub has been generated, we have to use a
   1026   // fall-back Abort mechanism.
   1027   //
   1028   // Note that this stub must be generated before any use of Abort.
   1029   MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm);
   1030 
   1031   ASM_LOCATION("CEntryStub::Generate entry");
   1032   ProfileEntryHookStub::MaybeCallEntryHook(masm);
   1033 
   1034   // Register parameters:
   1035   //    x0: argc (including receiver, untagged)
   1036   //    x1: target
   1037   //
   1038   // The stack on entry holds the arguments and the receiver, with the receiver
   1039   // at the highest address:
   1040   //
   1041   //    jssp]argc-1]: receiver
   1042   //    jssp[argc-2]: arg[argc-2]
   1043   //    ...           ...
   1044   //    jssp[1]:      arg[1]
   1045   //    jssp[0]:      arg[0]
   1046   //
   1047   // The arguments are in reverse order, so that arg[argc-2] is actually the
   1048   // first argument to the target function and arg[0] is the last.
   1049   DCHECK(jssp.Is(__ StackPointer()));
   1050   const Register& argc_input = x0;
   1051   const Register& target_input = x1;
   1052 
   1053   // Calculate argv, argc and the target address, and store them in
   1054   // callee-saved registers so we can retry the call without having to reload
   1055   // these arguments.
   1056   // TODO(jbramley): If the first call attempt succeeds in the common case (as
   1057   // it should), then we might be better off putting these parameters directly
   1058   // into their argument registers, rather than using callee-saved registers and
   1059   // preserving them on the stack.
   1060   const Register& argv = x21;
   1061   const Register& argc = x22;
   1062   const Register& target = x23;
   1063 
   1064   // Derive argv from the stack pointer so that it points to the first argument
   1065   // (arg[argc-2]), or just below the receiver in case there are no arguments.
   1066   //  - Adjust for the arg[] array.
   1067   Register temp_argv = x11;
   1068   __ Add(temp_argv, jssp, Operand(x0, LSL, kPointerSizeLog2));
   1069   //  - Adjust for the receiver.
   1070   __ Sub(temp_argv, temp_argv, 1 * kPointerSize);
   1071 
   1072   // Enter the exit frame. Reserve three slots to preserve x21-x23 callee-saved
   1073   // registers.
   1074   FrameScope scope(masm, StackFrame::MANUAL);
   1075   __ EnterExitFrame(save_doubles(), x10, 3);
   1076   DCHECK(csp.Is(__ StackPointer()));
   1077 
   1078   // Poke callee-saved registers into reserved space.
   1079   __ Poke(argv, 1 * kPointerSize);
   1080   __ Poke(argc, 2 * kPointerSize);
   1081   __ Poke(target, 3 * kPointerSize);
   1082 
   1083   // We normally only keep tagged values in callee-saved registers, as they
   1084   // could be pushed onto the stack by called stubs and functions, and on the
   1085   // stack they can confuse the GC. However, we're only calling C functions
   1086   // which can push arbitrary data onto the stack anyway, and so the GC won't
   1087   // examine that part of the stack.
   1088   __ Mov(argc, argc_input);
   1089   __ Mov(target, target_input);
   1090   __ Mov(argv, temp_argv);
   1091 
   1092   // x21 : argv
   1093   // x22 : argc
   1094   // x23 : call target
   1095   //
   1096   // The stack (on entry) holds the arguments and the receiver, with the
   1097   // receiver at the highest address:
   1098   //
   1099   //         argv[8]:     receiver
   1100   // argv -> argv[0]:     arg[argc-2]
   1101   //         ...          ...
   1102   //         argv[...]:   arg[1]
   1103   //         argv[...]:   arg[0]
   1104   //
   1105   // Immediately below (after) this is the exit frame, as constructed by
   1106   // EnterExitFrame:
   1107   //         fp[8]:    CallerPC (lr)
   1108   //   fp -> fp[0]:    CallerFP (old fp)
   1109   //         fp[-8]:   Space reserved for SPOffset.
   1110   //         fp[-16]:  CodeObject()
   1111   //         csp[...]: Saved doubles, if saved_doubles is true.
   1112   //         csp[32]:  Alignment padding, if necessary.
   1113   //         csp[24]:  Preserved x23 (used for target).
   1114   //         csp[16]:  Preserved x22 (used for argc).
   1115   //         csp[8]:   Preserved x21 (used for argv).
   1116   //  csp -> csp[0]:   Space reserved for the return address.
   1117   //
   1118   // After a successful call, the exit frame, preserved registers (x21-x23) and
   1119   // the arguments (including the receiver) are dropped or popped as
   1120   // appropriate. The stub then returns.
   1121   //
   1122   // After an unsuccessful call, the exit frame and suchlike are left
   1123   // untouched, and the stub either throws an exception by jumping to one of
   1124   // the exception_returned label.
   1125 
   1126   DCHECK(csp.Is(__ StackPointer()));
   1127 
   1128   // Prepare AAPCS64 arguments to pass to the builtin.
   1129   __ Mov(x0, argc);
   1130   __ Mov(x1, argv);
   1131   __ Mov(x2, ExternalReference::isolate_address(isolate()));
   1132 
   1133   Label return_location;
   1134   __ Adr(x12, &return_location);
   1135   __ Poke(x12, 0);
   1136 
   1137   if (__ emit_debug_code()) {
   1138     // Verify that the slot below fp[kSPOffset]-8 points to the return location
   1139     // (currently in x12).
   1140     UseScratchRegisterScope temps(masm);
   1141     Register temp = temps.AcquireX();
   1142     __ Ldr(temp, MemOperand(fp, ExitFrameConstants::kSPOffset));
   1143     __ Ldr(temp, MemOperand(temp, -static_cast<int64_t>(kXRegSize)));
   1144     __ Cmp(temp, x12);
   1145     __ Check(eq, kReturnAddressNotFoundInFrame);
   1146   }
   1147 
   1148   // Call the builtin.
   1149   __ Blr(target);
   1150   __ Bind(&return_location);
   1151 
   1152   //  x0    result      The return code from the call.
   1153   //  x21   argv
   1154   //  x22   argc
   1155   //  x23   target
   1156   const Register& result = x0;
   1157 
   1158   // Check result for exception sentinel.
   1159   Label exception_returned;
   1160   __ CompareRoot(result, Heap::kExceptionRootIndex);
   1161   __ B(eq, &exception_returned);
   1162 
   1163   // The call succeeded, so unwind the stack and return.
   1164 
   1165   // Restore callee-saved registers x21-x23.
   1166   __ Mov(x11, argc);
   1167 
   1168   __ Peek(argv, 1 * kPointerSize);
   1169   __ Peek(argc, 2 * kPointerSize);
   1170   __ Peek(target, 3 * kPointerSize);
   1171 
   1172   __ LeaveExitFrame(save_doubles(), x10, true);
   1173   DCHECK(jssp.Is(__ StackPointer()));
   1174   // Pop or drop the remaining stack slots and return from the stub.
   1175   //         jssp[24]:    Arguments array (of size argc), including receiver.
   1176   //         jssp[16]:    Preserved x23 (used for target).
   1177   //         jssp[8]:     Preserved x22 (used for argc).
   1178   //         jssp[0]:     Preserved x21 (used for argv).
   1179   __ Drop(x11);
   1180   __ AssertFPCRState();
   1181   __ Ret();
   1182 
   1183   // The stack pointer is still csp if we aren't returning, and the frame
   1184   // hasn't changed (except for the return address).
   1185   __ SetStackPointer(csp);
   1186 
   1187   // Handling of exception.
   1188   __ Bind(&exception_returned);
   1189 
   1190   // Retrieve the pending exception.
   1191   ExternalReference pending_exception_address(
   1192       Isolate::kPendingExceptionAddress, isolate());
   1193   const Register& exception = result;
   1194   const Register& exception_address = x11;
   1195   __ Mov(exception_address, Operand(pending_exception_address));
   1196   __ Ldr(exception, MemOperand(exception_address));
   1197 
   1198   // Clear the pending exception.
   1199   __ Mov(x10, Operand(isolate()->factory()->the_hole_value()));
   1200   __ Str(x10, MemOperand(exception_address));
   1201 
   1202   //  x0    exception   The exception descriptor.
   1203   //  x21   argv
   1204   //  x22   argc
   1205   //  x23   target
   1206 
   1207   // Special handling of termination exceptions, which are uncatchable by
   1208   // JavaScript code.
   1209   Label throw_termination_exception;
   1210   __ Cmp(exception, Operand(isolate()->factory()->termination_exception()));
   1211   __ B(eq, &throw_termination_exception);
   1212 
   1213   // We didn't execute a return case, so the stack frame hasn't been updated
   1214   // (except for the return address slot). However, we don't need to initialize
   1215   // jssp because the throw method will immediately overwrite it when it
   1216   // unwinds the stack.
   1217   __ SetStackPointer(jssp);
   1218 
   1219   ASM_LOCATION("Throw normal");
   1220   __ Mov(argv, 0);
   1221   __ Mov(argc, 0);
   1222   __ Mov(target, 0);
   1223   __ Throw(x0, x10, x11, x12, x13);
   1224 
   1225   __ Bind(&throw_termination_exception);
   1226   ASM_LOCATION("Throw termination");
   1227   __ Mov(argv, 0);
   1228   __ Mov(argc, 0);
   1229   __ Mov(target, 0);
   1230   __ ThrowUncatchable(x0, x10, x11, x12, x13);
   1231 }
   1232 
   1233 
   1234 // This is the entry point from C++. 5 arguments are provided in x0-x4.
   1235 // See use of the CALL_GENERATED_CODE macro for example in src/execution.cc.
   1236 // Input:
   1237 //   x0: code entry.
   1238 //   x1: function.
   1239 //   x2: receiver.
   1240 //   x3: argc.
   1241 //   x4: argv.
   1242 // Output:
   1243 //   x0: result.
   1244 void JSEntryStub::Generate(MacroAssembler* masm) {
   1245   DCHECK(jssp.Is(__ StackPointer()));
   1246   Register code_entry = x0;
   1247 
   1248   // Enable instruction instrumentation. This only works on the simulator, and
   1249   // will have no effect on the model or real hardware.
   1250   __ EnableInstrumentation();
   1251 
   1252   Label invoke, handler_entry, exit;
   1253 
   1254   // Push callee-saved registers and synchronize the system stack pointer (csp)
   1255   // and the JavaScript stack pointer (jssp).
   1256   //
   1257   // We must not write to jssp until after the PushCalleeSavedRegisters()
   1258   // call, since jssp is itself a callee-saved register.
   1259   __ SetStackPointer(csp);
   1260   __ PushCalleeSavedRegisters();
   1261   __ Mov(jssp, csp);
   1262   __ SetStackPointer(jssp);
   1263 
   1264   // Configure the FPCR. We don't restore it, so this is technically not allowed
   1265   // according to AAPCS64. However, we only set default-NaN mode and this will
   1266   // be harmless for most C code. Also, it works for ARM.
   1267   __ ConfigureFPCR();
   1268 
   1269   ProfileEntryHookStub::MaybeCallEntryHook(masm);
   1270 
   1271   // Set up the reserved register for 0.0.
   1272   __ Fmov(fp_zero, 0.0);
   1273 
   1274   // Build an entry frame (see layout below).
   1275   int marker = type();
   1276   int64_t bad_frame_pointer = -1L;  // Bad frame pointer to fail if it is used.
   1277   __ Mov(x13, bad_frame_pointer);
   1278   __ Mov(x12, Smi::FromInt(marker));
   1279   __ Mov(x11, ExternalReference(Isolate::kCEntryFPAddress, isolate()));
   1280   __ Ldr(x10, MemOperand(x11));
   1281 
   1282   __ Push(x13, xzr, x12, x10);
   1283   // Set up fp.
   1284   __ Sub(fp, jssp, EntryFrameConstants::kCallerFPOffset);
   1285 
   1286   // Push the JS entry frame marker. Also set js_entry_sp if this is the
   1287   // outermost JS call.
   1288   Label non_outermost_js, done;
   1289   ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate());
   1290   __ Mov(x10, ExternalReference(js_entry_sp));
   1291   __ Ldr(x11, MemOperand(x10));
   1292   __ Cbnz(x11, &non_outermost_js);
   1293   __ Str(fp, MemOperand(x10));
   1294   __ Mov(x12, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME));
   1295   __ Push(x12);
   1296   __ B(&done);
   1297   __ Bind(&non_outermost_js);
   1298   // We spare one instruction by pushing xzr since the marker is 0.
   1299   DCHECK(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME) == NULL);
   1300   __ Push(xzr);
   1301   __ Bind(&done);
   1302 
   1303   // The frame set up looks like this:
   1304   // jssp[0] : JS entry frame marker.
   1305   // jssp[1] : C entry FP.
   1306   // jssp[2] : stack frame marker.
   1307   // jssp[3] : stack frmae marker.
   1308   // jssp[4] : bad frame pointer 0xfff...ff   <- fp points here.
   1309 
   1310 
   1311   // Jump to a faked try block that does the invoke, with a faked catch
   1312   // block that sets the pending exception.
   1313   __ B(&invoke);
   1314 
   1315   // Prevent the constant pool from being emitted between the record of the
   1316   // handler_entry position and the first instruction of the sequence here.
   1317   // There is no risk because Assembler::Emit() emits the instruction before
   1318   // checking for constant pool emission, but we do not want to depend on
   1319   // that.
   1320   {
   1321     Assembler::BlockPoolsScope block_pools(masm);
   1322     __ bind(&handler_entry);
   1323     handler_offset_ = handler_entry.pos();
   1324     // Caught exception: Store result (exception) in the pending exception
   1325     // field in the JSEnv and return a failure sentinel. Coming in here the
   1326     // fp will be invalid because the PushTryHandler below sets it to 0 to
   1327     // signal the existence of the JSEntry frame.
   1328     __ Mov(x10, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
   1329                                           isolate())));
   1330   }
   1331   __ Str(code_entry, MemOperand(x10));
   1332   __ LoadRoot(x0, Heap::kExceptionRootIndex);
   1333   __ B(&exit);
   1334 
   1335   // Invoke: Link this frame into the handler chain.  There's only one
   1336   // handler block in this code object, so its index is 0.
   1337   __ Bind(&invoke);
   1338   __ PushTryHandler(StackHandler::JS_ENTRY, 0);
   1339   // If an exception not caught by another handler occurs, this handler
   1340   // returns control to the code after the B(&invoke) above, which
   1341   // restores all callee-saved registers (including cp and fp) to their
   1342   // saved values before returning a failure to C.
   1343 
   1344   // Clear any pending exceptions.
   1345   __ Mov(x10, Operand(isolate()->factory()->the_hole_value()));
   1346   __ Mov(x11, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
   1347                                         isolate())));
   1348   __ Str(x10, MemOperand(x11));
   1349 
   1350   // Invoke the function by calling through the JS entry trampoline builtin.
   1351   // Notice that we cannot store a reference to the trampoline code directly in
   1352   // this stub, because runtime stubs are not traversed when doing GC.
   1353 
   1354   // Expected registers by Builtins::JSEntryTrampoline
   1355   // x0: code entry.
   1356   // x1: function.
   1357   // x2: receiver.
   1358   // x3: argc.
   1359   // x4: argv.
   1360   ExternalReference entry(type() == StackFrame::ENTRY_CONSTRUCT
   1361                               ? Builtins::kJSConstructEntryTrampoline
   1362                               : Builtins::kJSEntryTrampoline,
   1363                           isolate());
   1364   __ Mov(x10, entry);
   1365 
   1366   // Call the JSEntryTrampoline.
   1367   __ Ldr(x11, MemOperand(x10));  // Dereference the address.
   1368   __ Add(x12, x11, Code::kHeaderSize - kHeapObjectTag);
   1369   __ Blr(x12);
   1370 
   1371   // Unlink this frame from the handler chain.
   1372   __ PopTryHandler();
   1373 
   1374 
   1375   __ Bind(&exit);
   1376   // x0 holds the result.
   1377   // The stack pointer points to the top of the entry frame pushed on entry from
   1378   // C++ (at the beginning of this stub):
   1379   // jssp[0] : JS entry frame marker.
   1380   // jssp[1] : C entry FP.
   1381   // jssp[2] : stack frame marker.
   1382   // jssp[3] : stack frmae marker.
   1383   // jssp[4] : bad frame pointer 0xfff...ff   <- fp points here.
   1384 
   1385   // Check if the current stack frame is marked as the outermost JS frame.
   1386   Label non_outermost_js_2;
   1387   __ Pop(x10);
   1388   __ Cmp(x10, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME));
   1389   __ B(ne, &non_outermost_js_2);
   1390   __ Mov(x11, ExternalReference(js_entry_sp));
   1391   __ Str(xzr, MemOperand(x11));
   1392   __ Bind(&non_outermost_js_2);
   1393 
   1394   // Restore the top frame descriptors from the stack.
   1395   __ Pop(x10);
   1396   __ Mov(x11, ExternalReference(Isolate::kCEntryFPAddress, isolate()));
   1397   __ Str(x10, MemOperand(x11));
   1398 
   1399   // Reset the stack to the callee saved registers.
   1400   __ Drop(-EntryFrameConstants::kCallerFPOffset, kByteSizeInBytes);
   1401   // Restore the callee-saved registers and return.
   1402   DCHECK(jssp.Is(__ StackPointer()));
   1403   __ Mov(csp, jssp);
   1404   __ SetStackPointer(csp);
   1405   __ PopCalleeSavedRegisters();
   1406   // After this point, we must not modify jssp because it is a callee-saved
   1407   // register which we have just restored.
   1408   __ Ret();
   1409 }
   1410 
   1411 
   1412 void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
   1413   Label miss;
   1414   Register receiver = LoadDescriptor::ReceiverRegister();
   1415 
   1416   NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, x10,
   1417                                                           x11, &miss);
   1418 
   1419   __ Bind(&miss);
   1420   PropertyAccessCompiler::TailCallBuiltin(
   1421       masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
   1422 }
   1423 
   1424 
   1425 void InstanceofStub::Generate(MacroAssembler* masm) {
   1426   // Stack on entry:
   1427   // jssp[0]: function.
   1428   // jssp[8]: object.
   1429   //
   1430   // Returns result in x0. Zero indicates instanceof, smi 1 indicates not
   1431   // instanceof.
   1432 
   1433   Register result = x0;
   1434   Register function = right();
   1435   Register object = left();
   1436   Register scratch1 = x6;
   1437   Register scratch2 = x7;
   1438   Register res_true = x8;
   1439   Register res_false = x9;
   1440   // Only used if there was an inline map check site. (See
   1441   // LCodeGen::DoInstanceOfKnownGlobal().)
   1442   Register map_check_site = x4;
   1443   // Delta for the instructions generated between the inline map check and the
   1444   // instruction setting the result.
   1445   const int32_t kDeltaToLoadBoolResult = 4 * kInstructionSize;
   1446 
   1447   Label not_js_object, slow;
   1448 
   1449   if (!HasArgsInRegisters()) {
   1450     __ Pop(function, object);
   1451   }
   1452 
   1453   if (ReturnTrueFalseObject()) {
   1454     __ LoadTrueFalseRoots(res_true, res_false);
   1455   } else {
   1456     // This is counter-intuitive, but correct.
   1457     __ Mov(res_true, Smi::FromInt(0));
   1458     __ Mov(res_false, Smi::FromInt(1));
   1459   }
   1460 
   1461   // Check that the left hand side is a JS object and load its map as a side
   1462   // effect.
   1463   Register map = x12;
   1464   __ JumpIfSmi(object, &not_js_object);
   1465   __ IsObjectJSObjectType(object, map, scratch2, &not_js_object);
   1466 
   1467   // If there is a call site cache, don't look in the global cache, but do the
   1468   // real lookup and update the call site cache.
   1469   if (!HasCallSiteInlineCheck() && !ReturnTrueFalseObject()) {
   1470     Label miss;
   1471     __ JumpIfNotRoot(function, Heap::kInstanceofCacheFunctionRootIndex, &miss);
   1472     __ JumpIfNotRoot(map, Heap::kInstanceofCacheMapRootIndex, &miss);
   1473     __ LoadRoot(result, Heap::kInstanceofCacheAnswerRootIndex);
   1474     __ Ret();
   1475     __ Bind(&miss);
   1476   }
   1477 
   1478   // Get the prototype of the function.
   1479   Register prototype = x13;
   1480   __ TryGetFunctionPrototype(function, prototype, scratch2, &slow,
   1481                              MacroAssembler::kMissOnBoundFunction);
   1482 
   1483   // Check that the function prototype is a JS object.
   1484   __ JumpIfSmi(prototype, &slow);
   1485   __ IsObjectJSObjectType(prototype, scratch1, scratch2, &slow);
   1486 
   1487   // Update the global instanceof or call site inlined cache with the current
   1488   // map and function. The cached answer will be set when it is known below.
   1489   if (HasCallSiteInlineCheck()) {
   1490     // Patch the (relocated) inlined map check.
   1491     __ GetRelocatedValueLocation(map_check_site, scratch1);
   1492     // We have a cell, so need another level of dereferencing.
   1493     __ Ldr(scratch1, MemOperand(scratch1));
   1494     __ Str(map, FieldMemOperand(scratch1, Cell::kValueOffset));
   1495   } else {
   1496     __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
   1497     __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
   1498   }
   1499 
   1500   Label return_true, return_result;
   1501   Register smi_value = scratch1;
   1502   {
   1503     // Loop through the prototype chain looking for the function prototype.
   1504     Register chain_map = x1;
   1505     Register chain_prototype = x14;
   1506     Register null_value = x15;
   1507     Label loop;
   1508     __ Ldr(chain_prototype, FieldMemOperand(map, Map::kPrototypeOffset));
   1509     __ LoadRoot(null_value, Heap::kNullValueRootIndex);
   1510     // Speculatively set a result.
   1511     __ Mov(result, res_false);
   1512     if (!HasCallSiteInlineCheck() && ReturnTrueFalseObject()) {
   1513       // Value to store in the cache cannot be an object.
   1514       __ Mov(smi_value, Smi::FromInt(1));
   1515     }
   1516 
   1517     __ Bind(&loop);
   1518 
   1519     // If the chain prototype is the object prototype, return true.
   1520     __ Cmp(chain_prototype, prototype);
   1521     __ B(eq, &return_true);
   1522 
   1523     // If the chain prototype is null, we've reached the end of the chain, so
   1524     // return false.
   1525     __ Cmp(chain_prototype, null_value);
   1526     __ B(eq, &return_result);
   1527 
   1528     // Otherwise, load the next prototype in the chain, and loop.
   1529     __ Ldr(chain_map, FieldMemOperand(chain_prototype, HeapObject::kMapOffset));
   1530     __ Ldr(chain_prototype, FieldMemOperand(chain_map, Map::kPrototypeOffset));
   1531     __ B(&loop);
   1532   }
   1533 
   1534   // Return sequence when no arguments are on the stack.
   1535   // We cannot fall through to here.
   1536   __ Bind(&return_true);
   1537   __ Mov(result, res_true);
   1538   if (!HasCallSiteInlineCheck() && ReturnTrueFalseObject()) {
   1539     // Value to store in the cache cannot be an object.
   1540     __ Mov(smi_value, Smi::FromInt(0));
   1541   }
   1542   __ Bind(&return_result);
   1543   if (HasCallSiteInlineCheck()) {
   1544     DCHECK(ReturnTrueFalseObject());
   1545     __ Add(map_check_site, map_check_site, kDeltaToLoadBoolResult);
   1546     __ GetRelocatedValueLocation(map_check_site, scratch2);
   1547     __ Str(result, MemOperand(scratch2));
   1548   } else {
   1549     Register cached_value = ReturnTrueFalseObject() ? smi_value : result;
   1550     __ StoreRoot(cached_value, Heap::kInstanceofCacheAnswerRootIndex);
   1551   }
   1552   __ Ret();
   1553 
   1554   Label object_not_null, object_not_null_or_smi;
   1555 
   1556   __ Bind(&not_js_object);
   1557   Register object_type = x14;
   1558   //   x0   result        result return register (uninit)
   1559   //   x10  function      pointer to function
   1560   //   x11  object        pointer to object
   1561   //   x14  object_type   type of object (uninit)
   1562 
   1563   // Before null, smi and string checks, check that the rhs is a function.
   1564   // For a non-function rhs, an exception must be thrown.
   1565   __ JumpIfSmi(function, &slow);
   1566   __ JumpIfNotObjectType(
   1567       function, scratch1, object_type, JS_FUNCTION_TYPE, &slow);
   1568 
   1569   __ Mov(result, res_false);
   1570 
   1571   // Null is not instance of anything.
   1572   __ Cmp(object_type, Operand(isolate()->factory()->null_value()));
   1573   __ B(ne, &object_not_null);
   1574   __ Ret();
   1575 
   1576   __ Bind(&object_not_null);
   1577   // Smi values are not instances of anything.
   1578   __ JumpIfNotSmi(object, &object_not_null_or_smi);
   1579   __ Ret();
   1580 
   1581   __ Bind(&object_not_null_or_smi);
   1582   // String values are not instances of anything.
   1583   __ IsObjectJSStringType(object, scratch2, &slow);
   1584   __ Ret();
   1585 
   1586   // Slow-case. Tail call builtin.
   1587   __ Bind(&slow);
   1588   {
   1589     FrameScope scope(masm, StackFrame::INTERNAL);
   1590     // Arguments have either been passed into registers or have been previously
   1591     // popped. We need to push them before calling builtin.
   1592     __ Push(object, function);
   1593     __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
   1594   }
   1595   if (ReturnTrueFalseObject()) {
   1596     // Reload true/false because they were clobbered in the builtin call.
   1597     __ LoadTrueFalseRoots(res_true, res_false);
   1598     __ Cmp(result, 0);
   1599     __ Csel(result, res_true, res_false, eq);
   1600   }
   1601   __ Ret();
   1602 }
   1603 
   1604 
   1605 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   1606   Register arg_count = ArgumentsAccessReadDescriptor::parameter_count();
   1607   Register key = ArgumentsAccessReadDescriptor::index();
   1608   DCHECK(arg_count.is(x0));
   1609   DCHECK(key.is(x1));
   1610 
   1611   // The displacement is the offset of the last parameter (if any) relative
   1612   // to the frame pointer.
   1613   static const int kDisplacement =
   1614       StandardFrameConstants::kCallerSPOffset - kPointerSize;
   1615 
   1616   // Check that the key is a smi.
   1617   Label slow;
   1618   __ JumpIfNotSmi(key, &slow);
   1619 
   1620   // Check if the calling frame is an arguments adaptor frame.
   1621   Register local_fp = x11;
   1622   Register caller_fp = x11;
   1623   Register caller_ctx = x12;
   1624   Label skip_adaptor;
   1625   __ Ldr(caller_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
   1626   __ Ldr(caller_ctx, MemOperand(caller_fp,
   1627                                 StandardFrameConstants::kContextOffset));
   1628   __ Cmp(caller_ctx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
   1629   __ Csel(local_fp, fp, caller_fp, ne);
   1630   __ B(ne, &skip_adaptor);
   1631 
   1632   // Load the actual arguments limit found in the arguments adaptor frame.
   1633   __ Ldr(arg_count, MemOperand(caller_fp,
   1634                                ArgumentsAdaptorFrameConstants::kLengthOffset));
   1635   __ Bind(&skip_adaptor);
   1636 
   1637   // Check index against formal parameters count limit. Use unsigned comparison
   1638   // to get negative check for free: branch if key < 0 or key >= arg_count.
   1639   __ Cmp(key, arg_count);
   1640   __ B(hs, &slow);
   1641 
   1642   // Read the argument from the stack and return it.
   1643   __ Sub(x10, arg_count, key);
   1644   __ Add(x10, local_fp, Operand::UntagSmiAndScale(x10, kPointerSizeLog2));
   1645   __ Ldr(x0, MemOperand(x10, kDisplacement));
   1646   __ Ret();
   1647 
   1648   // Slow case: handle non-smi or out-of-bounds access to arguments by calling
   1649   // the runtime system.
   1650   __ Bind(&slow);
   1651   __ Push(key);
   1652   __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
   1653 }
   1654 
   1655 
   1656 void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
   1657   // Stack layout on entry.
   1658   //  jssp[0]:  number of parameters (tagged)
   1659   //  jssp[8]:  address of receiver argument
   1660   //  jssp[16]: function
   1661 
   1662   // Check if the calling frame is an arguments adaptor frame.
   1663   Label runtime;
   1664   Register caller_fp = x10;
   1665   __ Ldr(caller_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
   1666   // Load and untag the context.
   1667   __ Ldr(w11, UntagSmiMemOperand(caller_fp,
   1668                                  StandardFrameConstants::kContextOffset));
   1669   __ Cmp(w11, StackFrame::ARGUMENTS_ADAPTOR);
   1670   __ B(ne, &runtime);
   1671 
   1672   // Patch the arguments.length and parameters pointer in the current frame.
   1673   __ Ldr(x11, MemOperand(caller_fp,
   1674                          ArgumentsAdaptorFrameConstants::kLengthOffset));
   1675   __ Poke(x11, 0 * kXRegSize);
   1676   __ Add(x10, caller_fp, Operand::UntagSmiAndScale(x11, kPointerSizeLog2));
   1677   __ Add(x10, x10, StandardFrameConstants::kCallerSPOffset);
   1678   __ Poke(x10, 1 * kXRegSize);
   1679 
   1680   __ Bind(&runtime);
   1681   __ TailCallRuntime(Runtime::kNewSloppyArguments, 3, 1);
   1682 }
   1683 
   1684 
   1685 void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
   1686   // Stack layout on entry.
   1687   //  jssp[0]:  number of parameters (tagged)
   1688   //  jssp[8]:  address of receiver argument
   1689   //  jssp[16]: function
   1690   //
   1691   // Returns pointer to result object in x0.
   1692 
   1693   // Note: arg_count_smi is an alias of param_count_smi.
   1694   Register arg_count_smi = x3;
   1695   Register param_count_smi = x3;
   1696   Register param_count = x7;
   1697   Register recv_arg = x14;
   1698   Register function = x4;
   1699   __ Pop(param_count_smi, recv_arg, function);
   1700   __ SmiUntag(param_count, param_count_smi);
   1701 
   1702   // Check if the calling frame is an arguments adaptor frame.
   1703   Register caller_fp = x11;
   1704   Register caller_ctx = x12;
   1705   Label runtime;
   1706   Label adaptor_frame, try_allocate;
   1707   __ Ldr(caller_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
   1708   __ Ldr(caller_ctx, MemOperand(caller_fp,
   1709                                 StandardFrameConstants::kContextOffset));
   1710   __ Cmp(caller_ctx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
   1711   __ B(eq, &adaptor_frame);
   1712 
   1713   // No adaptor, parameter count = argument count.
   1714 
   1715   //   x1   mapped_params number of mapped params, min(params, args) (uninit)
   1716   //   x2   arg_count     number of function arguments (uninit)
   1717   //   x3   arg_count_smi number of function arguments (smi)
   1718   //   x4   function      function pointer
   1719   //   x7   param_count   number of function parameters
   1720   //   x11  caller_fp     caller's frame pointer
   1721   //   x14  recv_arg      pointer to receiver arguments
   1722 
   1723   Register arg_count = x2;
   1724   __ Mov(arg_count, param_count);
   1725   __ B(&try_allocate);
   1726 
   1727   // We have an adaptor frame. Patch the parameters pointer.
   1728   __ Bind(&adaptor_frame);
   1729   __ Ldr(arg_count_smi,
   1730          MemOperand(caller_fp,
   1731                     ArgumentsAdaptorFrameConstants::kLengthOffset));
   1732   __ SmiUntag(arg_count, arg_count_smi);
   1733   __ Add(x10, caller_fp, Operand(arg_count, LSL, kPointerSizeLog2));
   1734   __ Add(recv_arg, x10, StandardFrameConstants::kCallerSPOffset);
   1735 
   1736   // Compute the mapped parameter count = min(param_count, arg_count)
   1737   Register mapped_params = x1;
   1738   __ Cmp(param_count, arg_count);
   1739   __ Csel(mapped_params, param_count, arg_count, lt);
   1740 
   1741   __ Bind(&try_allocate);
   1742 
   1743   //   x0   alloc_obj     pointer to allocated objects: param map, backing
   1744   //                      store, arguments (uninit)
   1745   //   x1   mapped_params number of mapped parameters, min(params, args)
   1746   //   x2   arg_count     number of function arguments
   1747   //   x3   arg_count_smi number of function arguments (smi)
   1748   //   x4   function      function pointer
   1749   //   x7   param_count   number of function parameters
   1750   //   x10  size          size of objects to allocate (uninit)
   1751   //   x14  recv_arg      pointer to receiver arguments
   1752 
   1753   // Compute the size of backing store, parameter map, and arguments object.
   1754   // 1. Parameter map, has two extra words containing context and backing
   1755   // store.
   1756   const int kParameterMapHeaderSize =
   1757       FixedArray::kHeaderSize + 2 * kPointerSize;
   1758 
   1759   // Calculate the parameter map size, assuming it exists.
   1760   Register size = x10;
   1761   __ Mov(size, Operand(mapped_params, LSL, kPointerSizeLog2));
   1762   __ Add(size, size, kParameterMapHeaderSize);
   1763 
   1764   // If there are no mapped parameters, set the running size total to zero.
   1765   // Otherwise, use the parameter map size calculated earlier.
   1766   __ Cmp(mapped_params, 0);
   1767   __ CzeroX(size, eq);
   1768 
   1769   // 2. Add the size of the backing store and arguments object.
   1770   __ Add(size, size, Operand(arg_count, LSL, kPointerSizeLog2));
   1771   __ Add(size, size,
   1772          FixedArray::kHeaderSize + Heap::kSloppyArgumentsObjectSize);
   1773 
   1774   // Do the allocation of all three objects in one go. Assign this to x0, as it
   1775   // will be returned to the caller.
   1776   Register alloc_obj = x0;
   1777   __ Allocate(size, alloc_obj, x11, x12, &runtime, TAG_OBJECT);
   1778 
   1779   // Get the arguments boilerplate from the current (global) context.
   1780 
   1781   //   x0   alloc_obj       pointer to allocated objects (param map, backing
   1782   //                        store, arguments)
   1783   //   x1   mapped_params   number of mapped parameters, min(params, args)
   1784   //   x2   arg_count       number of function arguments
   1785   //   x3   arg_count_smi   number of function arguments (smi)
   1786   //   x4   function        function pointer
   1787   //   x7   param_count     number of function parameters
   1788   //   x11  sloppy_args_map offset to args (or aliased args) map (uninit)
   1789   //   x14  recv_arg        pointer to receiver arguments
   1790 
   1791   Register global_object = x10;
   1792   Register global_ctx = x10;
   1793   Register sloppy_args_map = x11;
   1794   Register aliased_args_map = x10;
   1795   __ Ldr(global_object, GlobalObjectMemOperand());
   1796   __ Ldr(global_ctx, FieldMemOperand(global_object,
   1797                                      GlobalObject::kNativeContextOffset));
   1798 
   1799   __ Ldr(sloppy_args_map,
   1800          ContextMemOperand(global_ctx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
   1801   __ Ldr(aliased_args_map,
   1802          ContextMemOperand(global_ctx, Context::ALIASED_ARGUMENTS_MAP_INDEX));
   1803   __ Cmp(mapped_params, 0);
   1804   __ CmovX(sloppy_args_map, aliased_args_map, ne);
   1805 
   1806   // Copy the JS object part.
   1807   __ Str(sloppy_args_map, FieldMemOperand(alloc_obj, JSObject::kMapOffset));
   1808   __ LoadRoot(x10, Heap::kEmptyFixedArrayRootIndex);
   1809   __ Str(x10, FieldMemOperand(alloc_obj, JSObject::kPropertiesOffset));
   1810   __ Str(x10, FieldMemOperand(alloc_obj, JSObject::kElementsOffset));
   1811 
   1812   // Set up the callee in-object property.
   1813   STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
   1814   const int kCalleeOffset = JSObject::kHeaderSize +
   1815                             Heap::kArgumentsCalleeIndex * kPointerSize;
   1816   __ AssertNotSmi(function);
   1817   __ Str(function, FieldMemOperand(alloc_obj, kCalleeOffset));
   1818 
   1819   // Use the length and set that as an in-object property.
   1820   STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
   1821   const int kLengthOffset = JSObject::kHeaderSize +
   1822                             Heap::kArgumentsLengthIndex * kPointerSize;
   1823   __ Str(arg_count_smi, FieldMemOperand(alloc_obj, kLengthOffset));
   1824 
   1825   // Set up the elements pointer in the allocated arguments object.
   1826   // If we allocated a parameter map, "elements" will point there, otherwise
   1827   // it will point to the backing store.
   1828 
   1829   //   x0   alloc_obj     pointer to allocated objects (param map, backing
   1830   //                      store, arguments)
   1831   //   x1   mapped_params number of mapped parameters, min(params, args)
   1832   //   x2   arg_count     number of function arguments
   1833   //   x3   arg_count_smi number of function arguments (smi)
   1834   //   x4   function      function pointer
   1835   //   x5   elements      pointer to parameter map or backing store (uninit)
   1836   //   x6   backing_store pointer to backing store (uninit)
   1837   //   x7   param_count   number of function parameters
   1838   //   x14  recv_arg      pointer to receiver arguments
   1839 
   1840   Register elements = x5;
   1841   __ Add(elements, alloc_obj, Heap::kSloppyArgumentsObjectSize);
   1842   __ Str(elements, FieldMemOperand(alloc_obj, JSObject::kElementsOffset));
   1843 
   1844   // Initialize parameter map. If there are no mapped arguments, we're done.
   1845   Label skip_parameter_map;
   1846   __ Cmp(mapped_params, 0);
   1847   // Set up backing store address, because it is needed later for filling in
   1848   // the unmapped arguments.
   1849   Register backing_store = x6;
   1850   __ CmovX(backing_store, elements, eq);
   1851   __ B(eq, &skip_parameter_map);
   1852 
   1853   __ LoadRoot(x10, Heap::kSloppyArgumentsElementsMapRootIndex);
   1854   __ Str(x10, FieldMemOperand(elements, FixedArray::kMapOffset));
   1855   __ Add(x10, mapped_params, 2);
   1856   __ SmiTag(x10);
   1857   __ Str(x10, FieldMemOperand(elements, FixedArray::kLengthOffset));
   1858   __ Str(cp, FieldMemOperand(elements,
   1859                              FixedArray::kHeaderSize + 0 * kPointerSize));
   1860   __ Add(x10, elements, Operand(mapped_params, LSL, kPointerSizeLog2));
   1861   __ Add(x10, x10, kParameterMapHeaderSize);
   1862   __ Str(x10, FieldMemOperand(elements,
   1863                               FixedArray::kHeaderSize + 1 * kPointerSize));
   1864 
   1865   // Copy the parameter slots and the holes in the arguments.
   1866   // We need to fill in mapped_parameter_count slots. Then index the context,
   1867   // where parameters are stored in reverse order, at:
   1868   //
   1869   //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS + parameter_count - 1
   1870   //
   1871   // The mapped parameter thus needs to get indices:
   1872   //
   1873   //   MIN_CONTEXT_SLOTS + parameter_count - 1 ..
   1874   //     MIN_CONTEXT_SLOTS + parameter_count - mapped_parameter_count
   1875   //
   1876   // We loop from right to left.
   1877 
   1878   //   x0   alloc_obj     pointer to allocated objects (param map, backing
   1879   //                      store, arguments)
   1880   //   x1   mapped_params number of mapped parameters, min(params, args)
   1881   //   x2   arg_count     number of function arguments
   1882   //   x3   arg_count_smi number of function arguments (smi)
   1883   //   x4   function      function pointer
   1884   //   x5   elements      pointer to parameter map or backing store (uninit)
   1885   //   x6   backing_store pointer to backing store (uninit)
   1886   //   x7   param_count   number of function parameters
   1887   //   x11  loop_count    parameter loop counter (uninit)
   1888   //   x12  index         parameter index (smi, uninit)
   1889   //   x13  the_hole      hole value (uninit)
   1890   //   x14  recv_arg      pointer to receiver arguments
   1891 
   1892   Register loop_count = x11;
   1893   Register index = x12;
   1894   Register the_hole = x13;
   1895   Label parameters_loop, parameters_test;
   1896   __ Mov(loop_count, mapped_params);
   1897   __ Add(index, param_count, static_cast<int>(Context::MIN_CONTEXT_SLOTS));
   1898   __ Sub(index, index, mapped_params);
   1899   __ SmiTag(index);
   1900   __ LoadRoot(the_hole, Heap::kTheHoleValueRootIndex);
   1901   __ Add(backing_store, elements, Operand(loop_count, LSL, kPointerSizeLog2));
   1902   __ Add(backing_store, backing_store, kParameterMapHeaderSize);
   1903 
   1904   __ B(&parameters_test);
   1905 
   1906   __ Bind(&parameters_loop);
   1907   __ Sub(loop_count, loop_count, 1);
   1908   __ Mov(x10, Operand(loop_count, LSL, kPointerSizeLog2));
   1909   __ Add(x10, x10, kParameterMapHeaderSize - kHeapObjectTag);
   1910   __ Str(index, MemOperand(elements, x10));
   1911   __ Sub(x10, x10, kParameterMapHeaderSize - FixedArray::kHeaderSize);
   1912   __ Str(the_hole, MemOperand(backing_store, x10));
   1913   __ Add(index, index, Smi::FromInt(1));
   1914   __ Bind(&parameters_test);
   1915   __ Cbnz(loop_count, &parameters_loop);
   1916 
   1917   __ Bind(&skip_parameter_map);
   1918   // Copy arguments header and remaining slots (if there are any.)
   1919   __ LoadRoot(x10, Heap::kFixedArrayMapRootIndex);
   1920   __ Str(x10, FieldMemOperand(backing_store, FixedArray::kMapOffset));
   1921   __ Str(arg_count_smi, FieldMemOperand(backing_store,
   1922                                         FixedArray::kLengthOffset));
   1923 
   1924   //   x0   alloc_obj     pointer to allocated objects (param map, backing
   1925   //                      store, arguments)
   1926   //   x1   mapped_params number of mapped parameters, min(params, args)
   1927   //   x2   arg_count     number of function arguments
   1928   //   x4   function      function pointer
   1929   //   x3   arg_count_smi number of function arguments (smi)
   1930   //   x6   backing_store pointer to backing store (uninit)
   1931   //   x14  recv_arg      pointer to receiver arguments
   1932 
   1933   Label arguments_loop, arguments_test;
   1934   __ Mov(x10, mapped_params);
   1935   __ Sub(recv_arg, recv_arg, Operand(x10, LSL, kPointerSizeLog2));
   1936   __ B(&arguments_test);
   1937 
   1938   __ Bind(&arguments_loop);
   1939   __ Sub(recv_arg, recv_arg, kPointerSize);
   1940   __ Ldr(x11, MemOperand(recv_arg));
   1941   __ Add(x12, backing_store, Operand(x10, LSL, kPointerSizeLog2));
   1942   __ Str(x11, FieldMemOperand(x12, FixedArray::kHeaderSize));
   1943   __ Add(x10, x10, 1);
   1944 
   1945   __ Bind(&arguments_test);
   1946   __ Cmp(x10, arg_count);
   1947   __ B(lt, &arguments_loop);
   1948 
   1949   __ Ret();
   1950 
   1951   // Do the runtime call to allocate the arguments object.
   1952   __ Bind(&runtime);
   1953   __ Push(function, recv_arg, arg_count_smi);
   1954   __ TailCallRuntime(Runtime::kNewSloppyArguments, 3, 1);
   1955 }
   1956 
   1957 
   1958 void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) {
   1959   // Return address is in lr.
   1960   Label slow;
   1961 
   1962   Register receiver = LoadDescriptor::ReceiverRegister();
   1963   Register key = LoadDescriptor::NameRegister();
   1964 
   1965   // Check that the key is an array index, that is Uint32.
   1966   __ TestAndBranchIfAnySet(key, kSmiTagMask | kSmiSignMask, &slow);
   1967 
   1968   // Everything is fine, call runtime.
   1969   __ Push(receiver, key);
   1970   __ TailCallExternalReference(
   1971       ExternalReference(IC_Utility(IC::kLoadElementWithInterceptor),
   1972                         masm->isolate()),
   1973       2, 1);
   1974 
   1975   __ Bind(&slow);
   1976   PropertyAccessCompiler::TailCallBuiltin(
   1977       masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
   1978 }
   1979 
   1980 
   1981 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
   1982   // Stack layout on entry.
   1983   //  jssp[0]:  number of parameters (tagged)
   1984   //  jssp[8]:  address of receiver argument
   1985   //  jssp[16]: function
   1986   //
   1987   // Returns pointer to result object in x0.
   1988 
   1989   // Get the stub arguments from the frame, and make an untagged copy of the
   1990   // parameter count.
   1991   Register param_count_smi = x1;
   1992   Register params = x2;
   1993   Register function = x3;
   1994   Register param_count = x13;
   1995   __ Pop(param_count_smi, params, function);
   1996   __ SmiUntag(param_count, param_count_smi);
   1997 
   1998   // Test if arguments adaptor needed.
   1999   Register caller_fp = x11;
   2000   Register caller_ctx = x12;
   2001   Label try_allocate, runtime;
   2002   __ Ldr(caller_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
   2003   __ Ldr(caller_ctx, MemOperand(caller_fp,
   2004                                 StandardFrameConstants::kContextOffset));
   2005   __ Cmp(caller_ctx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
   2006   __ B(ne, &try_allocate);
   2007 
   2008   //   x1   param_count_smi   number of parameters passed to function (smi)
   2009   //   x2   params            pointer to parameters
   2010   //   x3   function          function pointer
   2011   //   x11  caller_fp         caller's frame pointer
   2012   //   x13  param_count       number of parameters passed to function
   2013 
   2014   // Patch the argument length and parameters pointer.
   2015   __ Ldr(param_count_smi,
   2016          MemOperand(caller_fp,
   2017                     ArgumentsAdaptorFrameConstants::kLengthOffset));
   2018   __ SmiUntag(param_count, param_count_smi);
   2019   __ Add(x10, caller_fp, Operand(param_count, LSL, kPointerSizeLog2));
   2020   __ Add(params, x10, StandardFrameConstants::kCallerSPOffset);
   2021 
   2022   // Try the new space allocation. Start out with computing the size of the
   2023   // arguments object and the elements array in words.
   2024   Register size = x10;
   2025   __ Bind(&try_allocate);
   2026   __ Add(size, param_count, FixedArray::kHeaderSize / kPointerSize);
   2027   __ Cmp(param_count, 0);
   2028   __ CzeroX(size, eq);
   2029   __ Add(size, size, Heap::kStrictArgumentsObjectSize / kPointerSize);
   2030 
   2031   // Do the allocation of both objects in one go. Assign this to x0, as it will
   2032   // be returned to the caller.
   2033   Register alloc_obj = x0;
   2034   __ Allocate(size, alloc_obj, x11, x12, &runtime,
   2035               static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
   2036 
   2037   // Get the arguments boilerplate from the current (native) context.
   2038   Register global_object = x10;
   2039   Register global_ctx = x10;
   2040   Register strict_args_map = x4;
   2041   __ Ldr(global_object, GlobalObjectMemOperand());
   2042   __ Ldr(global_ctx, FieldMemOperand(global_object,
   2043                                      GlobalObject::kNativeContextOffset));
   2044   __ Ldr(strict_args_map,
   2045          ContextMemOperand(global_ctx, Context::STRICT_ARGUMENTS_MAP_INDEX));
   2046 
   2047   //   x0   alloc_obj         pointer to allocated objects: parameter array and
   2048   //                          arguments object
   2049   //   x1   param_count_smi   number of parameters passed to function (smi)
   2050   //   x2   params            pointer to parameters
   2051   //   x3   function          function pointer
   2052   //   x4   strict_args_map   offset to arguments map
   2053   //   x13  param_count       number of parameters passed to function
   2054   __ Str(strict_args_map, FieldMemOperand(alloc_obj, JSObject::kMapOffset));
   2055   __ LoadRoot(x5, Heap::kEmptyFixedArrayRootIndex);
   2056   __ Str(x5, FieldMemOperand(alloc_obj, JSObject::kPropertiesOffset));
   2057   __ Str(x5, FieldMemOperand(alloc_obj, JSObject::kElementsOffset));
   2058 
   2059   // Set the smi-tagged length as an in-object property.
   2060   STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
   2061   const int kLengthOffset = JSObject::kHeaderSize +
   2062                             Heap::kArgumentsLengthIndex * kPointerSize;
   2063   __ Str(param_count_smi, FieldMemOperand(alloc_obj, kLengthOffset));
   2064 
   2065   // If there are no actual arguments, we're done.
   2066   Label done;
   2067   __ Cbz(param_count, &done);
   2068 
   2069   // Set up the elements pointer in the allocated arguments object and
   2070   // initialize the header in the elements fixed array.
   2071   Register elements = x5;
   2072   __ Add(elements, alloc_obj, Heap::kStrictArgumentsObjectSize);
   2073   __ Str(elements, FieldMemOperand(alloc_obj, JSObject::kElementsOffset));
   2074   __ LoadRoot(x10, Heap::kFixedArrayMapRootIndex);
   2075   __ Str(x10, FieldMemOperand(elements, FixedArray::kMapOffset));
   2076   __ Str(param_count_smi, FieldMemOperand(elements, FixedArray::kLengthOffset));
   2077 
   2078   //   x0   alloc_obj         pointer to allocated objects: parameter array and
   2079   //                          arguments object
   2080   //   x1   param_count_smi   number of parameters passed to function (smi)
   2081   //   x2   params            pointer to parameters
   2082   //   x3   function          function pointer
   2083   //   x4   array             pointer to array slot (uninit)
   2084   //   x5   elements          pointer to elements array of alloc_obj
   2085   //   x13  param_count       number of parameters passed to function
   2086 
   2087   // Copy the fixed array slots.
   2088   Label loop;
   2089   Register array = x4;
   2090   // Set up pointer to first array slot.
   2091   __ Add(array, elements, FixedArray::kHeaderSize - kHeapObjectTag);
   2092 
   2093   __ Bind(&loop);
   2094   // Pre-decrement the parameters pointer by kPointerSize on each iteration.
   2095   // Pre-decrement in order to skip receiver.
   2096   __ Ldr(x10, MemOperand(params, -kPointerSize, PreIndex));
   2097   // Post-increment elements by kPointerSize on each iteration.
   2098   __ Str(x10, MemOperand(array, kPointerSize, PostIndex));
   2099   __ Sub(param_count, param_count, 1);
   2100   __ Cbnz(param_count, &loop);
   2101 
   2102   // Return from stub.
   2103   __ Bind(&done);
   2104   __ Ret();
   2105 
   2106   // Do the runtime call to allocate the arguments object.
   2107   __ Bind(&runtime);
   2108   __ Push(function, params, param_count_smi);
   2109   __ TailCallRuntime(Runtime::kNewStrictArguments, 3, 1);
   2110 }
   2111 
   2112 
   2113 void RegExpExecStub::Generate(MacroAssembler* masm) {
   2114 #ifdef V8_INTERPRETED_REGEXP
   2115   __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
   2116 #else  // V8_INTERPRETED_REGEXP
   2117 
   2118   // Stack frame on entry.
   2119   //  jssp[0]: last_match_info (expected JSArray)
   2120   //  jssp[8]: previous index
   2121   //  jssp[16]: subject string
   2122   //  jssp[24]: JSRegExp object
   2123   Label runtime;
   2124 
   2125   // Use of registers for this function.
   2126 
   2127   // Variable registers:
   2128   //   x10-x13                                  used as scratch registers
   2129   //   w0       string_type                     type of subject string
   2130   //   x2       jsstring_length                 subject string length
   2131   //   x3       jsregexp_object                 JSRegExp object
   2132   //   w4       string_encoding                 Latin1 or UC16
   2133   //   w5       sliced_string_offset            if the string is a SlicedString
   2134   //                                            offset to the underlying string
   2135   //   w6       string_representation           groups attributes of the string:
   2136   //                                              - is a string
   2137   //                                              - type of the string
   2138   //                                              - is a short external string
   2139   Register string_type = w0;
   2140   Register jsstring_length = x2;
   2141   Register jsregexp_object = x3;
   2142   Register string_encoding = w4;
   2143   Register sliced_string_offset = w5;
   2144   Register string_representation = w6;
   2145 
   2146   // These are in callee save registers and will be preserved by the call
   2147   // to the native RegExp code, as this code is called using the normal
   2148   // C calling convention. When calling directly from generated code the
   2149   // native RegExp code will not do a GC and therefore the content of
   2150   // these registers are safe to use after the call.
   2151 
   2152   //   x19       subject                        subject string
   2153   //   x20       regexp_data                    RegExp data (FixedArray)
   2154   //   x21       last_match_info_elements       info relative to the last match
   2155   //                                            (FixedArray)
   2156   //   x22       code_object                    generated regexp code
   2157   Register subject = x19;
   2158   Register regexp_data = x20;
   2159   Register last_match_info_elements = x21;
   2160   Register code_object = x22;
   2161 
   2162   // TODO(jbramley): Is it necessary to preserve these? I don't think ARM does.
   2163   CPURegList used_callee_saved_registers(subject,
   2164                                          regexp_data,
   2165                                          last_match_info_elements,
   2166                                          code_object);
   2167   __ PushCPURegList(used_callee_saved_registers);
   2168 
   2169   // Stack frame.
   2170   //  jssp[0] : x19
   2171   //  jssp[8] : x20
   2172   //  jssp[16]: x21
   2173   //  jssp[24]: x22
   2174   //  jssp[32]: last_match_info (JSArray)
   2175   //  jssp[40]: previous index
   2176   //  jssp[48]: subject string
   2177   //  jssp[56]: JSRegExp object
   2178 
   2179   const int kLastMatchInfoOffset = 4 * kPointerSize;
   2180   const int kPreviousIndexOffset = 5 * kPointerSize;
   2181   const int kSubjectOffset = 6 * kPointerSize;
   2182   const int kJSRegExpOffset = 7 * kPointerSize;
   2183 
   2184   // Ensure that a RegExp stack is allocated.
   2185   ExternalReference address_of_regexp_stack_memory_address =
   2186       ExternalReference::address_of_regexp_stack_memory_address(isolate());
   2187   ExternalReference address_of_regexp_stack_memory_size =
   2188       ExternalReference::address_of_regexp_stack_memory_size(isolate());
   2189   __ Mov(x10, address_of_regexp_stack_memory_size);
   2190   __ Ldr(x10, MemOperand(x10));
   2191   __ Cbz(x10, &runtime);
   2192 
   2193   // Check that the first argument is a JSRegExp object.
   2194   DCHECK(jssp.Is(__ StackPointer()));
   2195   __ Peek(jsregexp_object, kJSRegExpOffset);
   2196   __ JumpIfSmi(jsregexp_object, &runtime);
   2197   __ JumpIfNotObjectType(jsregexp_object, x10, x10, JS_REGEXP_TYPE, &runtime);
   2198 
   2199   // Check that the RegExp has been compiled (data contains a fixed array).
   2200   __ Ldr(regexp_data, FieldMemOperand(jsregexp_object, JSRegExp::kDataOffset));
   2201   if (FLAG_debug_code) {
   2202     STATIC_ASSERT(kSmiTag == 0);
   2203     __ Tst(regexp_data, kSmiTagMask);
   2204     __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected);
   2205     __ CompareObjectType(regexp_data, x10, x10, FIXED_ARRAY_TYPE);
   2206     __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected);
   2207   }
   2208 
   2209   // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
   2210   __ Ldr(x10, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset));
   2211   __ Cmp(x10, Smi::FromInt(JSRegExp::IRREGEXP));
   2212   __ B(ne, &runtime);
   2213 
   2214   // Check that the number of captures fit in the static offsets vector buffer.
   2215   // We have always at least one capture for the whole match, plus additional
   2216   // ones due to capturing parentheses. A capture takes 2 registers.
   2217   // The number of capture registers then is (number_of_captures + 1) * 2.
   2218   __ Ldrsw(x10,
   2219            UntagSmiFieldMemOperand(regexp_data,
   2220                                    JSRegExp::kIrregexpCaptureCountOffset));
   2221   // Check (number_of_captures + 1) * 2 <= offsets vector size
   2222   //             number_of_captures * 2 <= offsets vector size - 2
   2223   STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
   2224   __ Add(x10, x10, x10);
   2225   __ Cmp(x10, Isolate::kJSRegexpStaticOffsetsVectorSize - 2);
   2226   __ B(hi, &runtime);
   2227 
   2228   // Initialize offset for possibly sliced string.
   2229   __ Mov(sliced_string_offset, 0);
   2230 
   2231   DCHECK(jssp.Is(__ StackPointer()));
   2232   __ Peek(subject, kSubjectOffset);
   2233   __ JumpIfSmi(subject, &runtime);
   2234 
   2235   __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset));
   2236   __ Ldrb(string_type, FieldMemOperand(x10, Map::kInstanceTypeOffset));
   2237 
   2238   __ Ldr(jsstring_length, FieldMemOperand(subject, String::kLengthOffset));
   2239 
   2240   // Handle subject string according to its encoding and representation:
   2241   // (1) Sequential string?  If yes, go to (5).
   2242   // (2) Anything but sequential or cons?  If yes, go to (6).
   2243   // (3) Cons string.  If the string is flat, replace subject with first string.
   2244   //     Otherwise bailout.
   2245   // (4) Is subject external?  If yes, go to (7).
   2246   // (5) Sequential string.  Load regexp code according to encoding.
   2247   // (E) Carry on.
   2248   /// [...]
   2249 
   2250   // Deferred code at the end of the stub:
   2251   // (6) Not a long external string?  If yes, go to (8).
   2252   // (7) External string.  Make it, offset-wise, look like a sequential string.
   2253   //     Go to (5).
   2254   // (8) Short external string or not a string?  If yes, bail out to runtime.
   2255   // (9) Sliced string.  Replace subject with parent.  Go to (4).
   2256 
   2257   Label check_underlying;   // (4)
   2258   Label seq_string;         // (5)
   2259   Label not_seq_nor_cons;   // (6)
   2260   Label external_string;    // (7)
   2261   Label not_long_external;  // (8)
   2262 
   2263   // (1) Sequential string?  If yes, go to (5).
   2264   __ And(string_representation,
   2265          string_type,
   2266          kIsNotStringMask |
   2267              kStringRepresentationMask |
   2268              kShortExternalStringMask);
   2269   // We depend on the fact that Strings of type
   2270   // SeqString and not ShortExternalString are defined
   2271   // by the following pattern:
   2272   //   string_type: 0XX0 XX00
   2273   //                ^  ^   ^^
   2274   //                |  |   ||
   2275   //                |  |   is a SeqString
   2276   //                |  is not a short external String
   2277   //                is a String
   2278   STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
   2279   STATIC_ASSERT(kShortExternalStringTag != 0);
   2280   __ Cbz(string_representation, &seq_string);  // Go to (5).
   2281 
   2282   // (2) Anything but sequential or cons?  If yes, go to (6).
   2283   STATIC_ASSERT(kConsStringTag < kExternalStringTag);
   2284   STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
   2285   STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
   2286   STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
   2287   __ Cmp(string_representation, kExternalStringTag);
   2288   __ B(ge, &not_seq_nor_cons);  // Go to (6).
   2289 
   2290   // (3) Cons string.  Check that it's flat.
   2291   __ Ldr(x10, FieldMemOperand(subject, ConsString::kSecondOffset));
   2292   __ JumpIfNotRoot(x10, Heap::kempty_stringRootIndex, &runtime);
   2293   // Replace subject with first string.
   2294   __ Ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
   2295 
   2296   // (4) Is subject external?  If yes, go to (7).
   2297   __ Bind(&check_underlying);
   2298   // Reload the string type.
   2299   __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset));
   2300   __ Ldrb(string_type, FieldMemOperand(x10, Map::kInstanceTypeOffset));
   2301   STATIC_ASSERT(kSeqStringTag == 0);
   2302   // The underlying external string is never a short external string.
   2303   STATIC_ASSERT(ExternalString::kMaxShortLength < ConsString::kMinLength);
   2304   STATIC_ASSERT(ExternalString::kMaxShortLength < SlicedString::kMinLength);
   2305   __ TestAndBranchIfAnySet(string_type.X(),
   2306                            kStringRepresentationMask,
   2307                            &external_string);  // Go to (7).
   2308 
   2309   // (5) Sequential string.  Load regexp code according to encoding.
   2310   __ Bind(&seq_string);
   2311 
   2312   // Check that the third argument is a positive smi less than the subject
   2313   // string length. A negative value will be greater (unsigned comparison).
   2314   DCHECK(jssp.Is(__ StackPointer()));
   2315   __ Peek(x10, kPreviousIndexOffset);
   2316   __ JumpIfNotSmi(x10, &runtime);
   2317   __ Cmp(jsstring_length, x10);
   2318   __ B(ls, &runtime);
   2319 
   2320   // Argument 2 (x1): We need to load argument 2 (the previous index) into x1
   2321   // before entering the exit frame.
   2322   __ SmiUntag(x1, x10);
   2323 
   2324   // The third bit determines the string encoding in string_type.
   2325   STATIC_ASSERT(kOneByteStringTag == 0x04);
   2326   STATIC_ASSERT(kTwoByteStringTag == 0x00);
   2327   STATIC_ASSERT(kStringEncodingMask == 0x04);
   2328 
   2329   // Find the code object based on the assumptions above.
   2330   // kDataOneByteCodeOffset and kDataUC16CodeOffset are adjacent, adds an offset
   2331   // of kPointerSize to reach the latter.
   2332   DCHECK_EQ(JSRegExp::kDataOneByteCodeOffset + kPointerSize,
   2333             JSRegExp::kDataUC16CodeOffset);
   2334   __ Mov(x10, kPointerSize);
   2335   // We will need the encoding later: Latin1 = 0x04
   2336   //                                  UC16   = 0x00
   2337   __ Ands(string_encoding, string_type, kStringEncodingMask);
   2338   __ CzeroX(x10, ne);
   2339   __ Add(x10, regexp_data, x10);
   2340   __ Ldr(code_object, FieldMemOperand(x10, JSRegExp::kDataOneByteCodeOffset));
   2341 
   2342   // (E) Carry on.  String handling is done.
   2343 
   2344   // Check that the irregexp code has been generated for the actual string
   2345   // encoding. If it has, the field contains a code object otherwise it contains
   2346   // a smi (code flushing support).
   2347   __ JumpIfSmi(code_object, &runtime);
   2348 
   2349   // All checks done. Now push arguments for native regexp code.
   2350   __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1,
   2351                       x10,
   2352                       x11);
   2353 
   2354   // Isolates: note we add an additional parameter here (isolate pointer).
   2355   __ EnterExitFrame(false, x10, 1);
   2356   DCHECK(csp.Is(__ StackPointer()));
   2357 
   2358   // We have 9 arguments to pass to the regexp code, therefore we have to pass
   2359   // one on the stack and the rest as registers.
   2360 
   2361   // Note that the placement of the argument on the stack isn't standard
   2362   // AAPCS64:
   2363   // csp[0]: Space for the return address placed by DirectCEntryStub.
   2364   // csp[8]: Argument 9, the current isolate address.
   2365 
   2366   __ Mov(x10, ExternalReference::isolate_address(isolate()));
   2367   __ Poke(x10, kPointerSize);
   2368 
   2369   Register length = w11;
   2370   Register previous_index_in_bytes = w12;
   2371   Register start = x13;
   2372 
   2373   // Load start of the subject string.
   2374   __ Add(start, subject, SeqString::kHeaderSize - kHeapObjectTag);
   2375   // Load the length from the original subject string from the previous stack
   2376   // frame. Therefore we have to use fp, which points exactly to two pointer
   2377   // sizes below the previous sp. (Because creating a new stack frame pushes
   2378   // the previous fp onto the stack and decrements sp by 2 * kPointerSize.)
   2379   __ Ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
   2380   __ Ldr(length, UntagSmiFieldMemOperand(subject, String::kLengthOffset));
   2381 
   2382   // Handle UC16 encoding, two bytes make one character.
   2383   //   string_encoding: if Latin1: 0x04
   2384   //                    if UC16:   0x00
   2385   STATIC_ASSERT(kStringEncodingMask == 0x04);
   2386   __ Ubfx(string_encoding, string_encoding, 2, 1);
   2387   __ Eor(string_encoding, string_encoding, 1);
   2388   //   string_encoding: if Latin1: 0
   2389   //                    if UC16:   1
   2390 
   2391   // Convert string positions from characters to bytes.
   2392   // Previous index is in x1.
   2393   __ Lsl(previous_index_in_bytes, w1, string_encoding);
   2394   __ Lsl(length, length, string_encoding);
   2395   __ Lsl(sliced_string_offset, sliced_string_offset, string_encoding);
   2396 
   2397   // Argument 1 (x0): Subject string.
   2398   __ Mov(x0, subject);
   2399 
   2400   // Argument 2 (x1): Previous index, already there.
   2401 
   2402   // Argument 3 (x2): Get the start of input.
   2403   // Start of input = start of string + previous index + substring offset
   2404   //                                                     (0 if the string
   2405   //                                                      is not sliced).
   2406   __ Add(w10, previous_index_in_bytes, sliced_string_offset);
   2407   __ Add(x2, start, Operand(w10, UXTW));
   2408 
   2409   // Argument 4 (x3):
   2410   // End of input = start of input + (length of input - previous index)
   2411   __ Sub(w10, length, previous_index_in_bytes);
   2412   __ Add(x3, x2, Operand(w10, UXTW));
   2413 
   2414   // Argument 5 (x4): static offsets vector buffer.
   2415   __ Mov(x4, ExternalReference::address_of_static_offsets_vector(isolate()));
   2416 
   2417   // Argument 6 (x5): Set the number of capture registers to zero to force
   2418   // global regexps to behave as non-global. This stub is not used for global
   2419   // regexps.
   2420   __ Mov(x5, 0);
   2421 
   2422   // Argument 7 (x6): Start (high end) of backtracking stack memory area.
   2423   __ Mov(x10, address_of_regexp_stack_memory_address);
   2424   __ Ldr(x10, MemOperand(x10));
   2425   __ Mov(x11, address_of_regexp_stack_memory_size);
   2426   __ Ldr(x11, MemOperand(x11));
   2427   __ Add(x6, x10, x11);
   2428 
   2429   // Argument 8 (x7): Indicate that this is a direct call from JavaScript.
   2430   __ Mov(x7, 1);
   2431 
   2432   // Locate the code entry and call it.
   2433   __ Add(code_object, code_object, Code::kHeaderSize - kHeapObjectTag);
   2434   DirectCEntryStub stub(isolate());
   2435   stub.GenerateCall(masm, code_object);
   2436 
   2437   __ LeaveExitFrame(false, x10, true);
   2438 
   2439   // The generated regexp code returns an int32 in w0.
   2440   Label failure, exception;
   2441   __ CompareAndBranch(w0, NativeRegExpMacroAssembler::FAILURE, eq, &failure);
   2442   __ CompareAndBranch(w0,
   2443                       NativeRegExpMacroAssembler::EXCEPTION,
   2444                       eq,
   2445                       &exception);
   2446   __ CompareAndBranch(w0, NativeRegExpMacroAssembler::RETRY, eq, &runtime);
   2447 
   2448   // Success: process the result from the native regexp code.
   2449   Register number_of_capture_registers = x12;
   2450 
   2451   // Calculate number of capture registers (number_of_captures + 1) * 2
   2452   // and store it in the last match info.
   2453   __ Ldrsw(x10,
   2454            UntagSmiFieldMemOperand(regexp_data,
   2455                                    JSRegExp::kIrregexpCaptureCountOffset));
   2456   __ Add(x10, x10, x10);
   2457   __ Add(number_of_capture_registers, x10, 2);
   2458 
   2459   // Check that the fourth object is a JSArray object.
   2460   DCHECK(jssp.Is(__ StackPointer()));
   2461   __ Peek(x10, kLastMatchInfoOffset);
   2462   __ JumpIfSmi(x10, &runtime);
   2463   __ JumpIfNotObjectType(x10, x11, x11, JS_ARRAY_TYPE, &runtime);
   2464 
   2465   // Check that the JSArray is the fast case.
   2466   __ Ldr(last_match_info_elements,
   2467          FieldMemOperand(x10, JSArray::kElementsOffset));
   2468   __ Ldr(x10,
   2469          FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
   2470   __ JumpIfNotRoot(x10, Heap::kFixedArrayMapRootIndex, &runtime);
   2471 
   2472   // Check that the last match info has space for the capture registers and the
   2473   // additional information (overhead).
   2474   //     (number_of_captures + 1) * 2 + overhead <= last match info size
   2475   //     (number_of_captures * 2) + 2 + overhead <= last match info size
   2476   //      number_of_capture_registers + overhead <= last match info size
   2477   __ Ldrsw(x10,
   2478            UntagSmiFieldMemOperand(last_match_info_elements,
   2479                                    FixedArray::kLengthOffset));
   2480   __ Add(x11, number_of_capture_registers, RegExpImpl::kLastMatchOverhead);
   2481   __ Cmp(x11, x10);
   2482   __ B(gt, &runtime);
   2483 
   2484   // Store the capture count.
   2485   __ SmiTag(x10, number_of_capture_registers);
   2486   __ Str(x10,
   2487          FieldMemOperand(last_match_info_elements,
   2488                          RegExpImpl::kLastCaptureCountOffset));
   2489   // Store last subject and last input.
   2490   __ Str(subject,
   2491          FieldMemOperand(last_match_info_elements,
   2492                          RegExpImpl::kLastSubjectOffset));
   2493   // Use x10 as the subject string in order to only need
   2494   // one RecordWriteStub.
   2495   __ Mov(x10, subject);
   2496   __ RecordWriteField(last_match_info_elements,
   2497                       RegExpImpl::kLastSubjectOffset,
   2498                       x10,
   2499                       x11,
   2500                       kLRHasNotBeenSaved,
   2501                       kDontSaveFPRegs);
   2502   __ Str(subject,
   2503          FieldMemOperand(last_match_info_elements,
   2504                          RegExpImpl::kLastInputOffset));
   2505   __ Mov(x10, subject);
   2506   __ RecordWriteField(last_match_info_elements,
   2507                       RegExpImpl::kLastInputOffset,
   2508                       x10,
   2509                       x11,
   2510                       kLRHasNotBeenSaved,
   2511                       kDontSaveFPRegs);
   2512 
   2513   Register last_match_offsets = x13;
   2514   Register offsets_vector_index = x14;
   2515   Register current_offset = x15;
   2516 
   2517   // Get the static offsets vector filled by the native regexp code
   2518   // and fill the last match info.
   2519   ExternalReference address_of_static_offsets_vector =
   2520       ExternalReference::address_of_static_offsets_vector(isolate());
   2521   __ Mov(offsets_vector_index, address_of_static_offsets_vector);
   2522 
   2523   Label next_capture, done;
   2524   // Capture register counter starts from number of capture registers and
   2525   // iterates down to zero (inclusive).
   2526   __ Add(last_match_offsets,
   2527          last_match_info_elements,
   2528          RegExpImpl::kFirstCaptureOffset - kHeapObjectTag);
   2529   __ Bind(&next_capture);
   2530   __ Subs(number_of_capture_registers, number_of_capture_registers, 2);
   2531   __ B(mi, &done);
   2532   // Read two 32 bit values from the static offsets vector buffer into
   2533   // an X register
   2534   __ Ldr(current_offset,
   2535          MemOperand(offsets_vector_index, kWRegSize * 2, PostIndex));
   2536   // Store the smi values in the last match info.
   2537   __ SmiTag(x10, current_offset);
   2538   // Clearing the 32 bottom bits gives us a Smi.
   2539   STATIC_ASSERT(kSmiTag == 0);
   2540   __ Bic(x11, current_offset, kSmiShiftMask);
   2541   __ Stp(x10,
   2542          x11,
   2543          MemOperand(last_match_offsets, kXRegSize * 2, PostIndex));
   2544   __ B(&next_capture);
   2545   __ Bind(&done);
   2546 
   2547   // Return last match info.
   2548   __ Peek(x0, kLastMatchInfoOffset);
   2549   __ PopCPURegList(used_callee_saved_registers);
   2550   // Drop the 4 arguments of the stub from the stack.
   2551   __ Drop(4);
   2552   __ Ret();
   2553 
   2554   __ Bind(&exception);
   2555   Register exception_value = x0;
   2556   // A stack overflow (on the backtrack stack) may have occured
   2557   // in the RegExp code but no exception has been created yet.
   2558   // If there is no pending exception, handle that in the runtime system.
   2559   __ Mov(x10, Operand(isolate()->factory()->the_hole_value()));
   2560   __ Mov(x11,
   2561          Operand(ExternalReference(Isolate::kPendingExceptionAddress,
   2562                                    isolate())));
   2563   __ Ldr(exception_value, MemOperand(x11));
   2564   __ Cmp(x10, exception_value);
   2565   __ B(eq, &runtime);
   2566 
   2567   __ Str(x10, MemOperand(x11));  // Clear pending exception.
   2568 
   2569   // Check if the exception is a termination. If so, throw as uncatchable.
   2570   Label termination_exception;
   2571   __ JumpIfRoot(exception_value,
   2572                 Heap::kTerminationExceptionRootIndex,
   2573                 &termination_exception);
   2574 
   2575   __ Throw(exception_value, x10, x11, x12, x13);
   2576 
   2577   __ Bind(&termination_exception);
   2578   __ ThrowUncatchable(exception_value, x10, x11, x12, x13);
   2579 
   2580   __ Bind(&failure);
   2581   __ Mov(x0, Operand(isolate()->factory()->null_value()));
   2582   __ PopCPURegList(used_callee_saved_registers);
   2583   // Drop the 4 arguments of the stub from the stack.
   2584   __ Drop(4);
   2585   __ Ret();
   2586 
   2587   __ Bind(&runtime);
   2588   __ PopCPURegList(used_callee_saved_registers);
   2589   __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
   2590 
   2591   // Deferred code for string handling.
   2592   // (6) Not a long external string?  If yes, go to (8).
   2593   __ Bind(&not_seq_nor_cons);
   2594   // Compare flags are still set.
   2595   __ B(ne, &not_long_external);  // Go to (8).
   2596 
   2597   // (7) External string. Make it, offset-wise, look like a sequential string.
   2598   __ Bind(&external_string);
   2599   if (masm->emit_debug_code()) {
   2600     // Assert that we do not have a cons or slice (indirect strings) here.
   2601     // Sequential strings have already been ruled out.
   2602     __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset));
   2603     __ Ldrb(x10, FieldMemOperand(x10, Map::kInstanceTypeOffset));
   2604     __ Tst(x10, kIsIndirectStringMask);
   2605     __ Check(eq, kExternalStringExpectedButNotFound);
   2606     __ And(x10, x10, kStringRepresentationMask);
   2607     __ Cmp(x10, 0);
   2608     __ Check(ne, kExternalStringExpectedButNotFound);
   2609   }
   2610   __ Ldr(subject,
   2611          FieldMemOperand(subject, ExternalString::kResourceDataOffset));
   2612   // Move the pointer so that offset-wise, it looks like a sequential string.
   2613   STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
   2614   __ Sub(subject, subject, SeqTwoByteString::kHeaderSize - kHeapObjectTag);
   2615   __ B(&seq_string);    // Go to (5).
   2616 
   2617   // (8) If this is a short external string or not a string, bail out to
   2618   // runtime.
   2619   __ Bind(&not_long_external);
   2620   STATIC_ASSERT(kShortExternalStringTag != 0);
   2621   __ TestAndBranchIfAnySet(string_representation,
   2622                            kShortExternalStringMask | kIsNotStringMask,
   2623                            &runtime);
   2624 
   2625   // (9) Sliced string. Replace subject with parent.
   2626   __ Ldr(sliced_string_offset,
   2627          UntagSmiFieldMemOperand(subject, SlicedString::kOffsetOffset));
   2628   __ Ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
   2629   __ B(&check_underlying);    // Go to (4).
   2630 #endif
   2631 }
   2632 
   2633 
   2634 static void GenerateRecordCallTarget(MacroAssembler* masm,
   2635                                      Register argc,
   2636                                      Register function,
   2637                                      Register feedback_vector,
   2638                                      Register index,
   2639                                      Register scratch1,
   2640                                      Register scratch2) {
   2641   ASM_LOCATION("GenerateRecordCallTarget");
   2642   DCHECK(!AreAliased(scratch1, scratch2,
   2643                      argc, function, feedback_vector, index));
   2644   // Cache the called function in a feedback vector slot. Cache states are
   2645   // uninitialized, monomorphic (indicated by a JSFunction), and megamorphic.
   2646   //  argc :            number of arguments to the construct function
   2647   //  function :        the function to call
   2648   //  feedback_vector : the feedback vector
   2649   //  index :           slot in feedback vector (smi)
   2650   Label initialize, done, miss, megamorphic, not_array_function;
   2651 
   2652   DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()),
   2653             masm->isolate()->heap()->megamorphic_symbol());
   2654   DCHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(masm->isolate()),
   2655             masm->isolate()->heap()->uninitialized_symbol());
   2656 
   2657   // Load the cache state.
   2658   __ Add(scratch1, feedback_vector,
   2659          Operand::UntagSmiAndScale(index, kPointerSizeLog2));
   2660   __ Ldr(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
   2661 
   2662   // A monomorphic cache hit or an already megamorphic state: invoke the
   2663   // function without changing the state.
   2664   __ Cmp(scratch1, function);
   2665   __ B(eq, &done);
   2666 
   2667   if (!FLAG_pretenuring_call_new) {
   2668     // If we came here, we need to see if we are the array function.
   2669     // If we didn't have a matching function, and we didn't find the megamorph
   2670     // sentinel, then we have in the slot either some other function or an
   2671     // AllocationSite. Do a map check on the object in scratch1 register.
   2672     __ Ldr(scratch2, FieldMemOperand(scratch1, AllocationSite::kMapOffset));
   2673     __ JumpIfNotRoot(scratch2, Heap::kAllocationSiteMapRootIndex, &miss);
   2674 
   2675     // Make sure the function is the Array() function
   2676     __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, scratch1);
   2677     __ Cmp(function, scratch1);
   2678     __ B(ne, &megamorphic);
   2679     __ B(&done);
   2680   }
   2681 
   2682   __ Bind(&miss);
   2683 
   2684   // A monomorphic miss (i.e, here the cache is not uninitialized) goes
   2685   // megamorphic.
   2686   __ JumpIfRoot(scratch1, Heap::kUninitializedSymbolRootIndex, &initialize);
   2687   // MegamorphicSentinel is an immortal immovable object (undefined) so no
   2688   // write-barrier is needed.
   2689   __ Bind(&megamorphic);
   2690   __ Add(scratch1, feedback_vector,
   2691          Operand::UntagSmiAndScale(index, kPointerSizeLog2));
   2692   __ LoadRoot(scratch2, Heap::kMegamorphicSymbolRootIndex);
   2693   __ Str(scratch2, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
   2694   __ B(&done);
   2695 
   2696   // An uninitialized cache is patched with the function or sentinel to
   2697   // indicate the ElementsKind if function is the Array constructor.
   2698   __ Bind(&initialize);
   2699 
   2700   if (!FLAG_pretenuring_call_new) {
   2701     // Make sure the function is the Array() function
   2702     __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, scratch1);
   2703     __ Cmp(function, scratch1);
   2704     __ B(ne, &not_array_function);
   2705 
   2706     // The target function is the Array constructor,
   2707     // Create an AllocationSite if we don't already have it, store it in the
   2708     // slot.
   2709     {
   2710       FrameScope scope(masm, StackFrame::INTERNAL);
   2711       CreateAllocationSiteStub create_stub(masm->isolate());
   2712 
   2713       // Arguments register must be smi-tagged to call out.
   2714       __ SmiTag(argc);
   2715       __ Push(argc, function, feedback_vector, index);
   2716 
   2717       // CreateAllocationSiteStub expect the feedback vector in x2 and the slot
   2718       // index in x3.
   2719       DCHECK(feedback_vector.Is(x2) && index.Is(x3));
   2720       __ CallStub(&create_stub);
   2721 
   2722       __ Pop(index, feedback_vector, function, argc);
   2723       __ SmiUntag(argc);
   2724     }
   2725     __ B(&done);
   2726 
   2727     __ Bind(&not_array_function);
   2728   }
   2729 
   2730   // An uninitialized cache is patched with the function.
   2731 
   2732   __ Add(scratch1, feedback_vector,
   2733          Operand::UntagSmiAndScale(index, kPointerSizeLog2));
   2734   __ Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag);
   2735   __ Str(function, MemOperand(scratch1, 0));
   2736 
   2737   __ Push(function);
   2738   __ RecordWrite(feedback_vector, scratch1, function, kLRHasNotBeenSaved,
   2739                  kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
   2740   __ Pop(function);
   2741 
   2742   __ Bind(&done);
   2743 }
   2744 
   2745 
   2746 static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
   2747   // Do not transform the receiver for strict mode functions.
   2748   __ Ldr(x3, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
   2749   __ Ldr(w4, FieldMemOperand(x3, SharedFunctionInfo::kCompilerHintsOffset));
   2750   __ Tbnz(w4, SharedFunctionInfo::kStrictModeFunction, cont);
   2751 
   2752   // Do not transform the receiver for native (Compilerhints already in x3).
   2753   __ Tbnz(w4, SharedFunctionInfo::kNative, cont);
   2754 }
   2755 
   2756 
   2757 static void EmitSlowCase(MacroAssembler* masm,
   2758                          int argc,
   2759                          Register function,
   2760                          Register type,
   2761                          Label* non_function) {
   2762   // Check for function proxy.
   2763   // x10 : function type.
   2764   __ CompareAndBranch(type, JS_FUNCTION_PROXY_TYPE, ne, non_function);
   2765   __ Push(function);  // put proxy as additional argument
   2766   __ Mov(x0, argc + 1);
   2767   __ Mov(x2, 0);
   2768   __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY);
   2769   {
   2770     Handle<Code> adaptor =
   2771         masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
   2772     __ Jump(adaptor, RelocInfo::CODE_TARGET);
   2773   }
   2774 
   2775   // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
   2776   // of the original receiver from the call site).
   2777   __ Bind(non_function);
   2778   __ Poke(function, argc * kXRegSize);
   2779   __ Mov(x0, argc);  // Set up the number of arguments.
   2780   __ Mov(x2, 0);
   2781   __ GetBuiltinFunction(function, Builtins::CALL_NON_FUNCTION);
   2782   __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
   2783           RelocInfo::CODE_TARGET);
   2784 }
   2785 
   2786 
   2787 static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
   2788   // Wrap the receiver and patch it back onto the stack.
   2789   { FrameScope frame_scope(masm, StackFrame::INTERNAL);
   2790     __ Push(x1, x3);
   2791     __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
   2792     __ Pop(x1);
   2793   }
   2794   __ Poke(x0, argc * kPointerSize);
   2795   __ B(cont);
   2796 }
   2797 
   2798 
   2799 static void CallFunctionNoFeedback(MacroAssembler* masm,
   2800                                    int argc, bool needs_checks,
   2801                                    bool call_as_method) {
   2802   // x1  function    the function to call
   2803   Register function = x1;
   2804   Register type = x4;
   2805   Label slow, non_function, wrap, cont;
   2806 
   2807   // TODO(jbramley): This function has a lot of unnamed registers. Name them,
   2808   // and tidy things up a bit.
   2809 
   2810   if (needs_checks) {
   2811     // Check that the function is really a JavaScript function.
   2812     __ JumpIfSmi(function, &non_function);
   2813 
   2814     // Goto slow case if we do not have a function.
   2815     __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow);
   2816   }
   2817 
   2818   // Fast-case: Invoke the function now.
   2819   // x1  function  pushed function
   2820   ParameterCount actual(argc);
   2821 
   2822   if (call_as_method) {
   2823     if (needs_checks) {
   2824       EmitContinueIfStrictOrNative(masm, &cont);
   2825     }
   2826 
   2827     // Compute the receiver in sloppy mode.
   2828     __ Peek(x3, argc * kPointerSize);
   2829 
   2830     if (needs_checks) {
   2831       __ JumpIfSmi(x3, &wrap);
   2832       __ JumpIfObjectType(x3, x10, type, FIRST_SPEC_OBJECT_TYPE, &wrap, lt);
   2833     } else {
   2834       __ B(&wrap);
   2835     }
   2836 
   2837     __ Bind(&cont);
   2838   }
   2839 
   2840   __ InvokeFunction(function,
   2841                     actual,
   2842                     JUMP_FUNCTION,
   2843                     NullCallWrapper());
   2844   if (needs_checks) {
   2845     // Slow-case: Non-function called.
   2846     __ Bind(&slow);
   2847     EmitSlowCase(masm, argc, function, type, &non_function);
   2848   }
   2849 
   2850   if (call_as_method) {
   2851     __ Bind(&wrap);
   2852     EmitWrapCase(masm, argc, &cont);
   2853   }
   2854 }
   2855 
   2856 
   2857 void CallFunctionStub::Generate(MacroAssembler* masm) {
   2858   ASM_LOCATION("CallFunctionStub::Generate");
   2859   CallFunctionNoFeedback(masm, argc(), NeedsChecks(), CallAsMethod());
   2860 }
   2861 
   2862 
   2863 void CallConstructStub::Generate(MacroAssembler* masm) {
   2864   ASM_LOCATION("CallConstructStub::Generate");
   2865   // x0 : number of arguments
   2866   // x1 : the function to call
   2867   // x2 : feedback vector
   2868   // x3 : slot in feedback vector (smi) (if r2 is not the megamorphic symbol)
   2869   Register function = x1;
   2870   Label slow, non_function_call;
   2871 
   2872   // Check that the function is not a smi.
   2873   __ JumpIfSmi(function, &non_function_call);
   2874   // Check that the function is a JSFunction.
   2875   Register object_type = x10;
   2876   __ JumpIfNotObjectType(function, object_type, object_type, JS_FUNCTION_TYPE,
   2877                          &slow);
   2878 
   2879   if (RecordCallTarget()) {
   2880     GenerateRecordCallTarget(masm, x0, function, x2, x3, x4, x5);
   2881 
   2882     __ Add(x5, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
   2883     if (FLAG_pretenuring_call_new) {
   2884       // Put the AllocationSite from the feedback vector into x2.
   2885       // By adding kPointerSize we encode that we know the AllocationSite
   2886       // entry is at the feedback vector slot given by x3 + 1.
   2887       __ Ldr(x2, FieldMemOperand(x5, FixedArray::kHeaderSize + kPointerSize));
   2888     } else {
   2889     Label feedback_register_initialized;
   2890       // Put the AllocationSite from the feedback vector into x2, or undefined.
   2891       __ Ldr(x2, FieldMemOperand(x5, FixedArray::kHeaderSize));
   2892       __ Ldr(x5, FieldMemOperand(x2, AllocationSite::kMapOffset));
   2893       __ JumpIfRoot(x5, Heap::kAllocationSiteMapRootIndex,
   2894                     &feedback_register_initialized);
   2895       __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
   2896       __ bind(&feedback_register_initialized);
   2897     }
   2898 
   2899     __ AssertUndefinedOrAllocationSite(x2, x5);
   2900   }
   2901 
   2902   // Jump to the function-specific construct stub.
   2903   Register jump_reg = x4;
   2904   Register shared_func_info = jump_reg;
   2905   Register cons_stub = jump_reg;
   2906   Register cons_stub_code = jump_reg;
   2907   __ Ldr(shared_func_info,
   2908          FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
   2909   __ Ldr(cons_stub,
   2910          FieldMemOperand(shared_func_info,
   2911                          SharedFunctionInfo::kConstructStubOffset));
   2912   __ Add(cons_stub_code, cons_stub, Code::kHeaderSize - kHeapObjectTag);
   2913   __ Br(cons_stub_code);
   2914 
   2915   Label do_call;
   2916   __ Bind(&slow);
   2917   __ Cmp(object_type, JS_FUNCTION_PROXY_TYPE);
   2918   __ B(ne, &non_function_call);
   2919   __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
   2920   __ B(&do_call);
   2921 
   2922   __ Bind(&non_function_call);
   2923   __ GetBuiltinFunction(x1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
   2924 
   2925   __ Bind(&do_call);
   2926   // Set expected number of arguments to zero (not changing x0).
   2927   __ Mov(x2, 0);
   2928   __ Jump(isolate()->builtins()->ArgumentsAdaptorTrampoline(),
   2929           RelocInfo::CODE_TARGET);
   2930 }
   2931 
   2932 
   2933 static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) {
   2934   __ Ldr(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
   2935   __ Ldr(vector, FieldMemOperand(vector,
   2936                                  JSFunction::kSharedFunctionInfoOffset));
   2937   __ Ldr(vector, FieldMemOperand(vector,
   2938                                  SharedFunctionInfo::kFeedbackVectorOffset));
   2939 }
   2940 
   2941 
   2942 void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
   2943   // x1 - function
   2944   // x3 - slot id
   2945   Label miss;
   2946   Register function = x1;
   2947   Register feedback_vector = x2;
   2948   Register index = x3;
   2949   Register scratch = x4;
   2950 
   2951   EmitLoadTypeFeedbackVector(masm, feedback_vector);
   2952 
   2953   __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, scratch);
   2954   __ Cmp(function, scratch);
   2955   __ B(ne, &miss);
   2956 
   2957   __ Mov(x0, Operand(arg_count()));
   2958 
   2959   __ Add(scratch, feedback_vector,
   2960          Operand::UntagSmiAndScale(index, kPointerSizeLog2));
   2961   __ Ldr(scratch, FieldMemOperand(scratch, FixedArray::kHeaderSize));
   2962 
   2963   // Verify that scratch contains an AllocationSite
   2964   Register map = x5;
   2965   __ Ldr(map, FieldMemOperand(scratch, HeapObject::kMapOffset));
   2966   __ JumpIfNotRoot(map, Heap::kAllocationSiteMapRootIndex, &miss);
   2967 
   2968   Register allocation_site = feedback_vector;
   2969   __ Mov(allocation_site, scratch);
   2970   ArrayConstructorStub stub(masm->isolate(), arg_count());
   2971   __ TailCallStub(&stub);
   2972 
   2973   __ bind(&miss);
   2974   GenerateMiss(masm);
   2975 
   2976   // The slow case, we need this no matter what to complete a call after a miss.
   2977   CallFunctionNoFeedback(masm,
   2978                          arg_count(),
   2979                          true,
   2980                          CallAsMethod());
   2981 
   2982   __ Unreachable();
   2983 }
   2984 
   2985 
   2986 void CallICStub::Generate(MacroAssembler* masm) {
   2987   ASM_LOCATION("CallICStub");
   2988 
   2989   // x1 - function
   2990   // x3 - slot id (Smi)
   2991   Label extra_checks_or_miss, slow_start;
   2992   Label slow, non_function, wrap, cont;
   2993   Label have_js_function;
   2994   int argc = arg_count();
   2995   ParameterCount actual(argc);
   2996 
   2997   Register function = x1;
   2998   Register feedback_vector = x2;
   2999   Register index = x3;
   3000   Register type = x4;
   3001 
   3002   EmitLoadTypeFeedbackVector(masm, feedback_vector);
   3003 
   3004   // The checks. First, does x1 match the recorded monomorphic target?
   3005   __ Add(x4, feedback_vector,
   3006          Operand::UntagSmiAndScale(index, kPointerSizeLog2));
   3007   __ Ldr(x4, FieldMemOperand(x4, FixedArray::kHeaderSize));
   3008 
   3009   __ Cmp(x4, function);
   3010   __ B(ne, &extra_checks_or_miss);
   3011 
   3012   __ bind(&have_js_function);
   3013   if (CallAsMethod()) {
   3014     EmitContinueIfStrictOrNative(masm, &cont);
   3015 
   3016     // Compute the receiver in sloppy mode.
   3017     __ Peek(x3, argc * kPointerSize);
   3018 
   3019     __ JumpIfSmi(x3, &wrap);
   3020     __ JumpIfObjectType(x3, x10, type, FIRST_SPEC_OBJECT_TYPE, &wrap, lt);
   3021 
   3022     __ Bind(&cont);
   3023   }
   3024 
   3025   __ InvokeFunction(function,
   3026                     actual,
   3027                     JUMP_FUNCTION,
   3028                     NullCallWrapper());
   3029 
   3030   __ bind(&slow);
   3031   EmitSlowCase(masm, argc, function, type, &non_function);
   3032 
   3033   if (CallAsMethod()) {
   3034     __ bind(&wrap);
   3035     EmitWrapCase(masm, argc, &cont);
   3036   }
   3037 
   3038   __ bind(&extra_checks_or_miss);
   3039   Label miss;
   3040 
   3041   __ JumpIfRoot(x4, Heap::kMegamorphicSymbolRootIndex, &slow_start);
   3042   __ JumpIfRoot(x4, Heap::kUninitializedSymbolRootIndex, &miss);
   3043 
   3044   if (!FLAG_trace_ic) {
   3045     // We are going megamorphic. If the feedback is a JSFunction, it is fine
   3046     // to handle it here. More complex cases are dealt with in the runtime.
   3047     __ AssertNotSmi(x4);
   3048     __ JumpIfNotObjectType(x4, x5, x5, JS_FUNCTION_TYPE, &miss);
   3049     __ Add(x4, feedback_vector,
   3050            Operand::UntagSmiAndScale(index, kPointerSizeLog2));
   3051     __ LoadRoot(x5, Heap::kMegamorphicSymbolRootIndex);
   3052     __ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize));
   3053     __ B(&slow_start);
   3054   }
   3055 
   3056   // We are here because tracing is on or we are going monomorphic.
   3057   __ bind(&miss);
   3058   GenerateMiss(masm);
   3059 
   3060   // the slow case
   3061   __ bind(&slow_start);
   3062 
   3063   // Check that the function is really a JavaScript function.
   3064   __ JumpIfSmi(function, &non_function);
   3065 
   3066   // Goto slow case if we do not have a function.
   3067   __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow);
   3068   __ B(&have_js_function);
   3069 }
   3070 
   3071 
   3072 void CallICStub::GenerateMiss(MacroAssembler* masm) {
   3073   ASM_LOCATION("CallICStub[Miss]");
   3074 
   3075   // Get the receiver of the function from the stack; 1 ~ return address.
   3076   __ Peek(x4, (arg_count() + 1) * kPointerSize);
   3077 
   3078   {
   3079     FrameScope scope(masm, StackFrame::INTERNAL);
   3080 
   3081     // Push the receiver and the function and feedback info.
   3082     __ Push(x4, x1, x2, x3);
   3083 
   3084     // Call the entry.
   3085     IC::UtilityId id = GetICState() == DEFAULT ? IC::kCallIC_Miss
   3086                                                : IC::kCallIC_Customization_Miss;
   3087 
   3088     ExternalReference miss = ExternalReference(IC_Utility(id),
   3089                                                masm->isolate());
   3090     __ CallExternalReference(miss, 4);
   3091 
   3092     // Move result to edi and exit the internal frame.
   3093     __ Mov(x1, x0);
   3094   }
   3095 }
   3096 
   3097 
   3098 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
   3099   // If the receiver is a smi trigger the non-string case.
   3100   __ JumpIfSmi(object_, receiver_not_string_);
   3101 
   3102   // Fetch the instance type of the receiver into result register.
   3103   __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
   3104   __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
   3105 
   3106   // If the receiver is not a string trigger the non-string case.
   3107   __ TestAndBranchIfAnySet(result_, kIsNotStringMask, receiver_not_string_);
   3108 
   3109   // If the index is non-smi trigger the non-smi case.
   3110   __ JumpIfNotSmi(index_, &index_not_smi_);
   3111 
   3112   __ Bind(&got_smi_index_);
   3113   // Check for index out of range.
   3114   __ Ldrsw(result_, UntagSmiFieldMemOperand(object_, String::kLengthOffset));
   3115   __ Cmp(result_, Operand::UntagSmi(index_));
   3116   __ B(ls, index_out_of_range_);
   3117 
   3118   __ SmiUntag(index_);
   3119 
   3120   StringCharLoadGenerator::Generate(masm,
   3121                                     object_,
   3122                                     index_.W(),
   3123                                     result_,
   3124                                     &call_runtime_);
   3125   __ SmiTag(result_);
   3126   __ Bind(&exit_);
   3127 }
   3128 
   3129 
   3130 void StringCharCodeAtGenerator::GenerateSlow(
   3131     MacroAssembler* masm,
   3132     const RuntimeCallHelper& call_helper) {
   3133   __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
   3134 
   3135   __ Bind(&index_not_smi_);
   3136   // If index is a heap number, try converting it to an integer.
   3137   __ JumpIfNotHeapNumber(index_, index_not_number_);
   3138   call_helper.BeforeCall(masm);
   3139   // Save object_ on the stack and pass index_ as argument for runtime call.
   3140   __ Push(object_, index_);
   3141   if (index_flags_ == STRING_INDEX_IS_NUMBER) {
   3142     __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
   3143   } else {
   3144     DCHECK(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
   3145     // NumberToSmi discards numbers that are not exact integers.
   3146     __ CallRuntime(Runtime::kNumberToSmi, 1);
   3147   }
   3148   // Save the conversion result before the pop instructions below
   3149   // have a chance to overwrite it.
   3150   __ Mov(index_, x0);
   3151   __ Pop(object_);
   3152   // Reload the instance type.
   3153   __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
   3154   __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
   3155   call_helper.AfterCall(masm);
   3156 
   3157   // If index is still not a smi, it must be out of range.
   3158   __ JumpIfNotSmi(index_, index_out_of_range_);
   3159   // Otherwise, return to the fast path.
   3160   __ B(&got_smi_index_);
   3161 
   3162   // Call runtime. We get here when the receiver is a string and the
   3163   // index is a number, but the code of getting the actual character
   3164   // is too complex (e.g., when the string needs to be flattened).
   3165   __ Bind(&call_runtime_);
   3166   call_helper.BeforeCall(masm);
   3167   __ SmiTag(index_);
   3168   __ Push(object_, index_);
   3169   __ CallRuntime(Runtime::kStringCharCodeAtRT, 2);
   3170   __ Mov(result_, x0);
   3171   call_helper.AfterCall(masm);
   3172   __ B(&exit_);
   3173 
   3174   __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
   3175 }
   3176 
   3177 
   3178 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
   3179   __ JumpIfNotSmi(code_, &slow_case_);
   3180   __ Cmp(code_, Smi::FromInt(String::kMaxOneByteCharCode));
   3181   __ B(hi, &slow_case_);
   3182 
   3183   __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
   3184   // At this point code register contains smi tagged one-byte char code.
   3185   __ Add(result_, result_, Operand::UntagSmiAndScale(code_, kPointerSizeLog2));
   3186   __ Ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
   3187   __ JumpIfRoot(result_, Heap::kUndefinedValueRootIndex, &slow_case_);
   3188   __ Bind(&exit_);
   3189 }
   3190 
   3191 
   3192 void StringCharFromCodeGenerator::GenerateSlow(
   3193     MacroAssembler* masm,
   3194     const RuntimeCallHelper& call_helper) {
   3195   __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
   3196 
   3197   __ Bind(&slow_case_);
   3198   call_helper.BeforeCall(masm);
   3199   __ Push(code_);
   3200   __ CallRuntime(Runtime::kCharFromCode, 1);
   3201   __ Mov(result_, x0);
   3202   call_helper.AfterCall(masm);
   3203   __ B(&exit_);
   3204 
   3205   __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
   3206 }
   3207 
   3208 
   3209 void CompareICStub::GenerateSmis(MacroAssembler* masm) {
   3210   // Inputs are in x0 (lhs) and x1 (rhs).
   3211   DCHECK(state() == CompareICState::SMI);
   3212   ASM_LOCATION("CompareICStub[Smis]");
   3213   Label miss;
   3214   // Bail out (to 'miss') unless both x0 and x1 are smis.
   3215   __ JumpIfEitherNotSmi(x0, x1, &miss);
   3216 
   3217   if (GetCondition() == eq) {
   3218     // For equality we do not care about the sign of the result.
   3219     __ Sub(x0, x0, x1);
   3220   } else {
   3221     // Untag before subtracting to avoid handling overflow.
   3222     __ SmiUntag(x1);
   3223     __ Sub(x0, x1, Operand::UntagSmi(x0));
   3224   }
   3225   __ Ret();
   3226 
   3227   __ Bind(&miss);
   3228   GenerateMiss(masm);
   3229 }
   3230 
   3231 
   3232 void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
   3233   DCHECK(state() == CompareICState::NUMBER);
   3234   ASM_LOCATION("CompareICStub[HeapNumbers]");
   3235 
   3236   Label unordered, maybe_undefined1, maybe_undefined2;
   3237   Label miss, handle_lhs, values_in_d_regs;
   3238   Label untag_rhs, untag_lhs;
   3239 
   3240   Register result = x0;
   3241   Register rhs = x0;
   3242   Register lhs = x1;
   3243   FPRegister rhs_d = d0;
   3244   FPRegister lhs_d = d1;
   3245 
   3246   if (left() == CompareICState::SMI) {
   3247     __ JumpIfNotSmi(lhs, &miss);
   3248   }
   3249   if (right() == CompareICState::SMI) {
   3250     __ JumpIfNotSmi(rhs, &miss);
   3251   }
   3252 
   3253   __ SmiUntagToDouble(rhs_d, rhs, kSpeculativeUntag);
   3254   __ SmiUntagToDouble(lhs_d, lhs, kSpeculativeUntag);
   3255 
   3256   // Load rhs if it's a heap number.
   3257   __ JumpIfSmi(rhs, &handle_lhs);
   3258   __ JumpIfNotHeapNumber(rhs, &maybe_undefined1);
   3259   __ Ldr(rhs_d, FieldMemOperand(rhs, HeapNumber::kValueOffset));
   3260 
   3261   // Load lhs if it's a heap number.
   3262   __ Bind(&handle_lhs);
   3263   __ JumpIfSmi(lhs, &values_in_d_regs);
   3264   __ JumpIfNotHeapNumber(lhs, &maybe_undefined2);
   3265   __ Ldr(lhs_d, FieldMemOperand(lhs, HeapNumber::kValueOffset));
   3266 
   3267   __ Bind(&values_in_d_regs);
   3268   __ Fcmp(lhs_d, rhs_d);
   3269   __ B(vs, &unordered);  // Overflow flag set if either is NaN.
   3270   STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1));
   3271   __ Cset(result, gt);  // gt => 1, otherwise (lt, eq) => 0 (EQUAL).
   3272   __ Csinv(result, result, xzr, ge);  // lt => -1, gt => 1, eq => 0.
   3273   __ Ret();
   3274 
   3275   __ Bind(&unordered);
   3276   CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
   3277                      CompareICState::GENERIC, CompareICState::GENERIC);
   3278   __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
   3279 
   3280   __ Bind(&maybe_undefined1);
   3281   if (Token::IsOrderedRelationalCompareOp(op())) {
   3282     __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss);
   3283     __ JumpIfSmi(lhs, &unordered);
   3284     __ JumpIfNotHeapNumber(lhs, &maybe_undefined2);
   3285     __ B(&unordered);
   3286   }
   3287 
   3288   __ Bind(&maybe_undefined2);
   3289   if (Token::IsOrderedRelationalCompareOp(op())) {
   3290     __ JumpIfRoot(lhs, Heap::kUndefinedValueRootIndex, &unordered);
   3291   }
   3292 
   3293   __ Bind(&miss);
   3294   GenerateMiss(masm);
   3295 }
   3296 
   3297 
   3298 void CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) {
   3299   DCHECK(state() == CompareICState::INTERNALIZED_STRING);
   3300   ASM_LOCATION("CompareICStub[InternalizedStrings]");
   3301   Label miss;
   3302 
   3303   Register result = x0;
   3304   Register rhs = x0;
   3305   Register lhs = x1;
   3306 
   3307   // Check that both operands are heap objects.
   3308   __ JumpIfEitherSmi(lhs, rhs, &miss);
   3309 
   3310   // Check that both operands are internalized strings.
   3311   Register rhs_map = x10;
   3312   Register lhs_map = x11;
   3313   Register rhs_type = x10;
   3314   Register lhs_type = x11;
   3315   __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset));
   3316   __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset));
   3317   __ Ldrb(lhs_type, FieldMemOperand(lhs_map, Map::kInstanceTypeOffset));
   3318   __ Ldrb(rhs_type, FieldMemOperand(rhs_map, Map::kInstanceTypeOffset));
   3319 
   3320   STATIC_ASSERT((kInternalizedTag == 0) && (kStringTag == 0));
   3321   __ Orr(x12, lhs_type, rhs_type);
   3322   __ TestAndBranchIfAnySet(
   3323       x12, kIsNotStringMask | kIsNotInternalizedMask, &miss);
   3324 
   3325   // Internalized strings are compared by identity.
   3326   STATIC_ASSERT(EQUAL == 0);
   3327   __ Cmp(lhs, rhs);
   3328   __ Cset(result, ne);
   3329   __ Ret();
   3330 
   3331   __ Bind(&miss);
   3332   GenerateMiss(masm);
   3333 }
   3334 
   3335 
   3336 void CompareICStub::GenerateUniqueNames(MacroAssembler* masm) {
   3337   DCHECK(state() == CompareICState::UNIQUE_NAME);
   3338   ASM_LOCATION("CompareICStub[UniqueNames]");
   3339   DCHECK(GetCondition() == eq);
   3340   Label miss;
   3341 
   3342   Register result = x0;
   3343   Register rhs = x0;
   3344   Register lhs = x1;
   3345 
   3346   Register lhs_instance_type = w2;
   3347   Register rhs_instance_type = w3;
   3348 
   3349   // Check that both operands are heap objects.
   3350   __ JumpIfEitherSmi(lhs, rhs, &miss);
   3351 
   3352   // Check that both operands are unique names. This leaves the instance
   3353   // types loaded in tmp1 and tmp2.
   3354   __ Ldr(x10, FieldMemOperand(lhs, HeapObject::kMapOffset));
   3355   __ Ldr(x11, FieldMemOperand(rhs, HeapObject::kMapOffset));
   3356   __ Ldrb(lhs_instance_type, FieldMemOperand(x10, Map::kInstanceTypeOffset));
   3357   __ Ldrb(rhs_instance_type, FieldMemOperand(x11, Map::kInstanceTypeOffset));
   3358 
   3359   // To avoid a miss, each instance type should be either SYMBOL_TYPE or it
   3360   // should have kInternalizedTag set.
   3361   __ JumpIfNotUniqueNameInstanceType(lhs_instance_type, &miss);
   3362   __ JumpIfNotUniqueNameInstanceType(rhs_instance_type, &miss);
   3363 
   3364   // Unique names are compared by identity.
   3365   STATIC_ASSERT(EQUAL == 0);
   3366   __ Cmp(lhs, rhs);
   3367   __ Cset(result, ne);
   3368   __ Ret();
   3369 
   3370   __ Bind(&miss);
   3371   GenerateMiss(masm);
   3372 }
   3373 
   3374 
   3375 void CompareICStub::GenerateStrings(MacroAssembler* masm) {
   3376   DCHECK(state() == CompareICState::STRING);
   3377   ASM_LOCATION("CompareICStub[Strings]");
   3378 
   3379   Label miss;
   3380 
   3381   bool equality = Token::IsEqualityOp(op());
   3382 
   3383   Register result = x0;
   3384   Register rhs = x0;
   3385   Register lhs = x1;
   3386 
   3387   // Check that both operands are heap objects.
   3388   __ JumpIfEitherSmi(rhs, lhs, &miss);
   3389 
   3390   // Check that both operands are strings.
   3391   Register rhs_map = x10;
   3392   Register lhs_map = x11;
   3393   Register rhs_type = x10;
   3394   Register lhs_type = x11;
   3395   __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset));
   3396   __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset));
   3397   __ Ldrb(lhs_type, FieldMemOperand(lhs_map, Map::kInstanceTypeOffset));
   3398   __ Ldrb(rhs_type, FieldMemOperand(rhs_map, Map::kInstanceTypeOffset));
   3399   STATIC_ASSERT(kNotStringTag != 0);
   3400   __ Orr(x12, lhs_type, rhs_type);
   3401   __ Tbnz(x12, MaskToBit(kIsNotStringMask), &miss);
   3402 
   3403   // Fast check for identical strings.
   3404   Label not_equal;
   3405   __ Cmp(lhs, rhs);
   3406   __ B(ne, &not_equal);
   3407   __ Mov(result, EQUAL);
   3408   __ Ret();
   3409 
   3410   __ Bind(&not_equal);
   3411   // Handle not identical strings
   3412 
   3413   // Check that both strings are internalized strings. If they are, we're done
   3414   // because we already know they are not identical. We know they are both
   3415   // strings.
   3416   if (equality) {
   3417     DCHECK(GetCondition() == eq);
   3418     STATIC_ASSERT(kInternalizedTag == 0);
   3419     Label not_internalized_strings;
   3420     __ Orr(x12, lhs_type, rhs_type);
   3421     __ TestAndBranchIfAnySet(
   3422         x12, kIsNotInternalizedMask, &not_internalized_strings);
   3423     // Result is in rhs (x0), and not EQUAL, as rhs is not a smi.
   3424     __ Ret();
   3425     __ Bind(&not_internalized_strings);
   3426   }
   3427 
   3428   // Check that both strings are sequential one-byte.
   3429   Label runtime;
   3430   __ JumpIfBothInstanceTypesAreNotSequentialOneByte(lhs_type, rhs_type, x12,
   3431                                                     x13, &runtime);
   3432 
   3433   // Compare flat one-byte strings. Returns when done.
   3434   if (equality) {
   3435     StringHelper::GenerateFlatOneByteStringEquals(masm, lhs, rhs, x10, x11,
   3436                                                   x12);
   3437   } else {
   3438     StringHelper::GenerateCompareFlatOneByteStrings(masm, lhs, rhs, x10, x11,
   3439                                                     x12, x13);
   3440   }
   3441 
   3442   // Handle more complex cases in runtime.
   3443   __ Bind(&runtime);
   3444   __ Push(lhs, rhs);
   3445   if (equality) {
   3446     __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
   3447   } else {
   3448     __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
   3449   }
   3450 
   3451   __ Bind(&miss);
   3452   GenerateMiss(masm);
   3453 }
   3454 
   3455 
   3456 void CompareICStub::GenerateObjects(MacroAssembler* masm) {
   3457   DCHECK(state() == CompareICState::OBJECT);
   3458   ASM_LOCATION("CompareICStub[Objects]");
   3459 
   3460   Label miss;
   3461 
   3462   Register result = x0;
   3463   Register rhs = x0;
   3464   Register lhs = x1;
   3465 
   3466   __ JumpIfEitherSmi(rhs, lhs, &miss);
   3467 
   3468   __ JumpIfNotObjectType(rhs, x10, x10, JS_OBJECT_TYPE, &miss);
   3469   __ JumpIfNotObjectType(lhs, x10, x10, JS_OBJECT_TYPE, &miss);
   3470 
   3471   DCHECK(GetCondition() == eq);
   3472   __ Sub(result, rhs, lhs);
   3473   __ Ret();
   3474 
   3475   __ Bind(&miss);
   3476   GenerateMiss(masm);
   3477 }
   3478 
   3479 
   3480 void CompareICStub::GenerateKnownObjects(MacroAssembler* masm) {
   3481   ASM_LOCATION("CompareICStub[KnownObjects]");
   3482 
   3483   Label miss;
   3484 
   3485   Register result = x0;
   3486   Register rhs = x0;
   3487   Register lhs = x1;
   3488 
   3489   __ JumpIfEitherSmi(rhs, lhs, &miss);
   3490 
   3491   Register rhs_map = x10;
   3492   Register lhs_map = x11;
   3493   __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset));
   3494   __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset));
   3495   __ Cmp(rhs_map, Operand(known_map_));
   3496   __ B(ne, &miss);
   3497   __ Cmp(lhs_map, Operand(known_map_));
   3498   __ B(ne, &miss);
   3499 
   3500   __ Sub(result, rhs, lhs);
   3501   __ Ret();
   3502 
   3503   __ Bind(&miss);
   3504   GenerateMiss(masm);
   3505 }
   3506 
   3507 
   3508 // This method handles the case where a compare stub had the wrong
   3509 // implementation. It calls a miss handler, which re-writes the stub. All other
   3510 // CompareICStub::Generate* methods should fall back into this one if their
   3511 // operands were not the expected types.
   3512 void CompareICStub::GenerateMiss(MacroAssembler* masm) {
   3513   ASM_LOCATION("CompareICStub[Miss]");
   3514 
   3515   Register stub_entry = x11;
   3516   {
   3517     ExternalReference miss =
   3518       ExternalReference(IC_Utility(IC::kCompareIC_Miss), isolate());
   3519 
   3520     FrameScope scope(masm, StackFrame::INTERNAL);
   3521     Register op = x10;
   3522     Register left = x1;
   3523     Register right = x0;
   3524     // Preserve some caller-saved registers.
   3525     __ Push(x1, x0, lr);
   3526     // Push the arguments.
   3527     __ Mov(op, Smi::FromInt(this->op()));
   3528     __ Push(left, right, op);
   3529 
   3530     // Call the miss handler. This also pops the arguments.
   3531     __ CallExternalReference(miss, 3);
   3532 
   3533     // Compute the entry point of the rewritten stub.
   3534     __ Add(stub_entry, x0, Code::kHeaderSize - kHeapObjectTag);
   3535     // Restore caller-saved registers.
   3536     __ Pop(lr, x0, x1);
   3537   }
   3538 
   3539   // Tail-call to the new stub.
   3540   __ Jump(stub_entry);
   3541 }
   3542 
   3543 
   3544 void SubStringStub::Generate(MacroAssembler* masm) {
   3545   ASM_LOCATION("SubStringStub::Generate");
   3546   Label runtime;
   3547 
   3548   // Stack frame on entry.
   3549   //  lr: return address
   3550   //  jssp[0]:  substring "to" offset
   3551   //  jssp[8]:  substring "from" offset
   3552   //  jssp[16]: pointer to string object
   3553 
   3554   // This stub is called from the native-call %_SubString(...), so
   3555   // nothing can be assumed about the arguments. It is tested that:
   3556   //  "string" is a sequential string,
   3557   //  both "from" and "to" are smis, and
   3558   //  0 <= from <= to <= string.length (in debug mode.)
   3559   // If any of these assumptions fail, we call the runtime system.
   3560 
   3561   static const int kToOffset = 0 * kPointerSize;
   3562   static const int kFromOffset = 1 * kPointerSize;
   3563   static const int kStringOffset = 2 * kPointerSize;
   3564 
   3565   Register to = x0;
   3566   Register from = x15;
   3567   Register input_string = x10;
   3568   Register input_length = x11;
   3569   Register input_type = x12;
   3570   Register result_string = x0;
   3571   Register result_length = x1;
   3572   Register temp = x3;
   3573 
   3574   __ Peek(to, kToOffset);
   3575   __ Peek(from, kFromOffset);
   3576 
   3577   // Check that both from and to are smis. If not, jump to runtime.
   3578   __ JumpIfEitherNotSmi(from, to, &runtime);
   3579   __ SmiUntag(from);
   3580   __ SmiUntag(to);
   3581 
   3582   // Calculate difference between from and to. If to < from, branch to runtime.
   3583   __ Subs(result_length, to, from);
   3584   __ B(mi, &runtime);
   3585 
   3586   // Check from is positive.
   3587   __ Tbnz(from, kWSignBit, &runtime);
   3588 
   3589   // Make sure first argument is a string.
   3590   __ Peek(input_string, kStringOffset);
   3591   __ JumpIfSmi(input_string, &runtime);
   3592   __ IsObjectJSStringType(input_string, input_type, &runtime);
   3593 
   3594   Label single_char;
   3595   __ Cmp(result_length, 1);
   3596   __ B(eq, &single_char);
   3597 
   3598   // Short-cut for the case of trivial substring.
   3599   Label return_x0;
   3600   __ Ldrsw(input_length,
   3601            UntagSmiFieldMemOperand(input_string, String::kLengthOffset));
   3602 
   3603   __ Cmp(result_length, input_length);
   3604   __ CmovX(x0, input_string, eq);
   3605   // Return original string.
   3606   __ B(eq, &return_x0);
   3607 
   3608   // Longer than original string's length or negative: unsafe arguments.
   3609   __ B(hi, &runtime);
   3610 
   3611   // Shorter than original string's length: an actual substring.
   3612 
   3613   //   x0   to               substring end character offset
   3614   //   x1   result_length    length of substring result
   3615   //   x10  input_string     pointer to input string object
   3616   //   x10  unpacked_string  pointer to unpacked string object
   3617   //   x11  input_length     length of input string
   3618   //   x12  input_type       instance type of input string
   3619   //   x15  from             substring start character offset
   3620 
   3621   // Deal with different string types: update the index if necessary and put
   3622   // the underlying string into register unpacked_string.
   3623   Label underlying_unpacked, sliced_string, seq_or_external_string;
   3624   Label update_instance_type;
   3625   // If the string is not indirect, it can only be sequential or external.
   3626   STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
   3627   STATIC_ASSERT(kIsIndirectStringMask != 0);
   3628 
   3629   // Test for string types, and branch/fall through to appropriate unpacking
   3630   // code.
   3631   __ Tst(input_type, kIsIndirectStringMask);
   3632   __ B(eq, &seq_or_external_string);
   3633   __ Tst(input_type, kSlicedNotConsMask);
   3634   __ B(ne, &sliced_string);
   3635 
   3636   Register unpacked_string = input_string;
   3637 
   3638   // Cons string. Check whether it is flat, then fetch first part.
   3639   __ Ldr(temp, FieldMemOperand(input_string, ConsString::kSecondOffset));
   3640   __ JumpIfNotRoot(temp, Heap::kempty_stringRootIndex, &runtime);
   3641   __ Ldr(unpacked_string,
   3642          FieldMemOperand(input_string, ConsString::kFirstOffset));
   3643   __ B(&update_instance_type);
   3644 
   3645   __ Bind(&sliced_string);
   3646   // Sliced string. Fetch parent and correct start index by offset.
   3647   __ Ldrsw(temp,
   3648            UntagSmiFieldMemOperand(input_string, SlicedString::kOffsetOffset));
   3649   __ Add(from, from, temp);
   3650   __ Ldr(unpacked_string,
   3651          FieldMemOperand(input_string, SlicedString::kParentOffset));
   3652 
   3653   __ Bind(&update_instance_type);
   3654   __ Ldr(temp, FieldMemOperand(unpacked_string, HeapObject::kMapOffset));
   3655   __ Ldrb(input_type, FieldMemOperand(temp, Map::kInstanceTypeOffset));
   3656   // Now control must go to &underlying_unpacked. Since the no code is generated
   3657   // before then we fall through instead of generating a useless branch.
   3658 
   3659   __ Bind(&seq_or_external_string);
   3660   // Sequential or external string. Registers unpacked_string and input_string
   3661   // alias, so there's nothing to do here.
   3662   // Note that if code is added here, the above code must be updated.
   3663 
   3664   //   x0   result_string    pointer to result string object (uninit)
   3665   //   x1   result_length    length of substring result
   3666   //   x10  unpacked_string  pointer to unpacked string object
   3667   //   x11  input_length     length of input string
   3668   //   x12  input_type       instance type of input string
   3669   //   x15  from             substring start character offset
   3670   __ Bind(&underlying_unpacked);
   3671 
   3672   if (FLAG_string_slices) {
   3673     Label copy_routine;
   3674     __ Cmp(result_length, SlicedString::kMinLength);
   3675     // Short slice. Copy instead of slicing.
   3676     __ B(lt, &copy_routine);
   3677     // Allocate new sliced string. At this point we do not reload the instance
   3678     // type including the string encoding because we simply rely on the info
   3679     // provided by the original string. It does not matter if the original
   3680     // string's encoding is wrong because we always have to recheck encoding of
   3681     // the newly created string's parent anyway due to externalized strings.
   3682     Label two_byte_slice, set_slice_header;
   3683     STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
   3684     STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
   3685     __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_slice);
   3686     __ AllocateOneByteSlicedString(result_string, result_length, x3, x4,
   3687                                    &runtime);
   3688     __ B(&set_slice_header);
   3689 
   3690     __ Bind(&two_byte_slice);
   3691     __ AllocateTwoByteSlicedString(result_string, result_length, x3, x4,
   3692                                    &runtime);
   3693 
   3694     __ Bind(&set_slice_header);
   3695     __ SmiTag(from);
   3696     __ Str(from, FieldMemOperand(result_string, SlicedString::kOffsetOffset));
   3697     __ Str(unpacked_string,
   3698            FieldMemOperand(result_string, SlicedString::kParentOffset));
   3699     __ B(&return_x0);
   3700 
   3701     __ Bind(&copy_routine);
   3702   }
   3703 
   3704   //   x0   result_string    pointer to result string object (uninit)
   3705   //   x1   result_length    length of substring result
   3706   //   x10  unpacked_string  pointer to unpacked string object
   3707   //   x11  input_length     length of input string
   3708   //   x12  input_type       instance type of input string
   3709   //   x13  unpacked_char0   pointer to first char of unpacked string (uninit)
   3710   //   x13  substring_char0  pointer to first char of substring (uninit)
   3711   //   x14  result_char0     pointer to first char of result (uninit)
   3712   //   x15  from             substring start character offset
   3713   Register unpacked_char0 = x13;
   3714   Register substring_char0 = x13;
   3715   Register result_char0 = x14;
   3716   Label two_byte_sequential, sequential_string, allocate_result;
   3717   STATIC_ASSERT(kExternalStringTag != 0);
   3718   STATIC_ASSERT(kSeqStringTag == 0);
   3719 
   3720   __ Tst(input_type, kExternalStringTag);
   3721   __ B(eq, &sequential_string);
   3722 
   3723   __ Tst(input_type, kShortExternalStringTag);
   3724   __ B(ne, &runtime);
   3725   __ Ldr(unpacked_char0,
   3726          FieldMemOperand(unpacked_string, ExternalString::kResourceDataOffset));
   3727   // unpacked_char0 points to the first character of the underlying string.
   3728   __ B(&allocate_result);
   3729 
   3730   __ Bind(&sequential_string);
   3731   // Locate first character of underlying subject string.
   3732   STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
   3733   __ Add(unpacked_char0, unpacked_string,
   3734          SeqOneByteString::kHeaderSize - kHeapObjectTag);
   3735 
   3736   __ Bind(&allocate_result);
   3737   // Sequential one-byte string. Allocate the result.
   3738   STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
   3739   __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_sequential);
   3740 
   3741   // Allocate and copy the resulting one-byte string.
   3742   __ AllocateOneByteString(result_string, result_length, x3, x4, x5, &runtime);
   3743 
   3744   // Locate first character of substring to copy.
   3745   __ Add(substring_char0, unpacked_char0, from);
   3746 
   3747   // Locate first character of result.
   3748   __ Add(result_char0, result_string,
   3749          SeqOneByteString::kHeaderSize - kHeapObjectTag);
   3750 
   3751   STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
   3752   __ CopyBytes(result_char0, substring_char0, result_length, x3, kCopyLong);
   3753   __ B(&return_x0);
   3754 
   3755   // Allocate and copy the resulting two-byte string.
   3756   __ Bind(&two_byte_sequential);
   3757   __ AllocateTwoByteString(result_string, result_length, x3, x4, x5, &runtime);
   3758 
   3759   // Locate first character of substring to copy.
   3760   __ Add(substring_char0, unpacked_char0, Operand(from, LSL, 1));
   3761 
   3762   // Locate first character of result.
   3763   __ Add(result_char0, result_string,
   3764          SeqTwoByteString::kHeaderSize - kHeapObjectTag);
   3765 
   3766   STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
   3767   __ Add(result_length, result_length, result_length);
   3768   __ CopyBytes(result_char0, substring_char0, result_length, x3, kCopyLong);
   3769 
   3770   __ Bind(&return_x0);
   3771   Counters* counters = isolate()->counters();
   3772   __ IncrementCounter(counters->sub_string_native(), 1, x3, x4);
   3773   __ Drop(3);
   3774   __ Ret();
   3775 
   3776   __ Bind(&runtime);
   3777   __ TailCallRuntime(Runtime::kSubString, 3, 1);
   3778 
   3779   __ bind(&single_char);
   3780   // x1: result_length
   3781   // x10: input_string
   3782   // x12: input_type
   3783   // x15: from (untagged)
   3784   __ SmiTag(from);
   3785   StringCharAtGenerator generator(
   3786       input_string, from, result_length, x0,
   3787       &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
   3788   generator.GenerateFast(masm);
   3789   __ Drop(3);
   3790   __ Ret();
   3791   generator.SkipSlow(masm, &runtime);
   3792 }
   3793 
   3794 
   3795 void StringHelper::GenerateFlatOneByteStringEquals(
   3796     MacroAssembler* masm, Register left, Register right, Register scratch1,
   3797     Register scratch2, Register scratch3) {
   3798   DCHECK(!AreAliased(left, right, scratch1, scratch2, scratch3));
   3799   Register result = x0;
   3800   Register left_length = scratch1;
   3801   Register right_length = scratch2;
   3802 
   3803   // Compare lengths. If lengths differ, strings can't be equal. Lengths are
   3804   // smis, and don't need to be untagged.
   3805   Label strings_not_equal, check_zero_length;
   3806   __ Ldr(left_length, FieldMemOperand(left, String::kLengthOffset));
   3807   __ Ldr(right_length, FieldMemOperand(right, String::kLengthOffset));
   3808   __ Cmp(left_length, right_length);
   3809   __ B(eq, &check_zero_length);
   3810 
   3811   __ Bind(&strings_not_equal);
   3812   __ Mov(result, Smi::FromInt(NOT_EQUAL));
   3813   __ Ret();
   3814 
   3815   // Check if the length is zero. If so, the strings must be equal (and empty.)
   3816   Label compare_chars;
   3817   __ Bind(&check_zero_length);
   3818   STATIC_ASSERT(kSmiTag == 0);
   3819   __ Cbnz(left_length, &compare_chars);
   3820   __ Mov(result, Smi::FromInt(EQUAL));
   3821   __ Ret();
   3822 
   3823   // Compare characters. Falls through if all characters are equal.
   3824   __ Bind(&compare_chars);
   3825   GenerateOneByteCharsCompareLoop(masm, left, right, left_length, scratch2,
   3826                                   scratch3, &strings_not_equal);
   3827 
   3828   // Characters in strings are equal.
   3829   __ Mov(result, Smi::FromInt(EQUAL));
   3830   __ Ret();
   3831 }
   3832 
   3833 
   3834 void StringHelper::GenerateCompareFlatOneByteStrings(
   3835     MacroAssembler* masm, Register left, Register right, Register scratch1,
   3836     Register scratch2, Register scratch3, Register scratch4) {
   3837   DCHECK(!AreAliased(left, right, scratch1, scratch2, scratch3, scratch4));
   3838   Label result_not_equal, compare_lengths;
   3839 
   3840   // Find minimum length and length difference.
   3841   Register length_delta = scratch3;
   3842   __ Ldr(scratch1, FieldMemOperand(left, String::kLengthOffset));
   3843   __ Ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
   3844   __ Subs(length_delta, scratch1, scratch2);
   3845 
   3846   Register min_length = scratch1;
   3847   __ Csel(min_length, scratch2, scratch1, gt);
   3848   __ Cbz(min_length, &compare_lengths);
   3849 
   3850   // Compare loop.
   3851   GenerateOneByteCharsCompareLoop(masm, left, right, min_length, scratch2,
   3852                                   scratch4, &result_not_equal);
   3853 
   3854   // Compare lengths - strings up to min-length are equal.
   3855   __ Bind(&compare_lengths);
   3856 
   3857   DCHECK(Smi::FromInt(EQUAL) == static_cast<Smi*>(0));
   3858 
   3859   // Use length_delta as result if it's zero.
   3860   Register result = x0;
   3861   __ Subs(result, length_delta, 0);
   3862 
   3863   __ Bind(&result_not_equal);
   3864   Register greater = x10;
   3865   Register less = x11;
   3866   __ Mov(greater, Smi::FromInt(GREATER));
   3867   __ Mov(less, Smi::FromInt(LESS));
   3868   __ CmovX(result, greater, gt);
   3869   __ CmovX(result, less, lt);
   3870   __ Ret();
   3871 }
   3872 
   3873 
   3874 void StringHelper::GenerateOneByteCharsCompareLoop(
   3875     MacroAssembler* masm, Register left, Register right, Register length,
   3876     Register scratch1, Register scratch2, Label* chars_not_equal) {
   3877   DCHECK(!AreAliased(left, right, length, scratch1, scratch2));
   3878 
   3879   // Change index to run from -length to -1 by adding length to string
   3880   // start. This means that loop ends when index reaches zero, which
   3881   // doesn't need an additional compare.
   3882   __ SmiUntag(length);
   3883   __ Add(scratch1, length, SeqOneByteString::kHeaderSize - kHeapObjectTag);
   3884   __ Add(left, left, scratch1);
   3885   __ Add(right, right, scratch1);
   3886 
   3887   Register index = length;
   3888   __ Neg(index, length);  // index = -length;
   3889 
   3890   // Compare loop
   3891   Label loop;
   3892   __ Bind(&loop);
   3893   __ Ldrb(scratch1, MemOperand(left, index));
   3894   __ Ldrb(scratch2, MemOperand(right, index));
   3895   __ Cmp(scratch1, scratch2);
   3896   __ B(ne, chars_not_equal);
   3897   __ Add(index, index, 1);
   3898   __ Cbnz(index, &loop);
   3899 }
   3900 
   3901 
   3902 void StringCompareStub::Generate(MacroAssembler* masm) {
   3903   Label runtime;
   3904 
   3905   Counters* counters = isolate()->counters();
   3906 
   3907   // Stack frame on entry.
   3908   //  sp[0]: right string
   3909   //  sp[8]: left string
   3910   Register right = x10;
   3911   Register left = x11;
   3912   Register result = x0;
   3913   __ Pop(right, left);
   3914 
   3915   Label not_same;
   3916   __ Subs(result, right, left);
   3917   __ B(ne, &not_same);
   3918   STATIC_ASSERT(EQUAL == 0);
   3919   __ IncrementCounter(counters->string_compare_native(), 1, x3, x4);
   3920   __ Ret();
   3921 
   3922   __ Bind(&not_same);
   3923 
   3924   // Check that both objects are sequential one-byte strings.
   3925   __ JumpIfEitherIsNotSequentialOneByteStrings(left, right, x12, x13, &runtime);
   3926 
   3927   // Compare flat one-byte strings natively. Remove arguments from stack first,
   3928   // as this function will generate a return.
   3929   __ IncrementCounter(counters->string_compare_native(), 1, x3, x4);
   3930   StringHelper::GenerateCompareFlatOneByteStrings(masm, left, right, x12, x13,
   3931                                                   x14, x15);
   3932 
   3933   __ Bind(&runtime);
   3934 
   3935   // Push arguments back on to the stack.
   3936   //  sp[0] = right string
   3937   //  sp[8] = left string.
   3938   __ Push(left, right);
   3939 
   3940   // Call the runtime.
   3941   // Returns -1 (less), 0 (equal), or 1 (greater) tagged as a small integer.
   3942   __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
   3943 }
   3944 
   3945 
   3946 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
   3947   // ----------- S t a t e -------------
   3948   //  -- x1    : left
   3949   //  -- x0    : right
   3950   //  -- lr    : return address
   3951   // -----------------------------------
   3952 
   3953   // Load x2 with the allocation site.  We stick an undefined dummy value here
   3954   // and replace it with the real allocation site later when we instantiate this
   3955   // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
   3956   __ LoadObject(x2, handle(isolate()->heap()->undefined_value()));
   3957 
   3958   // Make sure that we actually patched the allocation site.
   3959   if (FLAG_debug_code) {
   3960     __ AssertNotSmi(x2, kExpectedAllocationSite);
   3961     __ Ldr(x10, FieldMemOperand(x2, HeapObject::kMapOffset));
   3962     __ AssertRegisterIsRoot(x10, Heap::kAllocationSiteMapRootIndex,
   3963                             kExpectedAllocationSite);
   3964   }
   3965 
   3966   // Tail call into the stub that handles binary operations with allocation
   3967   // sites.
   3968   BinaryOpWithAllocationSiteStub stub(isolate(), state());
   3969   __ TailCallStub(&stub);
   3970 }
   3971 
   3972 
   3973 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
   3974   // We need some extra registers for this stub, they have been allocated
   3975   // but we need to save them before using them.
   3976   regs_.Save(masm);
   3977 
   3978   if (remembered_set_action() == EMIT_REMEMBERED_SET) {
   3979     Label dont_need_remembered_set;
   3980 
   3981     Register val = regs_.scratch0();
   3982     __ Ldr(val, MemOperand(regs_.address()));
   3983     __ JumpIfNotInNewSpace(val, &dont_need_remembered_set);
   3984 
   3985     __ CheckPageFlagSet(regs_.object(), val, 1 << MemoryChunk::SCAN_ON_SCAVENGE,
   3986                         &dont_need_remembered_set);
   3987 
   3988     // First notify the incremental marker if necessary, then update the
   3989     // remembered set.
   3990     CheckNeedsToInformIncrementalMarker(
   3991         masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
   3992     InformIncrementalMarker(masm);
   3993     regs_.Restore(masm);  // Restore the extra scratch registers we used.
   3994 
   3995     __ RememberedSetHelper(object(), address(),
   3996                            value(),  // scratch1
   3997                            save_fp_regs_mode(), MacroAssembler::kReturnAtEnd);
   3998 
   3999     __ Bind(&dont_need_remembered_set);
   4000   }
   4001 
   4002   CheckNeedsToInformIncrementalMarker(
   4003       masm, kReturnOnNoNeedToInformIncrementalMarker, mode);
   4004   InformIncrementalMarker(masm);
   4005   regs_.Restore(masm);  // Restore the extra scratch registers we used.
   4006   __ Ret();
   4007 }
   4008 
   4009 
   4010 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
   4011   regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode());
   4012   Register address =
   4013     x0.Is(regs_.address()) ? regs_.scratch0() : regs_.address();
   4014   DCHECK(!address.Is(regs_.object()));
   4015   DCHECK(!address.Is(x0));
   4016   __ Mov(address, regs_.address());
   4017   __ Mov(x0, regs_.object());
   4018   __ Mov(x1, address);
   4019   __ Mov(x2, ExternalReference::isolate_address(isolate()));
   4020 
   4021   AllowExternalCallThatCantCauseGC scope(masm);
   4022   ExternalReference function =
   4023       ExternalReference::incremental_marking_record_write_function(
   4024           isolate());
   4025   __ CallCFunction(function, 3, 0);
   4026 
   4027   regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode());
   4028 }
   4029 
   4030 
   4031 void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
   4032     MacroAssembler* masm,
   4033     OnNoNeedToInformIncrementalMarker on_no_need,
   4034     Mode mode) {
   4035   Label on_black;
   4036   Label need_incremental;
   4037   Label need_incremental_pop_scratch;
   4038 
   4039   Register mem_chunk = regs_.scratch0();
   4040   Register counter = regs_.scratch1();
   4041   __ Bic(mem_chunk, regs_.object(), Page::kPageAlignmentMask);
   4042   __ Ldr(counter,
   4043          MemOperand(mem_chunk, MemoryChunk::kWriteBarrierCounterOffset));
   4044   __ Subs(counter, counter, 1);
   4045   __ Str(counter,
   4046          MemOperand(mem_chunk, MemoryChunk::kWriteBarrierCounterOffset));
   4047   __ B(mi, &need_incremental);
   4048 
   4049   // If the object is not black we don't have to inform the incremental marker.
   4050   __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black);
   4051 
   4052   regs_.Restore(masm);  // Restore the extra scratch registers we used.
   4053   if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
   4054     __ RememberedSetHelper(object(), address(),
   4055                            value(),  // scratch1
   4056                            save_fp_regs_mode(), MacroAssembler::kReturnAtEnd);
   4057   } else {
   4058     __ Ret();
   4059   }
   4060 
   4061   __ Bind(&on_black);
   4062   // Get the value from the slot.
   4063   Register val = regs_.scratch0();
   4064   __ Ldr(val, MemOperand(regs_.address()));
   4065 
   4066   if (mode == INCREMENTAL_COMPACTION) {
   4067     Label ensure_not_white;
   4068 
   4069     __ CheckPageFlagClear(val, regs_.scratch1(),
   4070                           MemoryChunk::kEvacuationCandidateMask,
   4071                           &ensure_not_white);
   4072 
   4073     __ CheckPageFlagClear(regs_.object(),
   4074                           regs_.scratch1(),
   4075                           MemoryChunk::kSkipEvacuationSlotsRecordingMask,
   4076                           &need_incremental);
   4077 
   4078     __ Bind(&ensure_not_white);
   4079   }
   4080 
   4081   // We need extra registers for this, so we push the object and the address
   4082   // register temporarily.
   4083   __ Push(regs_.address(), regs_.object());
   4084   __ EnsureNotWhite(val,
   4085                     regs_.scratch1(),  // Scratch.
   4086                     regs_.object(),    // Scratch.
   4087                     regs_.address(),   // Scratch.
   4088                     regs_.scratch2(),  // Scratch.
   4089                     &need_incremental_pop_scratch);
   4090   __ Pop(regs_.object(), regs_.address());
   4091 
   4092   regs_.Restore(masm);  // Restore the extra scratch registers we used.
   4093   if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
   4094     __ RememberedSetHelper(object(), address(),
   4095                            value(),  // scratch1
   4096                            save_fp_regs_mode(), MacroAssembler::kReturnAtEnd);
   4097   } else {
   4098     __ Ret();
   4099   }
   4100 
   4101   __ Bind(&need_incremental_pop_scratch);
   4102   __ Pop(regs_.object(), regs_.address());
   4103 
   4104   __ Bind(&need_incremental);
   4105   // Fall through when we need to inform the incremental marker.
   4106 }
   4107 
   4108 
   4109 void RecordWriteStub::Generate(MacroAssembler* masm) {
   4110   Label skip_to_incremental_noncompacting;
   4111   Label skip_to_incremental_compacting;
   4112 
   4113   // We patch these two first instructions back and forth between a nop and
   4114   // real branch when we start and stop incremental heap marking.
   4115   // Initially the stub is expected to be in STORE_BUFFER_ONLY mode, so 2 nops
   4116   // are generated.
   4117   // See RecordWriteStub::Patch for details.
   4118   {
   4119     InstructionAccurateScope scope(masm, 2);
   4120     __ adr(xzr, &skip_to_incremental_noncompacting);
   4121     __ adr(xzr, &skip_to_incremental_compacting);
   4122   }
   4123 
   4124   if (remembered_set_action() == EMIT_REMEMBERED_SET) {
   4125     __ RememberedSetHelper(object(), address(),
   4126                            value(),  // scratch1
   4127                            save_fp_regs_mode(), MacroAssembler::kReturnAtEnd);
   4128   }
   4129   __ Ret();
   4130 
   4131   __ Bind(&skip_to_incremental_noncompacting);
   4132   GenerateIncremental(masm, INCREMENTAL);
   4133 
   4134   __ Bind(&skip_to_incremental_compacting);
   4135   GenerateIncremental(masm, INCREMENTAL_COMPACTION);
   4136 }
   4137 
   4138 
   4139 void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
   4140   // x0     value            element value to store
   4141   // x3     index_smi        element index as smi
   4142   // sp[0]  array_index_smi  array literal index in function as smi
   4143   // sp[1]  array            array literal
   4144 
   4145   Register value = x0;
   4146   Register index_smi = x3;
   4147 
   4148   Register array = x1;
   4149   Register array_map = x2;
   4150   Register array_index_smi = x4;
   4151   __ PeekPair(array_index_smi, array, 0);
   4152   __ Ldr(array_map, FieldMemOperand(array, JSObject::kMapOffset));
   4153 
   4154   Label double_elements, smi_element, fast_elements, slow_elements;
   4155   Register bitfield2 = x10;
   4156   __ Ldrb(bitfield2, FieldMemOperand(array_map, Map::kBitField2Offset));
   4157 
   4158   // Jump if array's ElementsKind is not FAST*_SMI_ELEMENTS, FAST_ELEMENTS or
   4159   // FAST_HOLEY_ELEMENTS.
   4160   STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
   4161   STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
   4162   STATIC_ASSERT(FAST_ELEMENTS == 2);
   4163   STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
   4164   __ Cmp(bitfield2, Map::kMaximumBitField2FastHoleyElementValue);
   4165   __ B(hi, &double_elements);
   4166 
   4167   __ JumpIfSmi(value, &smi_element);
   4168 
   4169   // Jump if array's ElementsKind is not FAST_ELEMENTS or FAST_HOLEY_ELEMENTS.
   4170   __ Tbnz(bitfield2, MaskToBit(FAST_ELEMENTS << Map::ElementsKindBits::kShift),
   4171           &fast_elements);
   4172 
   4173   // Store into the array literal requires an elements transition. Call into
   4174   // the runtime.
   4175   __ Bind(&slow_elements);
   4176   __ Push(array, index_smi, value);
   4177   __ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
   4178   __ Ldr(x11, FieldMemOperand(x10, JSFunction::kLiteralsOffset));
   4179   __ Push(x11, array_index_smi);
   4180   __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
   4181 
   4182   // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
   4183   __ Bind(&fast_elements);
   4184   __ Ldr(x10, FieldMemOperand(array, JSObject::kElementsOffset));
   4185   __ Add(x11, x10, Operand::UntagSmiAndScale(index_smi, kPointerSizeLog2));
   4186   __ Add(x11, x11, FixedArray::kHeaderSize - kHeapObjectTag);
   4187   __ Str(value, MemOperand(x11));
   4188   // Update the write barrier for the array store.
   4189   __ RecordWrite(x10, x11, value, kLRHasNotBeenSaved, kDontSaveFPRegs,
   4190                  EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
   4191   __ Ret();
   4192 
   4193   // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
   4194   // and value is Smi.
   4195   __ Bind(&smi_element);
   4196   __ Ldr(x10, FieldMemOperand(array, JSObject::kElementsOffset));
   4197   __ Add(x11, x10, Operand::UntagSmiAndScale(index_smi, kPointerSizeLog2));
   4198   __ Str(value, FieldMemOperand(x11, FixedArray::kHeaderSize));
   4199   __ Ret();
   4200 
   4201   __ Bind(&double_elements);
   4202   __ Ldr(x10, FieldMemOperand(array, JSObject::kElementsOffset));
   4203   __ StoreNumberToDoubleElements(value, index_smi, x10, x11, d0,
   4204                                  &slow_elements);
   4205   __ Ret();
   4206 }
   4207 
   4208 
   4209 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
   4210   CEntryStub ces(isolate(), 1, kSaveFPRegs);
   4211   __ Call(ces.GetCode(), RelocInfo::CODE_TARGET);
   4212   int parameter_count_offset =
   4213       StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
   4214   __ Ldr(x1, MemOperand(fp, parameter_count_offset));
   4215   if (function_mode() == JS_FUNCTION_STUB_MODE) {
   4216     __ Add(x1, x1, 1);
   4217   }
   4218   masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
   4219   __ Drop(x1);
   4220   // Return to IC Miss stub, continuation still on stack.
   4221   __ Ret();
   4222 }
   4223 
   4224 
   4225 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   4226   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
   4227   VectorLoadStub stub(isolate(), state());
   4228   __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
   4229 }
   4230 
   4231 
   4232 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   4233   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
   4234   VectorKeyedLoadStub stub(isolate());
   4235   __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
   4236 }
   4237 
   4238 
   4239 static unsigned int GetProfileEntryHookCallSize(MacroAssembler* masm) {
   4240   // The entry hook is a "BumpSystemStackPointer" instruction (sub),
   4241   // followed by a "Push lr" instruction, followed by a call.
   4242   unsigned int size =
   4243       Assembler::kCallSizeWithRelocation + (2 * kInstructionSize);
   4244   if (CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
   4245     // If ALWAYS_ALIGN_CSP then there will be an extra bic instruction in
   4246     // "BumpSystemStackPointer".
   4247     size += kInstructionSize;
   4248   }
   4249   return size;
   4250 }
   4251 
   4252 
   4253 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
   4254   if (masm->isolate()->function_entry_hook() != NULL) {
   4255     ProfileEntryHookStub stub(masm->isolate());
   4256     Assembler::BlockConstPoolScope no_const_pools(masm);
   4257     DontEmitDebugCodeScope no_debug_code(masm);
   4258     Label entry_hook_call_start;
   4259     __ Bind(&entry_hook_call_start);
   4260     __ Push(lr);
   4261     __ CallStub(&stub);
   4262     DCHECK(masm->SizeOfCodeGeneratedSince(&entry_hook_call_start) ==
   4263            GetProfileEntryHookCallSize(masm));
   4264 
   4265     __ Pop(lr);
   4266   }
   4267 }
   4268 
   4269 
   4270 void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
   4271   MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm);
   4272 
   4273   // Save all kCallerSaved registers (including lr), since this can be called
   4274   // from anywhere.
   4275   // TODO(jbramley): What about FP registers?
   4276   __ PushCPURegList(kCallerSaved);
   4277   DCHECK(kCallerSaved.IncludesAliasOf(lr));
   4278   const int kNumSavedRegs = kCallerSaved.Count();
   4279 
   4280   // Compute the function's address as the first argument.
   4281   __ Sub(x0, lr, GetProfileEntryHookCallSize(masm));
   4282 
   4283 #if V8_HOST_ARCH_ARM64
   4284   uintptr_t entry_hook =
   4285       reinterpret_cast<uintptr_t>(isolate()->function_entry_hook());
   4286   __ Mov(x10, entry_hook);
   4287 #else
   4288   // Under the simulator we need to indirect the entry hook through a trampoline
   4289   // function at a known address.
   4290   ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline));
   4291   __ Mov(x10, Operand(ExternalReference(&dispatcher,
   4292                                         ExternalReference::BUILTIN_CALL,
   4293                                         isolate())));
   4294   // It additionally takes an isolate as a third parameter
   4295   __ Mov(x2, ExternalReference::isolate_address(isolate()));
   4296 #endif
   4297 
   4298   // The caller's return address is above the saved temporaries.
   4299   // Grab its location for the second argument to the hook.
   4300   __ Add(x1, __ StackPointer(), kNumSavedRegs * kPointerSize);
   4301 
   4302   {
   4303     // Create a dummy frame, as CallCFunction requires this.
   4304     FrameScope frame(masm, StackFrame::MANUAL);
   4305     __ CallCFunction(x10, 2, 0);
   4306   }
   4307 
   4308   __ PopCPURegList(kCallerSaved);
   4309   __ Ret();
   4310 }
   4311 
   4312 
   4313 void DirectCEntryStub::Generate(MacroAssembler* masm) {
   4314   // When calling into C++ code the stack pointer must be csp.
   4315   // Therefore this code must use csp for peek/poke operations when the
   4316   // stub is generated. When the stub is called
   4317   // (via DirectCEntryStub::GenerateCall), the caller must setup an ExitFrame
   4318   // and configure the stack pointer *before* doing the call.
   4319   const Register old_stack_pointer = __ StackPointer();
   4320   __ SetStackPointer(csp);
   4321 
   4322   // Put return address on the stack (accessible to GC through exit frame pc).
   4323   __ Poke(lr, 0);
   4324   // Call the C++ function.
   4325   __ Blr(x10);
   4326   // Return to calling code.
   4327   __ Peek(lr, 0);
   4328   __ AssertFPCRState();
   4329   __ Ret();
   4330 
   4331   __ SetStackPointer(old_stack_pointer);
   4332 }
   4333 
   4334 void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
   4335                                     Register target) {
   4336   // Make sure the caller configured the stack pointer (see comment in
   4337   // DirectCEntryStub::Generate).
   4338   DCHECK(csp.Is(__ StackPointer()));
   4339 
   4340   intptr_t code =
   4341       reinterpret_cast<intptr_t>(GetCode().location());
   4342   __ Mov(lr, Operand(code, RelocInfo::CODE_TARGET));
   4343   __ Mov(x10, target);
   4344   // Branch to the stub.
   4345   __ Blr(lr);
   4346 }
   4347 
   4348 
   4349 // Probe the name dictionary in the 'elements' register.
   4350 // Jump to the 'done' label if a property with the given name is found.
   4351 // Jump to the 'miss' label otherwise.
   4352 //
   4353 // If lookup was successful 'scratch2' will be equal to elements + 4 * index.
   4354 // 'elements' and 'name' registers are preserved on miss.
   4355 void NameDictionaryLookupStub::GeneratePositiveLookup(
   4356     MacroAssembler* masm,
   4357     Label* miss,
   4358     Label* done,
   4359     Register elements,
   4360     Register name,
   4361     Register scratch1,
   4362     Register scratch2) {
   4363   DCHECK(!AreAliased(elements, name, scratch1, scratch2));
   4364 
   4365   // Assert that name contains a string.
   4366   __ AssertName(name);
   4367 
   4368   // Compute the capacity mask.
   4369   __ Ldrsw(scratch1, UntagSmiFieldMemOperand(elements, kCapacityOffset));
   4370   __ Sub(scratch1, scratch1, 1);
   4371 
   4372   // Generate an unrolled loop that performs a few probes before giving up.
   4373   for (int i = 0; i < kInlinedProbes; i++) {
   4374     // Compute the masked index: (hash + i + i * i) & mask.
   4375     __ Ldr(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
   4376     if (i > 0) {
   4377       // Add the probe offset (i + i * i) left shifted to avoid right shifting
   4378       // the hash in a separate instruction. The value hash + i + i * i is right
   4379       // shifted in the following and instruction.
   4380       DCHECK(NameDictionary::GetProbeOffset(i) <
   4381           1 << (32 - Name::kHashFieldOffset));
   4382       __ Add(scratch2, scratch2, Operand(
   4383           NameDictionary::GetProbeOffset(i) << Name::kHashShift));
   4384     }
   4385     __ And(scratch2, scratch1, Operand(scratch2, LSR, Name::kHashShift));
   4386 
   4387     // Scale the index by multiplying by the element size.
   4388     DCHECK(NameDictionary::kEntrySize == 3);
   4389     __ Add(scratch2, scratch2, Operand(scratch2, LSL, 1));
   4390 
   4391     // Check if the key is identical to the name.
   4392     UseScratchRegisterScope temps(masm);
   4393     Register scratch3 = temps.AcquireX();
   4394     __ Add(scratch2, elements, Operand(scratch2, LSL, kPointerSizeLog2));
   4395     __ Ldr(scratch3, FieldMemOperand(scratch2, kElementsStartOffset));
   4396     __ Cmp(name, scratch3);
   4397     __ B(eq, done);
   4398   }
   4399 
   4400   // The inlined probes didn't find the entry.
   4401   // Call the complete stub to scan the whole dictionary.
   4402 
   4403   CPURegList spill_list(CPURegister::kRegister, kXRegSizeInBits, 0, 6);
   4404   spill_list.Combine(lr);
   4405   spill_list.Remove(scratch1);
   4406   spill_list.Remove(scratch2);
   4407 
   4408   __ PushCPURegList(spill_list);
   4409 
   4410   if (name.is(x0)) {
   4411     DCHECK(!elements.is(x1));
   4412     __ Mov(x1, name);
   4413     __ Mov(x0, elements);
   4414   } else {
   4415     __ Mov(x0, elements);
   4416     __ Mov(x1, name);
   4417   }
   4418 
   4419   Label not_found;
   4420   NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP);
   4421   __ CallStub(&stub);
   4422   __ Cbz(x0, &not_found);
   4423   __ Mov(scratch2, x2);  // Move entry index into scratch2.
   4424   __ PopCPURegList(spill_list);
   4425   __ B(done);
   4426 
   4427   __ Bind(&not_found);
   4428   __ PopCPURegList(spill_list);
   4429   __ B(miss);
   4430 }
   4431 
   4432 
   4433 void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
   4434                                                       Label* miss,
   4435                                                       Label* done,
   4436                                                       Register receiver,
   4437                                                       Register properties,
   4438                                                       Handle<Name> name,
   4439                                                       Register scratch0) {
   4440   DCHECK(!AreAliased(receiver, properties, scratch0));
   4441   DCHECK(name->IsUniqueName());
   4442   // If names of slots in range from 1 to kProbes - 1 for the hash value are
   4443   // not equal to the name and kProbes-th slot is not used (its name is the
   4444   // undefined value), it guarantees the hash table doesn't contain the
   4445   // property. It's true even if some slots represent deleted properties
   4446   // (their names are the hole value).
   4447   for (int i = 0; i < kInlinedProbes; i++) {
   4448     // scratch0 points to properties hash.
   4449     // Compute the masked index: (hash + i + i * i) & mask.
   4450     Register index = scratch0;
   4451     // Capacity is smi 2^n.
   4452     __ Ldrsw(index, UntagSmiFieldMemOperand(properties, kCapacityOffset));
   4453     __ Sub(index, index, 1);
   4454     __ And(index, index, name->Hash() + NameDictionary::GetProbeOffset(i));
   4455 
   4456     // Scale the index by multiplying by the entry size.
   4457     DCHECK(NameDictionary::kEntrySize == 3);
   4458     __ Add(index, index, Operand(index, LSL, 1));  // index *= 3.
   4459 
   4460     Register entity_name = scratch0;
   4461     // Having undefined at this place means the name is not contained.
   4462     Register tmp = index;
   4463     __ Add(tmp, properties, Operand(index, LSL, kPointerSizeLog2));
   4464     __ Ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
   4465 
   4466     __ JumpIfRoot(entity_name, Heap::kUndefinedValueRootIndex, done);
   4467 
   4468     // Stop if found the property.
   4469     __ Cmp(entity_name, Operand(name));
   4470     __ B(eq, miss);
   4471 
   4472     Label good;
   4473     __ JumpIfRoot(entity_name, Heap::kTheHoleValueRootIndex, &good);
   4474 
   4475     // Check if the entry name is not a unique name.
   4476     __ Ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
   4477     __ Ldrb(entity_name,
   4478             FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
   4479     __ JumpIfNotUniqueNameInstanceType(entity_name, miss);
   4480     __ Bind(&good);
   4481   }
   4482 
   4483   CPURegList spill_list(CPURegister::kRegister, kXRegSizeInBits, 0, 6);
   4484   spill_list.Combine(lr);
   4485   spill_list.Remove(scratch0);  // Scratch registers don't need to be preserved.
   4486 
   4487   __ PushCPURegList(spill_list);
   4488 
   4489   __ Ldr(x0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
   4490   __ Mov(x1, Operand(name));
   4491   NameDictionaryLookupStub stub(masm->isolate(), NEGATIVE_LOOKUP);
   4492   __ CallStub(&stub);
   4493   // Move stub return value to scratch0. Note that scratch0 is not included in
   4494   // spill_list and won't be clobbered by PopCPURegList.
   4495   __ Mov(scratch0, x0);
   4496   __ PopCPURegList(spill_list);
   4497 
   4498   __ Cbz(scratch0, done);
   4499   __ B(miss);
   4500 }
   4501 
   4502 
   4503 void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
   4504   // This stub overrides SometimesSetsUpAFrame() to return false. That means
   4505   // we cannot call anything that could cause a GC from this stub.
   4506   //
   4507   // Arguments are in x0 and x1:
   4508   //   x0: property dictionary.
   4509   //   x1: the name of the property we are looking for.
   4510   //
   4511   // Return value is in x0 and is zero if lookup failed, non zero otherwise.
   4512   // If the lookup is successful, x2 will contains the index of the entry.
   4513 
   4514   Register result = x0;
   4515   Register dictionary = x0;
   4516   Register key = x1;
   4517   Register index = x2;
   4518   Register mask = x3;
   4519   Register hash = x4;
   4520   Register undefined = x5;
   4521   Register entry_key = x6;
   4522 
   4523   Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
   4524 
   4525   __ Ldrsw(mask, UntagSmiFieldMemOperand(dictionary, kCapacityOffset));
   4526   __ Sub(mask, mask, 1);
   4527 
   4528   __ Ldr(hash, FieldMemOperand(key, Name::kHashFieldOffset));
   4529   __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
   4530 
   4531   for (int i = kInlinedProbes; i < kTotalProbes; i++) {
   4532     // Compute the masked index: (hash + i + i * i) & mask.
   4533     // Capacity is smi 2^n.
   4534     if (i > 0) {
   4535       // Add the probe offset (i + i * i) left shifted to avoid right shifting
   4536       // the hash in a separate instruction. The value hash + i + i * i is right
   4537       // shifted in the following and instruction.
   4538       DCHECK(NameDictionary::GetProbeOffset(i) <
   4539              1 << (32 - Name::kHashFieldOffset));
   4540       __ Add(index, hash,
   4541              NameDictionary::GetProbeOffset(i) << Name::kHashShift);
   4542     } else {
   4543       __ Mov(index, hash);
   4544     }
   4545     __ And(index, mask, Operand(index, LSR, Name::kHashShift));
   4546 
   4547     // Scale the index by multiplying by the entry size.
   4548     DCHECK(NameDictionary::kEntrySize == 3);
   4549     __ Add(index, index, Operand(index, LSL, 1));  // index *= 3.
   4550 
   4551     __ Add(index, dictionary, Operand(index, LSL, kPointerSizeLog2));
   4552     __ Ldr(entry_key, FieldMemOperand(index, kElementsStartOffset));
   4553 
   4554     // Having undefined at this place means the name is not contained.
   4555     __ Cmp(entry_key, undefined);
   4556     __ B(eq, &not_in_dictionary);
   4557 
   4558     // Stop if found the property.
   4559     __ Cmp(entry_key, key);
   4560     __ B(eq, &in_dictionary);
   4561 
   4562     if (i != kTotalProbes - 1 && mode() == NEGATIVE_LOOKUP) {
   4563       // Check if the entry name is not a unique name.
   4564       __ Ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
   4565       __ Ldrb(entry_key, FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
   4566       __ JumpIfNotUniqueNameInstanceType(entry_key, &maybe_in_dictionary);
   4567     }
   4568   }
   4569 
   4570   __ Bind(&maybe_in_dictionary);
   4571   // If we are doing negative lookup then probing failure should be
   4572   // treated as a lookup success. For positive lookup, probing failure
   4573   // should be treated as lookup failure.
   4574   if (mode() == POSITIVE_LOOKUP) {
   4575     __ Mov(result, 0);
   4576     __ Ret();
   4577   }
   4578 
   4579   __ Bind(&in_dictionary);
   4580   __ Mov(result, 1);
   4581   __ Ret();
   4582 
   4583   __ Bind(&not_in_dictionary);
   4584   __ Mov(result, 0);
   4585   __ Ret();
   4586 }
   4587 
   4588 
   4589 template<class T>
   4590 static void CreateArrayDispatch(MacroAssembler* masm,
   4591                                 AllocationSiteOverrideMode mode) {
   4592   ASM_LOCATION("CreateArrayDispatch");
   4593   if (mode == DISABLE_ALLOCATION_SITES) {
   4594     T stub(masm->isolate(), GetInitialFastElementsKind(), mode);
   4595      __ TailCallStub(&stub);
   4596 
   4597   } else if (mode == DONT_OVERRIDE) {
   4598     Register kind = x3;
   4599     int last_index =
   4600         GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
   4601     for (int i = 0; i <= last_index; ++i) {
   4602       Label next;
   4603       ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i);
   4604       // TODO(jbramley): Is this the best way to handle this? Can we make the
   4605       // tail calls conditional, rather than hopping over each one?
   4606       __ CompareAndBranch(kind, candidate_kind, ne, &next);
   4607       T stub(masm->isolate(), candidate_kind);
   4608       __ TailCallStub(&stub);
   4609       __ Bind(&next);
   4610     }
   4611 
   4612     // If we reached this point there is a problem.
   4613     __ Abort(kUnexpectedElementsKindInArrayConstructor);
   4614 
   4615   } else {
   4616     UNREACHABLE();
   4617   }
   4618 }
   4619 
   4620 
   4621 // TODO(jbramley): If this needs to be a special case, make it a proper template
   4622 // specialization, and not a separate function.
   4623 static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
   4624                                            AllocationSiteOverrideMode mode) {
   4625   ASM_LOCATION("CreateArrayDispatchOneArgument");
   4626   // x0 - argc
   4627   // x1 - constructor?
   4628   // x2 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
   4629   // x3 - kind (if mode != DISABLE_ALLOCATION_SITES)
   4630   // sp[0] - last argument
   4631 
   4632   Register allocation_site = x2;
   4633   Register kind = x3;
   4634 
   4635   Label normal_sequence;
   4636   if (mode == DONT_OVERRIDE) {
   4637     STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
   4638     STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
   4639     STATIC_ASSERT(FAST_ELEMENTS == 2);
   4640     STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
   4641     STATIC_ASSERT(FAST_DOUBLE_ELEMENTS == 4);
   4642     STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
   4643 
   4644     // Is the low bit set? If so, the array is holey.
   4645     __ Tbnz(kind, 0, &normal_sequence);
   4646   }
   4647 
   4648   // Look at the last argument.
   4649   // TODO(jbramley): What does a 0 argument represent?
   4650   __ Peek(x10, 0);
   4651   __ Cbz(x10, &normal_sequence);
   4652 
   4653   if (mode == DISABLE_ALLOCATION_SITES) {
   4654     ElementsKind initial = GetInitialFastElementsKind();
   4655     ElementsKind holey_initial = GetHoleyElementsKind(initial);
   4656 
   4657     ArraySingleArgumentConstructorStub stub_holey(masm->isolate(),
   4658                                                   holey_initial,
   4659                                                   DISABLE_ALLOCATION_SITES);
   4660     __ TailCallStub(&stub_holey);
   4661 
   4662     __ Bind(&normal_sequence);
   4663     ArraySingleArgumentConstructorStub stub(masm->isolate(),
   4664                                             initial,
   4665                                             DISABLE_ALLOCATION_SITES);
   4666     __ TailCallStub(&stub);
   4667   } else if (mode == DONT_OVERRIDE) {
   4668     // We are going to create a holey array, but our kind is non-holey.
   4669     // Fix kind and retry (only if we have an allocation site in the slot).
   4670     __ Orr(kind, kind, 1);
   4671 
   4672     if (FLAG_debug_code) {
   4673       __ Ldr(x10, FieldMemOperand(allocation_site, 0));
   4674       __ JumpIfNotRoot(x10, Heap::kAllocationSiteMapRootIndex,
   4675                        &normal_sequence);
   4676       __ Assert(eq, kExpectedAllocationSite);
   4677     }
   4678 
   4679     // Save the resulting elements kind in type info. We can't just store 'kind'
   4680     // in the AllocationSite::transition_info field because elements kind is
   4681     // restricted to a portion of the field; upper bits need to be left alone.
   4682     STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
   4683     __ Ldr(x11, FieldMemOperand(allocation_site,
   4684                                 AllocationSite::kTransitionInfoOffset));
   4685     __ Add(x11, x11, Smi::FromInt(kFastElementsKindPackedToHoley));
   4686     __ Str(x11, FieldMemOperand(allocation_site,
   4687                                 AllocationSite::kTransitionInfoOffset));
   4688 
   4689     __ Bind(&normal_sequence);
   4690     int last_index =
   4691         GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
   4692     for (int i = 0; i <= last_index; ++i) {
   4693       Label next;
   4694       ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i);
   4695       __ CompareAndBranch(kind, candidate_kind, ne, &next);
   4696       ArraySingleArgumentConstructorStub stub(masm->isolate(), candidate_kind);
   4697       __ TailCallStub(&stub);
   4698       __ Bind(&next);
   4699     }
   4700 
   4701     // If we reached this point there is a problem.
   4702     __ Abort(kUnexpectedElementsKindInArrayConstructor);
   4703   } else {
   4704     UNREACHABLE();
   4705   }
   4706 }
   4707 
   4708 
   4709 template<class T>
   4710 static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
   4711   int to_index = GetSequenceIndexFromFastElementsKind(
   4712       TERMINAL_FAST_ELEMENTS_KIND);
   4713   for (int i = 0; i <= to_index; ++i) {
   4714     ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
   4715     T stub(isolate, kind);
   4716     stub.GetCode();
   4717     if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
   4718       T stub1(isolate, kind, DISABLE_ALLOCATION_SITES);
   4719       stub1.GetCode();
   4720     }
   4721   }
   4722 }
   4723 
   4724 
   4725 void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
   4726   ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
   4727       isolate);
   4728   ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
   4729       isolate);
   4730   ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
   4731       isolate);
   4732 }
   4733 
   4734 
   4735 void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
   4736     Isolate* isolate) {
   4737   ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
   4738   for (int i = 0; i < 2; i++) {
   4739     // For internal arrays we only need a few things
   4740     InternalArrayNoArgumentConstructorStub stubh1(isolate, kinds[i]);
   4741     stubh1.GetCode();
   4742     InternalArraySingleArgumentConstructorStub stubh2(isolate, kinds[i]);
   4743     stubh2.GetCode();
   4744     InternalArrayNArgumentsConstructorStub stubh3(isolate, kinds[i]);
   4745     stubh3.GetCode();
   4746   }
   4747 }
   4748 
   4749 
   4750 void ArrayConstructorStub::GenerateDispatchToArrayStub(
   4751     MacroAssembler* masm,
   4752     AllocationSiteOverrideMode mode) {
   4753   Register argc = x0;
   4754   if (argument_count() == ANY) {
   4755     Label zero_case, n_case;
   4756     __ Cbz(argc, &zero_case);
   4757     __ Cmp(argc, 1);
   4758     __ B(ne, &n_case);
   4759 
   4760     // One argument.
   4761     CreateArrayDispatchOneArgument(masm, mode);
   4762 
   4763     __ Bind(&zero_case);
   4764     // No arguments.
   4765     CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
   4766 
   4767     __ Bind(&n_case);
   4768     // N arguments.
   4769     CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
   4770 
   4771   } else if (argument_count() == NONE) {
   4772     CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
   4773   } else if (argument_count() == ONE) {
   4774     CreateArrayDispatchOneArgument(masm, mode);
   4775   } else if (argument_count() == MORE_THAN_ONE) {
   4776     CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
   4777   } else {
   4778     UNREACHABLE();
   4779   }
   4780 }
   4781 
   4782 
   4783 void ArrayConstructorStub::Generate(MacroAssembler* masm) {
   4784   ASM_LOCATION("ArrayConstructorStub::Generate");
   4785   // ----------- S t a t e -------------
   4786   //  -- x0 : argc (only if argument_count() == ANY)
   4787   //  -- x1 : constructor
   4788   //  -- x2 : AllocationSite or undefined
   4789   //  -- sp[0] : return address
   4790   //  -- sp[4] : last argument
   4791   // -----------------------------------
   4792   Register constructor = x1;
   4793   Register allocation_site = x2;
   4794 
   4795   if (FLAG_debug_code) {
   4796     // The array construct code is only set for the global and natives
   4797     // builtin Array functions which always have maps.
   4798 
   4799     Label unexpected_map, map_ok;
   4800     // Initial map for the builtin Array function should be a map.
   4801     __ Ldr(x10, FieldMemOperand(constructor,
   4802                                 JSFunction::kPrototypeOrInitialMapOffset));
   4803     // Will both indicate a NULL and a Smi.
   4804     __ JumpIfSmi(x10, &unexpected_map);
   4805     __ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok);
   4806     __ Bind(&unexpected_map);
   4807     __ Abort(kUnexpectedInitialMapForArrayFunction);
   4808     __ Bind(&map_ok);
   4809 
   4810     // We should either have undefined in the allocation_site register or a
   4811     // valid AllocationSite.
   4812     __ AssertUndefinedOrAllocationSite(allocation_site, x10);
   4813   }
   4814 
   4815   Register kind = x3;
   4816   Label no_info;
   4817   // Get the elements kind and case on that.
   4818   __ JumpIfRoot(allocation_site, Heap::kUndefinedValueRootIndex, &no_info);
   4819 
   4820   __ Ldrsw(kind,
   4821            UntagSmiFieldMemOperand(allocation_site,
   4822                                    AllocationSite::kTransitionInfoOffset));
   4823   __ And(kind, kind, AllocationSite::ElementsKindBits::kMask);
   4824   GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
   4825 
   4826   __ Bind(&no_info);
   4827   GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
   4828 }
   4829 
   4830 
   4831 void InternalArrayConstructorStub::GenerateCase(
   4832     MacroAssembler* masm, ElementsKind kind) {
   4833   Label zero_case, n_case;
   4834   Register argc = x0;
   4835 
   4836   __ Cbz(argc, &zero_case);
   4837   __ CompareAndBranch(argc, 1, ne, &n_case);
   4838 
   4839   // One argument.
   4840   if (IsFastPackedElementsKind(kind)) {
   4841     Label packed_case;
   4842 
   4843     // We might need to create a holey array; look at the first argument.
   4844     __ Peek(x10, 0);
   4845     __ Cbz(x10, &packed_case);
   4846 
   4847     InternalArraySingleArgumentConstructorStub
   4848         stub1_holey(isolate(), GetHoleyElementsKind(kind));
   4849     __ TailCallStub(&stub1_holey);
   4850 
   4851     __ Bind(&packed_case);
   4852   }
   4853   InternalArraySingleArgumentConstructorStub stub1(isolate(), kind);
   4854   __ TailCallStub(&stub1);
   4855 
   4856   __ Bind(&zero_case);
   4857   // No arguments.
   4858   InternalArrayNoArgumentConstructorStub stub0(isolate(), kind);
   4859   __ TailCallStub(&stub0);
   4860 
   4861   __ Bind(&n_case);
   4862   // N arguments.
   4863   InternalArrayNArgumentsConstructorStub stubN(isolate(), kind);
   4864   __ TailCallStub(&stubN);
   4865 }
   4866 
   4867 
   4868 void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
   4869   // ----------- S t a t e -------------
   4870   //  -- x0 : argc
   4871   //  -- x1 : constructor
   4872   //  -- sp[0] : return address
   4873   //  -- sp[4] : last argument
   4874   // -----------------------------------
   4875 
   4876   Register constructor = x1;
   4877 
   4878   if (FLAG_debug_code) {
   4879     // The array construct code is only set for the global and natives
   4880     // builtin Array functions which always have maps.
   4881 
   4882     Label unexpected_map, map_ok;
   4883     // Initial map for the builtin Array function should be a map.
   4884     __ Ldr(x10, FieldMemOperand(constructor,
   4885                                 JSFunction::kPrototypeOrInitialMapOffset));
   4886     // Will both indicate a NULL and a Smi.
   4887     __ JumpIfSmi(x10, &unexpected_map);
   4888     __ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok);
   4889     __ Bind(&unexpected_map);
   4890     __ Abort(kUnexpectedInitialMapForArrayFunction);
   4891     __ Bind(&map_ok);
   4892   }
   4893 
   4894   Register kind = w3;
   4895   // Figure out the right elements kind
   4896   __ Ldr(x10, FieldMemOperand(constructor,
   4897                               JSFunction::kPrototypeOrInitialMapOffset));
   4898 
   4899   // Retrieve elements_kind from map.
   4900   __ LoadElementsKindFromMap(kind, x10);
   4901 
   4902   if (FLAG_debug_code) {
   4903     Label done;
   4904     __ Cmp(x3, FAST_ELEMENTS);
   4905     __ Ccmp(x3, FAST_HOLEY_ELEMENTS, ZFlag, ne);
   4906     __ Assert(eq, kInvalidElementsKindForInternalArrayOrInternalPackedArray);
   4907   }
   4908 
   4909   Label fast_elements_case;
   4910   __ CompareAndBranch(kind, FAST_ELEMENTS, eq, &fast_elements_case);
   4911   GenerateCase(masm, FAST_HOLEY_ELEMENTS);
   4912 
   4913   __ Bind(&fast_elements_case);
   4914   GenerateCase(masm, FAST_ELEMENTS);
   4915 }
   4916 
   4917 
   4918 void CallApiFunctionStub::Generate(MacroAssembler* masm) {
   4919   // ----------- S t a t e -------------
   4920   //  -- x0                  : callee
   4921   //  -- x4                  : call_data
   4922   //  -- x2                  : holder
   4923   //  -- x1                  : api_function_address
   4924   //  -- cp                  : context
   4925   //  --
   4926   //  -- sp[0]               : last argument
   4927   //  -- ...
   4928   //  -- sp[(argc - 1) * 8]  : first argument
   4929   //  -- sp[argc * 8]        : receiver
   4930   // -----------------------------------
   4931 
   4932   Register callee = x0;
   4933   Register call_data = x4;
   4934   Register holder = x2;
   4935   Register api_function_address = x1;
   4936   Register context = cp;
   4937 
   4938   int argc = this->argc();
   4939   bool is_store = this->is_store();
   4940   bool call_data_undefined = this->call_data_undefined();
   4941 
   4942   typedef FunctionCallbackArguments FCA;
   4943 
   4944   STATIC_ASSERT(FCA::kContextSaveIndex == 6);
   4945   STATIC_ASSERT(FCA::kCalleeIndex == 5);
   4946   STATIC_ASSERT(FCA::kDataIndex == 4);
   4947   STATIC_ASSERT(FCA::kReturnValueOffset == 3);
   4948   STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
   4949   STATIC_ASSERT(FCA::kIsolateIndex == 1);
   4950   STATIC_ASSERT(FCA::kHolderIndex == 0);
   4951   STATIC_ASSERT(FCA::kArgsLength == 7);
   4952 
   4953   // FunctionCallbackArguments: context, callee and call data.
   4954   __ Push(context, callee, call_data);
   4955 
   4956   // Load context from callee
   4957   __ Ldr(context, FieldMemOperand(callee, JSFunction::kContextOffset));
   4958 
   4959   if (!call_data_undefined) {
   4960     __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
   4961   }
   4962   Register isolate_reg = x5;
   4963   __ Mov(isolate_reg, ExternalReference::isolate_address(isolate()));
   4964 
   4965   // FunctionCallbackArguments:
   4966   //    return value, return value default, isolate, holder.
   4967   __ Push(call_data, call_data, isolate_reg, holder);
   4968 
   4969   // Prepare arguments.
   4970   Register args = x6;
   4971   __ Mov(args, masm->StackPointer());
   4972 
   4973   // Allocate the v8::Arguments structure in the arguments' space, since it's
   4974   // not controlled by GC.
   4975   const int kApiStackSpace = 4;
   4976 
   4977   // Allocate space for CallApiFunctionAndReturn can store some scratch
   4978   // registeres on the stack.
   4979   const int kCallApiFunctionSpillSpace = 4;
   4980 
   4981   FrameScope frame_scope(masm, StackFrame::MANUAL);
   4982   __ EnterExitFrame(false, x10, kApiStackSpace + kCallApiFunctionSpillSpace);
   4983 
   4984   DCHECK(!AreAliased(x0, api_function_address));
   4985   // x0 = FunctionCallbackInfo&
   4986   // Arguments is after the return address.
   4987   __ Add(x0, masm->StackPointer(), 1 * kPointerSize);
   4988   // FunctionCallbackInfo::implicit_args_ and FunctionCallbackInfo::values_
   4989   __ Add(x10, args, Operand((FCA::kArgsLength - 1 + argc) * kPointerSize));
   4990   __ Stp(args, x10, MemOperand(x0, 0 * kPointerSize));
   4991   // FunctionCallbackInfo::length_ = argc and
   4992   // FunctionCallbackInfo::is_construct_call = 0
   4993   __ Mov(x10, argc);
   4994   __ Stp(x10, xzr, MemOperand(x0, 2 * kPointerSize));
   4995 
   4996   const int kStackUnwindSpace = argc + FCA::kArgsLength + 1;
   4997   ExternalReference thunk_ref =
   4998       ExternalReference::invoke_function_callback(isolate());
   4999 
   5000   AllowExternalCallThatCantCauseGC scope(masm);
   5001   MemOperand context_restore_operand(
   5002       fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
   5003   // Stores return the first js argument
   5004   int return_value_offset = 0;
   5005   if (is_store) {
   5006     return_value_offset = 2 + FCA::kArgsLength;
   5007   } else {
   5008     return_value_offset = 2 + FCA::kReturnValueOffset;
   5009   }
   5010   MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
   5011 
   5012   const int spill_offset = 1 + kApiStackSpace;
   5013   __ CallApiFunctionAndReturn(api_function_address,
   5014                               thunk_ref,
   5015                               kStackUnwindSpace,
   5016                               spill_offset,
   5017                               return_value_operand,
   5018                               &context_restore_operand);
   5019 }
   5020 
   5021 
   5022 void CallApiGetterStub::Generate(MacroAssembler* masm) {
   5023   // ----------- S t a t e -------------
   5024   //  -- sp[0]                  : name
   5025   //  -- sp[8 - kArgsLength*8]  : PropertyCallbackArguments object
   5026   //  -- ...
   5027   //  -- x2                     : api_function_address
   5028   // -----------------------------------
   5029 
   5030   Register api_function_address = ApiGetterDescriptor::function_address();
   5031   DCHECK(api_function_address.is(x2));
   5032 
   5033   __ Mov(x0, masm->StackPointer());  // x0 = Handle<Name>
   5034   __ Add(x1, x0, 1 * kPointerSize);  // x1 = PCA
   5035 
   5036   const int kApiStackSpace = 1;
   5037 
   5038   // Allocate space for CallApiFunctionAndReturn can store some scratch
   5039   // registeres on the stack.
   5040   const int kCallApiFunctionSpillSpace = 4;
   5041 
   5042   FrameScope frame_scope(masm, StackFrame::MANUAL);
   5043   __ EnterExitFrame(false, x10, kApiStackSpace + kCallApiFunctionSpillSpace);
   5044 
   5045   // Create PropertyAccessorInfo instance on the stack above the exit frame with
   5046   // x1 (internal::Object** args_) as the data.
   5047   __ Poke(x1, 1 * kPointerSize);
   5048   __ Add(x1, masm->StackPointer(), 1 * kPointerSize);  // x1 = AccessorInfo&
   5049 
   5050   const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
   5051 
   5052   ExternalReference thunk_ref =
   5053       ExternalReference::invoke_accessor_getter_callback(isolate());
   5054 
   5055   const int spill_offset = 1 + kApiStackSpace;
   5056   __ CallApiFunctionAndReturn(api_function_address,
   5057                               thunk_ref,
   5058                               kStackUnwindSpace,
   5059                               spill_offset,
   5060                               MemOperand(fp, 6 * kPointerSize),
   5061                               NULL);
   5062 }
   5063 
   5064 
   5065 #undef __
   5066 
   5067 } }  // namespace v8::internal
   5068 
   5069 #endif  // V8_TARGET_ARCH_ARM64
   5070