V8 Project
code-stubs-arm64.cc
Go to the documentation of this file.
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"
13 #include "src/ic/ic.h"
14 #include "src/isolate.h"
15 #include "src/jsregexp.h"
17 #include "src/runtime/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,
36  } else {
37  descriptor->Initialize(x0, deopt_handler, constant_stack_parameter_count,
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,
70  } else {
71  descriptor->Initialize(x0, deopt_handler, constant_stack_parameter_count,
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();
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,
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.
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,
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.
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 
682  Isolate* isolate) {
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.
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 
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");
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();
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 
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.
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.
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 
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.
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,
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);
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);
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()) {
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 =
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;
1626  __ Ldr(caller_ctx, MemOperand(caller_fp,
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,
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;
1666  // Load and untag the context.
1667  __ Ldr(w11, UntagSmiMemOperand(caller_fp,
1670  __ B(ne, &runtime);
1671 
1672  // Patch the arguments.length and parameters pointer in the current frame.
1673  __ Ldr(x11, MemOperand(caller_fp,
1675  __ Poke(x11, 0 * kXRegSize);
1676  __ Add(x10, caller_fp, Operand::UntagSmiAndScale(x11, kPointerSizeLog2));
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;
1708  __ Ldr(caller_ctx, MemOperand(caller_fp,
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,
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 =
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,
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,
1798 
1799  __ Ldr(sloppy_args_map,
1801  __ Ldr(aliased_args_map,
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.
1814  const int kCalleeOffset = JSObject::kHeaderSize +
1816  __ AssertNotSmi(function);
1817  __ Str(function, FieldMemOperand(alloc_obj, kCalleeOffset));
1818 
1819  // Use the length and set that as an in-object property.
1821  const int kLengthOffset = JSObject::kHeaderSize +
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,
1860  __ Add(x10, elements, Operand(mapped_params, LSL, kPointerSizeLog2));
1861  __ Add(x10, x10, kParameterMapHeaderSize);
1862  __ Str(x10, FieldMemOperand(elements,
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,
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;
2003  __ Ldr(caller_ctx, MemOperand(caller_fp,
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,
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);
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,
2044  __ Ldr(strict_args_map,
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.
2061  const int kLengthOffset = JSObject::kHeaderSize +
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,
2221  // Check (number_of_captures + 1) * 2 <= offsets vector size
2222  // number_of_captures * 2 <= offsets vector size - 2
2224  __ Add(x10, x10, x10);
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,
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
2280  __ Cbz(string_representation, &seq_string); // Go to (5).
2281 
2282  // (2) Anything but sequential or cons? If yes, go to (6).
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));
2302  // The underlying external string is never a short external string.
2305  __ TestAndBranchIfAnySet(string_type.X(),
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.
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.
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
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,
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,
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,
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,
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,
2489  // Store last subject and last input.
2490  __ Str(subject,
2491  FieldMemOperand(last_match_info_elements,
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,
2498  x10,
2499  x11,
2501  kDontSaveFPRegs);
2502  __ Str(subject,
2503  FieldMemOperand(last_match_info_elements,
2505  __ Mov(x10, subject);
2506  __ RecordWriteField(last_match_info_elements,
2508  x10,
2509  x11,
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,
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,
2612  // Move the pointer so that offset-wise, it looks like a sequential string.
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);
2621  __ TestAndBranchIfAnySet(string_representation,
2623  &runtime);
2624 
2625  // (9) Sliced string. Replace subject with parent.
2626  __ Ldr(sliced_string_offset,
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 
2653  masm->isolate()->heap()->megamorphic_symbol());
2655  masm->isolate()->heap()->uninitialized_symbol());
2656 
2657  // Load the cache state.
2658  __ Add(scratch1, feedback_vector,
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,
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,
2734  __ Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag);
2735  __ Str(function, MemOperand(scratch1, 0));
2736 
2737  __ Push(function);
2738  __ RecordWrite(feedback_vector, scratch1, function, kLRHasNotBeenSaved,
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.
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(),
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.
2888  } else {
2889  Label feedback_register_initialized;
2890  // Put the AllocationSite from the feedback vector into x2, or undefined.
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,
2909  __ Ldr(cons_stub,
2910  FieldMemOperand(shared_func_info,
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(),
2930 }
2931 
2932 
2933 static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) {
2935  __ Ldr(vector, FieldMemOperand(vector,
2937  __ Ldr(vector, FieldMemOperand(vector,
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,
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,
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,
3051  __ LoadRoot(x5, Heap::kMegamorphicSymbolRootIndex);
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.
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.
3117 
3118  __ SmiUntag(index_);
3119 
3121  object_,
3122  index_.W(),
3123  result_,
3124  &call_runtime_);
3125  __ SmiTag(result_);
3126  __ Bind(&exit_);
3127 }
3128 
3129 
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_);
3142  __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
3143  } else {
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.
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_);
3181  __ B(hi, &slow_case_);
3182 
3183  __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
3184  // At this point code register contains smi tagged one-byte char code.
3187  __ JumpIfRoot(result_, Heap::kUndefinedValueRootIndex, &slow_case_);
3188  __ Bind(&exit_);
3189 }
3190 
3191 
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).
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) {
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,
3278  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
3279 
3280  __ Bind(&maybe_undefined1);
3282  __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss);
3283  __ JumpIfSmi(lhs, &unordered);
3284  __ JumpIfNotHeapNumber(lhs, &maybe_undefined2);
3285  __ B(&unordered);
3286  }
3287 
3288  __ Bind(&maybe_undefined2);
3290  __ JumpIfRoot(lhs, Heap::kUndefinedValueRootIndex, &unordered);
3291  }
3292 
3293  __ Bind(&miss);
3294  GenerateMiss(masm);
3295 }
3296 
3297 
3298 void CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) {
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(
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) {
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) {
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));
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);
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) {
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,
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.
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,
3649  __ Add(from, from, temp);
3650  __ Ldr(unpacked_string,
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;
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,
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;
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,
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.
3733  __ Add(unpacked_char0, unpacked_string,
3735 
3736  __ Bind(&allocate_result);
3737  // Sequential one-byte string. Allocate the result.
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,
3750 
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,
3765 
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 
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 
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 
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 
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.
3993  regs_.Restore(masm); // Restore the extra scratch registers we used.
3994 
3995  __ RememberedSetHelper(object(), address(),
3996  value(), // scratch1
3998 
3999  __ Bind(&dont_need_remembered_set);
4000  }
4001 
4005  regs_.Restore(masm); // Restore the extra scratch registers we used.
4006  __ Ret();
4007 }
4008 
4009 
4010 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
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 
4028 }
4029 
4030 
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,
4044  __ Subs(counter, counter, 1);
4045  __ Str(counter,
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.
4054  __ RememberedSetHelper(object(), address(),
4055  value(), // scratch1
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(),
4071  &ensure_not_white);
4072 
4073  __ CheckPageFlagClear(regs_.object(),
4074  regs_.scratch1(),
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.
4094  __ RememberedSetHelper(object(), address(),
4095  value(), // scratch1
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 
4125  __ RememberedSetHelper(object(), address(),
4126  value(), // scratch1
4128  }
4129  __ Ret();
4130 
4131  __ Bind(&skip_to_incremental_noncompacting);
4133 
4134  __ Bind(&skip_to_incremental_compacting);
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.
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.
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);
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,
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 =
4214  __ Ldr(x1, MemOperand(fp, parameter_count_offset));
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 =
4245  // If ALWAYS_ALIGN_CSP then there will be an extra bic instruction in
4246  // "BumpSystemStackPointer".
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.
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.
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.
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,
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 
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.
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,
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 =
4601  for (int i = 0; i <= last_index; ++i) {
4602  Label next;
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,
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) {
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) {
4655  ElementsKind holey_initial = GetHoleyElementsKind(initial);
4656 
4657  ArraySingleArgumentConstructorStub stub_holey(masm->isolate(),
4658  holey_initial,
4660  __ TailCallStub(&stub_holey);
4661 
4662  __ Bind(&normal_sequence);
4663  ArraySingleArgumentConstructorStub stub(masm->isolate(),
4664  initial,
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.
4683  __ Ldr(x11, FieldMemOperand(allocation_site,
4686  __ Str(x11, FieldMemOperand(allocation_site,
4688 
4689  __ Bind(&normal_sequence);
4690  int last_index =
4692  for (int i = 0; i <= last_index; ++i) {
4693  Label next;
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(
4713  for (int i = 0; i <= to_index; ++i) {
4715  T stub(isolate, kind);
4716  stub.GetCode();
4718  T stub1(isolate, kind, DISABLE_ALLOCATION_SITES);
4719  stub1.GetCode();
4720  }
4721  }
4722 }
4723 
4724 
4726  ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
4727  isolate);
4728  ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
4729  isolate);
4730  ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
4731  isolate);
4732 }
4733 
4734 
4736  Isolate* isolate) {
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 
4751  MacroAssembler* masm,
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,
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,
4825 
4826  __ Bind(&no_info);
4828 }
4829 
4830 
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,
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,
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);
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();
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
#define kCallerSavedFP
static AllocationSiteMode GetMode(ElementsKind boilerplate_elements_kind)
Definition: objects-inl.h:1591
static const int kTransitionInfoOffset
Definition: objects.h:8254
static const Register function_address()
void GenerateReadElement(MacroAssembler *masm)
void GenerateNewSloppySlow(MacroAssembler *masm)
void GenerateNewStrict(MacroAssembler *masm)
void GenerateNewSloppyFast(MacroAssembler *masm)
static void GenerateStubsAheadOfTime(Isolate *isolate)
void GenerateDispatchToArrayStub(MacroAssembler *masm, AllocationSiteOverrideMode mode)
ArgumentCountKey argument_count() const
Definition: code-stubs.h:732
friend class BlockConstPoolScope
static const int kCallSizeWithRelocation
static void GenerateAheadOfTime(Isolate *isolate)
Definition: code-stubs.cc:266
static const U kShift
Definition: utils.h:204
static const U kMask
Definition: utils.h:203
bool save_doubles() const
Definition: code-stubs.h:1423
static void GenerateAheadOfTime(Isolate *isolate)
CEntryStub(Isolate *isolate, int result_size, SaveFPRegsMode save_doubles=kDontSaveFPRegs)
Definition: code-stubs.h:1406
STATIC_ASSERT(Code::kArgumentsBits+2<=kStubMinorKeyBits)
bool CallAsMethod() const
Definition: code-stubs.h:811
void GenerateMiss(MacroAssembler *masm)
virtual InlineCacheState GetICState() const OVERRIDE
Definition: code-stubs.h:804
static const int kValueOffset
Definition: objects.h:9446
static const int kHeaderSize
Definition: objects.h:5373
Condition GetCondition() const
Definition: code-stubs.cc:354
void GenerateInternalizedStrings(MacroAssembler *masm)
void GenerateStrings(MacroAssembler *masm)
CompareICState::State state() const
Definition: code-stubs.h:1278
Token::Value op() const
Definition: code-stubs.h:1268
void GenerateMiss(MacroAssembler *masm)
CompareICState::State left() const
Definition: code-stubs.h:1272
void GenerateGeneric(MacroAssembler *masm)
CompareICState::State right() const
Definition: code-stubs.h:1275
void GenerateObjects(MacroAssembler *masm)
CompareICStub(Isolate *isolate, Token::Value op, CompareICState::State left, CompareICState::State right, CompareICState::State state)
Definition: code-stubs.h:1256
void GenerateNumbers(MacroAssembler *masm)
void GenerateUniqueNames(MacroAssembler *masm)
void GenerateKnownObjects(MacroAssembler *masm)
void GenerateSmis(MacroAssembler *masm)
static const int kFirstOffset
Definition: objects.h:9061
static const int kMinLength
Definition: objects.h:9066
static const int kSecondOffset
Definition: objects.h:9062
static bool IsSupported(CpuFeature f)
Definition: assembler.h:184
static void GenerateAheadOfTime(Isolate *isolate)
Definition: code-stubs.cc:725
void GenerateCall(MacroAssembler *masm, Register target)
Register source() const
Definition: code-stubs.h:1901
Register destination() const
Definition: code-stubs.h:1904
static const int kCallerFPOffset
Definition: frames-arm.h:80
static const int kMaxShortLength
Definition: objects.h:9141
static const int kResourceDataOffset
Definition: objects.h:9138
static const int kLengthOffset
Definition: objects.h:2392
static const int kHeaderSize
Definition: objects.h:2393
static const int kNativeContextOffset
Definition: objects.h:7459
static const int kEntrySize
Definition: objects.h:3276
static const int kMantissaBits
Definition: objects.h:1525
static const int kValueOffset
Definition: objects.h:1506
static const int kExponentBits
Definition: objects.h:1526
static const int kExponentBias
Definition: objects.h:1527
static const int kMapOffset
Definition: objects.h:1427
static const int kStrictArgumentsObjectSize
Definition: heap.h:674
static const int kSloppyArgumentsObjectSize
Definition: heap.h:671
static const int kArgumentsCalleeIndex
Definition: heap.h:679
static const int kArgumentsLengthIndex
Definition: heap.h:677
void GenerateLightweightMiss(MacroAssembler *masm, ExternalReference miss)
bool HasCallSiteInlineCheck() const
Definition: code-stubs.h:700
static Register right()
Definition: code-stubs.h:686
bool HasArgsInRegisters() const
Definition: code-stubs.h:698
static Register left()
Definition: code-stubs.h:685
bool ReturnTrueFalseObject() const
Definition: code-stubs.h:704
static void GenerateStubsAheadOfTime(Isolate *isolate)
void GenerateCase(MacroAssembler *masm, ElementsKind kind)
static const int kJSRegexpStaticOffsetsVectorSize
Definition: isolate.h:984
StackFrame::Type type() const
Definition: code-stubs.h:1454
static const int kSharedFunctionInfoOffset
Definition: objects.h:7379
static const int kContextOffset
Definition: objects.h:7381
static const int kLiteralsOffset
Definition: objects.h:7382
static const int kPrototypeOrInitialMapOffset
Definition: objects.h:7377
static const int kHeaderSize
Definition: objects.h:2195
static const int kPropertiesOffset
Definition: objects.h:2193
static const int kElementsOffset
Definition: objects.h:2194
static const int kDataOneByteCodeOffset
Definition: objects.h:7813
static const int kIrregexpCaptureCountOffset
Definition: objects.h:7817
static const int kDataTagOffset
Definition: objects.h:7811
static const int kDataOffset
Definition: objects.h:7771
static const int kDataUC16CodeOffset
Definition: objects.h:7815
static const Register ReceiverRegister()
static const Register NameRegister()
static const int8_t kMaximumBitField2FastHoleyElementValue
Definition: objects.h:6261
static const int kIsUndetectable
Definition: objects.h:6244
static const int kBitFieldOffset
Definition: objects.h:6228
static const int kInstanceTypeOffset
Definition: objects.h:6229
static const int kBitField2Offset
Definition: objects.h:6233
static const int kPrototypeOffset
Definition: objects.h:6190
static const Register exponent()
ExponentType exponent_type() const
Definition: code-stubs.h:780
static const Register exponent()
static const size_t kWriteBarrierCounterOffset
Definition: spaces.h:536
static const int kEvacuationCandidateMask
Definition: spaces.h:398
static const int kSkipEvacuationSlotsRecordingMask
Definition: spaces.h:400
NameDictionaryLookupStub(Isolate *isolate, LookupMode mode)
static void GeneratePositiveLookup(MacroAssembler *masm, Label *miss, Label *done, Register elements, Register name, Register r0, Register r1)
static void GenerateNegativeLookup(MacroAssembler *masm, Label *miss, Label *done, Register receiver, Register properties, Handle< Name > name, Register scratch0)
static const int kHashShift
Definition: objects.h:8499
static const int kHashFieldOffset
Definition: objects.h:8486
static void GenerateLoadFunctionPrototype(MacroAssembler *masm, Register receiver, Register scratch1, Register scratch2, Label *miss_label)
static Operand UntagSmiAndScale(Register smi, int scale)
static Operand UntagSmi(Register smi)
static const intptr_t kPageAlignmentMask
Definition: spaces.h:757
virtual void Generate(MacroAssembler *masm)=0
ProfileEntryHookStub(Isolate *isolate)
Definition: code-stubs.h:2373
static void MaybeCallEntryHook(MacroAssembler *masm)
static void EntryHookTrampoline(intptr_t function, intptr_t stack_pointer, Isolate *isolate)
Definition: code-stubs.cc:925
void SaveCallerSaveRegisters(MacroAssembler *masm, SaveFPRegsMode mode)
void RestoreCallerSaveRegisters(MacroAssembler *masm, SaveFPRegsMode mode)
void GenerateIncremental(MacroAssembler *masm, Mode mode)
void InformIncrementalMarker(MacroAssembler *masm)
RememberedSetAction remembered_set_action() const
SaveFPRegsMode save_fp_regs_mode() const
void CheckNeedsToInformIncrementalMarker(MacroAssembler *masm, OnNoNeedToInformIncrementalMarker on_no_need, Mode mode)
virtual void Generate(MacroAssembler *masm) OVERRIDE
static const int kLastCaptureCountOffset
Definition: jsregexp.h:168
static const int kLastSubjectOffset
Definition: jsregexp.h:170
static const int kLastMatchOverhead
Definition: jsregexp.h:165
static const int kLastInputOffset
Definition: jsregexp.h:172
static const int kFirstCaptureOffset
Definition: jsregexp.h:174
static void GenerateAheadOfTime(Isolate *isolate)
static const Function * FunctionForId(FunctionId id)
Definition: runtime.cc:9312
static const int kHeaderSize
Definition: objects.h:8941
static const int kConstructStubOffset
Definition: objects.h:6896
static const int kFeedbackVectorOffset
Definition: objects.h:6904
static const int kCompilerHintsOffset
Definition: objects.h:6961
static const int kMinLength
Definition: objects.h:9109
static const int kParentOffset
Definition: objects.h:9104
static const int kOffsetOffset
Definition: objects.h:9105
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
static const int kContextOffset
Definition: frames.h:162
static const int kCallerSPOffset
Definition: frames.h:167
static const int kCallerFPOffset
Definition: frames.h:165
static void GenerateFixedRegStubsAheadOfTime(Isolate *isolate)
StoreBufferOverflowStub(Isolate *isolate, SaveFPRegsMode save_fp)
Definition: code-stubs.h:2395
static void GenerateAheadOfTime(Isolate *isolate)
void GenerateFast(MacroAssembler *masm)
void GenerateSlow(MacroAssembler *masm, const RuntimeCallHelper &call_helper)
void GenerateFast(MacroAssembler *masm)
void GenerateSlow(MacroAssembler *masm, const RuntimeCallHelper &call_helper)
static void Generate(MacroAssembler *masm, Register string, Register index, Register result, Label *call_runtime)
static void GenerateOneByteCharsCompareLoop(MacroAssembler *masm, Register left, Register right, Register length, Register scratch1, Register scratch2, Label *chars_not_equal)
static void GenerateCompareFlatOneByteStrings(MacroAssembler *masm, Register left, Register right, Register scratch1, Register scratch2, Register scratch3, Register scratch4)
static void GenerateFlatOneByteStringEquals(MacroAssembler *masm, Register left, Register right, Register scratch1, Register scratch2, Register scratch3)
static const int32_t kMaxOneByteCharCode
Definition: objects.h:8811
static const int kLengthOffset
Definition: objects.h:8802
static const int kCallerStackParameterCountFrameOffset
Definition: frames.h:755
StubFunctionMode function_mode() const
Definition: code-stubs.h:2360
static void GenerateAheadOfTime(Isolate *isolate)
Definition: code-stubs.cc:917
static bool IsOrderedRelationalCompareOp(Value op)
Definition: token.h:206
static bool IsEqualityOp(Value op)
Definition: token.h:210
static Handle< Object > UninitializedSentinel(Isolate *isolate)
static Handle< Object > MegamorphicSentinel(Isolate *isolate)
static const Register VectorRegister()
#define __
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in only print modified registers Trace simulator debug messages Implied by trace sim abort randomize hashes to avoid predictable hash Fixed seed to use to hash property Print the time it takes to deserialize the snapshot A filename with extra code to be included in the A file to write the raw snapshot bytes to(mksnapshot only)") DEFINE_STRING(raw_context_file
enable harmony numeric enable harmony object literal extensions Optimize object size
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define FUNCTION_ADDR(f)
Definition: globals.h:195
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
#define ASM_LOCATION(message)
@ JUMP_FUNCTION
@ CALL_FUNCTION
AllocationFlags
@ SIZE_IN_WORDS
@ TAG_OBJECT
void USE(T)
Definition: macros.h:322
int int32_t
Definition: unicode.cc:24
static int Push(SpecialRPOStackFrame *stack, int depth, BasicBlock *child, int unvisited)
Definition: scheduler.cc:773
const int kPointerSize
Definition: globals.h:129
const LowDwVfpRegister d2
const uint32_t kStringEncodingMask
Definition: objects.h:555
@ ALWAYS_ALIGN_CSP
Definition: globals.h:632
const LowDwVfpRegister d7
ElementsKind GetFastElementsKindFromSequenceIndex(int sequence_number)
@ DONT_TRACK_ALLOCATION_SITE
Definition: objects.h:8084
@ kSeqStringTag
Definition: objects.h:563
@ kConsStringTag
Definition: objects.h:564
@ kSlicedStringTag
Definition: objects.h:566
@ kExternalStringTag
Definition: objects.h:565
const LowDwVfpRegister d6
bool AreAliased(const CPURegister &reg1, const CPURegister &reg2, const CPURegister &reg3=NoReg, const CPURegister &reg4=NoReg, const CPURegister &reg5=NoReg, const CPURegister &reg6=NoReg, const CPURegister &reg7=NoReg, const CPURegister &reg8=NoReg)
const Register cp
const unsigned kXRegSizeInBits
const LowDwVfpRegister d1
const intptr_t kSmiSignMask
Definition: globals.h:223
const uint32_t kTwoByteStringTag
Definition: objects.h:556
const uint32_t kShortExternalStringTag
Definition: objects.h:590
int MaskToBit(uint64_t mask)
const LowDwVfpRegister d0
const int kFastElementsKindPackedToHoley
Definition: elements-kind.h:71
const int kDoubleSize
Definition: globals.h:127
MemOperand GlobalObjectMemOperand()
const uint32_t kNotStringTag
Definition: objects.h:545
const Register fp
DwVfpRegister DoubleRegister
const int64_t kDSignMask
Register GetAllocatableRegisterThatIsNotOneOf(Register reg1, Register reg2=NoReg, Register reg3=NoReg, Register reg4=NoReg)
const int64_t kWSignBit
@ JS_FUNCTION_STUB_MODE
Definition: code-stubs.h:350
const int kPointerSizeLog2
Definition: globals.h:147
const uint32_t kStringTag
Definition: objects.h:544
MemOperand ContextMemOperand(Register context, int index)
@ JS_REGEXP_TYPE
Definition: objects.h:748
@ JS_ARRAY_TYPE
Definition: objects.h:738
@ FIXED_ARRAY_TYPE
Definition: objects.h:717
@ JS_OBJECT_TYPE
Definition: objects.h:731
@ ODDBALL_TYPE
Definition: objects.h:663
@ FIRST_SPEC_OBJECT_TYPE
Definition: objects.h:781
@ LAST_SPEC_OBJECT_TYPE
Definition: objects.h:782
@ HEAP_NUMBER_TYPE
Definition: objects.h:669
@ JS_FUNCTION_TYPE
Definition: objects.h:749
@ JS_FUNCTION_PROXY_TYPE
Definition: objects.h:726
@ FAST_HOLEY_DOUBLE_ELEMENTS
Definition: elements-kind.h:27
@ TERMINAL_FAST_ELEMENTS_KIND
Definition: elements-kind.h:63
@ FAST_HOLEY_SMI_ELEMENTS
Definition: elements-kind.h:17
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:146
const uint32_t kOneByteStringTag
Definition: objects.h:557
MemOperand FieldMemOperand(Register object, int offset)
const intptr_t kObjectAlignmentMask
Definition: globals.h:227
int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind)
bool IsFastPackedElementsKind(ElementsKind kind)
const uint32_t kShortExternalStringMask
Definition: objects.h:589
ElementsKind GetHoleyElementsKind(ElementsKind packed_kind)
const int64_t kXSignMask
const uint64_t kSmiShiftMask
AllocationSiteOverrideMode
Definition: code-stubs.h:716
@ DISABLE_ALLOCATION_SITES
Definition: code-stubs.h:718
const uint32_t kStringRepresentationMask
Definition: objects.h:561
const Register lr
byte * Address
Definition: globals.h:101
const uint32_t kSlicedNotConsMask
Definition: objects.h:579
const unsigned kXRegSize
const int kHeapObjectTag
Definition: v8.h:5737
MemOperand UntagSmiFieldMemOperand(Register object, int offset)
const unsigned kWRegSize
const uint32_t kInternalizedTag
Definition: objects.h:551
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
const intptr_t kSmiTagMask
Definition: v8.h:5744
const uint32_t kIsNotInternalizedMask
Definition: objects.h:549
const int kSmiTag
Definition: v8.h:5742
const unsigned kByteSizeInBytes
const LowDwVfpRegister d3
const uint32_t kIsNotStringMask
Definition: objects.h:543
const unsigned kInstructionSize
ElementsKind GetInitialFastElementsKind()
Definition: elements-kind.h:78
@ STRING_INDEX_IS_NUMBER
Definition: code-stubs.h:1590
@ STRING_INDEX_IS_ARRAY_INDEX
Definition: code-stubs.h:1595
void CopyBytes(uint8_t *target, uint8_t *source)
const uint32_t kIsIndirectStringMask
Definition: objects.h:568
MemOperand UntagSmiMemOperand(Register object, int offset)
const RegList kCallerSaved
Definition: frames-arm.h:50
const int64_t kXSignBit
const LowDwVfpRegister d4
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
static Handle< Value > Throw(Isolate *isolate, const char *message)
Definition: d8.cc:72
bool Is(const CPURegister &other) const
#define T(name, string, precedence)
Definition: token.cc:25