1// Copyright 2016 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#include "src/code-stub-assembler.h"
5#include "src/code-factory.h"
6#include "src/frames-inl.h"
7#include "src/frames.h"
8
9namespace v8 {
10namespace internal {
11
12using compiler::Node;
13
14CodeStubAssembler::CodeStubAssembler(compiler::CodeAssemblerState* state)
15    : compiler::CodeAssembler(state) {
16  if (DEBUG_BOOL && FLAG_csa_trap_on_node != nullptr) {
17    HandleBreakOnNode();
18  }
19}
20
21void CodeStubAssembler::HandleBreakOnNode() {
22  // FLAG_csa_trap_on_node should be in a form "STUB,NODE" where STUB is a
23  // string specifying the name of a stub and NODE is number specifying node id.
24  const char* name = state()->name();
25  size_t name_length = strlen(name);
26  if (strncmp(FLAG_csa_trap_on_node, name, name_length) != 0) {
27    // Different name.
28    return;
29  }
30  size_t option_length = strlen(FLAG_csa_trap_on_node);
31  if (option_length < name_length + 2 ||
32      FLAG_csa_trap_on_node[name_length] != ',') {
33    // Option is too short.
34    return;
35  }
36  const char* start = &FLAG_csa_trap_on_node[name_length + 1];
37  char* end;
38  int node_id = static_cast<int>(strtol(start, &end, 10));
39  if (start == end) {
40    // Bad node id.
41    return;
42  }
43  BreakOnNode(node_id);
44}
45
46void CodeStubAssembler::Assert(const NodeGenerator& codition_body,
47                               const char* message, const char* file,
48                               int line) {
49#if defined(DEBUG)
50  if (FLAG_debug_code) {
51    Label ok(this);
52    Label not_ok(this, Label::kDeferred);
53    if (message != nullptr && FLAG_code_comments) {
54      Comment("[ Assert: %s", message);
55    } else {
56      Comment("[ Assert");
57    }
58    Node* condition = codition_body();
59    DCHECK_NOT_NULL(condition);
60    Branch(condition, &ok, &not_ok);
61    Bind(&not_ok);
62    if (message != nullptr) {
63      char chars[1024];
64      Vector<char> buffer(chars);
65      if (file != nullptr) {
66        SNPrintF(buffer, "CSA_ASSERT failed: %s [%s:%d]\n", message, file,
67                 line);
68      } else {
69        SNPrintF(buffer, "CSA_ASSERT failed: %s\n", message);
70      }
71      CallRuntime(
72          Runtime::kGlobalPrint, SmiConstant(Smi::kZero),
73          HeapConstant(factory()->NewStringFromAsciiChecked(&(buffer[0]))));
74    }
75    DebugBreak();
76    Goto(&ok);
77    Bind(&ok);
78    Comment("] Assert");
79  }
80#endif
81}
82
83Node* CodeStubAssembler::Select(Node* condition, const NodeGenerator& true_body,
84                                const NodeGenerator& false_body,
85                                MachineRepresentation rep) {
86  Variable value(this, rep);
87  Label vtrue(this), vfalse(this), end(this);
88  Branch(condition, &vtrue, &vfalse);
89
90  Bind(&vtrue);
91  {
92    value.Bind(true_body());
93    Goto(&end);
94  }
95  Bind(&vfalse);
96  {
97    value.Bind(false_body());
98    Goto(&end);
99  }
100
101  Bind(&end);
102  return value.value();
103}
104
105Node* CodeStubAssembler::SelectConstant(Node* condition, Node* true_value,
106                                        Node* false_value,
107                                        MachineRepresentation rep) {
108  return Select(condition, [=] { return true_value; },
109                [=] { return false_value; }, rep);
110}
111
112Node* CodeStubAssembler::SelectInt32Constant(Node* condition, int true_value,
113                                             int false_value) {
114  return SelectConstant(condition, Int32Constant(true_value),
115                        Int32Constant(false_value),
116                        MachineRepresentation::kWord32);
117}
118
119Node* CodeStubAssembler::SelectIntPtrConstant(Node* condition, int true_value,
120                                              int false_value) {
121  return SelectConstant(condition, IntPtrConstant(true_value),
122                        IntPtrConstant(false_value),
123                        MachineType::PointerRepresentation());
124}
125
126Node* CodeStubAssembler::SelectBooleanConstant(Node* condition) {
127  return SelectConstant(condition, TrueConstant(), FalseConstant(),
128                        MachineRepresentation::kTagged);
129}
130
131Node* CodeStubAssembler::SelectTaggedConstant(Node* condition, Node* true_value,
132                                              Node* false_value) {
133  return SelectConstant(condition, true_value, false_value,
134                        MachineRepresentation::kTagged);
135}
136
137Node* CodeStubAssembler::SelectSmiConstant(Node* condition, Smi* true_value,
138                                           Smi* false_value) {
139  return SelectConstant(condition, SmiConstant(true_value),
140                        SmiConstant(false_value),
141                        MachineRepresentation::kTaggedSigned);
142}
143
144Node* CodeStubAssembler::NoContextConstant() { return NumberConstant(0); }
145
146#define HEAP_CONSTANT_ACCESSOR(rootName, name)     \
147  Node* CodeStubAssembler::name##Constant() {      \
148    return LoadRoot(Heap::k##rootName##RootIndex); \
149  }
150HEAP_CONSTANT_LIST(HEAP_CONSTANT_ACCESSOR);
151#undef HEAP_CONSTANT_ACCESSOR
152
153#define HEAP_CONSTANT_TEST(rootName, name)         \
154  Node* CodeStubAssembler::Is##name(Node* value) { \
155    return WordEqual(value, name##Constant());     \
156  }
157HEAP_CONSTANT_LIST(HEAP_CONSTANT_TEST);
158#undef HEAP_CONSTANT_TEST
159
160Node* CodeStubAssembler::HashSeed() {
161  return LoadAndUntagToWord32Root(Heap::kHashSeedRootIndex);
162}
163
164Node* CodeStubAssembler::StaleRegisterConstant() {
165  return LoadRoot(Heap::kStaleRegisterRootIndex);
166}
167
168Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) {
169  if (mode == SMI_PARAMETERS) {
170    return SmiConstant(Smi::FromInt(value));
171  } else {
172    DCHECK_EQ(INTPTR_PARAMETERS, mode);
173    return IntPtrConstant(value);
174  }
175}
176
177bool CodeStubAssembler::IsIntPtrOrSmiConstantZero(Node* test) {
178  int32_t constant_test;
179  Smi* smi_test;
180  if ((ToInt32Constant(test, constant_test) && constant_test == 0) ||
181      (ToSmiConstant(test, smi_test) && smi_test->value() == 0)) {
182    return true;
183  }
184  return false;
185}
186
187Node* CodeStubAssembler::IntPtrRoundUpToPowerOfTwo32(Node* value) {
188  Comment("IntPtrRoundUpToPowerOfTwo32");
189  CSA_ASSERT(this, UintPtrLessThanOrEqual(value, IntPtrConstant(0x80000000u)));
190  value = IntPtrSub(value, IntPtrConstant(1));
191  for (int i = 1; i <= 16; i *= 2) {
192    value = WordOr(value, WordShr(value, IntPtrConstant(i)));
193  }
194  return IntPtrAdd(value, IntPtrConstant(1));
195}
196
197Node* CodeStubAssembler::WordIsPowerOfTwo(Node* value) {
198  // value && !(value & (value - 1))
199  return WordEqual(
200      Select(
201          WordEqual(value, IntPtrConstant(0)),
202          [=] { return IntPtrConstant(1); },
203          [=] { return WordAnd(value, IntPtrSub(value, IntPtrConstant(1))); },
204          MachineType::PointerRepresentation()),
205      IntPtrConstant(0));
206}
207
208Node* CodeStubAssembler::Float64Round(Node* x) {
209  Node* one = Float64Constant(1.0);
210  Node* one_half = Float64Constant(0.5);
211
212  Label return_x(this);
213
214  // Round up {x} towards Infinity.
215  Variable var_x(this, MachineRepresentation::kFloat64, Float64Ceil(x));
216
217  GotoIf(Float64LessThanOrEqual(Float64Sub(var_x.value(), one_half), x),
218         &return_x);
219  var_x.Bind(Float64Sub(var_x.value(), one));
220  Goto(&return_x);
221
222  Bind(&return_x);
223  return var_x.value();
224}
225
226Node* CodeStubAssembler::Float64Ceil(Node* x) {
227  if (IsFloat64RoundUpSupported()) {
228    return Float64RoundUp(x);
229  }
230
231  Node* one = Float64Constant(1.0);
232  Node* zero = Float64Constant(0.0);
233  Node* two_52 = Float64Constant(4503599627370496.0E0);
234  Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
235
236  Variable var_x(this, MachineRepresentation::kFloat64, x);
237  Label return_x(this), return_minus_x(this);
238
239  // Check if {x} is greater than zero.
240  Label if_xgreaterthanzero(this), if_xnotgreaterthanzero(this);
241  Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero,
242         &if_xnotgreaterthanzero);
243
244  Bind(&if_xgreaterthanzero);
245  {
246    // Just return {x} unless it's in the range ]0,2^52[.
247    GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x);
248
249    // Round positive {x} towards Infinity.
250    var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52));
251    GotoIfNot(Float64LessThan(var_x.value(), x), &return_x);
252    var_x.Bind(Float64Add(var_x.value(), one));
253    Goto(&return_x);
254  }
255
256  Bind(&if_xnotgreaterthanzero);
257  {
258    // Just return {x} unless it's in the range ]-2^52,0[
259    GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x);
260    GotoIfNot(Float64LessThan(x, zero), &return_x);
261
262    // Round negated {x} towards Infinity and return the result negated.
263    Node* minus_x = Float64Neg(x);
264    var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
265    GotoIfNot(Float64GreaterThan(var_x.value(), minus_x), &return_minus_x);
266    var_x.Bind(Float64Sub(var_x.value(), one));
267    Goto(&return_minus_x);
268  }
269
270  Bind(&return_minus_x);
271  var_x.Bind(Float64Neg(var_x.value()));
272  Goto(&return_x);
273
274  Bind(&return_x);
275  return var_x.value();
276}
277
278Node* CodeStubAssembler::Float64Floor(Node* x) {
279  if (IsFloat64RoundDownSupported()) {
280    return Float64RoundDown(x);
281  }
282
283  Node* one = Float64Constant(1.0);
284  Node* zero = Float64Constant(0.0);
285  Node* two_52 = Float64Constant(4503599627370496.0E0);
286  Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
287
288  Variable var_x(this, MachineRepresentation::kFloat64, x);
289  Label return_x(this), return_minus_x(this);
290
291  // Check if {x} is greater than zero.
292  Label if_xgreaterthanzero(this), if_xnotgreaterthanzero(this);
293  Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero,
294         &if_xnotgreaterthanzero);
295
296  Bind(&if_xgreaterthanzero);
297  {
298    // Just return {x} unless it's in the range ]0,2^52[.
299    GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x);
300
301    // Round positive {x} towards -Infinity.
302    var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52));
303    GotoIfNot(Float64GreaterThan(var_x.value(), x), &return_x);
304    var_x.Bind(Float64Sub(var_x.value(), one));
305    Goto(&return_x);
306  }
307
308  Bind(&if_xnotgreaterthanzero);
309  {
310    // Just return {x} unless it's in the range ]-2^52,0[
311    GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x);
312    GotoIfNot(Float64LessThan(x, zero), &return_x);
313
314    // Round negated {x} towards -Infinity and return the result negated.
315    Node* minus_x = Float64Neg(x);
316    var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
317    GotoIfNot(Float64LessThan(var_x.value(), minus_x), &return_minus_x);
318    var_x.Bind(Float64Add(var_x.value(), one));
319    Goto(&return_minus_x);
320  }
321
322  Bind(&return_minus_x);
323  var_x.Bind(Float64Neg(var_x.value()));
324  Goto(&return_x);
325
326  Bind(&return_x);
327  return var_x.value();
328}
329
330Node* CodeStubAssembler::Float64RoundToEven(Node* x) {
331  if (IsFloat64RoundTiesEvenSupported()) {
332    return Float64RoundTiesEven(x);
333  }
334  // See ES#sec-touint8clamp for details.
335  Node* f = Float64Floor(x);
336  Node* f_and_half = Float64Add(f, Float64Constant(0.5));
337
338  Variable var_result(this, MachineRepresentation::kFloat64);
339  Label return_f(this), return_f_plus_one(this), done(this);
340
341  GotoIf(Float64LessThan(f_and_half, x), &return_f_plus_one);
342  GotoIf(Float64LessThan(x, f_and_half), &return_f);
343  {
344    Node* f_mod_2 = Float64Mod(f, Float64Constant(2.0));
345    Branch(Float64Equal(f_mod_2, Float64Constant(0.0)), &return_f,
346           &return_f_plus_one);
347  }
348
349  Bind(&return_f);
350  var_result.Bind(f);
351  Goto(&done);
352
353  Bind(&return_f_plus_one);
354  var_result.Bind(Float64Add(f, Float64Constant(1.0)));
355  Goto(&done);
356
357  Bind(&done);
358  return var_result.value();
359}
360
361Node* CodeStubAssembler::Float64Trunc(Node* x) {
362  if (IsFloat64RoundTruncateSupported()) {
363    return Float64RoundTruncate(x);
364  }
365
366  Node* one = Float64Constant(1.0);
367  Node* zero = Float64Constant(0.0);
368  Node* two_52 = Float64Constant(4503599627370496.0E0);
369  Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
370
371  Variable var_x(this, MachineRepresentation::kFloat64, x);
372  Label return_x(this), return_minus_x(this);
373
374  // Check if {x} is greater than 0.
375  Label if_xgreaterthanzero(this), if_xnotgreaterthanzero(this);
376  Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero,
377         &if_xnotgreaterthanzero);
378
379  Bind(&if_xgreaterthanzero);
380  {
381    if (IsFloat64RoundDownSupported()) {
382      var_x.Bind(Float64RoundDown(x));
383    } else {
384      // Just return {x} unless it's in the range ]0,2^52[.
385      GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x);
386
387      // Round positive {x} towards -Infinity.
388      var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52));
389      GotoIfNot(Float64GreaterThan(var_x.value(), x), &return_x);
390      var_x.Bind(Float64Sub(var_x.value(), one));
391    }
392    Goto(&return_x);
393  }
394
395  Bind(&if_xnotgreaterthanzero);
396  {
397    if (IsFloat64RoundUpSupported()) {
398      var_x.Bind(Float64RoundUp(x));
399      Goto(&return_x);
400    } else {
401      // Just return {x} unless its in the range ]-2^52,0[.
402      GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x);
403      GotoIfNot(Float64LessThan(x, zero), &return_x);
404
405      // Round negated {x} towards -Infinity and return result negated.
406      Node* minus_x = Float64Neg(x);
407      var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
408      GotoIfNot(Float64GreaterThan(var_x.value(), minus_x), &return_minus_x);
409      var_x.Bind(Float64Sub(var_x.value(), one));
410      Goto(&return_minus_x);
411    }
412  }
413
414  Bind(&return_minus_x);
415  var_x.Bind(Float64Neg(var_x.value()));
416  Goto(&return_x);
417
418  Bind(&return_x);
419  return var_x.value();
420}
421
422Node* CodeStubAssembler::SmiShiftBitsConstant() {
423  return IntPtrConstant(kSmiShiftSize + kSmiTagSize);
424}
425
426Node* CodeStubAssembler::SmiFromWord32(Node* value) {
427  value = ChangeInt32ToIntPtr(value);
428  return BitcastWordToTaggedSigned(WordShl(value, SmiShiftBitsConstant()));
429}
430
431Node* CodeStubAssembler::SmiTag(Node* value) {
432  int32_t constant_value;
433  if (ToInt32Constant(value, constant_value) && Smi::IsValid(constant_value)) {
434    return SmiConstant(Smi::FromInt(constant_value));
435  }
436  return BitcastWordToTaggedSigned(WordShl(value, SmiShiftBitsConstant()));
437}
438
439Node* CodeStubAssembler::SmiUntag(Node* value) {
440  return WordSar(BitcastTaggedToWord(value), SmiShiftBitsConstant());
441}
442
443Node* CodeStubAssembler::SmiToWord32(Node* value) {
444  Node* result = SmiUntag(value);
445  return TruncateWordToWord32(result);
446}
447
448Node* CodeStubAssembler::SmiToFloat64(Node* value) {
449  return ChangeInt32ToFloat64(SmiToWord32(value));
450}
451
452Node* CodeStubAssembler::SmiMax(Node* a, Node* b) {
453  return SelectTaggedConstant(SmiLessThan(a, b), b, a);
454}
455
456Node* CodeStubAssembler::SmiMin(Node* a, Node* b) {
457  return SelectTaggedConstant(SmiLessThan(a, b), a, b);
458}
459
460Node* CodeStubAssembler::SmiMod(Node* a, Node* b) {
461  Variable var_result(this, MachineRepresentation::kTagged);
462  Label return_result(this, &var_result),
463      return_minuszero(this, Label::kDeferred),
464      return_nan(this, Label::kDeferred);
465
466  // Untag {a} and {b}.
467  a = SmiToWord32(a);
468  b = SmiToWord32(b);
469
470  // Return NaN if {b} is zero.
471  GotoIf(Word32Equal(b, Int32Constant(0)), &return_nan);
472
473  // Check if {a} is non-negative.
474  Label if_aisnotnegative(this), if_aisnegative(this, Label::kDeferred);
475  Branch(Int32LessThanOrEqual(Int32Constant(0), a), &if_aisnotnegative,
476         &if_aisnegative);
477
478  Bind(&if_aisnotnegative);
479  {
480    // Fast case, don't need to check any other edge cases.
481    Node* r = Int32Mod(a, b);
482    var_result.Bind(SmiFromWord32(r));
483    Goto(&return_result);
484  }
485
486  Bind(&if_aisnegative);
487  {
488    if (SmiValuesAre32Bits()) {
489      // Check if {a} is kMinInt and {b} is -1 (only relevant if the
490      // kMinInt is actually representable as a Smi).
491      Label join(this);
492      GotoIfNot(Word32Equal(a, Int32Constant(kMinInt)), &join);
493      GotoIf(Word32Equal(b, Int32Constant(-1)), &return_minuszero);
494      Goto(&join);
495      Bind(&join);
496    }
497
498    // Perform the integer modulus operation.
499    Node* r = Int32Mod(a, b);
500
501    // Check if {r} is zero, and if so return -0, because we have to
502    // take the sign of the left hand side {a}, which is negative.
503    GotoIf(Word32Equal(r, Int32Constant(0)), &return_minuszero);
504
505    // The remainder {r} can be outside the valid Smi range on 32bit
506    // architectures, so we cannot just say SmiFromWord32(r) here.
507    var_result.Bind(ChangeInt32ToTagged(r));
508    Goto(&return_result);
509  }
510
511  Bind(&return_minuszero);
512  var_result.Bind(MinusZeroConstant());
513  Goto(&return_result);
514
515  Bind(&return_nan);
516  var_result.Bind(NanConstant());
517  Goto(&return_result);
518
519  Bind(&return_result);
520  return var_result.value();
521}
522
523Node* CodeStubAssembler::SmiMul(Node* a, Node* b) {
524  Variable var_result(this, MachineRepresentation::kTagged);
525  Variable var_lhs_float64(this, MachineRepresentation::kFloat64),
526      var_rhs_float64(this, MachineRepresentation::kFloat64);
527  Label return_result(this, &var_result);
528
529  // Both {a} and {b} are Smis. Convert them to integers and multiply.
530  Node* lhs32 = SmiToWord32(a);
531  Node* rhs32 = SmiToWord32(b);
532  Node* pair = Int32MulWithOverflow(lhs32, rhs32);
533
534  Node* overflow = Projection(1, pair);
535
536  // Check if the multiplication overflowed.
537  Label if_overflow(this, Label::kDeferred), if_notoverflow(this);
538  Branch(overflow, &if_overflow, &if_notoverflow);
539  Bind(&if_notoverflow);
540  {
541    // If the answer is zero, we may need to return -0.0, depending on the
542    // input.
543    Label answer_zero(this), answer_not_zero(this);
544    Node* answer = Projection(0, pair);
545    Node* zero = Int32Constant(0);
546    Branch(Word32Equal(answer, zero), &answer_zero, &answer_not_zero);
547    Bind(&answer_not_zero);
548    {
549      var_result.Bind(ChangeInt32ToTagged(answer));
550      Goto(&return_result);
551    }
552    Bind(&answer_zero);
553    {
554      Node* or_result = Word32Or(lhs32, rhs32);
555      Label if_should_be_negative_zero(this), if_should_be_zero(this);
556      Branch(Int32LessThan(or_result, zero), &if_should_be_negative_zero,
557             &if_should_be_zero);
558      Bind(&if_should_be_negative_zero);
559      {
560        var_result.Bind(MinusZeroConstant());
561        Goto(&return_result);
562      }
563      Bind(&if_should_be_zero);
564      {
565        var_result.Bind(SmiConstant(0));
566        Goto(&return_result);
567      }
568    }
569  }
570  Bind(&if_overflow);
571  {
572    var_lhs_float64.Bind(SmiToFloat64(a));
573    var_rhs_float64.Bind(SmiToFloat64(b));
574    Node* value = Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
575    Node* result = AllocateHeapNumberWithValue(value);
576    var_result.Bind(result);
577    Goto(&return_result);
578  }
579
580  Bind(&return_result);
581  return var_result.value();
582}
583
584Node* CodeStubAssembler::TruncateWordToWord32(Node* value) {
585  if (Is64()) {
586    return TruncateInt64ToInt32(value);
587  }
588  return value;
589}
590
591Node* CodeStubAssembler::TaggedIsSmi(Node* a) {
592  return WordEqual(WordAnd(BitcastTaggedToWord(a), IntPtrConstant(kSmiTagMask)),
593                   IntPtrConstant(0));
594}
595
596Node* CodeStubAssembler::TaggedIsNotSmi(Node* a) {
597  return WordNotEqual(
598      WordAnd(BitcastTaggedToWord(a), IntPtrConstant(kSmiTagMask)),
599      IntPtrConstant(0));
600}
601
602Node* CodeStubAssembler::TaggedIsPositiveSmi(Node* a) {
603  return WordEqual(WordAnd(BitcastTaggedToWord(a),
604                           IntPtrConstant(kSmiTagMask | kSmiSignMask)),
605                   IntPtrConstant(0));
606}
607
608Node* CodeStubAssembler::WordIsWordAligned(Node* word) {
609  return WordEqual(IntPtrConstant(0),
610                   WordAnd(word, IntPtrConstant((1 << kPointerSizeLog2) - 1)));
611}
612
613void CodeStubAssembler::BranchIfPrototypesHaveNoElements(
614    Node* receiver_map, Label* definitely_no_elements,
615    Label* possibly_elements) {
616  Variable var_map(this, MachineRepresentation::kTagged, receiver_map);
617  Label loop_body(this, &var_map);
618  Node* empty_elements = LoadRoot(Heap::kEmptyFixedArrayRootIndex);
619  Goto(&loop_body);
620
621  Bind(&loop_body);
622  {
623    Node* map = var_map.value();
624    Node* prototype = LoadMapPrototype(map);
625    GotoIf(WordEqual(prototype, NullConstant()), definitely_no_elements);
626    Node* prototype_map = LoadMap(prototype);
627    // Pessimistically assume elements if a Proxy, Special API Object,
628    // or JSValue wrapper is found on the prototype chain. After this
629    // instance type check, it's not necessary to check for interceptors or
630    // access checks.
631    GotoIf(Int32LessThanOrEqual(LoadMapInstanceType(prototype_map),
632                                Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
633           possibly_elements);
634    GotoIf(WordNotEqual(LoadElements(prototype), empty_elements),
635           possibly_elements);
636    var_map.Bind(prototype_map);
637    Goto(&loop_body);
638  }
639}
640
641void CodeStubAssembler::BranchIfJSReceiver(Node* object, Label* if_true,
642                                           Label* if_false) {
643  GotoIf(TaggedIsSmi(object), if_false);
644  STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
645  Branch(Int32GreaterThanOrEqual(LoadInstanceType(object),
646                                 Int32Constant(FIRST_JS_RECEIVER_TYPE)),
647         if_true, if_false);
648}
649
650void CodeStubAssembler::BranchIfJSObject(Node* object, Label* if_true,
651                                         Label* if_false) {
652  GotoIf(TaggedIsSmi(object), if_false);
653  STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
654  Branch(Int32GreaterThanOrEqual(LoadInstanceType(object),
655                                 Int32Constant(FIRST_JS_OBJECT_TYPE)),
656         if_true, if_false);
657}
658
659void CodeStubAssembler::BranchIfFastJSArray(
660    Node* object, Node* context, CodeStubAssembler::FastJSArrayAccessMode mode,
661    Label* if_true, Label* if_false) {
662  // Bailout if receiver is a Smi.
663  GotoIf(TaggedIsSmi(object), if_false);
664
665  Node* map = LoadMap(object);
666
667  // Bailout if instance type is not JS_ARRAY_TYPE.
668  GotoIf(Word32NotEqual(LoadMapInstanceType(map), Int32Constant(JS_ARRAY_TYPE)),
669         if_false);
670
671  Node* elements_kind = LoadMapElementsKind(map);
672
673  // Bailout if receiver has slow elements.
674  GotoIfNot(IsFastElementsKind(elements_kind), if_false);
675
676  // Check prototype chain if receiver does not have packed elements.
677  if (mode == FastJSArrayAccessMode::INBOUNDS_READ) {
678    GotoIfNot(IsHoleyFastElementsKind(elements_kind), if_true);
679  }
680  BranchIfPrototypesHaveNoElements(map, if_true, if_false);
681}
682
683Node* CodeStubAssembler::AllocateRawUnaligned(Node* size_in_bytes,
684                                              AllocationFlags flags,
685                                              Node* top_address,
686                                              Node* limit_address) {
687  Node* top = Load(MachineType::Pointer(), top_address);
688  Node* limit = Load(MachineType::Pointer(), limit_address);
689
690  // If there's not enough space, call the runtime.
691  Variable result(this, MachineRepresentation::kTagged);
692  Label runtime_call(this, Label::kDeferred), no_runtime_call(this);
693  Label merge_runtime(this, &result);
694
695  if (flags & kAllowLargeObjectAllocation) {
696    Label next(this);
697    GotoIf(IsRegularHeapObjectSize(size_in_bytes), &next);
698
699    Node* runtime_flags = SmiConstant(
700        Smi::FromInt(AllocateDoubleAlignFlag::encode(false) |
701                     AllocateTargetSpace::encode(AllocationSpace::LO_SPACE)));
702    Node* const runtime_result =
703        CallRuntime(Runtime::kAllocateInTargetSpace, NoContextConstant(),
704                    SmiTag(size_in_bytes), runtime_flags);
705    result.Bind(runtime_result);
706    Goto(&merge_runtime);
707
708    Bind(&next);
709  }
710
711  Node* new_top = IntPtrAdd(top, size_in_bytes);
712  Branch(UintPtrGreaterThanOrEqual(new_top, limit), &runtime_call,
713         &no_runtime_call);
714
715  Bind(&runtime_call);
716  Node* runtime_result;
717  if (flags & kPretenured) {
718    Node* runtime_flags = SmiConstant(
719        Smi::FromInt(AllocateDoubleAlignFlag::encode(false) |
720                     AllocateTargetSpace::encode(AllocationSpace::OLD_SPACE)));
721    runtime_result =
722        CallRuntime(Runtime::kAllocateInTargetSpace, NoContextConstant(),
723                    SmiTag(size_in_bytes), runtime_flags);
724  } else {
725    runtime_result = CallRuntime(Runtime::kAllocateInNewSpace,
726                                 NoContextConstant(), SmiTag(size_in_bytes));
727  }
728  result.Bind(runtime_result);
729  Goto(&merge_runtime);
730
731  // When there is enough space, return `top' and bump it up.
732  Bind(&no_runtime_call);
733  Node* no_runtime_result = top;
734  StoreNoWriteBarrier(MachineType::PointerRepresentation(), top_address,
735                      new_top);
736  no_runtime_result = BitcastWordToTagged(
737      IntPtrAdd(no_runtime_result, IntPtrConstant(kHeapObjectTag)));
738  result.Bind(no_runtime_result);
739  Goto(&merge_runtime);
740
741  Bind(&merge_runtime);
742  return result.value();
743}
744
745Node* CodeStubAssembler::AllocateRawAligned(Node* size_in_bytes,
746                                            AllocationFlags flags,
747                                            Node* top_address,
748                                            Node* limit_address) {
749  Node* top = Load(MachineType::Pointer(), top_address);
750  Node* limit = Load(MachineType::Pointer(), limit_address);
751  Variable adjusted_size(this, MachineType::PointerRepresentation(),
752                         size_in_bytes);
753  if (flags & kDoubleAlignment) {
754    Label aligned(this), not_aligned(this), merge(this, &adjusted_size);
755    Branch(WordAnd(top, IntPtrConstant(kDoubleAlignmentMask)), &not_aligned,
756           &aligned);
757
758    Bind(&not_aligned);
759    Node* not_aligned_size =
760        IntPtrAdd(size_in_bytes, IntPtrConstant(kPointerSize));
761    adjusted_size.Bind(not_aligned_size);
762    Goto(&merge);
763
764    Bind(&aligned);
765    Goto(&merge);
766
767    Bind(&merge);
768  }
769
770  Variable address(
771      this, MachineRepresentation::kTagged,
772      AllocateRawUnaligned(adjusted_size.value(), kNone, top, limit));
773
774  Label needs_filler(this), doesnt_need_filler(this),
775      merge_address(this, &address);
776  Branch(IntPtrEqual(adjusted_size.value(), size_in_bytes), &doesnt_need_filler,
777         &needs_filler);
778
779  Bind(&needs_filler);
780  // Store a filler and increase the address by kPointerSize.
781  StoreNoWriteBarrier(MachineType::PointerRepresentation(), top,
782                      LoadRoot(Heap::kOnePointerFillerMapRootIndex));
783  address.Bind(BitcastWordToTagged(
784      IntPtrAdd(address.value(), IntPtrConstant(kPointerSize))));
785  Goto(&merge_address);
786
787  Bind(&doesnt_need_filler);
788  Goto(&merge_address);
789
790  Bind(&merge_address);
791  // Update the top.
792  StoreNoWriteBarrier(MachineType::PointerRepresentation(), top_address,
793                      IntPtrAdd(top, adjusted_size.value()));
794  return address.value();
795}
796
797Node* CodeStubAssembler::Allocate(Node* size_in_bytes, AllocationFlags flags) {
798  Comment("Allocate");
799  bool const new_space = !(flags & kPretenured);
800  Node* top_address = ExternalConstant(
801      new_space
802          ? ExternalReference::new_space_allocation_top_address(isolate())
803          : ExternalReference::old_space_allocation_top_address(isolate()));
804  DCHECK_EQ(kPointerSize,
805            ExternalReference::new_space_allocation_limit_address(isolate())
806                    .address() -
807                ExternalReference::new_space_allocation_top_address(isolate())
808                    .address());
809  DCHECK_EQ(kPointerSize,
810            ExternalReference::old_space_allocation_limit_address(isolate())
811                    .address() -
812                ExternalReference::old_space_allocation_top_address(isolate())
813                    .address());
814  Node* limit_address = IntPtrAdd(top_address, IntPtrConstant(kPointerSize));
815
816#ifdef V8_HOST_ARCH_32_BIT
817  if (flags & kDoubleAlignment) {
818    return AllocateRawAligned(size_in_bytes, flags, top_address, limit_address);
819  }
820#endif
821
822  return AllocateRawUnaligned(size_in_bytes, flags, top_address, limit_address);
823}
824
825Node* CodeStubAssembler::Allocate(int size_in_bytes, AllocationFlags flags) {
826  return CodeStubAssembler::Allocate(IntPtrConstant(size_in_bytes), flags);
827}
828
829Node* CodeStubAssembler::InnerAllocate(Node* previous, Node* offset) {
830  return BitcastWordToTagged(IntPtrAdd(BitcastTaggedToWord(previous), offset));
831}
832
833Node* CodeStubAssembler::InnerAllocate(Node* previous, int offset) {
834  return InnerAllocate(previous, IntPtrConstant(offset));
835}
836
837Node* CodeStubAssembler::IsRegularHeapObjectSize(Node* size) {
838  return UintPtrLessThanOrEqual(size,
839                                IntPtrConstant(kMaxRegularHeapObjectSize));
840}
841
842void CodeStubAssembler::BranchIfToBooleanIsTrue(Node* value, Label* if_true,
843                                                Label* if_false) {
844  Label if_valueissmi(this), if_valueisnotsmi(this),
845      if_valueisheapnumber(this, Label::kDeferred);
846
847  // Rule out false {value}.
848  GotoIf(WordEqual(value, BooleanConstant(false)), if_false);
849
850  // Check if {value} is a Smi or a HeapObject.
851  Branch(TaggedIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
852
853  Bind(&if_valueissmi);
854  {
855    // The {value} is a Smi, only need to check against zero.
856    BranchIfSmiEqual(value, SmiConstant(0), if_false, if_true);
857  }
858
859  Bind(&if_valueisnotsmi);
860  {
861    // Check if {value} is the empty string.
862    GotoIf(IsEmptyString(value), if_false);
863
864    // The {value} is a HeapObject, load its map.
865    Node* value_map = LoadMap(value);
866
867    // Only null, undefined and document.all have the undetectable bit set,
868    // so we can return false immediately when that bit is set.
869    Node* value_map_bitfield = LoadMapBitField(value_map);
870    Node* value_map_undetectable =
871        Word32And(value_map_bitfield, Int32Constant(1 << Map::kIsUndetectable));
872
873    // Check if the {value} is undetectable.
874    GotoIfNot(Word32Equal(value_map_undetectable, Int32Constant(0)), if_false);
875
876    // We still need to handle numbers specially, but all other {value}s
877    // that make it here yield true.
878    Branch(IsHeapNumberMap(value_map), &if_valueisheapnumber, if_true);
879
880    Bind(&if_valueisheapnumber);
881    {
882      // Load the floating point value of {value}.
883      Node* value_value = LoadObjectField(value, HeapNumber::kValueOffset,
884                                          MachineType::Float64());
885
886      // Check if the floating point {value} is neither 0.0, -0.0 nor NaN.
887      Branch(Float64LessThan(Float64Constant(0.0), Float64Abs(value_value)),
888             if_true, if_false);
889    }
890  }
891}
892
893Node* CodeStubAssembler::LoadFromFrame(int offset, MachineType rep) {
894  Node* frame_pointer = LoadFramePointer();
895  return Load(rep, frame_pointer, IntPtrConstant(offset));
896}
897
898Node* CodeStubAssembler::LoadFromParentFrame(int offset, MachineType rep) {
899  Node* frame_pointer = LoadParentFramePointer();
900  return Load(rep, frame_pointer, IntPtrConstant(offset));
901}
902
903Node* CodeStubAssembler::LoadBufferObject(Node* buffer, int offset,
904                                          MachineType rep) {
905  return Load(rep, buffer, IntPtrConstant(offset));
906}
907
908Node* CodeStubAssembler::LoadObjectField(Node* object, int offset,
909                                         MachineType rep) {
910  return Load(rep, object, IntPtrConstant(offset - kHeapObjectTag));
911}
912
913Node* CodeStubAssembler::LoadObjectField(Node* object, Node* offset,
914                                         MachineType rep) {
915  return Load(rep, object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)));
916}
917
918Node* CodeStubAssembler::LoadAndUntagObjectField(Node* object, int offset) {
919  if (Is64()) {
920#if V8_TARGET_LITTLE_ENDIAN
921    offset += kPointerSize / 2;
922#endif
923    return ChangeInt32ToInt64(
924        LoadObjectField(object, offset, MachineType::Int32()));
925  } else {
926    return SmiToWord(LoadObjectField(object, offset, MachineType::AnyTagged()));
927  }
928}
929
930Node* CodeStubAssembler::LoadAndUntagToWord32ObjectField(Node* object,
931                                                         int offset) {
932  if (Is64()) {
933#if V8_TARGET_LITTLE_ENDIAN
934    offset += kPointerSize / 2;
935#endif
936    return LoadObjectField(object, offset, MachineType::Int32());
937  } else {
938    return SmiToWord32(
939        LoadObjectField(object, offset, MachineType::AnyTagged()));
940  }
941}
942
943Node* CodeStubAssembler::LoadAndUntagSmi(Node* base, int index) {
944  if (Is64()) {
945#if V8_TARGET_LITTLE_ENDIAN
946    index += kPointerSize / 2;
947#endif
948    return ChangeInt32ToInt64(
949        Load(MachineType::Int32(), base, IntPtrConstant(index)));
950  } else {
951    return SmiToWord(
952        Load(MachineType::AnyTagged(), base, IntPtrConstant(index)));
953  }
954}
955
956Node* CodeStubAssembler::LoadAndUntagToWord32Root(
957    Heap::RootListIndex root_index) {
958  Node* roots_array_start =
959      ExternalConstant(ExternalReference::roots_array_start(isolate()));
960  int index = root_index * kPointerSize;
961  if (Is64()) {
962#if V8_TARGET_LITTLE_ENDIAN
963    index += kPointerSize / 2;
964#endif
965    return Load(MachineType::Int32(), roots_array_start, IntPtrConstant(index));
966  } else {
967    return SmiToWord32(Load(MachineType::AnyTagged(), roots_array_start,
968                            IntPtrConstant(index)));
969  }
970}
971
972Node* CodeStubAssembler::StoreAndTagSmi(Node* base, int offset, Node* value) {
973  if (Is64()) {
974    int zero_offset = offset + kPointerSize / 2;
975    int payload_offset = offset;
976#if V8_TARGET_LITTLE_ENDIAN
977    std::swap(zero_offset, payload_offset);
978#endif
979    StoreNoWriteBarrier(MachineRepresentation::kWord32, base,
980                        IntPtrConstant(zero_offset), Int32Constant(0));
981    return StoreNoWriteBarrier(MachineRepresentation::kWord32, base,
982                               IntPtrConstant(payload_offset),
983                               TruncateInt64ToInt32(value));
984  } else {
985    return StoreNoWriteBarrier(MachineRepresentation::kTaggedSigned, base,
986                               IntPtrConstant(offset), SmiTag(value));
987  }
988}
989
990Node* CodeStubAssembler::LoadHeapNumberValue(Node* object) {
991  return LoadObjectField(object, HeapNumber::kValueOffset,
992                         MachineType::Float64());
993}
994
995Node* CodeStubAssembler::LoadMap(Node* object) {
996  return LoadObjectField(object, HeapObject::kMapOffset);
997}
998
999Node* CodeStubAssembler::LoadInstanceType(Node* object) {
1000  return LoadMapInstanceType(LoadMap(object));
1001}
1002
1003Node* CodeStubAssembler::HasInstanceType(Node* object,
1004                                         InstanceType instance_type) {
1005  return Word32Equal(LoadInstanceType(object), Int32Constant(instance_type));
1006}
1007
1008Node* CodeStubAssembler::DoesntHaveInstanceType(Node* object,
1009                                                InstanceType instance_type) {
1010  return Word32NotEqual(LoadInstanceType(object), Int32Constant(instance_type));
1011}
1012
1013Node* CodeStubAssembler::LoadProperties(Node* object) {
1014  return LoadObjectField(object, JSObject::kPropertiesOffset);
1015}
1016
1017Node* CodeStubAssembler::LoadElements(Node* object) {
1018  return LoadObjectField(object, JSObject::kElementsOffset);
1019}
1020
1021Node* CodeStubAssembler::LoadJSArrayLength(Node* array) {
1022  CSA_ASSERT(this, IsJSArray(array));
1023  return LoadObjectField(array, JSArray::kLengthOffset);
1024}
1025
1026Node* CodeStubAssembler::LoadFixedArrayBaseLength(Node* array) {
1027  return LoadObjectField(array, FixedArrayBase::kLengthOffset);
1028}
1029
1030Node* CodeStubAssembler::LoadAndUntagFixedArrayBaseLength(Node* array) {
1031  return LoadAndUntagObjectField(array, FixedArrayBase::kLengthOffset);
1032}
1033
1034Node* CodeStubAssembler::LoadMapBitField(Node* map) {
1035  CSA_SLOW_ASSERT(this, IsMap(map));
1036  return LoadObjectField(map, Map::kBitFieldOffset, MachineType::Uint8());
1037}
1038
1039Node* CodeStubAssembler::LoadMapBitField2(Node* map) {
1040  CSA_SLOW_ASSERT(this, IsMap(map));
1041  return LoadObjectField(map, Map::kBitField2Offset, MachineType::Uint8());
1042}
1043
1044Node* CodeStubAssembler::LoadMapBitField3(Node* map) {
1045  CSA_SLOW_ASSERT(this, IsMap(map));
1046  return LoadObjectField(map, Map::kBitField3Offset, MachineType::Uint32());
1047}
1048
1049Node* CodeStubAssembler::LoadMapInstanceType(Node* map) {
1050  return LoadObjectField(map, Map::kInstanceTypeOffset, MachineType::Uint8());
1051}
1052
1053Node* CodeStubAssembler::LoadMapElementsKind(Node* map) {
1054  CSA_SLOW_ASSERT(this, IsMap(map));
1055  Node* bit_field2 = LoadMapBitField2(map);
1056  return DecodeWord32<Map::ElementsKindBits>(bit_field2);
1057}
1058
1059Node* CodeStubAssembler::LoadMapDescriptors(Node* map) {
1060  CSA_SLOW_ASSERT(this, IsMap(map));
1061  return LoadObjectField(map, Map::kDescriptorsOffset);
1062}
1063
1064Node* CodeStubAssembler::LoadMapPrototype(Node* map) {
1065  CSA_SLOW_ASSERT(this, IsMap(map));
1066  return LoadObjectField(map, Map::kPrototypeOffset);
1067}
1068
1069Node* CodeStubAssembler::LoadMapPrototypeInfo(Node* map,
1070                                              Label* if_no_proto_info) {
1071  CSA_ASSERT(this, IsMap(map));
1072  Node* prototype_info =
1073      LoadObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
1074  GotoIf(TaggedIsSmi(prototype_info), if_no_proto_info);
1075  GotoIfNot(WordEqual(LoadMap(prototype_info),
1076                      LoadRoot(Heap::kPrototypeInfoMapRootIndex)),
1077            if_no_proto_info);
1078  return prototype_info;
1079}
1080
1081Node* CodeStubAssembler::LoadMapInstanceSize(Node* map) {
1082  CSA_SLOW_ASSERT(this, IsMap(map));
1083  return ChangeUint32ToWord(
1084      LoadObjectField(map, Map::kInstanceSizeOffset, MachineType::Uint8()));
1085}
1086
1087Node* CodeStubAssembler::LoadMapInobjectProperties(Node* map) {
1088  CSA_SLOW_ASSERT(this, IsMap(map));
1089  // See Map::GetInObjectProperties() for details.
1090  STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
1091  CSA_ASSERT(this,
1092             Int32GreaterThanOrEqual(LoadMapInstanceType(map),
1093                                     Int32Constant(FIRST_JS_OBJECT_TYPE)));
1094  return ChangeUint32ToWord(LoadObjectField(
1095      map, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset,
1096      MachineType::Uint8()));
1097}
1098
1099Node* CodeStubAssembler::LoadMapConstructorFunctionIndex(Node* map) {
1100  CSA_SLOW_ASSERT(this, IsMap(map));
1101  // See Map::GetConstructorFunctionIndex() for details.
1102  STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
1103  CSA_ASSERT(this, Int32LessThanOrEqual(LoadMapInstanceType(map),
1104                                        Int32Constant(LAST_PRIMITIVE_TYPE)));
1105  return ChangeUint32ToWord(LoadObjectField(
1106      map, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset,
1107      MachineType::Uint8()));
1108}
1109
1110Node* CodeStubAssembler::LoadMapConstructor(Node* map) {
1111  CSA_SLOW_ASSERT(this, IsMap(map));
1112  Variable result(this, MachineRepresentation::kTagged,
1113                  LoadObjectField(map, Map::kConstructorOrBackPointerOffset));
1114
1115  Label done(this), loop(this, &result);
1116  Goto(&loop);
1117  Bind(&loop);
1118  {
1119    GotoIf(TaggedIsSmi(result.value()), &done);
1120    Node* is_map_type =
1121        Word32Equal(LoadInstanceType(result.value()), Int32Constant(MAP_TYPE));
1122    GotoIfNot(is_map_type, &done);
1123    result.Bind(
1124        LoadObjectField(result.value(), Map::kConstructorOrBackPointerOffset));
1125    Goto(&loop);
1126  }
1127  Bind(&done);
1128  return result.value();
1129}
1130
1131Node* CodeStubAssembler::LoadSharedFunctionInfoSpecialField(
1132    Node* shared, int offset, ParameterMode mode) {
1133  if (Is64()) {
1134    Node* result = LoadObjectField(shared, offset, MachineType::Int32());
1135    if (mode == SMI_PARAMETERS) {
1136      result = SmiTag(result);
1137    } else {
1138      result = ChangeUint32ToWord(result);
1139    }
1140    return result;
1141  } else {
1142    Node* result = LoadObjectField(shared, offset);
1143    if (mode != SMI_PARAMETERS) {
1144      result = SmiUntag(result);
1145    }
1146    return result;
1147  }
1148}
1149
1150Node* CodeStubAssembler::LoadNameHashField(Node* name) {
1151  CSA_ASSERT(this, IsName(name));
1152  return LoadObjectField(name, Name::kHashFieldOffset, MachineType::Uint32());
1153}
1154
1155Node* CodeStubAssembler::LoadNameHash(Node* name, Label* if_hash_not_computed) {
1156  Node* hash_field = LoadNameHashField(name);
1157  if (if_hash_not_computed != nullptr) {
1158    GotoIf(Word32Equal(
1159               Word32And(hash_field, Int32Constant(Name::kHashNotComputedMask)),
1160               Int32Constant(0)),
1161           if_hash_not_computed);
1162  }
1163  return Word32Shr(hash_field, Int32Constant(Name::kHashShift));
1164}
1165
1166Node* CodeStubAssembler::LoadStringLength(Node* object) {
1167  CSA_ASSERT(this, IsString(object));
1168  return LoadObjectField(object, String::kLengthOffset);
1169}
1170
1171Node* CodeStubAssembler::LoadJSValueValue(Node* object) {
1172  CSA_ASSERT(this, IsJSValue(object));
1173  return LoadObjectField(object, JSValue::kValueOffset);
1174}
1175
1176Node* CodeStubAssembler::LoadWeakCellValueUnchecked(Node* weak_cell) {
1177  // TODO(ishell): fix callers.
1178  return LoadObjectField(weak_cell, WeakCell::kValueOffset);
1179}
1180
1181Node* CodeStubAssembler::LoadWeakCellValue(Node* weak_cell, Label* if_cleared) {
1182  CSA_ASSERT(this, IsWeakCell(weak_cell));
1183  Node* value = LoadWeakCellValueUnchecked(weak_cell);
1184  if (if_cleared != nullptr) {
1185    GotoIf(WordEqual(value, IntPtrConstant(0)), if_cleared);
1186  }
1187  return value;
1188}
1189
1190Node* CodeStubAssembler::LoadFixedArrayElement(Node* object, Node* index_node,
1191                                               int additional_offset,
1192                                               ParameterMode parameter_mode) {
1193  int32_t header_size =
1194      FixedArray::kHeaderSize + additional_offset - kHeapObjectTag;
1195  Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_ELEMENTS,
1196                                        parameter_mode, header_size);
1197  return Load(MachineType::AnyTagged(), object, offset);
1198}
1199
1200Node* CodeStubAssembler::LoadFixedTypedArrayElement(
1201    Node* data_pointer, Node* index_node, ElementsKind elements_kind,
1202    ParameterMode parameter_mode) {
1203  Node* offset =
1204      ElementOffsetFromIndex(index_node, elements_kind, parameter_mode, 0);
1205  MachineType type;
1206  switch (elements_kind) {
1207    case UINT8_ELEMENTS: /* fall through */
1208    case UINT8_CLAMPED_ELEMENTS:
1209      type = MachineType::Uint8();
1210      break;
1211    case INT8_ELEMENTS:
1212      type = MachineType::Int8();
1213      break;
1214    case UINT16_ELEMENTS:
1215      type = MachineType::Uint16();
1216      break;
1217    case INT16_ELEMENTS:
1218      type = MachineType::Int16();
1219      break;
1220    case UINT32_ELEMENTS:
1221      type = MachineType::Uint32();
1222      break;
1223    case INT32_ELEMENTS:
1224      type = MachineType::Int32();
1225      break;
1226    case FLOAT32_ELEMENTS:
1227      type = MachineType::Float32();
1228      break;
1229    case FLOAT64_ELEMENTS:
1230      type = MachineType::Float64();
1231      break;
1232    default:
1233      UNREACHABLE();
1234  }
1235  return Load(type, data_pointer, offset);
1236}
1237
1238Node* CodeStubAssembler::LoadAndUntagToWord32FixedArrayElement(
1239    Node* object, Node* index_node, int additional_offset,
1240    ParameterMode parameter_mode) {
1241  int32_t header_size =
1242      FixedArray::kHeaderSize + additional_offset - kHeapObjectTag;
1243#if V8_TARGET_LITTLE_ENDIAN
1244  if (Is64()) {
1245    header_size += kPointerSize / 2;
1246  }
1247#endif
1248  Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_ELEMENTS,
1249                                        parameter_mode, header_size);
1250  if (Is64()) {
1251    return Load(MachineType::Int32(), object, offset);
1252  } else {
1253    return SmiToWord32(Load(MachineType::AnyTagged(), object, offset));
1254  }
1255}
1256
1257Node* CodeStubAssembler::LoadFixedDoubleArrayElement(
1258    Node* object, Node* index_node, MachineType machine_type,
1259    int additional_offset, ParameterMode parameter_mode, Label* if_hole) {
1260  CSA_ASSERT(this, IsFixedDoubleArray(object));
1261  int32_t header_size =
1262      FixedDoubleArray::kHeaderSize + additional_offset - kHeapObjectTag;
1263  Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_DOUBLE_ELEMENTS,
1264                                        parameter_mode, header_size);
1265  return LoadDoubleWithHoleCheck(object, offset, if_hole, machine_type);
1266}
1267
1268Node* CodeStubAssembler::LoadDoubleWithHoleCheck(Node* base, Node* offset,
1269                                                 Label* if_hole,
1270                                                 MachineType machine_type) {
1271  if (if_hole) {
1272    // TODO(ishell): Compare only the upper part for the hole once the
1273    // compiler is able to fold addition of already complex |offset| with
1274    // |kIeeeDoubleExponentWordOffset| into one addressing mode.
1275    if (Is64()) {
1276      Node* element = Load(MachineType::Uint64(), base, offset);
1277      GotoIf(Word64Equal(element, Int64Constant(kHoleNanInt64)), if_hole);
1278    } else {
1279      Node* element_upper = Load(
1280          MachineType::Uint32(), base,
1281          IntPtrAdd(offset, IntPtrConstant(kIeeeDoubleExponentWordOffset)));
1282      GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)),
1283             if_hole);
1284    }
1285  }
1286  if (machine_type.IsNone()) {
1287    // This means the actual value is not needed.
1288    return nullptr;
1289  }
1290  return Load(machine_type, base, offset);
1291}
1292
1293Node* CodeStubAssembler::LoadContextElement(Node* context, int slot_index) {
1294  int offset = Context::SlotOffset(slot_index);
1295  return Load(MachineType::AnyTagged(), context, IntPtrConstant(offset));
1296}
1297
1298Node* CodeStubAssembler::LoadContextElement(Node* context, Node* slot_index) {
1299  Node* offset =
1300      IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
1301                IntPtrConstant(Context::kHeaderSize - kHeapObjectTag));
1302  return Load(MachineType::AnyTagged(), context, offset);
1303}
1304
1305Node* CodeStubAssembler::StoreContextElement(Node* context, int slot_index,
1306                                             Node* value) {
1307  int offset = Context::SlotOffset(slot_index);
1308  return Store(context, IntPtrConstant(offset), value);
1309}
1310
1311Node* CodeStubAssembler::StoreContextElement(Node* context, Node* slot_index,
1312                                             Node* value) {
1313  Node* offset =
1314      IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
1315                IntPtrConstant(Context::kHeaderSize - kHeapObjectTag));
1316  return Store(context, offset, value);
1317}
1318
1319Node* CodeStubAssembler::StoreContextElementNoWriteBarrier(Node* context,
1320                                                           int slot_index,
1321                                                           Node* value) {
1322  int offset = Context::SlotOffset(slot_index);
1323  return StoreNoWriteBarrier(MachineRepresentation::kTagged, context,
1324                             IntPtrConstant(offset), value);
1325}
1326
1327Node* CodeStubAssembler::LoadNativeContext(Node* context) {
1328  return LoadContextElement(context, Context::NATIVE_CONTEXT_INDEX);
1329}
1330
1331Node* CodeStubAssembler::LoadJSArrayElementsMap(ElementsKind kind,
1332                                                Node* native_context) {
1333  CSA_ASSERT(this, IsNativeContext(native_context));
1334  return LoadContextElement(native_context, Context::ArrayMapIndex(kind));
1335}
1336
1337Node* CodeStubAssembler::StoreHeapNumberValue(Node* object, Node* value) {
1338  return StoreObjectFieldNoWriteBarrier(object, HeapNumber::kValueOffset, value,
1339                                        MachineRepresentation::kFloat64);
1340}
1341
1342Node* CodeStubAssembler::StoreObjectField(
1343    Node* object, int offset, Node* value) {
1344  DCHECK_NE(HeapObject::kMapOffset, offset);  // Use StoreMap instead.
1345  return Store(object, IntPtrConstant(offset - kHeapObjectTag), value);
1346}
1347
1348Node* CodeStubAssembler::StoreObjectField(Node* object, Node* offset,
1349                                          Node* value) {
1350  int const_offset;
1351  if (ToInt32Constant(offset, const_offset)) {
1352    return StoreObjectField(object, const_offset, value);
1353  }
1354  return Store(object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)),
1355               value);
1356}
1357
1358Node* CodeStubAssembler::StoreObjectFieldNoWriteBarrier(
1359    Node* object, int offset, Node* value, MachineRepresentation rep) {
1360  return StoreNoWriteBarrier(rep, object,
1361                             IntPtrConstant(offset - kHeapObjectTag), value);
1362}
1363
1364Node* CodeStubAssembler::StoreObjectFieldNoWriteBarrier(
1365    Node* object, Node* offset, Node* value, MachineRepresentation rep) {
1366  int const_offset;
1367  if (ToInt32Constant(offset, const_offset)) {
1368    return StoreObjectFieldNoWriteBarrier(object, const_offset, value, rep);
1369  }
1370  return StoreNoWriteBarrier(
1371      rep, object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)), value);
1372}
1373
1374Node* CodeStubAssembler::StoreMap(Node* object, Node* map) {
1375  CSA_SLOW_ASSERT(this, IsMap(map));
1376  return StoreWithMapWriteBarrier(
1377      object, IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), map);
1378}
1379
1380Node* CodeStubAssembler::StoreMapNoWriteBarrier(
1381    Node* object, Heap::RootListIndex map_root_index) {
1382  return StoreMapNoWriteBarrier(object, LoadRoot(map_root_index));
1383}
1384
1385Node* CodeStubAssembler::StoreMapNoWriteBarrier(Node* object, Node* map) {
1386  CSA_SLOW_ASSERT(this, IsMap(map));
1387  return StoreNoWriteBarrier(
1388      MachineRepresentation::kTagged, object,
1389      IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), map);
1390}
1391
1392Node* CodeStubAssembler::StoreObjectFieldRoot(Node* object, int offset,
1393                                              Heap::RootListIndex root_index) {
1394  if (Heap::RootIsImmortalImmovable(root_index)) {
1395    return StoreObjectFieldNoWriteBarrier(object, offset, LoadRoot(root_index));
1396  } else {
1397    return StoreObjectField(object, offset, LoadRoot(root_index));
1398  }
1399}
1400
1401Node* CodeStubAssembler::StoreFixedArrayElement(Node* object, Node* index_node,
1402                                                Node* value,
1403                                                WriteBarrierMode barrier_mode,
1404                                                int additional_offset,
1405                                                ParameterMode parameter_mode) {
1406  DCHECK(barrier_mode == SKIP_WRITE_BARRIER ||
1407         barrier_mode == UPDATE_WRITE_BARRIER);
1408  int header_size =
1409      FixedArray::kHeaderSize + additional_offset - kHeapObjectTag;
1410  Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_ELEMENTS,
1411                                        parameter_mode, header_size);
1412  if (barrier_mode == SKIP_WRITE_BARRIER) {
1413    return StoreNoWriteBarrier(MachineRepresentation::kTagged, object, offset,
1414                               value);
1415  } else {
1416    return Store(object, offset, value);
1417  }
1418}
1419
1420Node* CodeStubAssembler::StoreFixedDoubleArrayElement(
1421    Node* object, Node* index_node, Node* value, ParameterMode parameter_mode) {
1422  CSA_ASSERT(this, IsFixedDoubleArray(object));
1423  Node* offset =
1424      ElementOffsetFromIndex(index_node, FAST_DOUBLE_ELEMENTS, parameter_mode,
1425                             FixedArray::kHeaderSize - kHeapObjectTag);
1426  MachineRepresentation rep = MachineRepresentation::kFloat64;
1427  return StoreNoWriteBarrier(rep, object, offset, value);
1428}
1429
1430Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* context,
1431                                            Node* array,
1432                                            CodeStubArguments& args,
1433                                            Variable& arg_index,
1434                                            Label* bailout) {
1435  Comment("BuildAppendJSArray: %s", ElementsKindToString(kind));
1436  Label pre_bailout(this);
1437  Label success(this);
1438  Variable var_tagged_length(this, MachineRepresentation::kTagged);
1439  ParameterMode mode = OptimalParameterMode();
1440  Variable var_length(this, OptimalParameterRepresentation(),
1441                      TaggedToParameter(LoadJSArrayLength(array), mode));
1442  Variable var_elements(this, MachineRepresentation::kTagged,
1443                        LoadElements(array));
1444  Node* capacity =
1445      TaggedToParameter(LoadFixedArrayBaseLength(var_elements.value()), mode);
1446
1447  // Resize the capacity of the fixed array if it doesn't fit.
1448  Label fits(this, &var_elements);
1449  Node* first = arg_index.value();
1450  Node* growth = IntPtrSub(args.GetLength(), first);
1451  Node* new_length =
1452      IntPtrOrSmiAdd(WordToParameter(growth, mode), var_length.value(), mode);
1453  GotoIfNot(IntPtrOrSmiGreaterThan(new_length, capacity, mode), &fits);
1454  Node* new_capacity = CalculateNewElementsCapacity(new_length, mode);
1455  var_elements.Bind(GrowElementsCapacity(array, var_elements.value(), kind,
1456                                         kind, capacity, new_capacity, mode,
1457                                         &pre_bailout));
1458  Goto(&fits);
1459  Bind(&fits);
1460  Node* elements = var_elements.value();
1461
1462  // Push each argument onto the end of the array now that there is enough
1463  // capacity.
1464  CodeStubAssembler::VariableList push_vars({&var_length}, zone());
1465  args.ForEach(
1466      push_vars,
1467      [this, kind, mode, elements, &var_length, &pre_bailout](Node* arg) {
1468        if (IsFastSmiElementsKind(kind)) {
1469          GotoIf(TaggedIsNotSmi(arg), &pre_bailout);
1470        } else if (IsFastDoubleElementsKind(kind)) {
1471          GotoIfNotNumber(arg, &pre_bailout);
1472        }
1473        if (IsFastDoubleElementsKind(kind)) {
1474          Node* double_value = ChangeNumberToFloat64(arg);
1475          StoreFixedDoubleArrayElement(elements, var_length.value(),
1476                                       Float64SilenceNaN(double_value), mode);
1477        } else {
1478          WriteBarrierMode barrier_mode = IsFastSmiElementsKind(kind)
1479                                              ? SKIP_WRITE_BARRIER
1480                                              : UPDATE_WRITE_BARRIER;
1481          StoreFixedArrayElement(elements, var_length.value(), arg,
1482                                 barrier_mode, 0, mode);
1483        }
1484        Increment(var_length, 1, mode);
1485      },
1486      first, nullptr);
1487  {
1488    Node* length = ParameterToTagged(var_length.value(), mode);
1489    var_tagged_length.Bind(length);
1490    StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
1491    Goto(&success);
1492  }
1493
1494  Bind(&pre_bailout);
1495  {
1496    Node* length = ParameterToTagged(var_length.value(), mode);
1497    var_tagged_length.Bind(length);
1498    Node* diff = SmiSub(length, LoadJSArrayLength(array));
1499    StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
1500    arg_index.Bind(IntPtrAdd(arg_index.value(), SmiUntag(diff)));
1501    Goto(bailout);
1502  }
1503
1504  Bind(&success);
1505  return var_tagged_length.value();
1506}
1507
1508Node* CodeStubAssembler::AllocateHeapNumber(MutableMode mode) {
1509  Node* result = Allocate(HeapNumber::kSize, kNone);
1510  Heap::RootListIndex heap_map_index =
1511      mode == IMMUTABLE ? Heap::kHeapNumberMapRootIndex
1512                        : Heap::kMutableHeapNumberMapRootIndex;
1513  StoreMapNoWriteBarrier(result, heap_map_index);
1514  return result;
1515}
1516
1517Node* CodeStubAssembler::AllocateHeapNumberWithValue(Node* value,
1518                                                     MutableMode mode) {
1519  Node* result = AllocateHeapNumber(mode);
1520  StoreHeapNumberValue(result, value);
1521  return result;
1522}
1523
1524Node* CodeStubAssembler::AllocateSeqOneByteString(int length,
1525                                                  AllocationFlags flags) {
1526  Comment("AllocateSeqOneByteString");
1527  if (length == 0) {
1528    return LoadRoot(Heap::kempty_stringRootIndex);
1529  }
1530  Node* result = Allocate(SeqOneByteString::SizeFor(length), flags);
1531  DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex));
1532  StoreMapNoWriteBarrier(result, Heap::kOneByteStringMapRootIndex);
1533  StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset,
1534                                 SmiConstant(Smi::FromInt(length)));
1535  // Initialize both used and unused parts of hash field slot at once.
1536  StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldSlot,
1537                                 IntPtrConstant(String::kEmptyHashField),
1538                                 MachineType::PointerRepresentation());
1539  return result;
1540}
1541
1542Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length,
1543                                                  ParameterMode mode,
1544                                                  AllocationFlags flags) {
1545  Comment("AllocateSeqOneByteString");
1546  Variable var_result(this, MachineRepresentation::kTagged);
1547
1548  // Compute the SeqOneByteString size and check if it fits into new space.
1549  Label if_lengthiszero(this), if_sizeissmall(this),
1550      if_notsizeissmall(this, Label::kDeferred), if_join(this);
1551  GotoIf(WordEqual(length, IntPtrOrSmiConstant(0, mode)), &if_lengthiszero);
1552
1553  Node* raw_size = GetArrayAllocationSize(
1554      length, UINT8_ELEMENTS, mode,
1555      SeqOneByteString::kHeaderSize + kObjectAlignmentMask);
1556  Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask));
1557  Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)),
1558         &if_sizeissmall, &if_notsizeissmall);
1559
1560  Bind(&if_sizeissmall);
1561  {
1562    // Just allocate the SeqOneByteString in new space.
1563    Node* result = Allocate(size, flags);
1564    DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex));
1565    StoreMapNoWriteBarrier(result, Heap::kOneByteStringMapRootIndex);
1566    StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset,
1567                                   ParameterToTagged(length, mode));
1568    // Initialize both used and unused parts of hash field slot at once.
1569    StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldSlot,
1570                                   IntPtrConstant(String::kEmptyHashField),
1571                                   MachineType::PointerRepresentation());
1572    var_result.Bind(result);
1573    Goto(&if_join);
1574  }
1575
1576  Bind(&if_notsizeissmall);
1577  {
1578    // We might need to allocate in large object space, go to the runtime.
1579    Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context,
1580                               ParameterToTagged(length, mode));
1581    var_result.Bind(result);
1582    Goto(&if_join);
1583  }
1584
1585  Bind(&if_lengthiszero);
1586  {
1587    var_result.Bind(LoadRoot(Heap::kempty_stringRootIndex));
1588    Goto(&if_join);
1589  }
1590
1591  Bind(&if_join);
1592  return var_result.value();
1593}
1594
1595Node* CodeStubAssembler::AllocateSeqTwoByteString(int length,
1596                                                  AllocationFlags flags) {
1597  Comment("AllocateSeqTwoByteString");
1598  if (length == 0) {
1599    return LoadRoot(Heap::kempty_stringRootIndex);
1600  }
1601  Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags);
1602  DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex));
1603  StoreMapNoWriteBarrier(result, Heap::kStringMapRootIndex);
1604  StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset,
1605                                 SmiConstant(Smi::FromInt(length)));
1606  // Initialize both used and unused parts of hash field slot at once.
1607  StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldSlot,
1608                                 IntPtrConstant(String::kEmptyHashField),
1609                                 MachineType::PointerRepresentation());
1610  return result;
1611}
1612
1613Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length,
1614                                                  ParameterMode mode,
1615                                                  AllocationFlags flags) {
1616  Comment("AllocateSeqTwoByteString");
1617  Variable var_result(this, MachineRepresentation::kTagged);
1618
1619  // Compute the SeqTwoByteString size and check if it fits into new space.
1620  Label if_lengthiszero(this), if_sizeissmall(this),
1621      if_notsizeissmall(this, Label::kDeferred), if_join(this);
1622  GotoIf(WordEqual(length, IntPtrOrSmiConstant(0, mode)), &if_lengthiszero);
1623
1624  Node* raw_size = GetArrayAllocationSize(
1625      length, UINT16_ELEMENTS, mode,
1626      SeqOneByteString::kHeaderSize + kObjectAlignmentMask);
1627  Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask));
1628  Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)),
1629         &if_sizeissmall, &if_notsizeissmall);
1630
1631  Bind(&if_sizeissmall);
1632  {
1633    // Just allocate the SeqTwoByteString in new space.
1634    Node* result = Allocate(size, flags);
1635    DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex));
1636    StoreMapNoWriteBarrier(result, Heap::kStringMapRootIndex);
1637    StoreObjectFieldNoWriteBarrier(
1638        result, SeqTwoByteString::kLengthOffset,
1639        mode == SMI_PARAMETERS ? length : SmiFromWord(length));
1640    // Initialize both used and unused parts of hash field slot at once.
1641    StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldSlot,
1642                                   IntPtrConstant(String::kEmptyHashField),
1643                                   MachineType::PointerRepresentation());
1644    var_result.Bind(result);
1645    Goto(&if_join);
1646  }
1647
1648  Bind(&if_notsizeissmall);
1649  {
1650    // We might need to allocate in large object space, go to the runtime.
1651    Node* result =
1652        CallRuntime(Runtime::kAllocateSeqTwoByteString, context,
1653                    mode == SMI_PARAMETERS ? length : SmiFromWord(length));
1654    var_result.Bind(result);
1655    Goto(&if_join);
1656  }
1657
1658  Bind(&if_lengthiszero);
1659  {
1660    var_result.Bind(LoadRoot(Heap::kempty_stringRootIndex));
1661    Goto(&if_join);
1662  }
1663
1664  Bind(&if_join);
1665  return var_result.value();
1666}
1667
1668Node* CodeStubAssembler::AllocateSlicedString(
1669    Heap::RootListIndex map_root_index, Node* length, Node* parent,
1670    Node* offset) {
1671  CSA_ASSERT(this, TaggedIsSmi(length));
1672  Node* result = Allocate(SlicedString::kSize);
1673  DCHECK(Heap::RootIsImmortalImmovable(map_root_index));
1674  StoreMapNoWriteBarrier(result, map_root_index);
1675  StoreObjectFieldNoWriteBarrier(result, SlicedString::kLengthOffset, length,
1676                                 MachineRepresentation::kTagged);
1677  // Initialize both used and unused parts of hash field slot at once.
1678  StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldSlot,
1679                                 IntPtrConstant(String::kEmptyHashField),
1680                                 MachineType::PointerRepresentation());
1681  StoreObjectFieldNoWriteBarrier(result, SlicedString::kParentOffset, parent,
1682                                 MachineRepresentation::kTagged);
1683  StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset,
1684                                 MachineRepresentation::kTagged);
1685  return result;
1686}
1687
1688Node* CodeStubAssembler::AllocateSlicedOneByteString(Node* length, Node* parent,
1689                                                     Node* offset) {
1690  return AllocateSlicedString(Heap::kSlicedOneByteStringMapRootIndex, length,
1691                              parent, offset);
1692}
1693
1694Node* CodeStubAssembler::AllocateSlicedTwoByteString(Node* length, Node* parent,
1695                                                     Node* offset) {
1696  return AllocateSlicedString(Heap::kSlicedStringMapRootIndex, length, parent,
1697                              offset);
1698}
1699
1700Node* CodeStubAssembler::AllocateConsString(Heap::RootListIndex map_root_index,
1701                                            Node* length, Node* first,
1702                                            Node* second,
1703                                            AllocationFlags flags) {
1704  CSA_ASSERT(this, TaggedIsSmi(length));
1705  Node* result = Allocate(ConsString::kSize, flags);
1706  DCHECK(Heap::RootIsImmortalImmovable(map_root_index));
1707  StoreMapNoWriteBarrier(result, map_root_index);
1708  StoreObjectFieldNoWriteBarrier(result, ConsString::kLengthOffset, length,
1709                                 MachineRepresentation::kTagged);
1710  // Initialize both used and unused parts of hash field slot at once.
1711  StoreObjectFieldNoWriteBarrier(result, ConsString::kHashFieldSlot,
1712                                 IntPtrConstant(String::kEmptyHashField),
1713                                 MachineType::PointerRepresentation());
1714  bool const new_space = !(flags & kPretenured);
1715  if (new_space) {
1716    StoreObjectFieldNoWriteBarrier(result, ConsString::kFirstOffset, first,
1717                                   MachineRepresentation::kTagged);
1718    StoreObjectFieldNoWriteBarrier(result, ConsString::kSecondOffset, second,
1719                                   MachineRepresentation::kTagged);
1720  } else {
1721    StoreObjectField(result, ConsString::kFirstOffset, first);
1722    StoreObjectField(result, ConsString::kSecondOffset, second);
1723  }
1724  return result;
1725}
1726
1727Node* CodeStubAssembler::AllocateOneByteConsString(Node* length, Node* first,
1728                                                   Node* second,
1729                                                   AllocationFlags flags) {
1730  return AllocateConsString(Heap::kConsOneByteStringMapRootIndex, length, first,
1731                            second, flags);
1732}
1733
1734Node* CodeStubAssembler::AllocateTwoByteConsString(Node* length, Node* first,
1735                                                   Node* second,
1736                                                   AllocationFlags flags) {
1737  return AllocateConsString(Heap::kConsStringMapRootIndex, length, first,
1738                            second, flags);
1739}
1740
1741Node* CodeStubAssembler::NewConsString(Node* context, Node* length, Node* left,
1742                                       Node* right, AllocationFlags flags) {
1743  CSA_ASSERT(this, TaggedIsSmi(length));
1744  // Added string can be a cons string.
1745  Comment("Allocating ConsString");
1746  Node* left_instance_type = LoadInstanceType(left);
1747  Node* right_instance_type = LoadInstanceType(right);
1748
1749  // Compute intersection and difference of instance types.
1750  Node* anded_instance_types =
1751      Word32And(left_instance_type, right_instance_type);
1752  Node* xored_instance_types =
1753      Word32Xor(left_instance_type, right_instance_type);
1754
1755  // We create a one-byte cons string if
1756  // 1. both strings are one-byte, or
1757  // 2. at least one of the strings is two-byte, but happens to contain only
1758  //    one-byte characters.
1759  // To do this, we check
1760  // 1. if both strings are one-byte, or if the one-byte data hint is set in
1761  //    both strings, or
1762  // 2. if one of the strings has the one-byte data hint set and the other
1763  //    string is one-byte.
1764  STATIC_ASSERT(kOneByteStringTag != 0);
1765  STATIC_ASSERT(kOneByteDataHintTag != 0);
1766  Label one_byte_map(this);
1767  Label two_byte_map(this);
1768  Variable result(this, MachineRepresentation::kTagged);
1769  Label done(this, &result);
1770  GotoIf(Word32NotEqual(Word32And(anded_instance_types,
1771                                  Int32Constant(kStringEncodingMask |
1772                                                kOneByteDataHintTag)),
1773                        Int32Constant(0)),
1774         &one_byte_map);
1775  Branch(Word32NotEqual(Word32And(xored_instance_types,
1776                                  Int32Constant(kStringEncodingMask |
1777                                                kOneByteDataHintMask)),
1778                        Int32Constant(kOneByteStringTag | kOneByteDataHintTag)),
1779         &two_byte_map, &one_byte_map);
1780
1781  Bind(&one_byte_map);
1782  Comment("One-byte ConsString");
1783  result.Bind(AllocateOneByteConsString(length, left, right, flags));
1784  Goto(&done);
1785
1786  Bind(&two_byte_map);
1787  Comment("Two-byte ConsString");
1788  result.Bind(AllocateTwoByteConsString(length, left, right, flags));
1789  Goto(&done);
1790
1791  Bind(&done);
1792
1793  return result.value();
1794}
1795
1796Node* CodeStubAssembler::AllocateRegExpResult(Node* context, Node* length,
1797                                              Node* index, Node* input) {
1798  Node* const max_length =
1799      SmiConstant(Smi::FromInt(JSArray::kInitialMaxFastElementArray));
1800  CSA_ASSERT(this, SmiLessThanOrEqual(length, max_length));
1801  USE(max_length);
1802
1803  // Allocate the JSRegExpResult.
1804  // TODO(jgruber): Fold JSArray and FixedArray allocations, then remove
1805  // unneeded store of elements.
1806  Node* const result = Allocate(JSRegExpResult::kSize);
1807
1808  // TODO(jgruber): Store map as Heap constant?
1809  Node* const native_context = LoadNativeContext(context);
1810  Node* const map =
1811      LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX);
1812  StoreMapNoWriteBarrier(result, map);
1813
1814  // Initialize the header before allocating the elements.
1815  Node* const empty_array = EmptyFixedArrayConstant();
1816  DCHECK(Heap::RootIsImmortalImmovable(Heap::kEmptyFixedArrayRootIndex));
1817  StoreObjectFieldNoWriteBarrier(result, JSArray::kPropertiesOffset,
1818                                 empty_array);
1819  StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset, empty_array);
1820  StoreObjectFieldNoWriteBarrier(result, JSArray::kLengthOffset, length);
1821
1822  StoreObjectFieldNoWriteBarrier(result, JSRegExpResult::kIndexOffset, index);
1823  StoreObjectField(result, JSRegExpResult::kInputOffset, input);
1824
1825  Node* const zero = IntPtrConstant(0);
1826  Node* const length_intptr = SmiUntag(length);
1827  const ElementsKind elements_kind = FAST_ELEMENTS;
1828
1829  Node* const elements = AllocateFixedArray(elements_kind, length_intptr);
1830  StoreObjectField(result, JSArray::kElementsOffset, elements);
1831
1832  // Fill in the elements with undefined.
1833  FillFixedArrayWithValue(elements_kind, elements, zero, length_intptr,
1834                          Heap::kUndefinedValueRootIndex);
1835
1836  return result;
1837}
1838
1839Node* CodeStubAssembler::AllocateNameDictionary(int at_least_space_for) {
1840  return AllocateNameDictionary(IntPtrConstant(at_least_space_for));
1841}
1842
1843Node* CodeStubAssembler::AllocateNameDictionary(Node* at_least_space_for) {
1844  CSA_ASSERT(this, UintPtrLessThanOrEqual(
1845                       at_least_space_for,
1846                       IntPtrConstant(NameDictionary::kMaxCapacity)));
1847
1848  Node* capacity = HashTableComputeCapacity(at_least_space_for);
1849  CSA_ASSERT(this, WordIsPowerOfTwo(capacity));
1850
1851  Node* length = EntryToIndex<NameDictionary>(capacity);
1852  Node* store_size =
1853      IntPtrAdd(WordShl(length, IntPtrConstant(kPointerSizeLog2)),
1854                IntPtrConstant(NameDictionary::kHeaderSize));
1855
1856  Node* result = Allocate(store_size);
1857  Comment("Initialize NameDictionary");
1858  // Initialize FixedArray fields.
1859  DCHECK(Heap::RootIsImmortalImmovable(Heap::kHashTableMapRootIndex));
1860  StoreMapNoWriteBarrier(result, Heap::kHashTableMapRootIndex);
1861  StoreObjectFieldNoWriteBarrier(result, FixedArray::kLengthOffset,
1862                                 SmiFromWord(length));
1863  // Initialized HashTable fields.
1864  Node* zero = SmiConstant(0);
1865  StoreFixedArrayElement(result, NameDictionary::kNumberOfElementsIndex, zero,
1866                         SKIP_WRITE_BARRIER);
1867  StoreFixedArrayElement(result, NameDictionary::kNumberOfDeletedElementsIndex,
1868                         zero, SKIP_WRITE_BARRIER);
1869  StoreFixedArrayElement(result, NameDictionary::kCapacityIndex,
1870                         SmiTag(capacity), SKIP_WRITE_BARRIER);
1871  // Initialize Dictionary fields.
1872  Node* filler = LoadRoot(Heap::kUndefinedValueRootIndex);
1873  StoreFixedArrayElement(result, NameDictionary::kMaxNumberKeyIndex, filler,
1874                         SKIP_WRITE_BARRIER);
1875  StoreFixedArrayElement(result, NameDictionary::kNextEnumerationIndexIndex,
1876                         SmiConstant(PropertyDetails::kInitialIndex),
1877                         SKIP_WRITE_BARRIER);
1878
1879  // Initialize NameDictionary elements.
1880  Node* result_word = BitcastTaggedToWord(result);
1881  Node* start_address = IntPtrAdd(
1882      result_word, IntPtrConstant(NameDictionary::OffsetOfElementAt(
1883                                      NameDictionary::kElementsStartIndex) -
1884                                  kHeapObjectTag));
1885  Node* end_address = IntPtrAdd(
1886      result_word, IntPtrSub(store_size, IntPtrConstant(kHeapObjectTag)));
1887  StoreFieldsNoWriteBarrier(start_address, end_address, filler);
1888  return result;
1889}
1890
1891Node* CodeStubAssembler::AllocateJSObjectFromMap(Node* map, Node* properties,
1892                                                 Node* elements,
1893                                                 AllocationFlags flags) {
1894  CSA_ASSERT(this, IsMap(map));
1895  Node* size =
1896      IntPtrMul(LoadMapInstanceSize(map), IntPtrConstant(kPointerSize));
1897  CSA_ASSERT(this, IsRegularHeapObjectSize(size));
1898  Node* object = Allocate(size, flags);
1899  StoreMapNoWriteBarrier(object, map);
1900  InitializeJSObjectFromMap(object, map, size, properties, elements);
1901  return object;
1902}
1903
1904void CodeStubAssembler::InitializeJSObjectFromMap(Node* object, Node* map,
1905                                                  Node* size, Node* properties,
1906                                                  Node* elements) {
1907  // This helper assumes that the object is in new-space, as guarded by the
1908  // check in AllocatedJSObjectFromMap.
1909  if (properties == nullptr) {
1910    CSA_ASSERT(this, Word32BinaryNot(IsDictionaryMap((map))));
1911    StoreObjectFieldRoot(object, JSObject::kPropertiesOffset,
1912                         Heap::kEmptyFixedArrayRootIndex);
1913  } else {
1914    StoreObjectFieldNoWriteBarrier(object, JSObject::kPropertiesOffset,
1915                                   properties);
1916  }
1917  if (elements == nullptr) {
1918    StoreObjectFieldRoot(object, JSObject::kElementsOffset,
1919                         Heap::kEmptyFixedArrayRootIndex);
1920  } else {
1921    StoreObjectFieldNoWriteBarrier(object, JSObject::kElementsOffset, elements);
1922  }
1923  InitializeJSObjectBody(object, map, size, JSObject::kHeaderSize);
1924}
1925
1926void CodeStubAssembler::InitializeJSObjectBody(Node* object, Node* map,
1927                                               Node* size, int start_offset) {
1928  // TODO(cbruni): activate in-object slack tracking machinery.
1929  Comment("InitializeJSObjectBody");
1930  Node* filler = LoadRoot(Heap::kUndefinedValueRootIndex);
1931  // Calculate the untagged field addresses.
1932  object = BitcastTaggedToWord(object);
1933  Node* start_address =
1934      IntPtrAdd(object, IntPtrConstant(start_offset - kHeapObjectTag));
1935  Node* end_address =
1936      IntPtrSub(IntPtrAdd(object, size), IntPtrConstant(kHeapObjectTag));
1937  StoreFieldsNoWriteBarrier(start_address, end_address, filler);
1938}
1939
1940void CodeStubAssembler::StoreFieldsNoWriteBarrier(Node* start_address,
1941                                                  Node* end_address,
1942                                                  Node* value) {
1943  Comment("StoreFieldsNoWriteBarrier");
1944  CSA_ASSERT(this, WordIsWordAligned(start_address));
1945  CSA_ASSERT(this, WordIsWordAligned(end_address));
1946  BuildFastLoop(start_address, end_address,
1947                [this, value](Node* current) {
1948                  StoreNoWriteBarrier(MachineRepresentation::kTagged, current,
1949                                      value);
1950                },
1951                kPointerSize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
1952}
1953
1954Node* CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements(
1955    ElementsKind kind, Node* array_map, Node* length, Node* allocation_site) {
1956  Comment("begin allocation of JSArray without elements");
1957  int base_size = JSArray::kSize;
1958  if (allocation_site != nullptr) {
1959    base_size += AllocationMemento::kSize;
1960  }
1961
1962  Node* size = IntPtrConstant(base_size);
1963  Node* array = AllocateUninitializedJSArray(kind, array_map, length,
1964                                             allocation_site, size);
1965  return array;
1966}
1967
1968std::pair<Node*, Node*>
1969CodeStubAssembler::AllocateUninitializedJSArrayWithElements(
1970    ElementsKind kind, Node* array_map, Node* length, Node* allocation_site,
1971    Node* capacity, ParameterMode capacity_mode) {
1972  Comment("begin allocation of JSArray with elements");
1973  int base_size = JSArray::kSize;
1974
1975  if (allocation_site != nullptr) {
1976    base_size += AllocationMemento::kSize;
1977  }
1978
1979  int elements_offset = base_size;
1980
1981  // Compute space for elements
1982  base_size += FixedArray::kHeaderSize;
1983  Node* size = ElementOffsetFromIndex(capacity, kind, capacity_mode, base_size);
1984
1985  Node* array = AllocateUninitializedJSArray(kind, array_map, length,
1986                                             allocation_site, size);
1987
1988  Node* elements = InnerAllocate(array, elements_offset);
1989  StoreObjectFieldNoWriteBarrier(array, JSObject::kElementsOffset, elements);
1990
1991  return {array, elements};
1992}
1993
1994Node* CodeStubAssembler::AllocateUninitializedJSArray(ElementsKind kind,
1995                                                      Node* array_map,
1996                                                      Node* length,
1997                                                      Node* allocation_site,
1998                                                      Node* size_in_bytes) {
1999  Node* array = Allocate(size_in_bytes);
2000
2001  Comment("write JSArray headers");
2002  StoreMapNoWriteBarrier(array, array_map);
2003
2004  CSA_ASSERT(this, TaggedIsSmi(length));
2005  StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
2006
2007  StoreObjectFieldRoot(array, JSArray::kPropertiesOffset,
2008                       Heap::kEmptyFixedArrayRootIndex);
2009
2010  if (allocation_site != nullptr) {
2011    InitializeAllocationMemento(array, JSArray::kSize, allocation_site);
2012  }
2013  return array;
2014}
2015
2016Node* CodeStubAssembler::AllocateJSArray(ElementsKind kind, Node* array_map,
2017                                         Node* capacity, Node* length,
2018                                         Node* allocation_site,
2019                                         ParameterMode capacity_mode) {
2020  Node *array = nullptr, *elements = nullptr;
2021  if (IsIntPtrOrSmiConstantZero(capacity)) {
2022    // Array is empty. Use the shared empty fixed array instead of allocating a
2023    // new one.
2024    array = AllocateUninitializedJSArrayWithoutElements(kind, array_map, length,
2025                                                        nullptr);
2026    StoreObjectFieldRoot(array, JSArray::kElementsOffset,
2027                         Heap::kEmptyFixedArrayRootIndex);
2028  } else {
2029    // Allocate both array and elements object, and initialize the JSArray.
2030    std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
2031        kind, array_map, length, allocation_site, capacity, capacity_mode);
2032    // Setup elements object.
2033    Heap::RootListIndex elements_map_index =
2034        IsFastDoubleElementsKind(kind) ? Heap::kFixedDoubleArrayMapRootIndex
2035                                       : Heap::kFixedArrayMapRootIndex;
2036    DCHECK(Heap::RootIsImmortalImmovable(elements_map_index));
2037    StoreMapNoWriteBarrier(elements, elements_map_index);
2038    StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset,
2039                                   ParameterToTagged(capacity, capacity_mode));
2040    // Fill in the elements with holes.
2041    FillFixedArrayWithValue(kind, elements,
2042                            IntPtrOrSmiConstant(0, capacity_mode), capacity,
2043                            Heap::kTheHoleValueRootIndex, capacity_mode);
2044  }
2045
2046  return array;
2047}
2048
2049Node* CodeStubAssembler::AllocateFixedArray(ElementsKind kind,
2050                                            Node* capacity_node,
2051                                            ParameterMode mode,
2052                                            AllocationFlags flags) {
2053  CSA_ASSERT(this, IntPtrOrSmiGreaterThan(capacity_node,
2054                                          IntPtrOrSmiConstant(0, mode), mode));
2055  Node* total_size = GetFixedArrayAllocationSize(capacity_node, kind, mode);
2056
2057  // Allocate both array and elements object, and initialize the JSArray.
2058  Node* array = Allocate(total_size, flags);
2059  Heap::RootListIndex map_index = IsFastDoubleElementsKind(kind)
2060                                      ? Heap::kFixedDoubleArrayMapRootIndex
2061                                      : Heap::kFixedArrayMapRootIndex;
2062  DCHECK(Heap::RootIsImmortalImmovable(map_index));
2063  StoreMapNoWriteBarrier(array, map_index);
2064  StoreObjectFieldNoWriteBarrier(array, FixedArray::kLengthOffset,
2065                                 ParameterToTagged(capacity_node, mode));
2066  return array;
2067}
2068
2069void CodeStubAssembler::FillFixedArrayWithValue(
2070    ElementsKind kind, Node* array, Node* from_node, Node* to_node,
2071    Heap::RootListIndex value_root_index, ParameterMode mode) {
2072  bool is_double = IsFastDoubleElementsKind(kind);
2073  DCHECK(value_root_index == Heap::kTheHoleValueRootIndex ||
2074         value_root_index == Heap::kUndefinedValueRootIndex);
2075  DCHECK_IMPLIES(is_double, value_root_index == Heap::kTheHoleValueRootIndex);
2076  STATIC_ASSERT(kHoleNanLower32 == kHoleNanUpper32);
2077  Node* double_hole =
2078      Is64() ? Int64Constant(kHoleNanInt64) : Int32Constant(kHoleNanLower32);
2079  Node* value = LoadRoot(value_root_index);
2080
2081  BuildFastFixedArrayForEach(
2082      array, kind, from_node, to_node,
2083      [this, value, is_double, double_hole](Node* array, Node* offset) {
2084        if (is_double) {
2085          // Don't use doubles to store the hole double, since manipulating the
2086          // signaling NaN used for the hole in C++, e.g. with bit_cast, will
2087          // change its value on ia32 (the x87 stack is used to return values
2088          // and stores to the stack silently clear the signalling bit).
2089          //
2090          // TODO(danno): When we have a Float32/Float64 wrapper class that
2091          // preserves double bits during manipulation, remove this code/change
2092          // this to an indexed Float64 store.
2093          if (Is64()) {
2094            StoreNoWriteBarrier(MachineRepresentation::kWord64, array, offset,
2095                                double_hole);
2096          } else {
2097            StoreNoWriteBarrier(MachineRepresentation::kWord32, array, offset,
2098                                double_hole);
2099            StoreNoWriteBarrier(MachineRepresentation::kWord32, array,
2100                                IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
2101                                double_hole);
2102          }
2103        } else {
2104          StoreNoWriteBarrier(MachineRepresentation::kTagged, array, offset,
2105                              value);
2106        }
2107      },
2108      mode);
2109}
2110
2111void CodeStubAssembler::CopyFixedArrayElements(
2112    ElementsKind from_kind, Node* from_array, ElementsKind to_kind,
2113    Node* to_array, Node* element_count, Node* capacity,
2114    WriteBarrierMode barrier_mode, ParameterMode mode) {
2115  STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
2116  const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag;
2117  Comment("[ CopyFixedArrayElements");
2118
2119  // Typed array elements are not supported.
2120  DCHECK(!IsFixedTypedArrayElementsKind(from_kind));
2121  DCHECK(!IsFixedTypedArrayElementsKind(to_kind));
2122
2123  Label done(this);
2124  bool from_double_elements = IsFastDoubleElementsKind(from_kind);
2125  bool to_double_elements = IsFastDoubleElementsKind(to_kind);
2126  bool element_size_matches =
2127      Is64() ||
2128      IsFastDoubleElementsKind(from_kind) == IsFastDoubleElementsKind(to_kind);
2129  bool doubles_to_objects_conversion =
2130      IsFastDoubleElementsKind(from_kind) && IsFastObjectElementsKind(to_kind);
2131  bool needs_write_barrier =
2132      doubles_to_objects_conversion || (barrier_mode == UPDATE_WRITE_BARRIER &&
2133                                        IsFastObjectElementsKind(to_kind));
2134  Node* double_hole =
2135      Is64() ? Int64Constant(kHoleNanInt64) : Int32Constant(kHoleNanLower32);
2136
2137  if (doubles_to_objects_conversion) {
2138    // If the copy might trigger a GC, make sure that the FixedArray is
2139    // pre-initialized with holes to make sure that it's always in a
2140    // consistent state.
2141    FillFixedArrayWithValue(to_kind, to_array, IntPtrOrSmiConstant(0, mode),
2142                            capacity, Heap::kTheHoleValueRootIndex, mode);
2143  } else if (element_count != capacity) {
2144    FillFixedArrayWithValue(to_kind, to_array, element_count, capacity,
2145                            Heap::kTheHoleValueRootIndex, mode);
2146  }
2147
2148  Node* limit_offset = ElementOffsetFromIndex(
2149      IntPtrOrSmiConstant(0, mode), from_kind, mode, first_element_offset);
2150  Variable var_from_offset(this, MachineType::PointerRepresentation(),
2151                           ElementOffsetFromIndex(element_count, from_kind,
2152                                                  mode, first_element_offset));
2153  // This second variable is used only when the element sizes of source and
2154  // destination arrays do not match.
2155  Variable var_to_offset(this, MachineType::PointerRepresentation());
2156  if (element_size_matches) {
2157    var_to_offset.Bind(var_from_offset.value());
2158  } else {
2159    var_to_offset.Bind(ElementOffsetFromIndex(element_count, to_kind, mode,
2160                                              first_element_offset));
2161  }
2162
2163  Variable* vars[] = {&var_from_offset, &var_to_offset};
2164  Label decrement(this, 2, vars);
2165
2166  Branch(WordEqual(var_from_offset.value(), limit_offset), &done, &decrement);
2167
2168  Bind(&decrement);
2169  {
2170    Node* from_offset = IntPtrSub(
2171        var_from_offset.value(),
2172        IntPtrConstant(from_double_elements ? kDoubleSize : kPointerSize));
2173    var_from_offset.Bind(from_offset);
2174
2175    Node* to_offset;
2176    if (element_size_matches) {
2177      to_offset = from_offset;
2178    } else {
2179      to_offset = IntPtrSub(
2180          var_to_offset.value(),
2181          IntPtrConstant(to_double_elements ? kDoubleSize : kPointerSize));
2182      var_to_offset.Bind(to_offset);
2183    }
2184
2185    Label next_iter(this), store_double_hole(this);
2186    Label* if_hole;
2187    if (doubles_to_objects_conversion) {
2188      // The target elements array is already preinitialized with holes, so we
2189      // can just proceed with the next iteration.
2190      if_hole = &next_iter;
2191    } else if (IsFastDoubleElementsKind(to_kind)) {
2192      if_hole = &store_double_hole;
2193    } else {
2194      // In all the other cases don't check for holes and copy the data as is.
2195      if_hole = nullptr;
2196    }
2197
2198    Node* value = LoadElementAndPrepareForStore(
2199        from_array, var_from_offset.value(), from_kind, to_kind, if_hole);
2200
2201    if (needs_write_barrier) {
2202      Store(to_array, to_offset, value);
2203    } else if (to_double_elements) {
2204      StoreNoWriteBarrier(MachineRepresentation::kFloat64, to_array, to_offset,
2205                          value);
2206    } else {
2207      StoreNoWriteBarrier(MachineRepresentation::kTagged, to_array, to_offset,
2208                          value);
2209    }
2210    Goto(&next_iter);
2211
2212    if (if_hole == &store_double_hole) {
2213      Bind(&store_double_hole);
2214      // Don't use doubles to store the hole double, since manipulating the
2215      // signaling NaN used for the hole in C++, e.g. with bit_cast, will
2216      // change its value on ia32 (the x87 stack is used to return values
2217      // and stores to the stack silently clear the signalling bit).
2218      //
2219      // TODO(danno): When we have a Float32/Float64 wrapper class that
2220      // preserves double bits during manipulation, remove this code/change
2221      // this to an indexed Float64 store.
2222      if (Is64()) {
2223        StoreNoWriteBarrier(MachineRepresentation::kWord64, to_array, to_offset,
2224                            double_hole);
2225      } else {
2226        StoreNoWriteBarrier(MachineRepresentation::kWord32, to_array, to_offset,
2227                            double_hole);
2228        StoreNoWriteBarrier(MachineRepresentation::kWord32, to_array,
2229                            IntPtrAdd(to_offset, IntPtrConstant(kPointerSize)),
2230                            double_hole);
2231      }
2232      Goto(&next_iter);
2233    }
2234
2235    Bind(&next_iter);
2236    Node* compare = WordNotEqual(from_offset, limit_offset);
2237    Branch(compare, &decrement, &done);
2238  }
2239
2240  Bind(&done);
2241  IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1);
2242  Comment("] CopyFixedArrayElements");
2243}
2244
2245void CodeStubAssembler::CopyStringCharacters(Node* from_string, Node* to_string,
2246                                             Node* from_index, Node* to_index,
2247                                             Node* character_count,
2248                                             String::Encoding from_encoding,
2249                                             String::Encoding to_encoding,
2250                                             ParameterMode mode) {
2251  bool from_one_byte = from_encoding == String::ONE_BYTE_ENCODING;
2252  bool to_one_byte = to_encoding == String::ONE_BYTE_ENCODING;
2253  DCHECK_IMPLIES(to_one_byte, from_one_byte);
2254  Comment("CopyStringCharacters %s -> %s",
2255          from_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING",
2256          to_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING");
2257
2258  ElementsKind from_kind = from_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS;
2259  ElementsKind to_kind = to_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS;
2260  STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
2261  int header_size = SeqOneByteString::kHeaderSize - kHeapObjectTag;
2262  Node* from_offset =
2263      ElementOffsetFromIndex(from_index, from_kind, mode, header_size);
2264  Node* to_offset =
2265      ElementOffsetFromIndex(to_index, to_kind, mode, header_size);
2266  Node* byte_count = ElementOffsetFromIndex(character_count, from_kind, mode);
2267  Node* limit_offset = IntPtrAdd(from_offset, byte_count);
2268
2269  // Prepare the fast loop
2270  MachineType type =
2271      from_one_byte ? MachineType::Uint8() : MachineType::Uint16();
2272  MachineRepresentation rep = to_one_byte ? MachineRepresentation::kWord8
2273                                          : MachineRepresentation::kWord16;
2274  int from_increment = 1 << ElementsKindToShiftSize(from_kind);
2275  int to_increment = 1 << ElementsKindToShiftSize(to_kind);
2276
2277  Variable current_to_offset(this, MachineType::PointerRepresentation(),
2278                             to_offset);
2279  VariableList vars({&current_to_offset}, zone());
2280  int to_index_constant = 0, from_index_constant = 0;
2281  Smi* to_index_smi = nullptr;
2282  Smi* from_index_smi = nullptr;
2283  bool index_same = (from_encoding == to_encoding) &&
2284                    (from_index == to_index ||
2285                     (ToInt32Constant(from_index, from_index_constant) &&
2286                      ToInt32Constant(to_index, to_index_constant) &&
2287                      from_index_constant == to_index_constant) ||
2288                     (ToSmiConstant(from_index, from_index_smi) &&
2289                      ToSmiConstant(to_index, to_index_smi) &&
2290                      to_index_smi == from_index_smi));
2291  BuildFastLoop(vars, from_offset, limit_offset,
2292                [this, from_string, to_string, &current_to_offset, to_increment,
2293                 type, rep, index_same](Node* offset) {
2294                  Node* value = Load(type, from_string, offset);
2295                  StoreNoWriteBarrier(
2296                      rep, to_string,
2297                      index_same ? offset : current_to_offset.value(), value);
2298                  if (!index_same) {
2299                    Increment(current_to_offset, to_increment);
2300                  }
2301                },
2302                from_increment, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
2303}
2304
2305Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array,
2306                                                       Node* offset,
2307                                                       ElementsKind from_kind,
2308                                                       ElementsKind to_kind,
2309                                                       Label* if_hole) {
2310  if (IsFastDoubleElementsKind(from_kind)) {
2311    Node* value =
2312        LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64());
2313    if (!IsFastDoubleElementsKind(to_kind)) {
2314      value = AllocateHeapNumberWithValue(value);
2315    }
2316    return value;
2317
2318  } else {
2319    Node* value = Load(MachineType::AnyTagged(), array, offset);
2320    if (if_hole) {
2321      GotoIf(WordEqual(value, TheHoleConstant()), if_hole);
2322    }
2323    if (IsFastDoubleElementsKind(to_kind)) {
2324      if (IsFastSmiElementsKind(from_kind)) {
2325        value = SmiToFloat64(value);
2326      } else {
2327        value = LoadHeapNumberValue(value);
2328      }
2329    }
2330    return value;
2331  }
2332}
2333
2334Node* CodeStubAssembler::CalculateNewElementsCapacity(Node* old_capacity,
2335                                                      ParameterMode mode) {
2336  Node* half_old_capacity = WordOrSmiShr(old_capacity, 1, mode);
2337  Node* new_capacity = IntPtrOrSmiAdd(half_old_capacity, old_capacity, mode);
2338  Node* padding = IntPtrOrSmiConstant(16, mode);
2339  return IntPtrOrSmiAdd(new_capacity, padding, mode);
2340}
2341
2342Node* CodeStubAssembler::TryGrowElementsCapacity(Node* object, Node* elements,
2343                                                 ElementsKind kind, Node* key,
2344                                                 Label* bailout) {
2345  Node* capacity = LoadFixedArrayBaseLength(elements);
2346
2347  ParameterMode mode = OptimalParameterMode();
2348  capacity = TaggedToParameter(capacity, mode);
2349  key = TaggedToParameter(key, mode);
2350
2351  return TryGrowElementsCapacity(object, elements, kind, key, capacity, mode,
2352                                 bailout);
2353}
2354
2355Node* CodeStubAssembler::TryGrowElementsCapacity(Node* object, Node* elements,
2356                                                 ElementsKind kind, Node* key,
2357                                                 Node* capacity,
2358                                                 ParameterMode mode,
2359                                                 Label* bailout) {
2360  Comment("TryGrowElementsCapacity");
2361
2362  // If the gap growth is too big, fall back to the runtime.
2363  Node* max_gap = IntPtrOrSmiConstant(JSObject::kMaxGap, mode);
2364  Node* max_capacity = IntPtrOrSmiAdd(capacity, max_gap, mode);
2365  GotoIf(UintPtrOrSmiGreaterThanOrEqual(key, max_capacity, mode), bailout);
2366
2367  // Calculate the capacity of the new backing store.
2368  Node* new_capacity = CalculateNewElementsCapacity(
2369      IntPtrOrSmiAdd(key, IntPtrOrSmiConstant(1, mode), mode), mode);
2370  return GrowElementsCapacity(object, elements, kind, kind, capacity,
2371                              new_capacity, mode, bailout);
2372}
2373
2374Node* CodeStubAssembler::GrowElementsCapacity(
2375    Node* object, Node* elements, ElementsKind from_kind, ElementsKind to_kind,
2376    Node* capacity, Node* new_capacity, ParameterMode mode, Label* bailout) {
2377  Comment("[ GrowElementsCapacity");
2378  // If size of the allocation for the new capacity doesn't fit in a page
2379  // that we can bump-pointer allocate from, fall back to the runtime.
2380  int max_size = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(to_kind);
2381  GotoIf(UintPtrOrSmiGreaterThanOrEqual(
2382             new_capacity, IntPtrOrSmiConstant(max_size, mode), mode),
2383         bailout);
2384
2385  // Allocate the new backing store.
2386  Node* new_elements = AllocateFixedArray(to_kind, new_capacity, mode);
2387
2388  // Copy the elements from the old elements store to the new.
2389  // The size-check above guarantees that the |new_elements| is allocated
2390  // in new space so we can skip the write barrier.
2391  CopyFixedArrayElements(from_kind, elements, to_kind, new_elements, capacity,
2392                         new_capacity, SKIP_WRITE_BARRIER, mode);
2393
2394  StoreObjectField(object, JSObject::kElementsOffset, new_elements);
2395  Comment("] GrowElementsCapacity");
2396  return new_elements;
2397}
2398
2399void CodeStubAssembler::InitializeAllocationMemento(Node* base_allocation,
2400                                                    int base_allocation_size,
2401                                                    Node* allocation_site) {
2402  StoreObjectFieldNoWriteBarrier(
2403      base_allocation, AllocationMemento::kMapOffset + base_allocation_size,
2404      HeapConstant(Handle<Map>(isolate()->heap()->allocation_memento_map())));
2405  StoreObjectFieldNoWriteBarrier(
2406      base_allocation,
2407      AllocationMemento::kAllocationSiteOffset + base_allocation_size,
2408      allocation_site);
2409  if (FLAG_allocation_site_pretenuring) {
2410    Node* count = LoadObjectField(allocation_site,
2411                                  AllocationSite::kPretenureCreateCountOffset);
2412    Node* incremented_count = SmiAdd(count, SmiConstant(Smi::FromInt(1)));
2413    StoreObjectFieldNoWriteBarrier(allocation_site,
2414                                   AllocationSite::kPretenureCreateCountOffset,
2415                                   incremented_count);
2416  }
2417}
2418
2419Node* CodeStubAssembler::TryTaggedToFloat64(Node* value,
2420                                            Label* if_valueisnotnumber) {
2421  Label out(this);
2422  Variable var_result(this, MachineRepresentation::kFloat64);
2423
2424  // Check if the {value} is a Smi or a HeapObject.
2425  Label if_valueissmi(this), if_valueisnotsmi(this);
2426  Branch(TaggedIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
2427
2428  Bind(&if_valueissmi);
2429  {
2430    // Convert the Smi {value}.
2431    var_result.Bind(SmiToFloat64(value));
2432    Goto(&out);
2433  }
2434
2435  Bind(&if_valueisnotsmi);
2436  {
2437    // Check if {value} is a HeapNumber.
2438    Label if_valueisheapnumber(this);
2439    Branch(IsHeapNumberMap(LoadMap(value)), &if_valueisheapnumber,
2440           if_valueisnotnumber);
2441
2442    Bind(&if_valueisheapnumber);
2443    {
2444      // Load the floating point value.
2445      var_result.Bind(LoadHeapNumberValue(value));
2446      Goto(&out);
2447    }
2448  }
2449  Bind(&out);
2450  return var_result.value();
2451}
2452
2453Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) {
2454  // We might need to loop once due to ToNumber conversion.
2455  Variable var_value(this, MachineRepresentation::kTagged),
2456      var_result(this, MachineRepresentation::kFloat64);
2457  Label loop(this, &var_value), done_loop(this, &var_result);
2458  var_value.Bind(value);
2459  Goto(&loop);
2460  Bind(&loop);
2461  {
2462    Label if_valueisnotnumber(this, Label::kDeferred);
2463
2464    // Load the current {value}.
2465    value = var_value.value();
2466
2467    // Convert {value} to Float64 if it is a number and convert it to a number
2468    // otherwise.
2469    Node* const result = TryTaggedToFloat64(value, &if_valueisnotnumber);
2470    var_result.Bind(result);
2471    Goto(&done_loop);
2472
2473    Bind(&if_valueisnotnumber);
2474    {
2475      // Convert the {value} to a Number first.
2476      Callable callable = CodeFactory::NonNumberToNumber(isolate());
2477      var_value.Bind(CallStub(callable, context, value));
2478      Goto(&loop);
2479    }
2480  }
2481  Bind(&done_loop);
2482  return var_result.value();
2483}
2484
2485Node* CodeStubAssembler::TruncateTaggedToWord32(Node* context, Node* value) {
2486  // We might need to loop once due to ToNumber conversion.
2487  Variable var_value(this, MachineRepresentation::kTagged, value),
2488      var_result(this, MachineRepresentation::kWord32);
2489  Label loop(this, &var_value), done_loop(this, &var_result);
2490  Goto(&loop);
2491  Bind(&loop);
2492  {
2493    // Load the current {value}.
2494    value = var_value.value();
2495
2496    // Check if the {value} is a Smi or a HeapObject.
2497    Label if_valueissmi(this), if_valueisnotsmi(this);
2498    Branch(TaggedIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
2499
2500    Bind(&if_valueissmi);
2501    {
2502      // Convert the Smi {value}.
2503      var_result.Bind(SmiToWord32(value));
2504      Goto(&done_loop);
2505    }
2506
2507    Bind(&if_valueisnotsmi);
2508    {
2509      // Check if {value} is a HeapNumber.
2510      Label if_valueisheapnumber(this),
2511          if_valueisnotheapnumber(this, Label::kDeferred);
2512      Branch(IsHeapNumberMap(LoadMap(value)), &if_valueisheapnumber,
2513             &if_valueisnotheapnumber);
2514
2515      Bind(&if_valueisheapnumber);
2516      {
2517        // Truncate the floating point value.
2518        var_result.Bind(TruncateHeapNumberValueToWord32(value));
2519        Goto(&done_loop);
2520      }
2521
2522      Bind(&if_valueisnotheapnumber);
2523      {
2524        // Convert the {value} to a Number first.
2525        Callable callable = CodeFactory::NonNumberToNumber(isolate());
2526        var_value.Bind(CallStub(callable, context, value));
2527        Goto(&loop);
2528      }
2529    }
2530  }
2531  Bind(&done_loop);
2532  return var_result.value();
2533}
2534
2535Node* CodeStubAssembler::TruncateHeapNumberValueToWord32(Node* object) {
2536  Node* value = LoadHeapNumberValue(object);
2537  return TruncateFloat64ToWord32(value);
2538}
2539
2540Node* CodeStubAssembler::ChangeFloat64ToTagged(Node* value) {
2541  Node* value32 = RoundFloat64ToInt32(value);
2542  Node* value64 = ChangeInt32ToFloat64(value32);
2543
2544  Label if_valueisint32(this), if_valueisheapnumber(this), if_join(this);
2545
2546  Label if_valueisequal(this), if_valueisnotequal(this);
2547  Branch(Float64Equal(value, value64), &if_valueisequal, &if_valueisnotequal);
2548  Bind(&if_valueisequal);
2549  {
2550    GotoIfNot(Word32Equal(value32, Int32Constant(0)), &if_valueisint32);
2551    Branch(Int32LessThan(Float64ExtractHighWord32(value), Int32Constant(0)),
2552           &if_valueisheapnumber, &if_valueisint32);
2553  }
2554  Bind(&if_valueisnotequal);
2555  Goto(&if_valueisheapnumber);
2556
2557  Variable var_result(this, MachineRepresentation::kTagged);
2558  Bind(&if_valueisint32);
2559  {
2560    if (Is64()) {
2561      Node* result = SmiTag(ChangeInt32ToInt64(value32));
2562      var_result.Bind(result);
2563      Goto(&if_join);
2564    } else {
2565      Node* pair = Int32AddWithOverflow(value32, value32);
2566      Node* overflow = Projection(1, pair);
2567      Label if_overflow(this, Label::kDeferred), if_notoverflow(this);
2568      Branch(overflow, &if_overflow, &if_notoverflow);
2569      Bind(&if_overflow);
2570      Goto(&if_valueisheapnumber);
2571      Bind(&if_notoverflow);
2572      {
2573        Node* result = BitcastWordToTaggedSigned(Projection(0, pair));
2574        var_result.Bind(result);
2575        Goto(&if_join);
2576      }
2577    }
2578  }
2579  Bind(&if_valueisheapnumber);
2580  {
2581    Node* result = AllocateHeapNumberWithValue(value);
2582    var_result.Bind(result);
2583    Goto(&if_join);
2584  }
2585  Bind(&if_join);
2586  return var_result.value();
2587}
2588
2589Node* CodeStubAssembler::ChangeInt32ToTagged(Node* value) {
2590  if (Is64()) {
2591    return SmiTag(ChangeInt32ToInt64(value));
2592  }
2593  Variable var_result(this, MachineRepresentation::kTagged);
2594  Node* pair = Int32AddWithOverflow(value, value);
2595  Node* overflow = Projection(1, pair);
2596  Label if_overflow(this, Label::kDeferred), if_notoverflow(this),
2597      if_join(this);
2598  Branch(overflow, &if_overflow, &if_notoverflow);
2599  Bind(&if_overflow);
2600  {
2601    Node* value64 = ChangeInt32ToFloat64(value);
2602    Node* result = AllocateHeapNumberWithValue(value64);
2603    var_result.Bind(result);
2604  }
2605  Goto(&if_join);
2606  Bind(&if_notoverflow);
2607  {
2608    Node* result = BitcastWordToTaggedSigned(Projection(0, pair));
2609    var_result.Bind(result);
2610  }
2611  Goto(&if_join);
2612  Bind(&if_join);
2613  return var_result.value();
2614}
2615
2616Node* CodeStubAssembler::ChangeUint32ToTagged(Node* value) {
2617  Label if_overflow(this, Label::kDeferred), if_not_overflow(this),
2618      if_join(this);
2619  Variable var_result(this, MachineRepresentation::kTagged);
2620  // If {value} > 2^31 - 1, we need to store it in a HeapNumber.
2621  Branch(Uint32LessThan(Int32Constant(Smi::kMaxValue), value), &if_overflow,
2622         &if_not_overflow);
2623
2624  Bind(&if_not_overflow);
2625  {
2626    if (Is64()) {
2627      var_result.Bind(SmiTag(ChangeUint32ToUint64(value)));
2628    } else {
2629      // If tagging {value} results in an overflow, we need to use a HeapNumber
2630      // to represent it.
2631      Node* pair = Int32AddWithOverflow(value, value);
2632      Node* overflow = Projection(1, pair);
2633      GotoIf(overflow, &if_overflow);
2634
2635      Node* result = BitcastWordToTaggedSigned(Projection(0, pair));
2636      var_result.Bind(result);
2637    }
2638  }
2639  Goto(&if_join);
2640
2641  Bind(&if_overflow);
2642  {
2643    Node* float64_value = ChangeUint32ToFloat64(value);
2644    var_result.Bind(AllocateHeapNumberWithValue(float64_value));
2645  }
2646  Goto(&if_join);
2647
2648  Bind(&if_join);
2649  return var_result.value();
2650}
2651
2652Node* CodeStubAssembler::ToThisString(Node* context, Node* value,
2653                                      char const* method_name) {
2654  Variable var_value(this, MachineRepresentation::kTagged, value);
2655
2656  // Check if the {value} is a Smi or a HeapObject.
2657  Label if_valueissmi(this, Label::kDeferred), if_valueisnotsmi(this),
2658      if_valueisstring(this);
2659  Branch(TaggedIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
2660  Bind(&if_valueisnotsmi);
2661  {
2662    // Load the instance type of the {value}.
2663    Node* value_instance_type = LoadInstanceType(value);
2664
2665    // Check if the {value} is already String.
2666    Label if_valueisnotstring(this, Label::kDeferred);
2667    Branch(IsStringInstanceType(value_instance_type), &if_valueisstring,
2668           &if_valueisnotstring);
2669    Bind(&if_valueisnotstring);
2670    {
2671      // Check if the {value} is null.
2672      Label if_valueisnullorundefined(this, Label::kDeferred),
2673          if_valueisnotnullorundefined(this, Label::kDeferred),
2674          if_valueisnotnull(this, Label::kDeferred);
2675      Branch(WordEqual(value, NullConstant()), &if_valueisnullorundefined,
2676             &if_valueisnotnull);
2677      Bind(&if_valueisnotnull);
2678      {
2679        // Check if the {value} is undefined.
2680        Branch(WordEqual(value, UndefinedConstant()),
2681               &if_valueisnullorundefined, &if_valueisnotnullorundefined);
2682        Bind(&if_valueisnotnullorundefined);
2683        {
2684          // Convert the {value} to a String.
2685          Callable callable = CodeFactory::ToString(isolate());
2686          var_value.Bind(CallStub(callable, context, value));
2687          Goto(&if_valueisstring);
2688        }
2689      }
2690
2691      Bind(&if_valueisnullorundefined);
2692      {
2693        // The {value} is either null or undefined.
2694        CallRuntime(Runtime::kThrowCalledOnNullOrUndefined, context,
2695                    HeapConstant(factory()->NewStringFromAsciiChecked(
2696                        method_name, TENURED)));
2697        Unreachable();
2698      }
2699    }
2700  }
2701  Bind(&if_valueissmi);
2702  {
2703    // The {value} is a Smi, convert it to a String.
2704    Callable callable = CodeFactory::NumberToString(isolate());
2705    var_value.Bind(CallStub(callable, context, value));
2706    Goto(&if_valueisstring);
2707  }
2708  Bind(&if_valueisstring);
2709  return var_value.value();
2710}
2711
2712Node* CodeStubAssembler::ChangeNumberToFloat64(compiler::Node* value) {
2713  Variable result(this, MachineRepresentation::kFloat64);
2714  Label smi(this);
2715  Label done(this, &result);
2716  GotoIf(TaggedIsSmi(value), &smi);
2717  result.Bind(
2718      LoadObjectField(value, HeapNumber::kValueOffset, MachineType::Float64()));
2719  Goto(&done);
2720
2721  Bind(&smi);
2722  {
2723    result.Bind(SmiToFloat64(value));
2724    Goto(&done);
2725  }
2726
2727  Bind(&done);
2728  return result.value();
2729}
2730
2731Node* CodeStubAssembler::ToThisValue(Node* context, Node* value,
2732                                     PrimitiveType primitive_type,
2733                                     char const* method_name) {
2734  // We might need to loop once due to JSValue unboxing.
2735  Variable var_value(this, MachineRepresentation::kTagged, value);
2736  Label loop(this, &var_value), done_loop(this),
2737      done_throw(this, Label::kDeferred);
2738  Goto(&loop);
2739  Bind(&loop);
2740  {
2741    // Load the current {value}.
2742    value = var_value.value();
2743
2744    // Check if the {value} is a Smi or a HeapObject.
2745    GotoIf(TaggedIsSmi(value), (primitive_type == PrimitiveType::kNumber)
2746                                   ? &done_loop
2747                                   : &done_throw);
2748
2749    // Load the mape of the {value}.
2750    Node* value_map = LoadMap(value);
2751
2752    // Load the instance type of the {value}.
2753    Node* value_instance_type = LoadMapInstanceType(value_map);
2754
2755    // Check if {value} is a JSValue.
2756    Label if_valueisvalue(this, Label::kDeferred), if_valueisnotvalue(this);
2757    Branch(Word32Equal(value_instance_type, Int32Constant(JS_VALUE_TYPE)),
2758           &if_valueisvalue, &if_valueisnotvalue);
2759
2760    Bind(&if_valueisvalue);
2761    {
2762      // Load the actual value from the {value}.
2763      var_value.Bind(LoadObjectField(value, JSValue::kValueOffset));
2764      Goto(&loop);
2765    }
2766
2767    Bind(&if_valueisnotvalue);
2768    {
2769      switch (primitive_type) {
2770        case PrimitiveType::kBoolean:
2771          GotoIf(WordEqual(value_map, BooleanMapConstant()), &done_loop);
2772          break;
2773        case PrimitiveType::kNumber:
2774          GotoIf(
2775              Word32Equal(value_instance_type, Int32Constant(HEAP_NUMBER_TYPE)),
2776              &done_loop);
2777          break;
2778        case PrimitiveType::kString:
2779          GotoIf(IsStringInstanceType(value_instance_type), &done_loop);
2780          break;
2781        case PrimitiveType::kSymbol:
2782          GotoIf(Word32Equal(value_instance_type, Int32Constant(SYMBOL_TYPE)),
2783                 &done_loop);
2784          break;
2785      }
2786      Goto(&done_throw);
2787    }
2788  }
2789
2790  Bind(&done_throw);
2791  {
2792    // The {value} is not a compatible receiver for this method.
2793    CallRuntime(Runtime::kThrowNotGeneric, context,
2794                HeapConstant(factory()->NewStringFromAsciiChecked(method_name,
2795                                                                  TENURED)));
2796    Unreachable();
2797  }
2798
2799  Bind(&done_loop);
2800  return var_value.value();
2801}
2802
2803Node* CodeStubAssembler::ThrowIfNotInstanceType(Node* context, Node* value,
2804                                                InstanceType instance_type,
2805                                                char const* method_name) {
2806  Label out(this), throw_exception(this, Label::kDeferred);
2807  Variable var_value_map(this, MachineRepresentation::kTagged);
2808
2809  GotoIf(TaggedIsSmi(value), &throw_exception);
2810
2811  // Load the instance type of the {value}.
2812  var_value_map.Bind(LoadMap(value));
2813  Node* const value_instance_type = LoadMapInstanceType(var_value_map.value());
2814
2815  Branch(Word32Equal(value_instance_type, Int32Constant(instance_type)), &out,
2816         &throw_exception);
2817
2818  // The {value} is not a compatible receiver for this method.
2819  Bind(&throw_exception);
2820  CallRuntime(
2821      Runtime::kThrowIncompatibleMethodReceiver, context,
2822      HeapConstant(factory()->NewStringFromAsciiChecked(method_name, TENURED)),
2823      value);
2824  Unreachable();
2825
2826  Bind(&out);
2827  return var_value_map.value();
2828}
2829
2830Node* CodeStubAssembler::InstanceTypeEqual(Node* instance_type, int type) {
2831  return Word32Equal(instance_type, Int32Constant(type));
2832}
2833
2834Node* CodeStubAssembler::IsSpecialReceiverMap(Node* map) {
2835  Node* is_special = IsSpecialReceiverInstanceType(LoadMapInstanceType(map));
2836  uint32_t mask =
2837      1 << Map::kHasNamedInterceptor | 1 << Map::kIsAccessCheckNeeded;
2838  USE(mask);
2839  // Interceptors or access checks imply special receiver.
2840  CSA_ASSERT(this,
2841             SelectConstant(IsSetWord32(LoadMapBitField(map), mask), is_special,
2842                            Int32Constant(1), MachineRepresentation::kWord32));
2843  return is_special;
2844}
2845
2846Node* CodeStubAssembler::IsDictionaryMap(Node* map) {
2847  CSA_SLOW_ASSERT(this, IsMap(map));
2848  Node* bit_field3 = LoadMapBitField3(map);
2849  return Word32NotEqual(IsSetWord32<Map::DictionaryMap>(bit_field3),
2850                        Int32Constant(0));
2851}
2852
2853Node* CodeStubAssembler::IsCallableMap(Node* map) {
2854  CSA_ASSERT(this, IsMap(map));
2855  return Word32NotEqual(
2856      Word32And(LoadMapBitField(map), Int32Constant(1 << Map::kIsCallable)),
2857      Int32Constant(0));
2858}
2859
2860Node* CodeStubAssembler::IsCallable(Node* object) {
2861  return IsCallableMap(LoadMap(object));
2862}
2863
2864Node* CodeStubAssembler::IsConstructorMap(Node* map) {
2865  CSA_ASSERT(this, IsMap(map));
2866  return Word32NotEqual(
2867      Word32And(LoadMapBitField(map), Int32Constant(1 << Map::kIsConstructor)),
2868      Int32Constant(0));
2869}
2870
2871Node* CodeStubAssembler::IsSpecialReceiverInstanceType(Node* instance_type) {
2872  STATIC_ASSERT(JS_GLOBAL_OBJECT_TYPE <= LAST_SPECIAL_RECEIVER_TYPE);
2873  return Int32LessThanOrEqual(instance_type,
2874                              Int32Constant(LAST_SPECIAL_RECEIVER_TYPE));
2875}
2876
2877Node* CodeStubAssembler::IsStringInstanceType(Node* instance_type) {
2878  STATIC_ASSERT(INTERNALIZED_STRING_TYPE == FIRST_TYPE);
2879  return Int32LessThan(instance_type, Int32Constant(FIRST_NONSTRING_TYPE));
2880}
2881
2882Node* CodeStubAssembler::IsJSReceiverInstanceType(Node* instance_type) {
2883  STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2884  return Int32GreaterThanOrEqual(instance_type,
2885                                 Int32Constant(FIRST_JS_RECEIVER_TYPE));
2886}
2887
2888Node* CodeStubAssembler::IsJSReceiver(Node* object) {
2889  STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
2890  return IsJSReceiverInstanceType(LoadInstanceType(object));
2891}
2892
2893Node* CodeStubAssembler::IsJSReceiverMap(Node* map) {
2894  STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
2895  return IsJSReceiverInstanceType(LoadMapInstanceType(map));
2896}
2897
2898Node* CodeStubAssembler::IsJSObject(Node* object) {
2899  STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
2900  return Int32GreaterThanOrEqual(LoadInstanceType(object),
2901                                 Int32Constant(FIRST_JS_RECEIVER_TYPE));
2902}
2903
2904Node* CodeStubAssembler::IsJSGlobalProxy(Node* object) {
2905  return Word32Equal(LoadInstanceType(object),
2906                     Int32Constant(JS_GLOBAL_PROXY_TYPE));
2907}
2908
2909Node* CodeStubAssembler::IsMap(Node* map) {
2910  return HasInstanceType(map, MAP_TYPE);
2911}
2912
2913Node* CodeStubAssembler::IsJSValue(Node* map) {
2914  return HasInstanceType(map, JS_VALUE_TYPE);
2915}
2916
2917Node* CodeStubAssembler::IsJSArray(Node* object) {
2918  return HasInstanceType(object, JS_ARRAY_TYPE);
2919}
2920
2921Node* CodeStubAssembler::IsWeakCell(Node* object) {
2922  return HasInstanceType(object, WEAK_CELL_TYPE);
2923}
2924
2925Node* CodeStubAssembler::IsBoolean(Node* object) {
2926  return IsBooleanMap(LoadMap(object));
2927}
2928
2929Node* CodeStubAssembler::IsHeapNumber(Node* object) {
2930  return IsHeapNumberMap(LoadMap(object));
2931}
2932
2933Node* CodeStubAssembler::IsName(Node* object) {
2934  return Int32LessThanOrEqual(LoadInstanceType(object),
2935                              Int32Constant(LAST_NAME_TYPE));
2936}
2937
2938Node* CodeStubAssembler::IsString(Node* object) {
2939  return Int32LessThanOrEqual(LoadInstanceType(object),
2940                              Int32Constant(FIRST_NONSTRING_TYPE));
2941}
2942
2943Node* CodeStubAssembler::IsSymbol(Node* object) {
2944  return IsSymbolMap(LoadMap(object));
2945}
2946
2947Node* CodeStubAssembler::IsPrivateSymbol(Node* object) {
2948  return Select(
2949      IsSymbol(object),
2950      [=] {
2951        Node* const flags =
2952            SmiToWord32(LoadObjectField(object, Symbol::kFlagsOffset));
2953        const int kPrivateMask = 1 << Symbol::kPrivateBit;
2954        return IsSetWord32(flags, kPrivateMask);
2955      },
2956      [=] { return Int32Constant(0); }, MachineRepresentation::kWord32);
2957}
2958
2959Node* CodeStubAssembler::IsNativeContext(Node* object) {
2960  return WordEqual(LoadMap(object), LoadRoot(Heap::kNativeContextMapRootIndex));
2961}
2962
2963Node* CodeStubAssembler::IsFixedDoubleArray(Node* object) {
2964  return WordEqual(LoadMap(object), FixedDoubleArrayMapConstant());
2965}
2966
2967Node* CodeStubAssembler::IsHashTable(Node* object) {
2968  return WordEqual(LoadMap(object), LoadRoot(Heap::kHashTableMapRootIndex));
2969}
2970
2971Node* CodeStubAssembler::IsDictionary(Node* object) {
2972  return Word32Or(IsHashTable(object), IsUnseededNumberDictionary(object));
2973}
2974
2975Node* CodeStubAssembler::IsUnseededNumberDictionary(Node* object) {
2976  return WordEqual(LoadMap(object),
2977                   LoadRoot(Heap::kUnseededNumberDictionaryMapRootIndex));
2978}
2979
2980Node* CodeStubAssembler::IsJSFunction(Node* object) {
2981  return HasInstanceType(object, JS_FUNCTION_TYPE);
2982}
2983
2984Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index,
2985                                          ParameterMode parameter_mode) {
2986  CSA_ASSERT(this, IsString(string));
2987  // Translate the {index} into a Word.
2988  index = ParameterToWord(index, parameter_mode);
2989
2990  // We may need to loop in case of cons, thin, or sliced strings.
2991  Variable var_index(this, MachineType::PointerRepresentation(), index);
2992  Variable var_string(this, MachineRepresentation::kTagged, string);
2993  Variable var_result(this, MachineRepresentation::kWord32);
2994  Variable* loop_vars[] = {&var_index, &var_string};
2995  Label done_loop(this, &var_result), loop(this, 2, loop_vars);
2996  Goto(&loop);
2997  Bind(&loop);
2998  {
2999    // Load the current {index}.
3000    index = var_index.value();
3001
3002    // Load the current {string}.
3003    string = var_string.value();
3004
3005    // Load the instance type of the {string}.
3006    Node* string_instance_type = LoadInstanceType(string);
3007
3008    // Check if the {string} is a SeqString.
3009    Label if_stringissequential(this), if_stringisnotsequential(this);
3010    Branch(Word32Equal(Word32And(string_instance_type,
3011                                 Int32Constant(kStringRepresentationMask)),
3012                       Int32Constant(kSeqStringTag)),
3013           &if_stringissequential, &if_stringisnotsequential);
3014
3015    Bind(&if_stringissequential);
3016    {
3017      // Check if the {string} is a TwoByteSeqString or a OneByteSeqString.
3018      Label if_stringistwobyte(this), if_stringisonebyte(this);
3019      Branch(Word32Equal(Word32And(string_instance_type,
3020                                   Int32Constant(kStringEncodingMask)),
3021                         Int32Constant(kTwoByteStringTag)),
3022             &if_stringistwobyte, &if_stringisonebyte);
3023
3024      Bind(&if_stringisonebyte);
3025      {
3026        var_result.Bind(
3027            Load(MachineType::Uint8(), string,
3028                 IntPtrAdd(index, IntPtrConstant(SeqOneByteString::kHeaderSize -
3029                                                 kHeapObjectTag))));
3030        Goto(&done_loop);
3031      }
3032
3033      Bind(&if_stringistwobyte);
3034      {
3035        var_result.Bind(
3036            Load(MachineType::Uint16(), string,
3037                 IntPtrAdd(WordShl(index, IntPtrConstant(1)),
3038                           IntPtrConstant(SeqTwoByteString::kHeaderSize -
3039                                          kHeapObjectTag))));
3040        Goto(&done_loop);
3041      }
3042    }
3043
3044    Bind(&if_stringisnotsequential);
3045    {
3046      // Check if the {string} is a ConsString.
3047      Label if_stringiscons(this), if_stringisnotcons(this);
3048      Branch(Word32Equal(Word32And(string_instance_type,
3049                                   Int32Constant(kStringRepresentationMask)),
3050                         Int32Constant(kConsStringTag)),
3051             &if_stringiscons, &if_stringisnotcons);
3052
3053      Bind(&if_stringiscons);
3054      {
3055        // Check whether the right hand side is the empty string (i.e. if
3056        // this is really a flat string in a cons string). If that is not
3057        // the case we flatten the string first.
3058        Label if_rhsisempty(this), if_rhsisnotempty(this, Label::kDeferred);
3059        Node* rhs = LoadObjectField(string, ConsString::kSecondOffset);
3060        Branch(WordEqual(rhs, EmptyStringConstant()), &if_rhsisempty,
3061               &if_rhsisnotempty);
3062
3063        Bind(&if_rhsisempty);
3064        {
3065          // Just operate on the left hand side of the {string}.
3066          var_string.Bind(LoadObjectField(string, ConsString::kFirstOffset));
3067          Goto(&loop);
3068        }
3069
3070        Bind(&if_rhsisnotempty);
3071        {
3072          // Flatten the {string} and lookup in the resulting string.
3073          var_string.Bind(CallRuntime(Runtime::kFlattenString,
3074                                      NoContextConstant(), string));
3075          Goto(&loop);
3076        }
3077      }
3078
3079      Bind(&if_stringisnotcons);
3080      {
3081        // Check if the {string} is an ExternalString.
3082        Label if_stringisexternal(this), if_stringisnotexternal(this);
3083        Branch(Word32Equal(Word32And(string_instance_type,
3084                                     Int32Constant(kStringRepresentationMask)),
3085                           Int32Constant(kExternalStringTag)),
3086               &if_stringisexternal, &if_stringisnotexternal);
3087
3088        Bind(&if_stringisexternal);
3089        {
3090          // Check if the {string} is a short external string.
3091          Label if_stringisnotshort(this),
3092              if_stringisshort(this, Label::kDeferred);
3093          Branch(Word32Equal(Word32And(string_instance_type,
3094                                       Int32Constant(kShortExternalStringMask)),
3095                             Int32Constant(0)),
3096                 &if_stringisnotshort, &if_stringisshort);
3097
3098          Bind(&if_stringisnotshort);
3099          {
3100            // Load the actual resource data from the {string}.
3101            Node* string_resource_data =
3102                LoadObjectField(string, ExternalString::kResourceDataOffset,
3103                                MachineType::Pointer());
3104
3105            // Check if the {string} is a TwoByteExternalString or a
3106            // OneByteExternalString.
3107            Label if_stringistwobyte(this), if_stringisonebyte(this);
3108            Branch(Word32Equal(Word32And(string_instance_type,
3109                                         Int32Constant(kStringEncodingMask)),
3110                               Int32Constant(kTwoByteStringTag)),
3111                   &if_stringistwobyte, &if_stringisonebyte);
3112
3113            Bind(&if_stringisonebyte);
3114            {
3115              var_result.Bind(
3116                  Load(MachineType::Uint8(), string_resource_data, index));
3117              Goto(&done_loop);
3118            }
3119
3120            Bind(&if_stringistwobyte);
3121            {
3122              var_result.Bind(Load(MachineType::Uint16(), string_resource_data,
3123                                   WordShl(index, IntPtrConstant(1))));
3124              Goto(&done_loop);
3125            }
3126          }
3127
3128          Bind(&if_stringisshort);
3129          {
3130            // The {string} might be compressed, call the runtime.
3131            var_result.Bind(SmiToWord32(
3132                CallRuntime(Runtime::kExternalStringGetChar,
3133                            NoContextConstant(), string, SmiTag(index))));
3134            Goto(&done_loop);
3135          }
3136        }
3137
3138        Bind(&if_stringisnotexternal);
3139        {
3140          Label if_stringissliced(this), if_stringisthin(this);
3141          Branch(
3142              Word32Equal(Word32And(string_instance_type,
3143                                    Int32Constant(kStringRepresentationMask)),
3144                          Int32Constant(kSlicedStringTag)),
3145              &if_stringissliced, &if_stringisthin);
3146          Bind(&if_stringissliced);
3147          {
3148            // The {string} is a SlicedString, continue with its parent.
3149            Node* string_offset =
3150                LoadAndUntagObjectField(string, SlicedString::kOffsetOffset);
3151            Node* string_parent =
3152                LoadObjectField(string, SlicedString::kParentOffset);
3153            var_index.Bind(IntPtrAdd(index, string_offset));
3154            var_string.Bind(string_parent);
3155            Goto(&loop);
3156          }
3157          Bind(&if_stringisthin);
3158          {
3159            // The {string} is a ThinString, continue with its actual value.
3160            var_string.Bind(LoadObjectField(string, ThinString::kActualOffset));
3161            Goto(&loop);
3162          }
3163        }
3164      }
3165    }
3166  }
3167
3168  Bind(&done_loop);
3169  return var_result.value();
3170}
3171
3172Node* CodeStubAssembler::StringFromCharCode(Node* code) {
3173  Variable var_result(this, MachineRepresentation::kTagged);
3174
3175  // Check if the {code} is a one-byte char code.
3176  Label if_codeisonebyte(this), if_codeistwobyte(this, Label::kDeferred),
3177      if_done(this);
3178  Branch(Int32LessThanOrEqual(code, Int32Constant(String::kMaxOneByteCharCode)),
3179         &if_codeisonebyte, &if_codeistwobyte);
3180  Bind(&if_codeisonebyte);
3181  {
3182    // Load the isolate wide single character string cache.
3183    Node* cache = LoadRoot(Heap::kSingleCharacterStringCacheRootIndex);
3184    Node* code_index = ChangeUint32ToWord(code);
3185
3186    // Check if we have an entry for the {code} in the single character string
3187    // cache already.
3188    Label if_entryisundefined(this, Label::kDeferred),
3189        if_entryisnotundefined(this);
3190    Node* entry = LoadFixedArrayElement(cache, code_index);
3191    Branch(WordEqual(entry, UndefinedConstant()), &if_entryisundefined,
3192           &if_entryisnotundefined);
3193
3194    Bind(&if_entryisundefined);
3195    {
3196      // Allocate a new SeqOneByteString for {code} and store it in the {cache}.
3197      Node* result = AllocateSeqOneByteString(1);
3198      StoreNoWriteBarrier(
3199          MachineRepresentation::kWord8, result,
3200          IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag), code);
3201      StoreFixedArrayElement(cache, code_index, result);
3202      var_result.Bind(result);
3203      Goto(&if_done);
3204    }
3205
3206    Bind(&if_entryisnotundefined);
3207    {
3208      // Return the entry from the {cache}.
3209      var_result.Bind(entry);
3210      Goto(&if_done);
3211    }
3212  }
3213
3214  Bind(&if_codeistwobyte);
3215  {
3216    // Allocate a new SeqTwoByteString for {code}.
3217    Node* result = AllocateSeqTwoByteString(1);
3218    StoreNoWriteBarrier(
3219        MachineRepresentation::kWord16, result,
3220        IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code);
3221    var_result.Bind(result);
3222    Goto(&if_done);
3223  }
3224
3225  Bind(&if_done);
3226  return var_result.value();
3227}
3228
3229namespace {
3230
3231// A wrapper around CopyStringCharacters which determines the correct string
3232// encoding, allocates a corresponding sequential string, and then copies the
3233// given character range using CopyStringCharacters.
3234// |from_string| must be a sequential string. |from_index| and
3235// |character_count| must be Smis s.t.
3236// 0 <= |from_index| <= |from_index| + |character_count| < from_string.length.
3237Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context,
3238                                   Node* from, Node* from_instance_type,
3239                                   Node* from_index, Node* character_count) {
3240  typedef CodeStubAssembler::Label Label;
3241  typedef CodeStubAssembler::Variable Variable;
3242
3243  Label end(a), two_byte_sequential(a);
3244  Variable var_result(a, MachineRepresentation::kTagged);
3245
3246  Node* const smi_zero = a->SmiConstant(Smi::kZero);
3247
3248  STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
3249  a->GotoIf(a->Word32Equal(a->Word32And(from_instance_type,
3250                                        a->Int32Constant(kStringEncodingMask)),
3251                           a->Int32Constant(0)),
3252            &two_byte_sequential);
3253
3254  // The subject string is a sequential one-byte string.
3255  {
3256    Node* result =
3257        a->AllocateSeqOneByteString(context, a->SmiToWord(character_count));
3258    a->CopyStringCharacters(from, result, from_index, smi_zero, character_count,
3259                            String::ONE_BYTE_ENCODING,
3260                            String::ONE_BYTE_ENCODING,
3261                            CodeStubAssembler::SMI_PARAMETERS);
3262    var_result.Bind(result);
3263
3264    a->Goto(&end);
3265  }
3266
3267  // The subject string is a sequential two-byte string.
3268  a->Bind(&two_byte_sequential);
3269  {
3270    Node* result =
3271        a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count));
3272    a->CopyStringCharacters(from, result, from_index, smi_zero, character_count,
3273                            String::TWO_BYTE_ENCODING,
3274                            String::TWO_BYTE_ENCODING,
3275                            CodeStubAssembler::SMI_PARAMETERS);
3276    var_result.Bind(result);
3277
3278    a->Goto(&end);
3279  }
3280
3281  a->Bind(&end);
3282  return var_result.value();
3283}
3284
3285}  // namespace
3286
3287Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from,
3288                                   Node* to) {
3289  Label end(this);
3290  Label runtime(this);
3291
3292  Node* const int_zero = Int32Constant(0);
3293
3294  // Int32 variables.
3295  Variable var_instance_type(this, MachineRepresentation::kWord32, int_zero);
3296  Variable var_representation(this, MachineRepresentation::kWord32, int_zero);
3297
3298  Variable var_from(this, MachineRepresentation::kTagged, from);      // Smi.
3299  Variable var_string(this, MachineRepresentation::kTagged, string);  // String.
3300  Variable var_result(this, MachineRepresentation::kTagged);          // String.
3301
3302  // Make sure first argument is a string.
3303  CSA_ASSERT(this, TaggedIsNotSmi(string));
3304  CSA_ASSERT(this, IsString(string));
3305
3306  // Load the instance type of the {string}.
3307  Node* const instance_type = LoadInstanceType(string);
3308  var_instance_type.Bind(instance_type);
3309
3310  // Make sure that both from and to are non-negative smis.
3311
3312  GotoIfNot(TaggedIsPositiveSmi(from), &runtime);
3313  GotoIfNot(TaggedIsPositiveSmi(to), &runtime);
3314
3315  Node* const substr_length = SmiSub(to, from);
3316  Node* const string_length = LoadStringLength(string);
3317
3318  // Begin dispatching based on substring length.
3319
3320  Label original_string_or_invalid_length(this);
3321  GotoIf(SmiAboveOrEqual(substr_length, string_length),
3322         &original_string_or_invalid_length);
3323
3324  // A real substring (substr_length < string_length).
3325
3326  Label single_char(this);
3327  GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char);
3328
3329  // TODO(jgruber): Add an additional case for substring of length == 0?
3330
3331  // Deal with different string types: update the index if necessary
3332  // and put the underlying string into var_string.
3333
3334  // If the string is not indirect, it can only be sequential or external.
3335  STATIC_ASSERT(kIsIndirectStringMask ==
3336                (kSlicedStringTag & kConsStringTag & kThinStringTag));
3337  STATIC_ASSERT(kIsIndirectStringMask != 0);
3338  Label underlying_unpacked(this);
3339  GotoIf(Word32Equal(
3340             Word32And(instance_type, Int32Constant(kIsIndirectStringMask)),
3341             Int32Constant(0)),
3342         &underlying_unpacked);
3343
3344  // The subject string is a sliced, cons, or thin string.
3345
3346  Label thin_string(this), thin_or_sliced(this);
3347  var_representation.Bind(
3348      Word32And(instance_type, Int32Constant(kStringRepresentationMask)));
3349  GotoIf(
3350      Word32NotEqual(var_representation.value(), Int32Constant(kConsStringTag)),
3351      &thin_or_sliced);
3352
3353  // Cons string.  Check whether it is flat, then fetch first part.
3354  // Flat cons strings have an empty second part.
3355  {
3356    GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset),
3357                        EmptyStringConstant()),
3358           &runtime);
3359
3360    Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset);
3361    var_string.Bind(first_string_part);
3362    var_instance_type.Bind(LoadInstanceType(first_string_part));
3363    var_representation.Bind(Word32And(
3364        var_instance_type.value(), Int32Constant(kStringRepresentationMask)));
3365
3366    // The loaded first part might be a thin string.
3367    Branch(Word32Equal(Word32And(var_instance_type.value(),
3368                                 Int32Constant(kIsIndirectStringMask)),
3369                       Int32Constant(0)),
3370           &underlying_unpacked, &thin_string);
3371  }
3372
3373  Bind(&thin_or_sliced);
3374  {
3375    GotoIf(
3376        Word32Equal(var_representation.value(), Int32Constant(kThinStringTag)),
3377        &thin_string);
3378    // Otherwise it's a sliced string.
3379    // Fetch parent and correct start index by offset.
3380    Node* sliced_offset =
3381        LoadObjectField(var_string.value(), SlicedString::kOffsetOffset);
3382    var_from.Bind(SmiAdd(from, sliced_offset));
3383
3384    Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset);
3385    var_string.Bind(slice_parent);
3386
3387    Node* slice_parent_instance_type = LoadInstanceType(slice_parent);
3388    var_instance_type.Bind(slice_parent_instance_type);
3389
3390    // The loaded parent might be a thin string.
3391    Branch(Word32Equal(Word32And(var_instance_type.value(),
3392                                 Int32Constant(kIsIndirectStringMask)),
3393                       Int32Constant(0)),
3394           &underlying_unpacked, &thin_string);
3395  }
3396
3397  Bind(&thin_string);
3398  {
3399    Node* actual_string =
3400        LoadObjectField(var_string.value(), ThinString::kActualOffset);
3401    var_string.Bind(actual_string);
3402    var_instance_type.Bind(LoadInstanceType(actual_string));
3403    Goto(&underlying_unpacked);
3404  }
3405
3406  // The subject string can only be external or sequential string of either
3407  // encoding at this point.
3408  Label external_string(this);
3409  Bind(&underlying_unpacked);
3410  {
3411    if (FLAG_string_slices) {
3412      Label copy_routine(this);
3413
3414      // Short slice.  Copy instead of slicing.
3415      GotoIf(SmiLessThan(substr_length,
3416                         SmiConstant(Smi::FromInt(SlicedString::kMinLength))),
3417             &copy_routine);
3418
3419      // Allocate new sliced string.
3420
3421      Label two_byte_slice(this);
3422      STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
3423      STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
3424
3425      Counters* counters = isolate()->counters();
3426      IncrementCounter(counters->sub_string_native(), 1);
3427
3428      GotoIf(Word32Equal(Word32And(var_instance_type.value(),
3429                                   Int32Constant(kStringEncodingMask)),
3430                         Int32Constant(0)),
3431             &two_byte_slice);
3432
3433      var_result.Bind(AllocateSlicedOneByteString(
3434          substr_length, var_string.value(), var_from.value()));
3435      Goto(&end);
3436
3437      Bind(&two_byte_slice);
3438
3439      var_result.Bind(AllocateSlicedTwoByteString(
3440          substr_length, var_string.value(), var_from.value()));
3441      Goto(&end);
3442
3443      Bind(&copy_routine);
3444    }
3445
3446    // The subject string can only be external or sequential string of either
3447    // encoding at this point.
3448    STATIC_ASSERT(kExternalStringTag != 0);
3449    STATIC_ASSERT(kSeqStringTag == 0);
3450    GotoIfNot(Word32Equal(Word32And(var_instance_type.value(),
3451                                    Int32Constant(kExternalStringTag)),
3452                          Int32Constant(0)),
3453              &external_string);
3454
3455    var_result.Bind(AllocAndCopyStringCharacters(
3456        this, context, var_string.value(), var_instance_type.value(),
3457        var_from.value(), substr_length));
3458
3459    Counters* counters = isolate()->counters();
3460    IncrementCounter(counters->sub_string_native(), 1);
3461
3462    Goto(&end);
3463  }
3464
3465  // Handle external string.
3466  Bind(&external_string);
3467  {
3468    Node* const fake_sequential_string = TryDerefExternalString(
3469        var_string.value(), var_instance_type.value(), &runtime);
3470
3471    var_result.Bind(AllocAndCopyStringCharacters(
3472        this, context, fake_sequential_string, var_instance_type.value(),
3473        var_from.value(), substr_length));
3474
3475    Counters* counters = isolate()->counters();
3476    IncrementCounter(counters->sub_string_native(), 1);
3477
3478    Goto(&end);
3479  }
3480
3481  // Substrings of length 1 are generated through CharCodeAt and FromCharCode.
3482  Bind(&single_char);
3483  {
3484    Node* char_code = StringCharCodeAt(var_string.value(), var_from.value());
3485    var_result.Bind(StringFromCharCode(char_code));
3486    Goto(&end);
3487  }
3488
3489  Bind(&original_string_or_invalid_length);
3490  {
3491    // Longer than original string's length or negative: unsafe arguments.
3492    GotoIf(SmiAbove(substr_length, string_length), &runtime);
3493
3494    // Equal length - check if {from, to} == {0, str.length}.
3495    GotoIf(SmiAbove(from, SmiConstant(Smi::kZero)), &runtime);
3496
3497    // Return the original string (substr_length == string_length).
3498
3499    Counters* counters = isolate()->counters();
3500    IncrementCounter(counters->sub_string_native(), 1);
3501
3502    var_result.Bind(string);
3503    Goto(&end);
3504  }
3505
3506  // Fall back to a runtime call.
3507  Bind(&runtime);
3508  {
3509    var_result.Bind(
3510        CallRuntime(Runtime::kSubString, context, string, from, to));
3511    Goto(&end);
3512  }
3513
3514  Bind(&end);
3515  return var_result.value();
3516}
3517
3518namespace {
3519
3520Node* IsExternalStringInstanceType(CodeStubAssembler* a,
3521                                   Node* const instance_type) {
3522  CSA_ASSERT(a, a->IsStringInstanceType(instance_type));
3523  return a->Word32Equal(
3524      a->Word32And(instance_type, a->Int32Constant(kStringRepresentationMask)),
3525      a->Int32Constant(kExternalStringTag));
3526}
3527
3528Node* IsShortExternalStringInstanceType(CodeStubAssembler* a,
3529                                        Node* const instance_type) {
3530  CSA_ASSERT(a, a->IsStringInstanceType(instance_type));
3531  STATIC_ASSERT(kShortExternalStringTag != 0);
3532  return a->Word32NotEqual(
3533      a->Word32And(instance_type, a->Int32Constant(kShortExternalStringMask)),
3534      a->Int32Constant(0));
3535}
3536
3537}  // namespace
3538
3539Node* CodeStubAssembler::TryDerefExternalString(Node* const string,
3540                                                Node* const instance_type,
3541                                                Label* if_bailout) {
3542  Label out(this);
3543
3544  USE(IsExternalStringInstanceType);
3545  CSA_ASSERT(this, IsExternalStringInstanceType(this, instance_type));
3546  GotoIf(IsShortExternalStringInstanceType(this, instance_type), if_bailout);
3547
3548  // Move the pointer so that offset-wise, it looks like a sequential string.
3549  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
3550
3551  Node* resource_data = LoadObjectField(
3552      string, ExternalString::kResourceDataOffset, MachineType::Pointer());
3553  Node* const fake_sequential_string =
3554      IntPtrSub(resource_data,
3555                IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
3556
3557  return fake_sequential_string;
3558}
3559
3560void CodeStubAssembler::MaybeDerefIndirectString(Variable* var_string,
3561                                                 Node* instance_type,
3562                                                 Variable* var_did_something) {
3563  Label deref(this), done(this, var_did_something);
3564  Node* representation =
3565      Word32And(instance_type, Int32Constant(kStringRepresentationMask));
3566  GotoIf(Word32Equal(representation, Int32Constant(kThinStringTag)), &deref);
3567  GotoIf(Word32NotEqual(representation, Int32Constant(kConsStringTag)), &done);
3568  // Cons string.
3569  Node* rhs = LoadObjectField(var_string->value(), ConsString::kSecondOffset);
3570  GotoIf(WordEqual(rhs, EmptyStringConstant()), &deref);
3571  Goto(&done);
3572
3573  Bind(&deref);
3574  STATIC_ASSERT(ThinString::kActualOffset == ConsString::kFirstOffset);
3575  var_string->Bind(
3576      LoadObjectField(var_string->value(), ThinString::kActualOffset));
3577  var_did_something->Bind(IntPtrConstant(1));
3578  Goto(&done);
3579
3580  Bind(&done);
3581}
3582
3583void CodeStubAssembler::MaybeDerefIndirectStrings(Variable* var_left,
3584                                                  Node* left_instance_type,
3585                                                  Variable* var_right,
3586                                                  Node* right_instance_type,
3587                                                  Label* did_something) {
3588  Variable var_did_something(this, MachineType::PointerRepresentation(),
3589                             IntPtrConstant(0));
3590  MaybeDerefIndirectString(var_left, left_instance_type, &var_did_something);
3591  MaybeDerefIndirectString(var_right, right_instance_type, &var_did_something);
3592
3593  GotoIf(WordNotEqual(var_did_something.value(), IntPtrConstant(0)),
3594         did_something);
3595  // Fall through if neither string was an indirect string.
3596}
3597
3598Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right,
3599                                   AllocationFlags flags) {
3600  Label check_right(this);
3601  Label runtime(this, Label::kDeferred);
3602  Label cons(this);
3603  Variable result(this, MachineRepresentation::kTagged);
3604  Label done(this, &result);
3605  Label done_native(this, &result);
3606  Counters* counters = isolate()->counters();
3607
3608  Node* left_length = LoadStringLength(left);
3609  GotoIf(WordNotEqual(IntPtrConstant(0), left_length), &check_right);
3610  result.Bind(right);
3611  Goto(&done_native);
3612
3613  Bind(&check_right);
3614  Node* right_length = LoadStringLength(right);
3615  GotoIf(WordNotEqual(IntPtrConstant(0), right_length), &cons);
3616  result.Bind(left);
3617  Goto(&done_native);
3618
3619  Bind(&cons);
3620  {
3621    CSA_ASSERT(this, TaggedIsSmi(left_length));
3622    CSA_ASSERT(this, TaggedIsSmi(right_length));
3623    Node* new_length = SmiAdd(left_length, right_length);
3624    GotoIf(SmiAboveOrEqual(new_length, SmiConstant(String::kMaxLength)),
3625           &runtime);
3626
3627    Variable var_left(this, MachineRepresentation::kTagged, left);
3628    Variable var_right(this, MachineRepresentation::kTagged, right);
3629    Variable* input_vars[2] = {&var_left, &var_right};
3630    Label non_cons(this, 2, input_vars);
3631    Label slow(this, Label::kDeferred);
3632    GotoIf(SmiLessThan(new_length, SmiConstant(ConsString::kMinLength)),
3633           &non_cons);
3634
3635    result.Bind(NewConsString(context, new_length, var_left.value(),
3636                              var_right.value(), flags));
3637    Goto(&done_native);
3638
3639    Bind(&non_cons);
3640
3641    Comment("Full string concatenate");
3642    Node* left_instance_type = LoadInstanceType(var_left.value());
3643    Node* right_instance_type = LoadInstanceType(var_right.value());
3644    // Compute intersection and difference of instance types.
3645
3646    Node* ored_instance_types =
3647        Word32Or(left_instance_type, right_instance_type);
3648    Node* xored_instance_types =
3649        Word32Xor(left_instance_type, right_instance_type);
3650
3651    // Check if both strings have the same encoding and both are sequential.
3652    GotoIf(Word32NotEqual(Word32And(xored_instance_types,
3653                                    Int32Constant(kStringEncodingMask)),
3654                          Int32Constant(0)),
3655           &runtime);
3656    GotoIf(Word32NotEqual(Word32And(ored_instance_types,
3657                                    Int32Constant(kStringRepresentationMask)),
3658                          Int32Constant(0)),
3659           &slow);
3660
3661    Label two_byte(this);
3662    GotoIf(Word32Equal(Word32And(ored_instance_types,
3663                                 Int32Constant(kStringEncodingMask)),
3664                       Int32Constant(kTwoByteStringTag)),
3665           &two_byte);
3666    // One-byte sequential string case
3667    Node* new_string =
3668        AllocateSeqOneByteString(context, new_length, SMI_PARAMETERS);
3669    CopyStringCharacters(var_left.value(), new_string, SmiConstant(Smi::kZero),
3670                         SmiConstant(Smi::kZero), left_length,
3671                         String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING,
3672                         SMI_PARAMETERS);
3673    CopyStringCharacters(var_right.value(), new_string, SmiConstant(Smi::kZero),
3674                         left_length, right_length, String::ONE_BYTE_ENCODING,
3675                         String::ONE_BYTE_ENCODING, SMI_PARAMETERS);
3676    result.Bind(new_string);
3677    Goto(&done_native);
3678
3679    Bind(&two_byte);
3680    {
3681      // Two-byte sequential string case
3682      new_string =
3683          AllocateSeqTwoByteString(context, new_length, SMI_PARAMETERS);
3684      CopyStringCharacters(var_left.value(), new_string,
3685                           SmiConstant(Smi::kZero), SmiConstant(Smi::kZero),
3686                           left_length, String::TWO_BYTE_ENCODING,
3687                           String::TWO_BYTE_ENCODING, SMI_PARAMETERS);
3688      CopyStringCharacters(var_right.value(), new_string,
3689                           SmiConstant(Smi::kZero), left_length, right_length,
3690                           String::TWO_BYTE_ENCODING, String::TWO_BYTE_ENCODING,
3691                           SMI_PARAMETERS);
3692      result.Bind(new_string);
3693      Goto(&done_native);
3694    }
3695
3696    Bind(&slow);
3697    {
3698      // Try to unwrap indirect strings, restart the above attempt on success.
3699      MaybeDerefIndirectStrings(&var_left, left_instance_type, &var_right,
3700                                right_instance_type, &non_cons);
3701      Goto(&runtime);
3702    }
3703  }
3704  Bind(&runtime);
3705  {
3706    result.Bind(CallRuntime(Runtime::kStringAdd, context, left, right));
3707    Goto(&done);
3708  }
3709
3710  Bind(&done_native);
3711  {
3712    IncrementCounter(counters->string_add_native(), 1);
3713    Goto(&done);
3714  }
3715
3716  Bind(&done);
3717  return result.value();
3718}
3719
3720Node* CodeStubAssembler::StringFromCodePoint(Node* codepoint,
3721                                             UnicodeEncoding encoding) {
3722  Variable var_result(this, MachineRepresentation::kTagged,
3723                      EmptyStringConstant());
3724
3725  Label if_isword16(this), if_isword32(this), return_result(this);
3726
3727  Branch(Uint32LessThan(codepoint, Int32Constant(0x10000)), &if_isword16,
3728         &if_isword32);
3729
3730  Bind(&if_isword16);
3731  {
3732    var_result.Bind(StringFromCharCode(codepoint));
3733    Goto(&return_result);
3734  }
3735
3736  Bind(&if_isword32);
3737  {
3738    switch (encoding) {
3739      case UnicodeEncoding::UTF16:
3740        break;
3741      case UnicodeEncoding::UTF32: {
3742        // Convert UTF32 to UTF16 code units, and store as a 32 bit word.
3743        Node* lead_offset = Int32Constant(0xD800 - (0x10000 >> 10));
3744
3745        // lead = (codepoint >> 10) + LEAD_OFFSET
3746        Node* lead =
3747            Int32Add(WordShr(codepoint, Int32Constant(10)), lead_offset);
3748
3749        // trail = (codepoint & 0x3FF) + 0xDC00;
3750        Node* trail = Int32Add(Word32And(codepoint, Int32Constant(0x3FF)),
3751                               Int32Constant(0xDC00));
3752
3753        // codpoint = (trail << 16) | lead;
3754        codepoint = Word32Or(WordShl(trail, Int32Constant(16)), lead);
3755        break;
3756      }
3757    }
3758
3759    Node* value = AllocateSeqTwoByteString(2);
3760    StoreNoWriteBarrier(
3761        MachineRepresentation::kWord32, value,
3762        IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag),
3763        codepoint);
3764    var_result.Bind(value);
3765    Goto(&return_result);
3766  }
3767
3768  Bind(&return_result);
3769  return var_result.value();
3770}
3771
3772Node* CodeStubAssembler::StringToNumber(Node* context, Node* input) {
3773  Label runtime(this, Label::kDeferred);
3774  Label end(this);
3775
3776  Variable var_result(this, MachineRepresentation::kTagged);
3777
3778  // Check if string has a cached array index.
3779  Node* hash = LoadNameHashField(input);
3780  Node* bit =
3781      Word32And(hash, Int32Constant(String::kContainsCachedArrayIndexMask));
3782  GotoIf(Word32NotEqual(bit, Int32Constant(0)), &runtime);
3783
3784  var_result.Bind(
3785      SmiTag(DecodeWordFromWord32<String::ArrayIndexValueBits>(hash)));
3786  Goto(&end);
3787
3788  Bind(&runtime);
3789  {
3790    var_result.Bind(CallRuntime(Runtime::kStringToNumber, context, input));
3791    Goto(&end);
3792  }
3793
3794  Bind(&end);
3795  return var_result.value();
3796}
3797
3798Node* CodeStubAssembler::NumberToString(Node* context, Node* argument) {
3799  Variable result(this, MachineRepresentation::kTagged);
3800  Label runtime(this, Label::kDeferred);
3801  Label smi(this);
3802  Label done(this, &result);
3803
3804  // Load the number string cache.
3805  Node* number_string_cache = LoadRoot(Heap::kNumberStringCacheRootIndex);
3806
3807  // Make the hash mask from the length of the number string cache. It
3808  // contains two elements (number and string) for each cache entry.
3809  // TODO(ishell): cleanup mask handling.
3810  Node* mask =
3811      BitcastTaggedToWord(LoadFixedArrayBaseLength(number_string_cache));
3812  Node* one = IntPtrConstant(1);
3813  mask = IntPtrSub(mask, one);
3814
3815  GotoIf(TaggedIsSmi(argument), &smi);
3816
3817  // Argument isn't smi, check to see if it's a heap-number.
3818  Node* map = LoadMap(argument);
3819  GotoIfNot(IsHeapNumberMap(map), &runtime);
3820
3821  // Make a hash from the two 32-bit values of the double.
3822  Node* low =
3823      LoadObjectField(argument, HeapNumber::kValueOffset, MachineType::Int32());
3824  Node* high = LoadObjectField(argument, HeapNumber::kValueOffset + kIntSize,
3825                               MachineType::Int32());
3826  Node* hash = Word32Xor(low, high);
3827  hash = ChangeInt32ToIntPtr(hash);
3828  hash = WordShl(hash, one);
3829  Node* index = WordAnd(hash, SmiUntag(BitcastWordToTagged(mask)));
3830
3831  // Cache entry's key must be a heap number
3832  Node* number_key = LoadFixedArrayElement(number_string_cache, index);
3833  GotoIf(TaggedIsSmi(number_key), &runtime);
3834  map = LoadMap(number_key);
3835  GotoIfNot(IsHeapNumberMap(map), &runtime);
3836
3837  // Cache entry's key must match the heap number value we're looking for.
3838  Node* low_compare = LoadObjectField(number_key, HeapNumber::kValueOffset,
3839                                      MachineType::Int32());
3840  Node* high_compare = LoadObjectField(
3841      number_key, HeapNumber::kValueOffset + kIntSize, MachineType::Int32());
3842  GotoIfNot(Word32Equal(low, low_compare), &runtime);
3843  GotoIfNot(Word32Equal(high, high_compare), &runtime);
3844
3845  // Heap number match, return value from cache entry.
3846  IncrementCounter(isolate()->counters()->number_to_string_native(), 1);
3847  result.Bind(LoadFixedArrayElement(number_string_cache, index, kPointerSize));
3848  Goto(&done);
3849
3850  Bind(&runtime);
3851  {
3852    // No cache entry, go to the runtime.
3853    result.Bind(CallRuntime(Runtime::kNumberToString, context, argument));
3854  }
3855  Goto(&done);
3856
3857  Bind(&smi);
3858  {
3859    // Load the smi key, make sure it matches the smi we're looking for.
3860    Node* smi_index = BitcastWordToTagged(
3861        WordAnd(WordShl(BitcastTaggedToWord(argument), one), mask));
3862    Node* smi_key = LoadFixedArrayElement(number_string_cache, smi_index, 0,
3863                                          SMI_PARAMETERS);
3864    GotoIf(WordNotEqual(smi_key, argument), &runtime);
3865
3866    // Smi match, return value from cache entry.
3867    IncrementCounter(isolate()->counters()->number_to_string_native(), 1);
3868    result.Bind(LoadFixedArrayElement(number_string_cache, smi_index,
3869                                      kPointerSize, SMI_PARAMETERS));
3870    Goto(&done);
3871  }
3872
3873  Bind(&done);
3874  return result.value();
3875}
3876
3877Node* CodeStubAssembler::ToName(Node* context, Node* value) {
3878  Label end(this);
3879  Variable var_result(this, MachineRepresentation::kTagged);
3880
3881  Label is_number(this);
3882  GotoIf(TaggedIsSmi(value), &is_number);
3883
3884  Label not_name(this);
3885  Node* value_instance_type = LoadInstanceType(value);
3886  STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE);
3887  GotoIf(Int32GreaterThan(value_instance_type, Int32Constant(LAST_NAME_TYPE)),
3888         &not_name);
3889
3890  var_result.Bind(value);
3891  Goto(&end);
3892
3893  Bind(&is_number);
3894  {
3895    Callable callable = CodeFactory::NumberToString(isolate());
3896    var_result.Bind(CallStub(callable, context, value));
3897    Goto(&end);
3898  }
3899
3900  Bind(&not_name);
3901  {
3902    GotoIf(Word32Equal(value_instance_type, Int32Constant(HEAP_NUMBER_TYPE)),
3903           &is_number);
3904
3905    Label not_oddball(this);
3906    GotoIf(Word32NotEqual(value_instance_type, Int32Constant(ODDBALL_TYPE)),
3907           &not_oddball);
3908
3909    var_result.Bind(LoadObjectField(value, Oddball::kToStringOffset));
3910    Goto(&end);
3911
3912    Bind(&not_oddball);
3913    {
3914      var_result.Bind(CallRuntime(Runtime::kToName, context, value));
3915      Goto(&end);
3916    }
3917  }
3918
3919  Bind(&end);
3920  return var_result.value();
3921}
3922
3923Node* CodeStubAssembler::NonNumberToNumber(Node* context, Node* input) {
3924  // Assert input is a HeapObject (not smi or heap number)
3925  CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(input)));
3926  CSA_ASSERT(this, Word32BinaryNot(IsHeapNumberMap(LoadMap(input))));
3927
3928  // We might need to loop once here due to ToPrimitive conversions.
3929  Variable var_input(this, MachineRepresentation::kTagged, input);
3930  Variable var_result(this, MachineRepresentation::kTagged);
3931  Label loop(this, &var_input);
3932  Label end(this);
3933  Goto(&loop);
3934  Bind(&loop);
3935  {
3936    // Load the current {input} value (known to be a HeapObject).
3937    Node* input = var_input.value();
3938
3939    // Dispatch on the {input} instance type.
3940    Node* input_instance_type = LoadInstanceType(input);
3941    Label if_inputisstring(this), if_inputisoddball(this),
3942        if_inputisreceiver(this, Label::kDeferred),
3943        if_inputisother(this, Label::kDeferred);
3944    GotoIf(IsStringInstanceType(input_instance_type), &if_inputisstring);
3945    GotoIf(Word32Equal(input_instance_type, Int32Constant(ODDBALL_TYPE)),
3946           &if_inputisoddball);
3947    Branch(IsJSReceiverInstanceType(input_instance_type), &if_inputisreceiver,
3948           &if_inputisother);
3949
3950    Bind(&if_inputisstring);
3951    {
3952      // The {input} is a String, use the fast stub to convert it to a Number.
3953      var_result.Bind(StringToNumber(context, input));
3954      Goto(&end);
3955    }
3956
3957    Bind(&if_inputisoddball);
3958    {
3959      // The {input} is an Oddball, we just need to load the Number value of it.
3960      var_result.Bind(LoadObjectField(input, Oddball::kToNumberOffset));
3961      Goto(&end);
3962    }
3963
3964    Bind(&if_inputisreceiver);
3965    {
3966      // The {input} is a JSReceiver, we need to convert it to a Primitive first
3967      // using the ToPrimitive type conversion, preferably yielding a Number.
3968      Callable callable = CodeFactory::NonPrimitiveToPrimitive(
3969          isolate(), ToPrimitiveHint::kNumber);
3970      Node* result = CallStub(callable, context, input);
3971
3972      // Check if the {result} is already a Number.
3973      Label if_resultisnumber(this), if_resultisnotnumber(this);
3974      GotoIf(TaggedIsSmi(result), &if_resultisnumber);
3975      Node* result_map = LoadMap(result);
3976      Branch(IsHeapNumberMap(result_map), &if_resultisnumber,
3977             &if_resultisnotnumber);
3978
3979      Bind(&if_resultisnumber);
3980      {
3981        // The ToPrimitive conversion already gave us a Number, so we're done.
3982        var_result.Bind(result);
3983        Goto(&end);
3984      }
3985
3986      Bind(&if_resultisnotnumber);
3987      {
3988        // We now have a Primitive {result}, but it's not yet a Number.
3989        var_input.Bind(result);
3990        Goto(&loop);
3991      }
3992    }
3993
3994    Bind(&if_inputisother);
3995    {
3996      // The {input} is something else (e.g. Symbol), let the runtime figure
3997      // out the correct exception.
3998      // Note: We cannot tail call to the runtime here, as js-to-wasm
3999      // trampolines also use this code currently, and they declare all
4000      // outgoing parameters as untagged, while we would push a tagged
4001      // object here.
4002      var_result.Bind(CallRuntime(Runtime::kToNumber, context, input));
4003      Goto(&end);
4004    }
4005  }
4006
4007  Bind(&end);
4008  return var_result.value();
4009}
4010
4011Node* CodeStubAssembler::ToNumber(Node* context, Node* input) {
4012  Variable var_result(this, MachineRepresentation::kTagged);
4013  Label end(this);
4014
4015  Label not_smi(this, Label::kDeferred);
4016  GotoIfNot(TaggedIsSmi(input), &not_smi);
4017  var_result.Bind(input);
4018  Goto(&end);
4019
4020  Bind(&not_smi);
4021  {
4022    Label not_heap_number(this, Label::kDeferred);
4023    Node* input_map = LoadMap(input);
4024    GotoIfNot(IsHeapNumberMap(input_map), &not_heap_number);
4025
4026    var_result.Bind(input);
4027    Goto(&end);
4028
4029    Bind(&not_heap_number);
4030    {
4031      var_result.Bind(NonNumberToNumber(context, input));
4032      Goto(&end);
4033    }
4034  }
4035
4036  Bind(&end);
4037  return var_result.value();
4038}
4039
4040Node* CodeStubAssembler::ToUint32(Node* context, Node* input) {
4041  Node* const float_zero = Float64Constant(0.0);
4042  Node* const float_two_32 = Float64Constant(static_cast<double>(1ULL << 32));
4043
4044  Label out(this);
4045
4046  Variable var_result(this, MachineRepresentation::kTagged, input);
4047
4048  // Early exit for positive smis.
4049  {
4050    // TODO(jgruber): This branch and the recheck below can be removed once we
4051    // have a ToNumber with multiple exits.
4052    Label next(this, Label::kDeferred);
4053    Branch(TaggedIsPositiveSmi(input), &out, &next);
4054    Bind(&next);
4055  }
4056
4057  Node* const number = ToNumber(context, input);
4058  var_result.Bind(number);
4059
4060  // Perhaps we have a positive smi now.
4061  {
4062    Label next(this, Label::kDeferred);
4063    Branch(TaggedIsPositiveSmi(number), &out, &next);
4064    Bind(&next);
4065  }
4066
4067  Label if_isnegativesmi(this), if_isheapnumber(this);
4068  Branch(TaggedIsSmi(number), &if_isnegativesmi, &if_isheapnumber);
4069
4070  Bind(&if_isnegativesmi);
4071  {
4072    // floor({input}) mod 2^32 === {input} + 2^32.
4073    Node* const float_number = SmiToFloat64(number);
4074    Node* const float_result = Float64Add(float_number, float_two_32);
4075    Node* const result = ChangeFloat64ToTagged(float_result);
4076    var_result.Bind(result);
4077    Goto(&out);
4078  }
4079
4080  Bind(&if_isheapnumber);
4081  {
4082    Label return_zero(this);
4083    Node* const value = LoadHeapNumberValue(number);
4084
4085    {
4086      // +-0.
4087      Label next(this);
4088      Branch(Float64Equal(value, float_zero), &return_zero, &next);
4089      Bind(&next);
4090    }
4091
4092    {
4093      // NaN.
4094      Label next(this);
4095      Branch(Float64Equal(value, value), &next, &return_zero);
4096      Bind(&next);
4097    }
4098
4099    {
4100      // +Infinity.
4101      Label next(this);
4102      Node* const positive_infinity =
4103          Float64Constant(std::numeric_limits<double>::infinity());
4104      Branch(Float64Equal(value, positive_infinity), &return_zero, &next);
4105      Bind(&next);
4106    }
4107
4108    {
4109      // -Infinity.
4110      Label next(this);
4111      Node* const negative_infinity =
4112          Float64Constant(-1.0 * std::numeric_limits<double>::infinity());
4113      Branch(Float64Equal(value, negative_infinity), &return_zero, &next);
4114      Bind(&next);
4115    }
4116
4117    // Return floor({input}) mod 2^32 (assuming mod semantics that always return
4118    // positive results).
4119    {
4120      Node* x = Float64Floor(value);
4121      x = Float64Mod(x, float_two_32);
4122      x = Float64Add(x, float_two_32);
4123      x = Float64Mod(x, float_two_32);
4124
4125      Node* const result = ChangeFloat64ToTagged(x);
4126      var_result.Bind(result);
4127      Goto(&out);
4128    }
4129
4130    Bind(&return_zero);
4131    {
4132      var_result.Bind(SmiConstant(Smi::kZero));
4133      Goto(&out);
4134    }
4135  }
4136
4137  Bind(&out);
4138  return var_result.value();
4139}
4140
4141Node* CodeStubAssembler::ToString(Node* context, Node* input) {
4142  Label is_number(this);
4143  Label runtime(this, Label::kDeferred);
4144  Variable result(this, MachineRepresentation::kTagged);
4145  Label done(this, &result);
4146
4147  GotoIf(TaggedIsSmi(input), &is_number);
4148
4149  Node* input_map = LoadMap(input);
4150  Node* input_instance_type = LoadMapInstanceType(input_map);
4151
4152  result.Bind(input);
4153  GotoIf(IsStringInstanceType(input_instance_type), &done);
4154
4155  Label not_heap_number(this);
4156  Branch(IsHeapNumberMap(input_map), &is_number, &not_heap_number);
4157
4158  Bind(&is_number);
4159  result.Bind(NumberToString(context, input));
4160  Goto(&done);
4161
4162  Bind(&not_heap_number);
4163  {
4164    GotoIf(Word32NotEqual(input_instance_type, Int32Constant(ODDBALL_TYPE)),
4165           &runtime);
4166    result.Bind(LoadObjectField(input, Oddball::kToStringOffset));
4167    Goto(&done);
4168  }
4169
4170  Bind(&runtime);
4171  {
4172    result.Bind(CallRuntime(Runtime::kToString, context, input));
4173    Goto(&done);
4174  }
4175
4176  Bind(&done);
4177  return result.value();
4178}
4179
4180Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) {
4181  Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this);
4182  Variable result(this, MachineRepresentation::kTagged);
4183  Label done(this, &result);
4184
4185  BranchIfJSReceiver(input, &if_isreceiver, &if_isnotreceiver);
4186
4187  Bind(&if_isreceiver);
4188  {
4189    // Convert {input} to a primitive first passing Number hint.
4190    Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate());
4191    result.Bind(CallStub(callable, context, input));
4192    Goto(&done);
4193  }
4194
4195  Bind(&if_isnotreceiver);
4196  {
4197    result.Bind(input);
4198    Goto(&done);
4199  }
4200
4201  Bind(&done);
4202  return result.value();
4203}
4204
4205Node* CodeStubAssembler::ToInteger(Node* context, Node* input,
4206                                   ToIntegerTruncationMode mode) {
4207  // We might need to loop once for ToNumber conversion.
4208  Variable var_arg(this, MachineRepresentation::kTagged, input);
4209  Label loop(this, &var_arg), out(this);
4210  Goto(&loop);
4211  Bind(&loop);
4212  {
4213    // Shared entry points.
4214    Label return_zero(this, Label::kDeferred);
4215
4216    // Load the current {arg} value.
4217    Node* arg = var_arg.value();
4218
4219    // Check if {arg} is a Smi.
4220    GotoIf(TaggedIsSmi(arg), &out);
4221
4222    // Check if {arg} is a HeapNumber.
4223    Label if_argisheapnumber(this),
4224        if_argisnotheapnumber(this, Label::kDeferred);
4225    Branch(IsHeapNumberMap(LoadMap(arg)), &if_argisheapnumber,
4226           &if_argisnotheapnumber);
4227
4228    Bind(&if_argisheapnumber);
4229    {
4230      // Load the floating-point value of {arg}.
4231      Node* arg_value = LoadHeapNumberValue(arg);
4232
4233      // Check if {arg} is NaN.
4234      GotoIfNot(Float64Equal(arg_value, arg_value), &return_zero);
4235
4236      // Truncate {arg} towards zero.
4237      Node* value = Float64Trunc(arg_value);
4238
4239      if (mode == kTruncateMinusZero) {
4240        // Truncate -0.0 to 0.
4241        GotoIf(Float64Equal(value, Float64Constant(0.0)), &return_zero);
4242      }
4243
4244      var_arg.Bind(ChangeFloat64ToTagged(value));
4245      Goto(&out);
4246    }
4247
4248    Bind(&if_argisnotheapnumber);
4249    {
4250      // Need to convert {arg} to a Number first.
4251      Callable callable = CodeFactory::NonNumberToNumber(isolate());
4252      var_arg.Bind(CallStub(callable, context, arg));
4253      Goto(&loop);
4254    }
4255
4256    Bind(&return_zero);
4257    var_arg.Bind(SmiConstant(Smi::kZero));
4258    Goto(&out);
4259  }
4260
4261  Bind(&out);
4262  return var_arg.value();
4263}
4264
4265Node* CodeStubAssembler::DecodeWord32(Node* word32, uint32_t shift,
4266                                      uint32_t mask) {
4267  return Word32Shr(Word32And(word32, Int32Constant(mask)),
4268                   static_cast<int>(shift));
4269}
4270
4271Node* CodeStubAssembler::DecodeWord(Node* word, uint32_t shift, uint32_t mask) {
4272  return WordShr(WordAnd(word, IntPtrConstant(mask)), static_cast<int>(shift));
4273}
4274
4275void CodeStubAssembler::SetCounter(StatsCounter* counter, int value) {
4276  if (FLAG_native_code_counters && counter->Enabled()) {
4277    Node* counter_address = ExternalConstant(ExternalReference(counter));
4278    StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address,
4279                        Int32Constant(value));
4280  }
4281}
4282
4283void CodeStubAssembler::IncrementCounter(StatsCounter* counter, int delta) {
4284  DCHECK(delta > 0);
4285  if (FLAG_native_code_counters && counter->Enabled()) {
4286    Node* counter_address = ExternalConstant(ExternalReference(counter));
4287    Node* value = Load(MachineType::Int32(), counter_address);
4288    value = Int32Add(value, Int32Constant(delta));
4289    StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address, value);
4290  }
4291}
4292
4293void CodeStubAssembler::DecrementCounter(StatsCounter* counter, int delta) {
4294  DCHECK(delta > 0);
4295  if (FLAG_native_code_counters && counter->Enabled()) {
4296    Node* counter_address = ExternalConstant(ExternalReference(counter));
4297    Node* value = Load(MachineType::Int32(), counter_address);
4298    value = Int32Sub(value, Int32Constant(delta));
4299    StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address, value);
4300  }
4301}
4302
4303void CodeStubAssembler::Increment(Variable& variable, int value,
4304                                  ParameterMode mode) {
4305  DCHECK_IMPLIES(mode == INTPTR_PARAMETERS,
4306                 variable.rep() == MachineType::PointerRepresentation());
4307  DCHECK_IMPLIES(mode == SMI_PARAMETERS,
4308                 variable.rep() == MachineRepresentation::kTagged ||
4309                     variable.rep() == MachineRepresentation::kTaggedSigned);
4310  variable.Bind(
4311      IntPtrOrSmiAdd(variable.value(), IntPtrOrSmiConstant(value, mode), mode));
4312}
4313
4314void CodeStubAssembler::Use(Label* label) {
4315  GotoIf(Word32Equal(Int32Constant(0), Int32Constant(1)), label);
4316}
4317
4318void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex,
4319                                  Variable* var_index, Label* if_keyisunique,
4320                                  Variable* var_unique, Label* if_bailout) {
4321  DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep());
4322  DCHECK_EQ(MachineRepresentation::kTagged, var_unique->rep());
4323  Comment("TryToName");
4324
4325  Label if_hascachedindex(this), if_keyisnotindex(this), if_thinstring(this);
4326  // Handle Smi and HeapNumber keys.
4327  var_index->Bind(TryToIntptr(key, &if_keyisnotindex));
4328  Goto(if_keyisindex);
4329
4330  Bind(&if_keyisnotindex);
4331  Node* key_map = LoadMap(key);
4332  var_unique->Bind(key);
4333  // Symbols are unique.
4334  GotoIf(IsSymbolMap(key_map), if_keyisunique);
4335  Node* key_instance_type = LoadMapInstanceType(key_map);
4336  // Miss if |key| is not a String.
4337  STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE);
4338  GotoIfNot(IsStringInstanceType(key_instance_type), if_bailout);
4339  // |key| is a String. Check if it has a cached array index.
4340  Node* hash = LoadNameHashField(key);
4341  Node* contains_index =
4342      Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask));
4343  GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex);
4344  // No cached array index. If the string knows that it contains an index,
4345  // then it must be an uncacheable index. Handle this case in the runtime.
4346  Node* not_an_index =
4347      Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask));
4348  GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout);
4349  // Check if we have a ThinString.
4350  GotoIf(Word32Equal(key_instance_type, Int32Constant(THIN_STRING_TYPE)),
4351         &if_thinstring);
4352  GotoIf(
4353      Word32Equal(key_instance_type, Int32Constant(THIN_ONE_BYTE_STRING_TYPE)),
4354      &if_thinstring);
4355  // Finally, check if |key| is internalized.
4356  STATIC_ASSERT(kNotInternalizedTag != 0);
4357  Node* not_internalized =
4358      Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask));
4359  GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), if_bailout);
4360  Goto(if_keyisunique);
4361
4362  Bind(&if_thinstring);
4363  var_unique->Bind(LoadObjectField(key, ThinString::kActualOffset));
4364  Goto(if_keyisunique);
4365
4366  Bind(&if_hascachedindex);
4367  var_index->Bind(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash));
4368  Goto(if_keyisindex);
4369}
4370
4371template <typename Dictionary>
4372Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) {
4373  Node* entry_index = IntPtrMul(entry, IntPtrConstant(Dictionary::kEntrySize));
4374  return IntPtrAdd(entry_index, IntPtrConstant(Dictionary::kElementsStartIndex +
4375                                               field_index));
4376}
4377
4378template Node* CodeStubAssembler::EntryToIndex<NameDictionary>(Node*, int);
4379template Node* CodeStubAssembler::EntryToIndex<GlobalDictionary>(Node*, int);
4380template Node* CodeStubAssembler::EntryToIndex<SeededNumberDictionary>(Node*,
4381                                                                       int);
4382
4383Node* CodeStubAssembler::HashTableComputeCapacity(Node* at_least_space_for) {
4384  Node* capacity = IntPtrRoundUpToPowerOfTwo32(
4385      WordShl(at_least_space_for, IntPtrConstant(1)));
4386  return IntPtrMax(capacity, IntPtrConstant(HashTableBase::kMinCapacity));
4387}
4388
4389Node* CodeStubAssembler::IntPtrMax(Node* left, Node* right) {
4390  return SelectConstant(IntPtrGreaterThanOrEqual(left, right), left, right,
4391                        MachineType::PointerRepresentation());
4392}
4393
4394Node* CodeStubAssembler::IntPtrMin(Node* left, Node* right) {
4395  return SelectConstant(IntPtrLessThanOrEqual(left, right), left, right,
4396                        MachineType::PointerRepresentation());
4397}
4398
4399template <class Dictionary>
4400Node* CodeStubAssembler::GetNumberOfElements(Node* dictionary) {
4401  return LoadFixedArrayElement(dictionary, Dictionary::kNumberOfElementsIndex);
4402}
4403
4404template <class Dictionary>
4405void CodeStubAssembler::SetNumberOfElements(Node* dictionary,
4406                                            Node* num_elements_smi) {
4407  StoreFixedArrayElement(dictionary, Dictionary::kNumberOfElementsIndex,
4408                         num_elements_smi, SKIP_WRITE_BARRIER);
4409}
4410
4411template <class Dictionary>
4412Node* CodeStubAssembler::GetNumberOfDeletedElements(Node* dictionary) {
4413  return LoadFixedArrayElement(dictionary,
4414                               Dictionary::kNumberOfDeletedElementsIndex);
4415}
4416
4417template <class Dictionary>
4418Node* CodeStubAssembler::GetCapacity(Node* dictionary) {
4419  return LoadFixedArrayElement(dictionary, Dictionary::kCapacityIndex);
4420}
4421
4422template <class Dictionary>
4423Node* CodeStubAssembler::GetNextEnumerationIndex(Node* dictionary) {
4424  return LoadFixedArrayElement(dictionary,
4425                               Dictionary::kNextEnumerationIndexIndex);
4426}
4427
4428template <class Dictionary>
4429void CodeStubAssembler::SetNextEnumerationIndex(Node* dictionary,
4430                                                Node* next_enum_index_smi) {
4431  StoreFixedArrayElement(dictionary, Dictionary::kNextEnumerationIndexIndex,
4432                         next_enum_index_smi, SKIP_WRITE_BARRIER);
4433}
4434
4435template <typename Dictionary>
4436void CodeStubAssembler::NameDictionaryLookup(Node* dictionary,
4437                                             Node* unique_name, Label* if_found,
4438                                             Variable* var_name_index,
4439                                             Label* if_not_found,
4440                                             int inlined_probes,
4441                                             LookupMode mode) {
4442  CSA_ASSERT(this, IsDictionary(dictionary));
4443  DCHECK_EQ(MachineType::PointerRepresentation(), var_name_index->rep());
4444  DCHECK_IMPLIES(mode == kFindInsertionIndex,
4445                 inlined_probes == 0 && if_found == nullptr);
4446  Comment("NameDictionaryLookup");
4447
4448  Node* capacity = SmiUntag(GetCapacity<Dictionary>(dictionary));
4449  Node* mask = IntPtrSub(capacity, IntPtrConstant(1));
4450  Node* hash = ChangeUint32ToWord(LoadNameHash(unique_name));
4451
4452  // See Dictionary::FirstProbe().
4453  Node* count = IntPtrConstant(0);
4454  Node* entry = WordAnd(hash, mask);
4455
4456  for (int i = 0; i < inlined_probes; i++) {
4457    Node* index = EntryToIndex<Dictionary>(entry);
4458    var_name_index->Bind(index);
4459
4460    Node* current = LoadFixedArrayElement(dictionary, index);
4461    GotoIf(WordEqual(current, unique_name), if_found);
4462
4463    // See Dictionary::NextProbe().
4464    count = IntPtrConstant(i + 1);
4465    entry = WordAnd(IntPtrAdd(entry, count), mask);
4466  }
4467  if (mode == kFindInsertionIndex) {
4468    // Appease the variable merging algorithm for "Goto(&loop)" below.
4469    var_name_index->Bind(IntPtrConstant(0));
4470  }
4471
4472  Node* undefined = UndefinedConstant();
4473  Node* the_hole = mode == kFindExisting ? nullptr : TheHoleConstant();
4474
4475  Variable var_count(this, MachineType::PointerRepresentation(), count);
4476  Variable var_entry(this, MachineType::PointerRepresentation(), entry);
4477  Variable* loop_vars[] = {&var_count, &var_entry, var_name_index};
4478  Label loop(this, 3, loop_vars);
4479  Goto(&loop);
4480  Bind(&loop);
4481  {
4482    Node* entry = var_entry.value();
4483
4484    Node* index = EntryToIndex<Dictionary>(entry);
4485    var_name_index->Bind(index);
4486
4487    Node* current = LoadFixedArrayElement(dictionary, index);
4488    GotoIf(WordEqual(current, undefined), if_not_found);
4489    if (mode == kFindExisting) {
4490      GotoIf(WordEqual(current, unique_name), if_found);
4491    } else {
4492      DCHECK_EQ(kFindInsertionIndex, mode);
4493      GotoIf(WordEqual(current, the_hole), if_not_found);
4494    }
4495
4496    // See Dictionary::NextProbe().
4497    Increment(var_count);
4498    entry = WordAnd(IntPtrAdd(entry, var_count.value()), mask);
4499
4500    var_entry.Bind(entry);
4501    Goto(&loop);
4502  }
4503}
4504
4505// Instantiate template methods to workaround GCC compilation issue.
4506template void CodeStubAssembler::NameDictionaryLookup<NameDictionary>(
4507    Node*, Node*, Label*, Variable*, Label*, int, LookupMode);
4508template void CodeStubAssembler::NameDictionaryLookup<GlobalDictionary>(
4509    Node*, Node*, Label*, Variable*, Label*, int, LookupMode);
4510
4511Node* CodeStubAssembler::ComputeIntegerHash(Node* key, Node* seed) {
4512  // See v8::internal::ComputeIntegerHash()
4513  Node* hash = TruncateWordToWord32(key);
4514  hash = Word32Xor(hash, seed);
4515  hash = Int32Add(Word32Xor(hash, Int32Constant(0xffffffff)),
4516                  Word32Shl(hash, Int32Constant(15)));
4517  hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(12)));
4518  hash = Int32Add(hash, Word32Shl(hash, Int32Constant(2)));
4519  hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(4)));
4520  hash = Int32Mul(hash, Int32Constant(2057));
4521  hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(16)));
4522  return Word32And(hash, Int32Constant(0x3fffffff));
4523}
4524
4525template <typename Dictionary>
4526void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary,
4527                                               Node* intptr_index,
4528                                               Label* if_found,
4529                                               Variable* var_entry,
4530                                               Label* if_not_found) {
4531  CSA_ASSERT(this, IsDictionary(dictionary));
4532  DCHECK_EQ(MachineType::PointerRepresentation(), var_entry->rep());
4533  Comment("NumberDictionaryLookup");
4534
4535  Node* capacity = SmiUntag(GetCapacity<Dictionary>(dictionary));
4536  Node* mask = IntPtrSub(capacity, IntPtrConstant(1));
4537
4538  Node* int32_seed;
4539  if (Dictionary::ShapeT::UsesSeed) {
4540    int32_seed = HashSeed();
4541  } else {
4542    int32_seed = Int32Constant(kZeroHashSeed);
4543  }
4544  Node* hash = ChangeUint32ToWord(ComputeIntegerHash(intptr_index, int32_seed));
4545  Node* key_as_float64 = RoundIntPtrToFloat64(intptr_index);
4546
4547  // See Dictionary::FirstProbe().
4548  Node* count = IntPtrConstant(0);
4549  Node* entry = WordAnd(hash, mask);
4550
4551  Node* undefined = UndefinedConstant();
4552  Node* the_hole = TheHoleConstant();
4553
4554  Variable var_count(this, MachineType::PointerRepresentation(), count);
4555  Variable* loop_vars[] = {&var_count, var_entry};
4556  Label loop(this, 2, loop_vars);
4557  var_entry->Bind(entry);
4558  Goto(&loop);
4559  Bind(&loop);
4560  {
4561    Node* entry = var_entry->value();
4562
4563    Node* index = EntryToIndex<Dictionary>(entry);
4564    Node* current = LoadFixedArrayElement(dictionary, index);
4565    GotoIf(WordEqual(current, undefined), if_not_found);
4566    Label next_probe(this);
4567    {
4568      Label if_currentissmi(this), if_currentisnotsmi(this);
4569      Branch(TaggedIsSmi(current), &if_currentissmi, &if_currentisnotsmi);
4570      Bind(&if_currentissmi);
4571      {
4572        Node* current_value = SmiUntag(current);
4573        Branch(WordEqual(current_value, intptr_index), if_found, &next_probe);
4574      }
4575      Bind(&if_currentisnotsmi);
4576      {
4577        GotoIf(WordEqual(current, the_hole), &next_probe);
4578        // Current must be the Number.
4579        Node* current_value = LoadHeapNumberValue(current);
4580        Branch(Float64Equal(current_value, key_as_float64), if_found,
4581               &next_probe);
4582      }
4583    }
4584
4585    Bind(&next_probe);
4586    // See Dictionary::NextProbe().
4587    Increment(var_count);
4588    entry = WordAnd(IntPtrAdd(entry, var_count.value()), mask);
4589
4590    var_entry->Bind(entry);
4591    Goto(&loop);
4592  }
4593}
4594
4595template <class Dictionary>
4596void CodeStubAssembler::FindInsertionEntry(Node* dictionary, Node* key,
4597                                           Variable* var_key_index) {
4598  UNREACHABLE();
4599}
4600
4601template <>
4602void CodeStubAssembler::FindInsertionEntry<NameDictionary>(
4603    Node* dictionary, Node* key, Variable* var_key_index) {
4604  Label done(this);
4605  NameDictionaryLookup<NameDictionary>(dictionary, key, nullptr, var_key_index,
4606                                       &done, 0, kFindInsertionIndex);
4607  Bind(&done);
4608}
4609
4610template <class Dictionary>
4611void CodeStubAssembler::InsertEntry(Node* dictionary, Node* key, Node* value,
4612                                    Node* index, Node* enum_index) {
4613  UNREACHABLE();  // Use specializations instead.
4614}
4615
4616template <>
4617void CodeStubAssembler::InsertEntry<NameDictionary>(Node* dictionary,
4618                                                    Node* name, Node* value,
4619                                                    Node* index,
4620                                                    Node* enum_index) {
4621  // Store name and value.
4622  StoreFixedArrayElement(dictionary, index, name);
4623  StoreValueByKeyIndex<NameDictionary>(dictionary, index, value);
4624
4625  // Prepare details of the new property.
4626  const int kInitialIndex = 0;
4627  PropertyDetails d(kData, NONE, kInitialIndex, PropertyCellType::kNoCell);
4628  enum_index =
4629      SmiShl(enum_index, PropertyDetails::DictionaryStorageField::kShift);
4630  STATIC_ASSERT(kInitialIndex == 0);
4631  Variable var_details(this, MachineRepresentation::kTaggedSigned,
4632                       SmiOr(SmiConstant(d.AsSmi()), enum_index));
4633
4634  // Private names must be marked non-enumerable.
4635  Label not_private(this, &var_details);
4636  GotoIfNot(IsSymbolMap(LoadMap(name)), &not_private);
4637  Node* flags = SmiToWord32(LoadObjectField(name, Symbol::kFlagsOffset));
4638  const int kPrivateMask = 1 << Symbol::kPrivateBit;
4639  GotoIfNot(IsSetWord32(flags, kPrivateMask), &not_private);
4640  Node* dont_enum =
4641      SmiShl(SmiConstant(DONT_ENUM), PropertyDetails::AttributesField::kShift);
4642  var_details.Bind(SmiOr(var_details.value(), dont_enum));
4643  Goto(&not_private);
4644  Bind(&not_private);
4645
4646  // Finally, store the details.
4647  StoreDetailsByKeyIndex<NameDictionary>(dictionary, index,
4648                                         var_details.value());
4649}
4650
4651template <>
4652void CodeStubAssembler::InsertEntry<GlobalDictionary>(Node* dictionary,
4653                                                      Node* key, Node* value,
4654                                                      Node* index,
4655                                                      Node* enum_index) {
4656  UNIMPLEMENTED();
4657}
4658
4659template <class Dictionary>
4660void CodeStubAssembler::Add(Node* dictionary, Node* key, Node* value,
4661                            Label* bailout) {
4662  Node* capacity = GetCapacity<Dictionary>(dictionary);
4663  Node* nof = GetNumberOfElements<Dictionary>(dictionary);
4664  Node* new_nof = SmiAdd(nof, SmiConstant(1));
4665  // Require 33% to still be free after adding additional_elements.
4666  // Computing "x + (x >> 1)" on a Smi x does not return a valid Smi!
4667  // But that's OK here because it's only used for a comparison.
4668  Node* required_capacity_pseudo_smi = SmiAdd(new_nof, SmiShr(new_nof, 1));
4669  GotoIf(SmiBelow(capacity, required_capacity_pseudo_smi), bailout);
4670  // Require rehashing if more than 50% of free elements are deleted elements.
4671  Node* deleted = GetNumberOfDeletedElements<Dictionary>(dictionary);
4672  CSA_ASSERT(this, SmiAbove(capacity, new_nof));
4673  Node* half_of_free_elements = SmiShr(SmiSub(capacity, new_nof), 1);
4674  GotoIf(SmiAbove(deleted, half_of_free_elements), bailout);
4675  Node* enum_index = nullptr;
4676  if (Dictionary::kIsEnumerable) {
4677    enum_index = GetNextEnumerationIndex<Dictionary>(dictionary);
4678    Node* new_enum_index = SmiAdd(enum_index, SmiConstant(1));
4679    Node* max_enum_index =
4680        SmiConstant(PropertyDetails::DictionaryStorageField::kMax);
4681    GotoIf(SmiAbove(new_enum_index, max_enum_index), bailout);
4682
4683    // No more bailouts after this point.
4684    // Operations from here on can have side effects.
4685
4686    SetNextEnumerationIndex<Dictionary>(dictionary, new_enum_index);
4687  } else {
4688    USE(enum_index);
4689  }
4690  SetNumberOfElements<Dictionary>(dictionary, new_nof);
4691
4692  Variable var_key_index(this, MachineType::PointerRepresentation());
4693  FindInsertionEntry<Dictionary>(dictionary, key, &var_key_index);
4694  InsertEntry<Dictionary>(dictionary, key, value, var_key_index.value(),
4695                          enum_index);
4696}
4697
4698template void CodeStubAssembler::Add<NameDictionary>(Node*, Node*, Node*,
4699                                                     Label*);
4700
4701void CodeStubAssembler::DescriptorLookupLinear(Node* unique_name,
4702                                               Node* descriptors, Node* nof,
4703                                               Label* if_found,
4704                                               Variable* var_name_index,
4705                                               Label* if_not_found) {
4706  Comment("DescriptorLookupLinear");
4707  Node* first_inclusive = IntPtrConstant(DescriptorArray::ToKeyIndex(0));
4708  Node* factor = IntPtrConstant(DescriptorArray::kEntrySize);
4709  Node* last_exclusive = IntPtrAdd(first_inclusive, IntPtrMul(nof, factor));
4710
4711  BuildFastLoop(last_exclusive, first_inclusive,
4712                [this, descriptors, unique_name, if_found,
4713                 var_name_index](Node* name_index) {
4714                  Node* candidate_name =
4715                      LoadFixedArrayElement(descriptors, name_index);
4716                  var_name_index->Bind(name_index);
4717                  GotoIf(WordEqual(candidate_name, unique_name), if_found);
4718                },
4719                -DescriptorArray::kEntrySize, INTPTR_PARAMETERS,
4720                IndexAdvanceMode::kPre);
4721  Goto(if_not_found);
4722}
4723
4724Node* CodeStubAssembler::DescriptorArrayNumberOfEntries(Node* descriptors) {
4725  return LoadAndUntagToWord32FixedArrayElement(
4726      descriptors, IntPtrConstant(DescriptorArray::kDescriptorLengthIndex));
4727}
4728
4729namespace {
4730
4731Node* DescriptorNumberToIndex(CodeStubAssembler* a, Node* descriptor_number) {
4732  Node* descriptor_size = a->Int32Constant(DescriptorArray::kEntrySize);
4733  Node* index = a->Int32Mul(descriptor_number, descriptor_size);
4734  return a->ChangeInt32ToIntPtr(index);
4735}
4736
4737}  // namespace
4738
4739Node* CodeStubAssembler::DescriptorArrayToKeyIndex(Node* descriptor_number) {
4740  return IntPtrAdd(IntPtrConstant(DescriptorArray::ToKeyIndex(0)),
4741                   DescriptorNumberToIndex(this, descriptor_number));
4742}
4743
4744Node* CodeStubAssembler::DescriptorArrayGetSortedKeyIndex(
4745    Node* descriptors, Node* descriptor_number) {
4746  const int details_offset = DescriptorArray::ToDetailsIndex(0) * kPointerSize;
4747  Node* details = LoadAndUntagToWord32FixedArrayElement(
4748      descriptors, DescriptorNumberToIndex(this, descriptor_number),
4749      details_offset);
4750  return DecodeWord32<PropertyDetails::DescriptorPointer>(details);
4751}
4752
4753Node* CodeStubAssembler::DescriptorArrayGetKey(Node* descriptors,
4754                                               Node* descriptor_number) {
4755  const int key_offset = DescriptorArray::ToKeyIndex(0) * kPointerSize;
4756  return LoadFixedArrayElement(descriptors,
4757                               DescriptorNumberToIndex(this, descriptor_number),
4758                               key_offset);
4759}
4760
4761void CodeStubAssembler::DescriptorLookupBinary(Node* unique_name,
4762                                               Node* descriptors, Node* nof,
4763                                               Label* if_found,
4764                                               Variable* var_name_index,
4765                                               Label* if_not_found) {
4766  Comment("DescriptorLookupBinary");
4767  Variable var_low(this, MachineRepresentation::kWord32, Int32Constant(0));
4768  Node* limit =
4769      Int32Sub(DescriptorArrayNumberOfEntries(descriptors), Int32Constant(1));
4770  Variable var_high(this, MachineRepresentation::kWord32, limit);
4771  Node* hash = LoadNameHashField(unique_name);
4772  CSA_ASSERT(this, Word32NotEqual(hash, Int32Constant(0)));
4773
4774  // Assume non-empty array.
4775  CSA_ASSERT(this, Uint32LessThanOrEqual(var_low.value(), var_high.value()));
4776
4777  Variable* loop_vars[] = {&var_high, &var_low};
4778  Label binary_loop(this, 2, loop_vars);
4779  Goto(&binary_loop);
4780  Bind(&binary_loop);
4781  {
4782    // mid = low + (high - low) / 2 (to avoid overflow in "(low + high) / 2").
4783    Node* mid =
4784        Int32Add(var_low.value(),
4785                 Word32Shr(Int32Sub(var_high.value(), var_low.value()), 1));
4786    // mid_name = descriptors->GetSortedKey(mid).
4787    Node* sorted_key_index = DescriptorArrayGetSortedKeyIndex(descriptors, mid);
4788    Node* mid_name = DescriptorArrayGetKey(descriptors, sorted_key_index);
4789
4790    Node* mid_hash = LoadNameHashField(mid_name);
4791
4792    Label mid_greater(this), mid_less(this), merge(this);
4793    Branch(Uint32GreaterThanOrEqual(mid_hash, hash), &mid_greater, &mid_less);
4794    Bind(&mid_greater);
4795    {
4796      var_high.Bind(mid);
4797      Goto(&merge);
4798    }
4799    Bind(&mid_less);
4800    {
4801      var_low.Bind(Int32Add(mid, Int32Constant(1)));
4802      Goto(&merge);
4803    }
4804    Bind(&merge);
4805    GotoIf(Word32NotEqual(var_low.value(), var_high.value()), &binary_loop);
4806  }
4807
4808  Label scan_loop(this, &var_low);
4809  Goto(&scan_loop);
4810  Bind(&scan_loop);
4811  {
4812    GotoIf(Int32GreaterThan(var_low.value(), limit), if_not_found);
4813
4814    Node* sort_index =
4815        DescriptorArrayGetSortedKeyIndex(descriptors, var_low.value());
4816    Node* current_name = DescriptorArrayGetKey(descriptors, sort_index);
4817    Node* current_hash = LoadNameHashField(current_name);
4818    GotoIf(Word32NotEqual(current_hash, hash), if_not_found);
4819    Label next(this);
4820    GotoIf(WordNotEqual(current_name, unique_name), &next);
4821    GotoIf(Int32GreaterThanOrEqual(sort_index, nof), if_not_found);
4822    var_name_index->Bind(DescriptorArrayToKeyIndex(sort_index));
4823    Goto(if_found);
4824
4825    Bind(&next);
4826    var_low.Bind(Int32Add(var_low.value(), Int32Constant(1)));
4827    Goto(&scan_loop);
4828  }
4829}
4830
4831void CodeStubAssembler::DescriptorLookup(Node* unique_name, Node* descriptors,
4832                                         Node* bitfield3, Label* if_found,
4833                                         Variable* var_name_index,
4834                                         Label* if_not_found) {
4835  Comment("DescriptorArrayLookup");
4836  Node* nof = DecodeWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3);
4837  GotoIf(Word32Equal(nof, Int32Constant(0)), if_not_found);
4838  Label linear_search(this), binary_search(this);
4839  const int kMaxElementsForLinearSearch = 32;
4840  Branch(Int32LessThanOrEqual(nof, Int32Constant(kMaxElementsForLinearSearch)),
4841         &linear_search, &binary_search);
4842  Bind(&linear_search);
4843  {
4844    DescriptorLookupLinear(unique_name, descriptors, ChangeInt32ToIntPtr(nof),
4845                           if_found, var_name_index, if_not_found);
4846  }
4847  Bind(&binary_search);
4848  {
4849    DescriptorLookupBinary(unique_name, descriptors, nof, if_found,
4850                           var_name_index, if_not_found);
4851  }
4852}
4853
4854void CodeStubAssembler::TryLookupProperty(
4855    Node* object, Node* map, Node* instance_type, Node* unique_name,
4856    Label* if_found_fast, Label* if_found_dict, Label* if_found_global,
4857    Variable* var_meta_storage, Variable* var_name_index, Label* if_not_found,
4858    Label* if_bailout) {
4859  DCHECK_EQ(MachineRepresentation::kTagged, var_meta_storage->rep());
4860  DCHECK_EQ(MachineType::PointerRepresentation(), var_name_index->rep());
4861
4862  Label if_objectisspecial(this);
4863  STATIC_ASSERT(JS_GLOBAL_OBJECT_TYPE <= LAST_SPECIAL_RECEIVER_TYPE);
4864  GotoIf(Int32LessThanOrEqual(instance_type,
4865                              Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
4866         &if_objectisspecial);
4867
4868  uint32_t mask =
4869      1 << Map::kHasNamedInterceptor | 1 << Map::kIsAccessCheckNeeded;
4870  CSA_ASSERT(this, Word32BinaryNot(IsSetWord32(LoadMapBitField(map), mask)));
4871  USE(mask);
4872
4873  Node* bit_field3 = LoadMapBitField3(map);
4874  Label if_isfastmap(this), if_isslowmap(this);
4875  Branch(IsSetWord32<Map::DictionaryMap>(bit_field3), &if_isslowmap,
4876         &if_isfastmap);
4877  Bind(&if_isfastmap);
4878  {
4879    Node* descriptors = LoadMapDescriptors(map);
4880    var_meta_storage->Bind(descriptors);
4881
4882    DescriptorLookup(unique_name, descriptors, bit_field3, if_found_fast,
4883                     var_name_index, if_not_found);
4884  }
4885  Bind(&if_isslowmap);
4886  {
4887    Node* dictionary = LoadProperties(object);
4888    var_meta_storage->Bind(dictionary);
4889
4890    NameDictionaryLookup<NameDictionary>(dictionary, unique_name, if_found_dict,
4891                                         var_name_index, if_not_found);
4892  }
4893  Bind(&if_objectisspecial);
4894  {
4895    // Handle global object here and other special objects in runtime.
4896    GotoIfNot(Word32Equal(instance_type, Int32Constant(JS_GLOBAL_OBJECT_TYPE)),
4897              if_bailout);
4898
4899    // Handle interceptors and access checks in runtime.
4900    Node* bit_field = LoadMapBitField(map);
4901    Node* mask = Int32Constant(1 << Map::kHasNamedInterceptor |
4902                               1 << Map::kIsAccessCheckNeeded);
4903    GotoIf(Word32NotEqual(Word32And(bit_field, mask), Int32Constant(0)),
4904           if_bailout);
4905
4906    Node* dictionary = LoadProperties(object);
4907    var_meta_storage->Bind(dictionary);
4908
4909    NameDictionaryLookup<GlobalDictionary>(
4910        dictionary, unique_name, if_found_global, var_name_index, if_not_found);
4911  }
4912}
4913
4914void CodeStubAssembler::TryHasOwnProperty(Node* object, Node* map,
4915                                          Node* instance_type,
4916                                          Node* unique_name, Label* if_found,
4917                                          Label* if_not_found,
4918                                          Label* if_bailout) {
4919  Comment("TryHasOwnProperty");
4920  Variable var_meta_storage(this, MachineRepresentation::kTagged);
4921  Variable var_name_index(this, MachineType::PointerRepresentation());
4922
4923  Label if_found_global(this);
4924  TryLookupProperty(object, map, instance_type, unique_name, if_found, if_found,
4925                    &if_found_global, &var_meta_storage, &var_name_index,
4926                    if_not_found, if_bailout);
4927  Bind(&if_found_global);
4928  {
4929    Variable var_value(this, MachineRepresentation::kTagged);
4930    Variable var_details(this, MachineRepresentation::kWord32);
4931    // Check if the property cell is not deleted.
4932    LoadPropertyFromGlobalDictionary(var_meta_storage.value(),
4933                                     var_name_index.value(), &var_value,
4934                                     &var_details, if_not_found);
4935    Goto(if_found);
4936  }
4937}
4938
4939void CodeStubAssembler::LoadPropertyFromFastObject(Node* object, Node* map,
4940                                                   Node* descriptors,
4941                                                   Node* name_index,
4942                                                   Variable* var_details,
4943                                                   Variable* var_value) {
4944  DCHECK_EQ(MachineRepresentation::kWord32, var_details->rep());
4945  DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
4946  Comment("[ LoadPropertyFromFastObject");
4947
4948  Node* details =
4949      LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index);
4950  var_details->Bind(details);
4951
4952  Node* location = DecodeWord32<PropertyDetails::LocationField>(details);
4953
4954  Label if_in_field(this), if_in_descriptor(this), done(this);
4955  Branch(Word32Equal(location, Int32Constant(kField)), &if_in_field,
4956         &if_in_descriptor);
4957  Bind(&if_in_field);
4958  {
4959    Node* field_index =
4960        DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
4961    Node* representation =
4962        DecodeWord32<PropertyDetails::RepresentationField>(details);
4963
4964    Node* inobject_properties = LoadMapInobjectProperties(map);
4965
4966    Label if_inobject(this), if_backing_store(this);
4967    Variable var_double_value(this, MachineRepresentation::kFloat64);
4968    Label rebox_double(this, &var_double_value);
4969    Branch(UintPtrLessThan(field_index, inobject_properties), &if_inobject,
4970           &if_backing_store);
4971    Bind(&if_inobject);
4972    {
4973      Comment("if_inobject");
4974      Node* field_offset =
4975          IntPtrMul(IntPtrSub(LoadMapInstanceSize(map),
4976                              IntPtrSub(inobject_properties, field_index)),
4977                    IntPtrConstant(kPointerSize));
4978
4979      Label if_double(this), if_tagged(this);
4980      Branch(Word32NotEqual(representation,
4981                            Int32Constant(Representation::kDouble)),
4982             &if_tagged, &if_double);
4983      Bind(&if_tagged);
4984      {
4985        var_value->Bind(LoadObjectField(object, field_offset));
4986        Goto(&done);
4987      }
4988      Bind(&if_double);
4989      {
4990        if (FLAG_unbox_double_fields) {
4991          var_double_value.Bind(
4992              LoadObjectField(object, field_offset, MachineType::Float64()));
4993        } else {
4994          Node* mutable_heap_number = LoadObjectField(object, field_offset);
4995          var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
4996        }
4997        Goto(&rebox_double);
4998      }
4999    }
5000    Bind(&if_backing_store);
5001    {
5002      Comment("if_backing_store");
5003      Node* properties = LoadProperties(object);
5004      field_index = IntPtrSub(field_index, inobject_properties);
5005      Node* value = LoadFixedArrayElement(properties, field_index);
5006
5007      Label if_double(this), if_tagged(this);
5008      Branch(Word32NotEqual(representation,
5009                            Int32Constant(Representation::kDouble)),
5010             &if_tagged, &if_double);
5011      Bind(&if_tagged);
5012      {
5013        var_value->Bind(value);
5014        Goto(&done);
5015      }
5016      Bind(&if_double);
5017      {
5018        var_double_value.Bind(LoadHeapNumberValue(value));
5019        Goto(&rebox_double);
5020      }
5021    }
5022    Bind(&rebox_double);
5023    {
5024      Comment("rebox_double");
5025      Node* heap_number = AllocateHeapNumberWithValue(var_double_value.value());
5026      var_value->Bind(heap_number);
5027      Goto(&done);
5028    }
5029  }
5030  Bind(&if_in_descriptor);
5031  {
5032    var_value->Bind(
5033        LoadValueByKeyIndex<DescriptorArray>(descriptors, name_index));
5034    Goto(&done);
5035  }
5036  Bind(&done);
5037
5038  Comment("] LoadPropertyFromFastObject");
5039}
5040
5041void CodeStubAssembler::LoadPropertyFromNameDictionary(Node* dictionary,
5042                                                       Node* name_index,
5043                                                       Variable* var_details,
5044                                                       Variable* var_value) {
5045  Comment("LoadPropertyFromNameDictionary");
5046  CSA_ASSERT(this, IsDictionary(dictionary));
5047
5048  var_details->Bind(
5049      LoadDetailsByKeyIndex<NameDictionary>(dictionary, name_index));
5050  var_value->Bind(LoadValueByKeyIndex<NameDictionary>(dictionary, name_index));
5051
5052  Comment("] LoadPropertyFromNameDictionary");
5053}
5054
5055void CodeStubAssembler::LoadPropertyFromGlobalDictionary(Node* dictionary,
5056                                                         Node* name_index,
5057                                                         Variable* var_details,
5058                                                         Variable* var_value,
5059                                                         Label* if_deleted) {
5060  Comment("[ LoadPropertyFromGlobalDictionary");
5061  CSA_ASSERT(this, IsDictionary(dictionary));
5062
5063  Node* property_cell =
5064      LoadValueByKeyIndex<GlobalDictionary>(dictionary, name_index);
5065
5066  Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
5067  GotoIf(WordEqual(value, TheHoleConstant()), if_deleted);
5068
5069  var_value->Bind(value);
5070
5071  Node* details = LoadAndUntagToWord32ObjectField(property_cell,
5072                                                  PropertyCell::kDetailsOffset);
5073  var_details->Bind(details);
5074
5075  Comment("] LoadPropertyFromGlobalDictionary");
5076}
5077
5078// |value| is the property backing store's contents, which is either a value
5079// or an accessor pair, as specified by |details|.
5080// Returns either the original value, or the result of the getter call.
5081Node* CodeStubAssembler::CallGetterIfAccessor(Node* value, Node* details,
5082                                              Node* context, Node* receiver,
5083                                              Label* if_bailout) {
5084  Variable var_value(this, MachineRepresentation::kTagged, value);
5085  Label done(this);
5086
5087  Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
5088  GotoIf(Word32Equal(kind, Int32Constant(kData)), &done);
5089
5090  // Accessor case.
5091  {
5092    Node* accessor_pair = value;
5093    GotoIf(Word32Equal(LoadInstanceType(accessor_pair),
5094                       Int32Constant(ACCESSOR_INFO_TYPE)),
5095           if_bailout);
5096    CSA_ASSERT(this, HasInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE));
5097    Node* getter = LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
5098    Node* getter_map = LoadMap(getter);
5099    Node* instance_type = LoadMapInstanceType(getter_map);
5100    // FunctionTemplateInfo getters are not supported yet.
5101    GotoIf(
5102        Word32Equal(instance_type, Int32Constant(FUNCTION_TEMPLATE_INFO_TYPE)),
5103        if_bailout);
5104
5105    // Return undefined if the {getter} is not callable.
5106    var_value.Bind(UndefinedConstant());
5107    GotoIfNot(IsCallableMap(getter_map), &done);
5108
5109    // Call the accessor.
5110    Callable callable = CodeFactory::Call(isolate());
5111    Node* result = CallJS(callable, context, getter, receiver);
5112    var_value.Bind(result);
5113    Goto(&done);
5114  }
5115
5116  Bind(&done);
5117  return var_value.value();
5118}
5119
5120void CodeStubAssembler::TryGetOwnProperty(
5121    Node* context, Node* receiver, Node* object, Node* map, Node* instance_type,
5122    Node* unique_name, Label* if_found_value, Variable* var_value,
5123    Label* if_not_found, Label* if_bailout) {
5124  DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
5125  Comment("TryGetOwnProperty");
5126
5127  Variable var_meta_storage(this, MachineRepresentation::kTagged);
5128  Variable var_entry(this, MachineType::PointerRepresentation());
5129
5130  Label if_found_fast(this), if_found_dict(this), if_found_global(this);
5131
5132  Variable var_details(this, MachineRepresentation::kWord32);
5133  Variable* vars[] = {var_value, &var_details};
5134  Label if_found(this, 2, vars);
5135
5136  TryLookupProperty(object, map, instance_type, unique_name, &if_found_fast,
5137                    &if_found_dict, &if_found_global, &var_meta_storage,
5138                    &var_entry, if_not_found, if_bailout);
5139  Bind(&if_found_fast);
5140  {
5141    Node* descriptors = var_meta_storage.value();
5142    Node* name_index = var_entry.value();
5143
5144    LoadPropertyFromFastObject(object, map, descriptors, name_index,
5145                               &var_details, var_value);
5146    Goto(&if_found);
5147  }
5148  Bind(&if_found_dict);
5149  {
5150    Node* dictionary = var_meta_storage.value();
5151    Node* entry = var_entry.value();
5152    LoadPropertyFromNameDictionary(dictionary, entry, &var_details, var_value);
5153    Goto(&if_found);
5154  }
5155  Bind(&if_found_global);
5156  {
5157    Node* dictionary = var_meta_storage.value();
5158    Node* entry = var_entry.value();
5159
5160    LoadPropertyFromGlobalDictionary(dictionary, entry, &var_details, var_value,
5161                                     if_not_found);
5162    Goto(&if_found);
5163  }
5164  // Here we have details and value which could be an accessor.
5165  Bind(&if_found);
5166  {
5167    Node* value = CallGetterIfAccessor(var_value->value(), var_details.value(),
5168                                       context, receiver, if_bailout);
5169    var_value->Bind(value);
5170    Goto(if_found_value);
5171  }
5172}
5173
5174void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
5175                                         Node* instance_type,
5176                                         Node* intptr_index, Label* if_found,
5177                                         Label* if_not_found,
5178                                         Label* if_bailout) {
5179  // Handle special objects in runtime.
5180  GotoIf(Int32LessThanOrEqual(instance_type,
5181                              Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
5182         if_bailout);
5183
5184  Node* elements_kind = LoadMapElementsKind(map);
5185
5186  // TODO(verwaest): Support other elements kinds as well.
5187  Label if_isobjectorsmi(this), if_isdouble(this), if_isdictionary(this),
5188      if_isfaststringwrapper(this), if_isslowstringwrapper(this), if_oob(this);
5189  // clang-format off
5190  int32_t values[] = {
5191      // Handled by {if_isobjectorsmi}.
5192      FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS,
5193          FAST_HOLEY_ELEMENTS,
5194      // Handled by {if_isdouble}.
5195      FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS,
5196      // Handled by {if_isdictionary}.
5197      DICTIONARY_ELEMENTS,
5198      // Handled by {if_isfaststringwrapper}.
5199      FAST_STRING_WRAPPER_ELEMENTS,
5200      // Handled by {if_isslowstringwrapper}.
5201      SLOW_STRING_WRAPPER_ELEMENTS,
5202      // Handled by {if_not_found}.
5203      NO_ELEMENTS,
5204  };
5205  Label* labels[] = {
5206      &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi,
5207          &if_isobjectorsmi,
5208      &if_isdouble, &if_isdouble,
5209      &if_isdictionary,
5210      &if_isfaststringwrapper,
5211      &if_isslowstringwrapper,
5212      if_not_found,
5213  };
5214  // clang-format on
5215  STATIC_ASSERT(arraysize(values) == arraysize(labels));
5216  Switch(elements_kind, if_bailout, values, labels, arraysize(values));
5217
5218  Bind(&if_isobjectorsmi);
5219  {
5220    Node* elements = LoadElements(object);
5221    Node* length = LoadAndUntagFixedArrayBaseLength(elements);
5222
5223    GotoIfNot(UintPtrLessThan(intptr_index, length), &if_oob);
5224
5225    Node* element = LoadFixedArrayElement(elements, intptr_index);
5226    Node* the_hole = TheHoleConstant();
5227    Branch(WordEqual(element, the_hole), if_not_found, if_found);
5228  }
5229  Bind(&if_isdouble);
5230  {
5231    Node* elements = LoadElements(object);
5232    Node* length = LoadAndUntagFixedArrayBaseLength(elements);
5233
5234    GotoIfNot(UintPtrLessThan(intptr_index, length), &if_oob);
5235
5236    // Check if the element is a double hole, but don't load it.
5237    LoadFixedDoubleArrayElement(elements, intptr_index, MachineType::None(), 0,
5238                                INTPTR_PARAMETERS, if_not_found);
5239    Goto(if_found);
5240  }
5241  Bind(&if_isdictionary);
5242  {
5243    // Negative keys must be converted to property names.
5244    GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), if_bailout);
5245
5246    Variable var_entry(this, MachineType::PointerRepresentation());
5247    Node* elements = LoadElements(object);
5248    NumberDictionaryLookup<SeededNumberDictionary>(
5249        elements, intptr_index, if_found, &var_entry, if_not_found);
5250  }
5251  Bind(&if_isfaststringwrapper);
5252  {
5253    CSA_ASSERT(this, HasInstanceType(object, JS_VALUE_TYPE));
5254    Node* string = LoadJSValueValue(object);
5255    CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string)));
5256    Node* length = LoadStringLength(string);
5257    GotoIf(UintPtrLessThan(intptr_index, SmiUntag(length)), if_found);
5258    Goto(&if_isobjectorsmi);
5259  }
5260  Bind(&if_isslowstringwrapper);
5261  {
5262    CSA_ASSERT(this, HasInstanceType(object, JS_VALUE_TYPE));
5263    Node* string = LoadJSValueValue(object);
5264    CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string)));
5265    Node* length = LoadStringLength(string);
5266    GotoIf(UintPtrLessThan(intptr_index, SmiUntag(length)), if_found);
5267    Goto(&if_isdictionary);
5268  }
5269  Bind(&if_oob);
5270  {
5271    // Positive OOB indices mean "not found", negative indices must be
5272    // converted to property names.
5273    GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), if_bailout);
5274    Goto(if_not_found);
5275  }
5276}
5277
5278// Instantiate template methods to workaround GCC compilation issue.
5279template void CodeStubAssembler::NumberDictionaryLookup<SeededNumberDictionary>(
5280    Node*, Node*, Label*, Variable*, Label*);
5281template void CodeStubAssembler::NumberDictionaryLookup<
5282    UnseededNumberDictionary>(Node*, Node*, Label*, Variable*, Label*);
5283
5284void CodeStubAssembler::TryPrototypeChainLookup(
5285    Node* receiver, Node* key, const LookupInHolder& lookup_property_in_holder,
5286    const LookupInHolder& lookup_element_in_holder, Label* if_end,
5287    Label* if_bailout) {
5288  // Ensure receiver is JSReceiver, otherwise bailout.
5289  Label if_objectisnotsmi(this);
5290  Branch(TaggedIsSmi(receiver), if_bailout, &if_objectisnotsmi);
5291  Bind(&if_objectisnotsmi);
5292
5293  Node* map = LoadMap(receiver);
5294  Node* instance_type = LoadMapInstanceType(map);
5295  {
5296    Label if_objectisreceiver(this);
5297    STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
5298    STATIC_ASSERT(FIRST_JS_RECEIVER_TYPE == JS_PROXY_TYPE);
5299    Branch(
5300        Int32GreaterThan(instance_type, Int32Constant(FIRST_JS_RECEIVER_TYPE)),
5301        &if_objectisreceiver, if_bailout);
5302    Bind(&if_objectisreceiver);
5303  }
5304
5305  Variable var_index(this, MachineType::PointerRepresentation());
5306  Variable var_unique(this, MachineRepresentation::kTagged);
5307
5308  Label if_keyisindex(this), if_iskeyunique(this);
5309  TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_unique,
5310            if_bailout);
5311
5312  Bind(&if_iskeyunique);
5313  {
5314    Variable var_holder(this, MachineRepresentation::kTagged, receiver);
5315    Variable var_holder_map(this, MachineRepresentation::kTagged, map);
5316    Variable var_holder_instance_type(this, MachineRepresentation::kWord32,
5317                                      instance_type);
5318
5319    Variable* merged_variables[] = {&var_holder, &var_holder_map,
5320                                    &var_holder_instance_type};
5321    Label loop(this, arraysize(merged_variables), merged_variables);
5322    Goto(&loop);
5323    Bind(&loop);
5324    {
5325      Node* holder_map = var_holder_map.value();
5326      Node* holder_instance_type = var_holder_instance_type.value();
5327
5328      Label next_proto(this);
5329      lookup_property_in_holder(receiver, var_holder.value(), holder_map,
5330                                holder_instance_type, var_unique.value(),
5331                                &next_proto, if_bailout);
5332      Bind(&next_proto);
5333
5334      // Bailout if it can be an integer indexed exotic case.
5335      GotoIf(
5336          Word32Equal(holder_instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
5337          if_bailout);
5338
5339      Node* proto = LoadMapPrototype(holder_map);
5340
5341      Label if_not_null(this);
5342      Branch(WordEqual(proto, NullConstant()), if_end, &if_not_null);
5343      Bind(&if_not_null);
5344
5345      Node* map = LoadMap(proto);
5346      Node* instance_type = LoadMapInstanceType(map);
5347
5348      var_holder.Bind(proto);
5349      var_holder_map.Bind(map);
5350      var_holder_instance_type.Bind(instance_type);
5351      Goto(&loop);
5352    }
5353  }
5354  Bind(&if_keyisindex);
5355  {
5356    Variable var_holder(this, MachineRepresentation::kTagged, receiver);
5357    Variable var_holder_map(this, MachineRepresentation::kTagged, map);
5358    Variable var_holder_instance_type(this, MachineRepresentation::kWord32,
5359                                      instance_type);
5360
5361    Variable* merged_variables[] = {&var_holder, &var_holder_map,
5362                                    &var_holder_instance_type};
5363    Label loop(this, arraysize(merged_variables), merged_variables);
5364    Goto(&loop);
5365    Bind(&loop);
5366    {
5367      Label next_proto(this);
5368      lookup_element_in_holder(receiver, var_holder.value(),
5369                               var_holder_map.value(),
5370                               var_holder_instance_type.value(),
5371                               var_index.value(), &next_proto, if_bailout);
5372      Bind(&next_proto);
5373
5374      Node* proto = LoadMapPrototype(var_holder_map.value());
5375
5376      Label if_not_null(this);
5377      Branch(WordEqual(proto, NullConstant()), if_end, &if_not_null);
5378      Bind(&if_not_null);
5379
5380      Node* map = LoadMap(proto);
5381      Node* instance_type = LoadMapInstanceType(map);
5382
5383      var_holder.Bind(proto);
5384      var_holder_map.Bind(map);
5385      var_holder_instance_type.Bind(instance_type);
5386      Goto(&loop);
5387    }
5388  }
5389}
5390
5391Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
5392                                             Node* object) {
5393  Variable var_result(this, MachineRepresentation::kTagged);
5394  Label return_false(this), return_true(this),
5395      return_runtime(this, Label::kDeferred), return_result(this);
5396
5397  // Goto runtime if {object} is a Smi.
5398  GotoIf(TaggedIsSmi(object), &return_runtime);
5399
5400  // Load map of {object}.
5401  Node* object_map = LoadMap(object);
5402
5403  // Lookup the {callable} and {object} map in the global instanceof cache.
5404  // Note: This is safe because we clear the global instanceof cache whenever
5405  // we change the prototype of any object.
5406  Node* instanceof_cache_function =
5407      LoadRoot(Heap::kInstanceofCacheFunctionRootIndex);
5408  Node* instanceof_cache_map = LoadRoot(Heap::kInstanceofCacheMapRootIndex);
5409  {
5410    Label instanceof_cache_miss(this);
5411    GotoIfNot(WordEqual(instanceof_cache_function, callable),
5412              &instanceof_cache_miss);
5413    GotoIfNot(WordEqual(instanceof_cache_map, object_map),
5414              &instanceof_cache_miss);
5415    var_result.Bind(LoadRoot(Heap::kInstanceofCacheAnswerRootIndex));
5416    Goto(&return_result);
5417    Bind(&instanceof_cache_miss);
5418  }
5419
5420  // Goto runtime if {callable} is a Smi.
5421  GotoIf(TaggedIsSmi(callable), &return_runtime);
5422
5423  // Load map of {callable}.
5424  Node* callable_map = LoadMap(callable);
5425
5426  // Goto runtime if {callable} is not a JSFunction.
5427  Node* callable_instance_type = LoadMapInstanceType(callable_map);
5428  GotoIfNot(
5429      Word32Equal(callable_instance_type, Int32Constant(JS_FUNCTION_TYPE)),
5430      &return_runtime);
5431
5432  // Goto runtime if {callable} is not a constructor or has
5433  // a non-instance "prototype".
5434  Node* callable_bitfield = LoadMapBitField(callable_map);
5435  GotoIfNot(
5436      Word32Equal(Word32And(callable_bitfield,
5437                            Int32Constant((1 << Map::kHasNonInstancePrototype) |
5438                                          (1 << Map::kIsConstructor))),
5439                  Int32Constant(1 << Map::kIsConstructor)),
5440      &return_runtime);
5441
5442  // Get the "prototype" (or initial map) of the {callable}.
5443  Node* callable_prototype =
5444      LoadObjectField(callable, JSFunction::kPrototypeOrInitialMapOffset);
5445  {
5446    Label callable_prototype_valid(this);
5447    Variable var_callable_prototype(this, MachineRepresentation::kTagged,
5448                                    callable_prototype);
5449
5450    // Resolve the "prototype" if the {callable} has an initial map.  Afterwards
5451    // the {callable_prototype} will be either the JSReceiver prototype object
5452    // or the hole value, which means that no instances of the {callable} were
5453    // created so far and hence we should return false.
5454    Node* callable_prototype_instance_type =
5455        LoadInstanceType(callable_prototype);
5456    GotoIfNot(
5457        Word32Equal(callable_prototype_instance_type, Int32Constant(MAP_TYPE)),
5458        &callable_prototype_valid);
5459    var_callable_prototype.Bind(
5460        LoadObjectField(callable_prototype, Map::kPrototypeOffset));
5461    Goto(&callable_prototype_valid);
5462    Bind(&callable_prototype_valid);
5463    callable_prototype = var_callable_prototype.value();
5464  }
5465
5466  // Update the global instanceof cache with the current {object} map and
5467  // {callable}.  The cached answer will be set when it is known below.
5468  StoreRoot(Heap::kInstanceofCacheFunctionRootIndex, callable);
5469  StoreRoot(Heap::kInstanceofCacheMapRootIndex, object_map);
5470
5471  // Loop through the prototype chain looking for the {callable} prototype.
5472  Variable var_object_map(this, MachineRepresentation::kTagged, object_map);
5473  Label loop(this, &var_object_map);
5474  Goto(&loop);
5475  Bind(&loop);
5476  {
5477    Node* object_map = var_object_map.value();
5478
5479    // Check if the current {object} needs to be access checked.
5480    Node* object_bitfield = LoadMapBitField(object_map);
5481    GotoIfNot(
5482        Word32Equal(Word32And(object_bitfield,
5483                              Int32Constant(1 << Map::kIsAccessCheckNeeded)),
5484                    Int32Constant(0)),
5485        &return_runtime);
5486
5487    // Check if the current {object} is a proxy.
5488    Node* object_instance_type = LoadMapInstanceType(object_map);
5489    GotoIf(Word32Equal(object_instance_type, Int32Constant(JS_PROXY_TYPE)),
5490           &return_runtime);
5491
5492    // Check the current {object} prototype.
5493    Node* object_prototype = LoadMapPrototype(object_map);
5494    GotoIf(WordEqual(object_prototype, NullConstant()), &return_false);
5495    GotoIf(WordEqual(object_prototype, callable_prototype), &return_true);
5496
5497    // Continue with the prototype.
5498    var_object_map.Bind(LoadMap(object_prototype));
5499    Goto(&loop);
5500  }
5501
5502  Bind(&return_true);
5503  StoreRoot(Heap::kInstanceofCacheAnswerRootIndex, BooleanConstant(true));
5504  var_result.Bind(BooleanConstant(true));
5505  Goto(&return_result);
5506
5507  Bind(&return_false);
5508  StoreRoot(Heap::kInstanceofCacheAnswerRootIndex, BooleanConstant(false));
5509  var_result.Bind(BooleanConstant(false));
5510  Goto(&return_result);
5511
5512  Bind(&return_runtime);
5513  {
5514    // Invalidate the global instanceof cache.
5515    StoreRoot(Heap::kInstanceofCacheFunctionRootIndex, SmiConstant(0));
5516    // Fallback to the runtime implementation.
5517    var_result.Bind(
5518        CallRuntime(Runtime::kOrdinaryHasInstance, context, callable, object));
5519  }
5520  Goto(&return_result);
5521
5522  Bind(&return_result);
5523  return var_result.value();
5524}
5525
5526Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node,
5527                                                ElementsKind kind,
5528                                                ParameterMode mode,
5529                                                int base_size) {
5530  int element_size_shift = ElementsKindToShiftSize(kind);
5531  int element_size = 1 << element_size_shift;
5532  int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize;
5533  intptr_t index = 0;
5534  bool constant_index = false;
5535  if (mode == SMI_PARAMETERS) {
5536    element_size_shift -= kSmiShiftBits;
5537    Smi* smi_index;
5538    constant_index = ToSmiConstant(index_node, smi_index);
5539    if (constant_index) index = smi_index->value();
5540    index_node = BitcastTaggedToWord(index_node);
5541  } else {
5542    DCHECK(mode == INTPTR_PARAMETERS);
5543    constant_index = ToIntPtrConstant(index_node, index);
5544  }
5545  if (constant_index) {
5546    return IntPtrConstant(base_size + element_size * index);
5547  }
5548
5549  Node* shifted_index =
5550      (element_size_shift == 0)
5551          ? index_node
5552          : ((element_size_shift > 0)
5553                 ? WordShl(index_node, IntPtrConstant(element_size_shift))
5554                 : WordShr(index_node, IntPtrConstant(-element_size_shift)));
5555  return IntPtrAdd(IntPtrConstant(base_size), shifted_index);
5556}
5557
5558Node* CodeStubAssembler::LoadFeedbackVectorForStub() {
5559  Node* function =
5560      LoadFromParentFrame(JavaScriptFrameConstants::kFunctionOffset);
5561  Node* cell = LoadObjectField(function, JSFunction::kFeedbackVectorOffset);
5562  return LoadObjectField(cell, Cell::kValueOffset);
5563}
5564
5565void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* feedback_vector,
5566                                       Node* slot_id) {
5567  // This method is used for binary op and compare feedback. These
5568  // vector nodes are initialized with a smi 0, so we can simply OR
5569  // our new feedback in place.
5570  Node* previous_feedback = LoadFixedArrayElement(feedback_vector, slot_id);
5571  Node* combined_feedback = SmiOr(previous_feedback, feedback);
5572  StoreFixedArrayElement(feedback_vector, slot_id, combined_feedback,
5573                         SKIP_WRITE_BARRIER);
5574}
5575
5576Node* CodeStubAssembler::LoadReceiverMap(Node* receiver) {
5577  Variable var_receiver_map(this, MachineRepresentation::kTagged);
5578  Label load_smi_map(this, Label::kDeferred), load_receiver_map(this),
5579      if_result(this);
5580
5581  Branch(TaggedIsSmi(receiver), &load_smi_map, &load_receiver_map);
5582  Bind(&load_smi_map);
5583  {
5584    var_receiver_map.Bind(LoadRoot(Heap::kHeapNumberMapRootIndex));
5585    Goto(&if_result);
5586  }
5587  Bind(&load_receiver_map);
5588  {
5589    var_receiver_map.Bind(LoadMap(receiver));
5590    Goto(&if_result);
5591  }
5592  Bind(&if_result);
5593  return var_receiver_map.value();
5594}
5595
5596Node* CodeStubAssembler::TryToIntptr(Node* key, Label* miss) {
5597  Variable var_intptr_key(this, MachineType::PointerRepresentation());
5598  Label done(this, &var_intptr_key), key_is_smi(this);
5599  GotoIf(TaggedIsSmi(key), &key_is_smi);
5600  // Try to convert a heap number to a Smi.
5601  GotoIfNot(IsHeapNumberMap(LoadMap(key)), miss);
5602  {
5603    Node* value = LoadHeapNumberValue(key);
5604    Node* int_value = RoundFloat64ToInt32(value);
5605    GotoIfNot(Float64Equal(value, ChangeInt32ToFloat64(int_value)), miss);
5606    var_intptr_key.Bind(ChangeInt32ToIntPtr(int_value));
5607    Goto(&done);
5608  }
5609
5610  Bind(&key_is_smi);
5611  {
5612    var_intptr_key.Bind(SmiUntag(key));
5613    Goto(&done);
5614  }
5615
5616  Bind(&done);
5617  return var_intptr_key.value();
5618}
5619
5620Node* CodeStubAssembler::EmitKeyedSloppyArguments(Node* receiver, Node* key,
5621                                                  Node* value, Label* bailout) {
5622  // Mapped arguments are actual arguments. Unmapped arguments are values added
5623  // to the arguments object after it was created for the call. Mapped arguments
5624  // are stored in the context at indexes given by elements[key + 2]. Unmapped
5625  // arguments are stored as regular indexed properties in the arguments array,
5626  // held at elements[1]. See NewSloppyArguments() in runtime.cc for a detailed
5627  // look at argument object construction.
5628  //
5629  // The sloppy arguments elements array has a special format:
5630  //
5631  // 0: context
5632  // 1: unmapped arguments array
5633  // 2: mapped_index0,
5634  // 3: mapped_index1,
5635  // ...
5636  //
5637  // length is 2 + min(number_of_actual_arguments, number_of_formal_arguments).
5638  // If key + 2 >= elements.length then attempt to look in the unmapped
5639  // arguments array (given by elements[1]) and return the value at key, missing
5640  // to the runtime if the unmapped arguments array is not a fixed array or if
5641  // key >= unmapped_arguments_array.length.
5642  //
5643  // Otherwise, t = elements[key + 2]. If t is the hole, then look up the value
5644  // in the unmapped arguments array, as described above. Otherwise, t is a Smi
5645  // index into the context array given at elements[0]. Return the value at
5646  // context[t].
5647
5648  bool is_load = value == nullptr;
5649
5650  GotoIfNot(TaggedIsSmi(key), bailout);
5651  key = SmiUntag(key);
5652  GotoIf(IntPtrLessThan(key, IntPtrConstant(0)), bailout);
5653
5654  Node* elements = LoadElements(receiver);
5655  Node* elements_length = LoadAndUntagFixedArrayBaseLength(elements);
5656
5657  Variable var_result(this, MachineRepresentation::kTagged);
5658  if (!is_load) {
5659    var_result.Bind(value);
5660  }
5661  Label if_mapped(this), if_unmapped(this), end(this, &var_result);
5662  Node* intptr_two = IntPtrConstant(2);
5663  Node* adjusted_length = IntPtrSub(elements_length, intptr_two);
5664
5665  GotoIf(UintPtrGreaterThanOrEqual(key, adjusted_length), &if_unmapped);
5666
5667  Node* mapped_index =
5668      LoadFixedArrayElement(elements, IntPtrAdd(key, intptr_two));
5669  Branch(WordEqual(mapped_index, TheHoleConstant()), &if_unmapped, &if_mapped);
5670
5671  Bind(&if_mapped);
5672  {
5673    CSA_ASSERT(this, TaggedIsSmi(mapped_index));
5674    mapped_index = SmiUntag(mapped_index);
5675    Node* the_context = LoadFixedArrayElement(elements, 0);
5676    // Assert that we can use LoadFixedArrayElement/StoreFixedArrayElement
5677    // methods for accessing Context.
5678    STATIC_ASSERT(Context::kHeaderSize == FixedArray::kHeaderSize);
5679    DCHECK_EQ(Context::SlotOffset(0) + kHeapObjectTag,
5680              FixedArray::OffsetOfElementAt(0));
5681    if (is_load) {
5682      Node* result = LoadFixedArrayElement(the_context, mapped_index);
5683      CSA_ASSERT(this, WordNotEqual(result, TheHoleConstant()));
5684      var_result.Bind(result);
5685    } else {
5686      StoreFixedArrayElement(the_context, mapped_index, value);
5687    }
5688    Goto(&end);
5689  }
5690
5691  Bind(&if_unmapped);
5692  {
5693    Node* backing_store = LoadFixedArrayElement(elements, 1);
5694    GotoIf(WordNotEqual(LoadMap(backing_store), FixedArrayMapConstant()),
5695           bailout);
5696
5697    Node* backing_store_length =
5698        LoadAndUntagFixedArrayBaseLength(backing_store);
5699    GotoIf(UintPtrGreaterThanOrEqual(key, backing_store_length), bailout);
5700
5701    // The key falls into unmapped range.
5702    if (is_load) {
5703      Node* result = LoadFixedArrayElement(backing_store, key);
5704      GotoIf(WordEqual(result, TheHoleConstant()), bailout);
5705      var_result.Bind(result);
5706    } else {
5707      StoreFixedArrayElement(backing_store, key, value);
5708    }
5709    Goto(&end);
5710  }
5711
5712  Bind(&end);
5713  return var_result.value();
5714}
5715
5716Node* CodeStubAssembler::LoadScriptContext(Node* context, int context_index) {
5717  Node* native_context = LoadNativeContext(context);
5718  Node* script_context_table =
5719      LoadContextElement(native_context, Context::SCRIPT_CONTEXT_TABLE_INDEX);
5720
5721  int offset =
5722      ScriptContextTable::GetContextOffset(context_index) - kHeapObjectTag;
5723  return Load(MachineType::AnyTagged(), script_context_table,
5724              IntPtrConstant(offset));
5725}
5726
5727namespace {
5728
5729// Converts typed array elements kind to a machine representations.
5730MachineRepresentation ElementsKindToMachineRepresentation(ElementsKind kind) {
5731  switch (kind) {
5732    case UINT8_CLAMPED_ELEMENTS:
5733    case UINT8_ELEMENTS:
5734    case INT8_ELEMENTS:
5735      return MachineRepresentation::kWord8;
5736    case UINT16_ELEMENTS:
5737    case INT16_ELEMENTS:
5738      return MachineRepresentation::kWord16;
5739    case UINT32_ELEMENTS:
5740    case INT32_ELEMENTS:
5741      return MachineRepresentation::kWord32;
5742    case FLOAT32_ELEMENTS:
5743      return MachineRepresentation::kFloat32;
5744    case FLOAT64_ELEMENTS:
5745      return MachineRepresentation::kFloat64;
5746    default:
5747      UNREACHABLE();
5748      return MachineRepresentation::kNone;
5749  }
5750}
5751
5752}  // namespace
5753
5754void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind,
5755                                     Node* index, Node* value,
5756                                     ParameterMode mode) {
5757  if (IsFixedTypedArrayElementsKind(kind)) {
5758    if (kind == UINT8_CLAMPED_ELEMENTS) {
5759      CSA_ASSERT(this,
5760                 Word32Equal(value, Word32And(Int32Constant(0xff), value)));
5761    }
5762    Node* offset = ElementOffsetFromIndex(index, kind, mode, 0);
5763    MachineRepresentation rep = ElementsKindToMachineRepresentation(kind);
5764    StoreNoWriteBarrier(rep, elements, offset, value);
5765    return;
5766  }
5767
5768  WriteBarrierMode barrier_mode =
5769      IsFastSmiElementsKind(kind) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
5770  if (IsFastDoubleElementsKind(kind)) {
5771    // Make sure we do not store signalling NaNs into double arrays.
5772    value = Float64SilenceNaN(value);
5773    StoreFixedDoubleArrayElement(elements, index, value, mode);
5774  } else {
5775    StoreFixedArrayElement(elements, index, value, barrier_mode, 0, mode);
5776  }
5777}
5778
5779Node* CodeStubAssembler::Int32ToUint8Clamped(Node* int32_value) {
5780  Label done(this);
5781  Node* int32_zero = Int32Constant(0);
5782  Node* int32_255 = Int32Constant(255);
5783  Variable var_value(this, MachineRepresentation::kWord32, int32_value);
5784  GotoIf(Uint32LessThanOrEqual(int32_value, int32_255), &done);
5785  var_value.Bind(int32_zero);
5786  GotoIf(Int32LessThan(int32_value, int32_zero), &done);
5787  var_value.Bind(int32_255);
5788  Goto(&done);
5789  Bind(&done);
5790  return var_value.value();
5791}
5792
5793Node* CodeStubAssembler::Float64ToUint8Clamped(Node* float64_value) {
5794  Label done(this);
5795  Variable var_value(this, MachineRepresentation::kWord32, Int32Constant(0));
5796  GotoIf(Float64LessThanOrEqual(float64_value, Float64Constant(0.0)), &done);
5797  var_value.Bind(Int32Constant(255));
5798  GotoIf(Float64LessThanOrEqual(Float64Constant(255.0), float64_value), &done);
5799  {
5800    Node* rounded_value = Float64RoundToEven(float64_value);
5801    var_value.Bind(TruncateFloat64ToWord32(rounded_value));
5802    Goto(&done);
5803  }
5804  Bind(&done);
5805  return var_value.value();
5806}
5807
5808Node* CodeStubAssembler::PrepareValueForWriteToTypedArray(
5809    Node* input, ElementsKind elements_kind, Label* bailout) {
5810  DCHECK(IsFixedTypedArrayElementsKind(elements_kind));
5811
5812  MachineRepresentation rep;
5813  switch (elements_kind) {
5814    case UINT8_ELEMENTS:
5815    case INT8_ELEMENTS:
5816    case UINT16_ELEMENTS:
5817    case INT16_ELEMENTS:
5818    case UINT32_ELEMENTS:
5819    case INT32_ELEMENTS:
5820    case UINT8_CLAMPED_ELEMENTS:
5821      rep = MachineRepresentation::kWord32;
5822      break;
5823    case FLOAT32_ELEMENTS:
5824      rep = MachineRepresentation::kFloat32;
5825      break;
5826    case FLOAT64_ELEMENTS:
5827      rep = MachineRepresentation::kFloat64;
5828      break;
5829    default:
5830      UNREACHABLE();
5831      return nullptr;
5832  }
5833
5834  Variable var_result(this, rep);
5835  Label done(this, &var_result), if_smi(this);
5836  GotoIf(TaggedIsSmi(input), &if_smi);
5837  // Try to convert a heap number to a Smi.
5838  GotoIfNot(IsHeapNumberMap(LoadMap(input)), bailout);
5839  {
5840    Node* value = LoadHeapNumberValue(input);
5841    if (rep == MachineRepresentation::kWord32) {
5842      if (elements_kind == UINT8_CLAMPED_ELEMENTS) {
5843        value = Float64ToUint8Clamped(value);
5844      } else {
5845        value = TruncateFloat64ToWord32(value);
5846      }
5847    } else if (rep == MachineRepresentation::kFloat32) {
5848      value = TruncateFloat64ToFloat32(value);
5849    } else {
5850      DCHECK_EQ(MachineRepresentation::kFloat64, rep);
5851    }
5852    var_result.Bind(value);
5853    Goto(&done);
5854  }
5855
5856  Bind(&if_smi);
5857  {
5858    Node* value = SmiToWord32(input);
5859    if (rep == MachineRepresentation::kFloat32) {
5860      value = RoundInt32ToFloat32(value);
5861    } else if (rep == MachineRepresentation::kFloat64) {
5862      value = ChangeInt32ToFloat64(value);
5863    } else {
5864      DCHECK_EQ(MachineRepresentation::kWord32, rep);
5865      if (elements_kind == UINT8_CLAMPED_ELEMENTS) {
5866        value = Int32ToUint8Clamped(value);
5867      }
5868    }
5869    var_result.Bind(value);
5870    Goto(&done);
5871  }
5872
5873  Bind(&done);
5874  return var_result.value();
5875}
5876
5877void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
5878                                         bool is_jsarray,
5879                                         ElementsKind elements_kind,
5880                                         KeyedAccessStoreMode store_mode,
5881                                         Label* bailout) {
5882  Node* elements = LoadElements(object);
5883  if (IsFastSmiOrObjectElementsKind(elements_kind) &&
5884      store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
5885    // Bailout in case of COW elements.
5886    GotoIf(WordNotEqual(LoadMap(elements),
5887                        LoadRoot(Heap::kFixedArrayMapRootIndex)),
5888           bailout);
5889  }
5890  // TODO(ishell): introduce TryToIntPtrOrSmi() and use OptimalParameterMode().
5891  ParameterMode parameter_mode = INTPTR_PARAMETERS;
5892  key = TryToIntptr(key, bailout);
5893
5894  if (IsFixedTypedArrayElementsKind(elements_kind)) {
5895    Label done(this);
5896    // TODO(ishell): call ToNumber() on value and don't bailout but be careful
5897    // to call it only once if we decide to bailout because of bounds checks.
5898
5899    value = PrepareValueForWriteToTypedArray(value, elements_kind, bailout);
5900
5901    // There must be no allocations between the buffer load and
5902    // and the actual store to backing store, because GC may decide that
5903    // the buffer is not alive or move the elements.
5904    // TODO(ishell): introduce DisallowHeapAllocationCode scope here.
5905
5906    // Check if buffer has been neutered.
5907    Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset);
5908    GotoIf(IsDetachedBuffer(buffer), bailout);
5909
5910    // Bounds check.
5911    Node* length = TaggedToParameter(
5912        LoadObjectField(object, JSTypedArray::kLengthOffset), parameter_mode);
5913
5914    if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
5915      // Skip the store if we write beyond the length.
5916      GotoIfNot(IntPtrLessThan(key, length), &done);
5917      // ... but bailout if the key is negative.
5918    } else {
5919      DCHECK_EQ(STANDARD_STORE, store_mode);
5920    }
5921    GotoIfNot(UintPtrLessThan(key, length), bailout);
5922
5923    // Backing store = external_pointer + base_pointer.
5924    Node* external_pointer =
5925        LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
5926                        MachineType::Pointer());
5927    Node* base_pointer =
5928        LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
5929    Node* backing_store =
5930        IntPtrAdd(external_pointer, BitcastTaggedToWord(base_pointer));
5931    StoreElement(backing_store, elements_kind, key, value, parameter_mode);
5932    Goto(&done);
5933
5934    Bind(&done);
5935    return;
5936  }
5937  DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
5938         IsFastDoubleElementsKind(elements_kind));
5939
5940  Node* length = is_jsarray ? LoadObjectField(object, JSArray::kLengthOffset)
5941                            : LoadFixedArrayBaseLength(elements);
5942  length = TaggedToParameter(length, parameter_mode);
5943
5944  // In case value is stored into a fast smi array, assure that the value is
5945  // a smi before manipulating the backing store. Otherwise the backing store
5946  // may be left in an invalid state.
5947  if (IsFastSmiElementsKind(elements_kind)) {
5948    GotoIfNot(TaggedIsSmi(value), bailout);
5949  } else if (IsFastDoubleElementsKind(elements_kind)) {
5950    value = TryTaggedToFloat64(value, bailout);
5951  }
5952
5953  if (IsGrowStoreMode(store_mode)) {
5954    elements = CheckForCapacityGrow(object, elements, elements_kind, length,
5955                                    key, parameter_mode, is_jsarray, bailout);
5956  } else {
5957    GotoIfNot(UintPtrLessThan(key, length), bailout);
5958
5959    if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW) &&
5960        IsFastSmiOrObjectElementsKind(elements_kind)) {
5961      elements = CopyElementsOnWrite(object, elements, elements_kind, length,
5962                                     parameter_mode, bailout);
5963    }
5964  }
5965  StoreElement(elements, elements_kind, key, value, parameter_mode);
5966}
5967
5968Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements,
5969                                              ElementsKind kind, Node* length,
5970                                              Node* key, ParameterMode mode,
5971                                              bool is_js_array,
5972                                              Label* bailout) {
5973  Variable checked_elements(this, MachineRepresentation::kTagged);
5974  Label grow_case(this), no_grow_case(this), done(this);
5975
5976  Node* condition;
5977  if (IsHoleyElementsKind(kind)) {
5978    condition = UintPtrGreaterThanOrEqual(key, length);
5979  } else {
5980    condition = WordEqual(key, length);
5981  }
5982  Branch(condition, &grow_case, &no_grow_case);
5983
5984  Bind(&grow_case);
5985  {
5986    Node* current_capacity =
5987        TaggedToParameter(LoadFixedArrayBaseLength(elements), mode);
5988
5989    checked_elements.Bind(elements);
5990
5991    Label fits_capacity(this);
5992    GotoIf(UintPtrLessThan(key, current_capacity), &fits_capacity);
5993    {
5994      Node* new_elements = TryGrowElementsCapacity(
5995          object, elements, kind, key, current_capacity, mode, bailout);
5996
5997      checked_elements.Bind(new_elements);
5998      Goto(&fits_capacity);
5999    }
6000    Bind(&fits_capacity);
6001
6002    if (is_js_array) {
6003      Node* new_length = IntPtrAdd(key, IntPtrOrSmiConstant(1, mode));
6004      StoreObjectFieldNoWriteBarrier(object, JSArray::kLengthOffset,
6005                                     ParameterToTagged(new_length, mode));
6006    }
6007    Goto(&done);
6008  }
6009
6010  Bind(&no_grow_case);
6011  {
6012    GotoIfNot(UintPtrLessThan(key, length), bailout);
6013    checked_elements.Bind(elements);
6014    Goto(&done);
6015  }
6016
6017  Bind(&done);
6018  return checked_elements.value();
6019}
6020
6021Node* CodeStubAssembler::CopyElementsOnWrite(Node* object, Node* elements,
6022                                             ElementsKind kind, Node* length,
6023                                             ParameterMode mode,
6024                                             Label* bailout) {
6025  Variable new_elements_var(this, MachineRepresentation::kTagged, elements);
6026  Label done(this);
6027
6028  GotoIfNot(
6029      WordEqual(LoadMap(elements), LoadRoot(Heap::kFixedCOWArrayMapRootIndex)),
6030      &done);
6031  {
6032    Node* capacity =
6033        TaggedToParameter(LoadFixedArrayBaseLength(elements), mode);
6034    Node* new_elements = GrowElementsCapacity(object, elements, kind, kind,
6035                                              length, capacity, mode, bailout);
6036
6037    new_elements_var.Bind(new_elements);
6038    Goto(&done);
6039  }
6040
6041  Bind(&done);
6042  return new_elements_var.value();
6043}
6044
6045void CodeStubAssembler::TransitionElementsKind(Node* object, Node* map,
6046                                               ElementsKind from_kind,
6047                                               ElementsKind to_kind,
6048                                               bool is_jsarray,
6049                                               Label* bailout) {
6050  DCHECK(!IsFastHoleyElementsKind(from_kind) ||
6051         IsFastHoleyElementsKind(to_kind));
6052  if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) {
6053    TrapAllocationMemento(object, bailout);
6054  }
6055
6056  if (!IsSimpleMapChangeTransition(from_kind, to_kind)) {
6057    Comment("Non-simple map transition");
6058    Node* elements = LoadElements(object);
6059
6060    Node* empty_fixed_array =
6061        HeapConstant(isolate()->factory()->empty_fixed_array());
6062
6063    Label done(this);
6064    GotoIf(WordEqual(elements, empty_fixed_array), &done);
6065
6066    // TODO(ishell): Use OptimalParameterMode().
6067    ParameterMode mode = INTPTR_PARAMETERS;
6068    Node* elements_length = SmiUntag(LoadFixedArrayBaseLength(elements));
6069    Node* array_length =
6070        is_jsarray ? SmiUntag(LoadObjectField(object, JSArray::kLengthOffset))
6071                   : elements_length;
6072
6073    GrowElementsCapacity(object, elements, from_kind, to_kind, array_length,
6074                         elements_length, mode, bailout);
6075    Goto(&done);
6076    Bind(&done);
6077  }
6078
6079  StoreMap(object, map);
6080}
6081
6082void CodeStubAssembler::TrapAllocationMemento(Node* object,
6083                                              Label* memento_found) {
6084  Comment("[ TrapAllocationMemento");
6085  Label no_memento_found(this);
6086  Label top_check(this), map_check(this);
6087
6088  Node* new_space_top_address = ExternalConstant(
6089      ExternalReference::new_space_allocation_top_address(isolate()));
6090  const int kMementoMapOffset = JSArray::kSize;
6091  const int kMementoLastWordOffset =
6092      kMementoMapOffset + AllocationMemento::kSize - kPointerSize;
6093
6094  // Bail out if the object is not in new space.
6095  Node* object_word = BitcastTaggedToWord(object);
6096  Node* object_page = PageFromAddress(object_word);
6097  {
6098    Node* page_flags = Load(MachineType::IntPtr(), object_page,
6099                            IntPtrConstant(Page::kFlagsOffset));
6100    GotoIf(WordEqual(WordAnd(page_flags,
6101                             IntPtrConstant(MemoryChunk::kIsInNewSpaceMask)),
6102                     IntPtrConstant(0)),
6103           &no_memento_found);
6104  }
6105
6106  Node* memento_last_word = IntPtrAdd(
6107      object_word, IntPtrConstant(kMementoLastWordOffset - kHeapObjectTag));
6108  Node* memento_last_word_page = PageFromAddress(memento_last_word);
6109
6110  Node* new_space_top = Load(MachineType::Pointer(), new_space_top_address);
6111  Node* new_space_top_page = PageFromAddress(new_space_top);
6112
6113  // If the object is in new space, we need to check whether respective
6114  // potential memento object is on the same page as the current top.
6115  GotoIf(WordEqual(memento_last_word_page, new_space_top_page), &top_check);
6116
6117  // The object is on a different page than allocation top. Bail out if the
6118  // object sits on the page boundary as no memento can follow and we cannot
6119  // touch the memory following it.
6120  Branch(WordEqual(object_page, memento_last_word_page), &map_check,
6121         &no_memento_found);
6122
6123  // If top is on the same page as the current object, we need to check whether
6124  // we are below top.
6125  Bind(&top_check);
6126  {
6127    Branch(UintPtrGreaterThanOrEqual(memento_last_word, new_space_top),
6128           &no_memento_found, &map_check);
6129  }
6130
6131  // Memento map check.
6132  Bind(&map_check);
6133  {
6134    Node* memento_map = LoadObjectField(object, kMementoMapOffset);
6135    Branch(
6136        WordEqual(memento_map, LoadRoot(Heap::kAllocationMementoMapRootIndex)),
6137        memento_found, &no_memento_found);
6138  }
6139  Bind(&no_memento_found);
6140  Comment("] TrapAllocationMemento");
6141}
6142
6143Node* CodeStubAssembler::PageFromAddress(Node* address) {
6144  return WordAnd(address, IntPtrConstant(~Page::kPageAlignmentMask));
6145}
6146
6147Node* CodeStubAssembler::EnumLength(Node* map) {
6148  CSA_ASSERT(this, IsMap(map));
6149  Node* bitfield_3 = LoadMapBitField3(map);
6150  Node* enum_length = DecodeWordFromWord32<Map::EnumLengthBits>(bitfield_3);
6151  return SmiTag(enum_length);
6152}
6153
6154void CodeStubAssembler::CheckEnumCache(Node* receiver, Label* use_cache,
6155                                       Label* use_runtime) {
6156  Variable current_js_object(this, MachineRepresentation::kTagged, receiver);
6157
6158  Variable current_map(this, MachineRepresentation::kTagged,
6159                       LoadMap(current_js_object.value()));
6160
6161  // These variables are updated in the loop below.
6162  Variable* loop_vars[2] = {&current_js_object, &current_map};
6163  Label loop(this, 2, loop_vars), next(this);
6164
6165  // Check if the enum length field is properly initialized, indicating that
6166  // there is an enum cache.
6167  {
6168    Node* invalid_enum_cache_sentinel =
6169        SmiConstant(Smi::FromInt(kInvalidEnumCacheSentinel));
6170    Node* enum_length = EnumLength(current_map.value());
6171    Branch(WordEqual(enum_length, invalid_enum_cache_sentinel), use_runtime,
6172           &loop);
6173  }
6174
6175  // Check that there are no elements. |current_js_object| contains
6176  // the current JS object we've reached through the prototype chain.
6177  Bind(&loop);
6178  {
6179    Label if_elements(this), if_no_elements(this);
6180    Node* elements = LoadElements(current_js_object.value());
6181    Node* empty_fixed_array = LoadRoot(Heap::kEmptyFixedArrayRootIndex);
6182    // Check that there are no elements.
6183    Branch(WordEqual(elements, empty_fixed_array), &if_no_elements,
6184           &if_elements);
6185    Bind(&if_elements);
6186    {
6187      // Second chance, the object may be using the empty slow element
6188      // dictionary.
6189      Node* slow_empty_dictionary =
6190          LoadRoot(Heap::kEmptySlowElementDictionaryRootIndex);
6191      Branch(WordNotEqual(elements, slow_empty_dictionary), use_runtime,
6192             &if_no_elements);
6193    }
6194
6195    Bind(&if_no_elements);
6196    {
6197      // Update map prototype.
6198      current_js_object.Bind(LoadMapPrototype(current_map.value()));
6199      Branch(WordEqual(current_js_object.value(), NullConstant()), use_cache,
6200             &next);
6201    }
6202  }
6203
6204  Bind(&next);
6205  {
6206    // For all objects but the receiver, check that the cache is empty.
6207    current_map.Bind(LoadMap(current_js_object.value()));
6208    Node* enum_length = EnumLength(current_map.value());
6209    Node* zero_constant = SmiConstant(Smi::kZero);
6210    Branch(WordEqual(enum_length, zero_constant), &loop, use_runtime);
6211  }
6212}
6213
6214Node* CodeStubAssembler::CreateAllocationSiteInFeedbackVector(
6215    Node* feedback_vector, Node* slot) {
6216  Node* size = IntPtrConstant(AllocationSite::kSize);
6217  Node* site = Allocate(size, CodeStubAssembler::kPretenured);
6218
6219  StoreMap(site, AllocationSiteMapConstant());
6220  Node* kind = SmiConstant(GetInitialFastElementsKind());
6221  StoreObjectFieldNoWriteBarrier(site, AllocationSite::kTransitionInfoOffset,
6222                                 kind);
6223
6224  // Unlike literals, constructed arrays don't have nested sites
6225  Node* zero = SmiConstant(0);
6226  StoreObjectFieldNoWriteBarrier(site, AllocationSite::kNestedSiteOffset, zero);
6227
6228  // Pretenuring calculation field.
6229  StoreObjectFieldNoWriteBarrier(site, AllocationSite::kPretenureDataOffset,
6230                                 zero);
6231
6232  // Pretenuring memento creation count field.
6233  StoreObjectFieldNoWriteBarrier(
6234      site, AllocationSite::kPretenureCreateCountOffset, zero);
6235
6236  // Store an empty fixed array for the code dependency.
6237  StoreObjectFieldRoot(site, AllocationSite::kDependentCodeOffset,
6238                       Heap::kEmptyFixedArrayRootIndex);
6239
6240  // Link the object to the allocation site list
6241  Node* site_list = ExternalConstant(
6242      ExternalReference::allocation_sites_list_address(isolate()));
6243  Node* next_site = LoadBufferObject(site_list, 0);
6244
6245  // TODO(mvstanton): This is a store to a weak pointer, which we may want to
6246  // mark as such in order to skip the write barrier, once we have a unified
6247  // system for weakness. For now we decided to keep it like this because having
6248  // an initial write barrier backed store makes this pointer strong until the
6249  // next GC, and allocation sites are designed to survive several GCs anyway.
6250  StoreObjectField(site, AllocationSite::kWeakNextOffset, next_site);
6251  StoreNoWriteBarrier(MachineRepresentation::kTagged, site_list, site);
6252
6253  StoreFixedArrayElement(feedback_vector, slot, site, UPDATE_WRITE_BARRIER, 0,
6254                         CodeStubAssembler::SMI_PARAMETERS);
6255  return site;
6256}
6257
6258Node* CodeStubAssembler::CreateWeakCellInFeedbackVector(Node* feedback_vector,
6259                                                        Node* slot,
6260                                                        Node* value) {
6261  Node* size = IntPtrConstant(WeakCell::kSize);
6262  Node* cell = Allocate(size, CodeStubAssembler::kPretenured);
6263
6264  // Initialize the WeakCell.
6265  DCHECK(Heap::RootIsImmortalImmovable(Heap::kWeakCellMapRootIndex));
6266  StoreMapNoWriteBarrier(cell, Heap::kWeakCellMapRootIndex);
6267  StoreObjectField(cell, WeakCell::kValueOffset, value);
6268  StoreObjectFieldRoot(cell, WeakCell::kNextOffset,
6269                       Heap::kTheHoleValueRootIndex);
6270
6271  // Store the WeakCell in the feedback vector.
6272  StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, 0,
6273                         CodeStubAssembler::SMI_PARAMETERS);
6274  return cell;
6275}
6276
6277Node* CodeStubAssembler::BuildFastLoop(
6278    const CodeStubAssembler::VariableList& vars, Node* start_index,
6279    Node* end_index, const FastLoopBody& body, int increment,
6280    ParameterMode parameter_mode, IndexAdvanceMode advance_mode) {
6281  MachineRepresentation index_rep = (parameter_mode == INTPTR_PARAMETERS)
6282                                        ? MachineType::PointerRepresentation()
6283                                        : MachineRepresentation::kTaggedSigned;
6284  Variable var(this, index_rep, start_index);
6285  VariableList vars_copy(vars, zone());
6286  vars_copy.Add(&var, zone());
6287  Label loop(this, vars_copy);
6288  Label after_loop(this);
6289  // Introduce an explicit second check of the termination condition before the
6290  // loop that helps turbofan generate better code. If there's only a single
6291  // check, then the CodeStubAssembler forces it to be at the beginning of the
6292  // loop requiring a backwards branch at the end of the loop (it's not possible
6293  // to force the loop header check at the end of the loop and branch forward to
6294  // it from the pre-header). The extra branch is slower in the case that the
6295  // loop actually iterates.
6296  Branch(WordEqual(var.value(), end_index), &after_loop, &loop);
6297  Bind(&loop);
6298  {
6299    if (advance_mode == IndexAdvanceMode::kPre) {
6300      Increment(var, increment, parameter_mode);
6301    }
6302    body(var.value());
6303    if (advance_mode == IndexAdvanceMode::kPost) {
6304      Increment(var, increment, parameter_mode);
6305    }
6306    Branch(WordNotEqual(var.value(), end_index), &loop, &after_loop);
6307  }
6308  Bind(&after_loop);
6309  return var.value();
6310}
6311
6312void CodeStubAssembler::BuildFastFixedArrayForEach(
6313    const CodeStubAssembler::VariableList& vars, Node* fixed_array,
6314    ElementsKind kind, Node* first_element_inclusive,
6315    Node* last_element_exclusive, const FastFixedArrayForEachBody& body,
6316    ParameterMode mode, ForEachDirection direction) {
6317  STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
6318  int32_t first_val;
6319  bool constant_first = ToInt32Constant(first_element_inclusive, first_val);
6320  int32_t last_val;
6321  bool constent_last = ToInt32Constant(last_element_exclusive, last_val);
6322  if (constant_first && constent_last) {
6323    int delta = last_val - first_val;
6324    DCHECK(delta >= 0);
6325    if (delta <= kElementLoopUnrollThreshold) {
6326      if (direction == ForEachDirection::kForward) {
6327        for (int i = first_val; i < last_val; ++i) {
6328          Node* index = IntPtrConstant(i);
6329          Node* offset =
6330              ElementOffsetFromIndex(index, kind, INTPTR_PARAMETERS,
6331                                     FixedArray::kHeaderSize - kHeapObjectTag);
6332          body(fixed_array, offset);
6333        }
6334      } else {
6335        for (int i = last_val - 1; i >= first_val; --i) {
6336          Node* index = IntPtrConstant(i);
6337          Node* offset =
6338              ElementOffsetFromIndex(index, kind, INTPTR_PARAMETERS,
6339                                     FixedArray::kHeaderSize - kHeapObjectTag);
6340          body(fixed_array, offset);
6341        }
6342      }
6343      return;
6344    }
6345  }
6346
6347  Node* start =
6348      ElementOffsetFromIndex(first_element_inclusive, kind, mode,
6349                             FixedArray::kHeaderSize - kHeapObjectTag);
6350  Node* limit =
6351      ElementOffsetFromIndex(last_element_exclusive, kind, mode,
6352                             FixedArray::kHeaderSize - kHeapObjectTag);
6353  if (direction == ForEachDirection::kReverse) std::swap(start, limit);
6354
6355  int increment = IsFastDoubleElementsKind(kind) ? kDoubleSize : kPointerSize;
6356  BuildFastLoop(
6357      vars, start, limit,
6358      [fixed_array, &body](Node* offset) { body(fixed_array, offset); },
6359      direction == ForEachDirection::kReverse ? -increment : increment,
6360      INTPTR_PARAMETERS,
6361      direction == ForEachDirection::kReverse ? IndexAdvanceMode::kPre
6362                                              : IndexAdvanceMode::kPost);
6363}
6364
6365void CodeStubAssembler::GotoIfFixedArraySizeDoesntFitInNewSpace(
6366    Node* element_count, Label* doesnt_fit, int base_size, ParameterMode mode) {
6367  int max_newspace_parameters =
6368      (kMaxRegularHeapObjectSize - base_size) / kPointerSize;
6369  GotoIf(IntPtrOrSmiGreaterThan(
6370             element_count, IntPtrOrSmiConstant(max_newspace_parameters, mode),
6371             mode),
6372         doesnt_fit);
6373}
6374
6375void CodeStubAssembler::InitializeFieldsWithRoot(
6376    Node* object, Node* start_offset, Node* end_offset,
6377    Heap::RootListIndex root_index) {
6378  start_offset = IntPtrAdd(start_offset, IntPtrConstant(-kHeapObjectTag));
6379  end_offset = IntPtrAdd(end_offset, IntPtrConstant(-kHeapObjectTag));
6380  Node* root_value = LoadRoot(root_index);
6381  BuildFastLoop(end_offset, start_offset,
6382                [this, object, root_value](Node* current) {
6383                  StoreNoWriteBarrier(MachineRepresentation::kTagged, object,
6384                                      current, root_value);
6385                },
6386                -kPointerSize, INTPTR_PARAMETERS,
6387                CodeStubAssembler::IndexAdvanceMode::kPre);
6388}
6389
6390void CodeStubAssembler::BranchIfNumericRelationalComparison(
6391    RelationalComparisonMode mode, Node* lhs, Node* rhs, Label* if_true,
6392    Label* if_false) {
6393  Label end(this);
6394  Variable result(this, MachineRepresentation::kTagged);
6395
6396  // Shared entry for floating point comparison.
6397  Label do_fcmp(this);
6398  Variable var_fcmp_lhs(this, MachineRepresentation::kFloat64),
6399      var_fcmp_rhs(this, MachineRepresentation::kFloat64);
6400
6401  // Check if the {lhs} is a Smi or a HeapObject.
6402  Label if_lhsissmi(this), if_lhsisnotsmi(this);
6403  Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
6404
6405  Bind(&if_lhsissmi);
6406  {
6407    // Check if {rhs} is a Smi or a HeapObject.
6408    Label if_rhsissmi(this), if_rhsisnotsmi(this);
6409    Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
6410
6411    Bind(&if_rhsissmi);
6412    {
6413      // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison.
6414      switch (mode) {
6415        case kLessThan:
6416          BranchIfSmiLessThan(lhs, rhs, if_true, if_false);
6417          break;
6418        case kLessThanOrEqual:
6419          BranchIfSmiLessThanOrEqual(lhs, rhs, if_true, if_false);
6420          break;
6421        case kGreaterThan:
6422          BranchIfSmiLessThan(rhs, lhs, if_true, if_false);
6423          break;
6424        case kGreaterThanOrEqual:
6425          BranchIfSmiLessThanOrEqual(rhs, lhs, if_true, if_false);
6426          break;
6427      }
6428    }
6429
6430    Bind(&if_rhsisnotsmi);
6431    {
6432      CSA_ASSERT(this, IsHeapNumberMap(LoadMap(rhs)));
6433      // Convert the {lhs} and {rhs} to floating point values, and
6434      // perform a floating point comparison.
6435      var_fcmp_lhs.Bind(SmiToFloat64(lhs));
6436      var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
6437      Goto(&do_fcmp);
6438    }
6439  }
6440
6441  Bind(&if_lhsisnotsmi);
6442  {
6443    CSA_ASSERT(this, IsHeapNumberMap(LoadMap(lhs)));
6444
6445    // Check if {rhs} is a Smi or a HeapObject.
6446    Label if_rhsissmi(this), if_rhsisnotsmi(this);
6447    Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
6448
6449    Bind(&if_rhsissmi);
6450    {
6451      // Convert the {lhs} and {rhs} to floating point values, and
6452      // perform a floating point comparison.
6453      var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs));
6454      var_fcmp_rhs.Bind(SmiToFloat64(rhs));
6455      Goto(&do_fcmp);
6456    }
6457
6458    Bind(&if_rhsisnotsmi);
6459    {
6460      CSA_ASSERT(this, IsHeapNumberMap(LoadMap(rhs)));
6461
6462      // Convert the {lhs} and {rhs} to floating point values, and
6463      // perform a floating point comparison.
6464      var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs));
6465      var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
6466      Goto(&do_fcmp);
6467    }
6468  }
6469
6470  Bind(&do_fcmp);
6471  {
6472    // Load the {lhs} and {rhs} floating point values.
6473    Node* lhs = var_fcmp_lhs.value();
6474    Node* rhs = var_fcmp_rhs.value();
6475
6476    // Perform a fast floating point comparison.
6477    switch (mode) {
6478      case kLessThan:
6479        Branch(Float64LessThan(lhs, rhs), if_true, if_false);
6480        break;
6481      case kLessThanOrEqual:
6482        Branch(Float64LessThanOrEqual(lhs, rhs), if_true, if_false);
6483        break;
6484      case kGreaterThan:
6485        Branch(Float64GreaterThan(lhs, rhs), if_true, if_false);
6486        break;
6487      case kGreaterThanOrEqual:
6488        Branch(Float64GreaterThanOrEqual(lhs, rhs), if_true, if_false);
6489        break;
6490    }
6491  }
6492}
6493
6494void CodeStubAssembler::GotoUnlessNumberLessThan(Node* lhs, Node* rhs,
6495                                                 Label* if_false) {
6496  Label if_true(this);
6497  BranchIfNumericRelationalComparison(kLessThan, lhs, rhs, &if_true, if_false);
6498  Bind(&if_true);
6499}
6500
6501Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
6502                                              Node* lhs, Node* rhs,
6503                                              Node* context) {
6504  Label return_true(this), return_false(this), end(this);
6505  Variable result(this, MachineRepresentation::kTagged);
6506
6507  // Shared entry for floating point comparison.
6508  Label do_fcmp(this);
6509  Variable var_fcmp_lhs(this, MachineRepresentation::kFloat64),
6510      var_fcmp_rhs(this, MachineRepresentation::kFloat64);
6511
6512  // We might need to loop several times due to ToPrimitive and/or ToNumber
6513  // conversions.
6514  Variable var_lhs(this, MachineRepresentation::kTagged, lhs),
6515      var_rhs(this, MachineRepresentation::kTagged, rhs);
6516  Variable* loop_vars[2] = {&var_lhs, &var_rhs};
6517  Label loop(this, 2, loop_vars);
6518  Goto(&loop);
6519  Bind(&loop);
6520  {
6521    // Load the current {lhs} and {rhs} values.
6522    lhs = var_lhs.value();
6523    rhs = var_rhs.value();
6524
6525    // Check if the {lhs} is a Smi or a HeapObject.
6526    Label if_lhsissmi(this), if_lhsisnotsmi(this);
6527    Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
6528
6529    Bind(&if_lhsissmi);
6530    {
6531      // Check if {rhs} is a Smi or a HeapObject.
6532      Label if_rhsissmi(this), if_rhsisnotsmi(this);
6533      Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
6534
6535      Bind(&if_rhsissmi);
6536      {
6537        // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison.
6538        switch (mode) {
6539          case kLessThan:
6540            BranchIfSmiLessThan(lhs, rhs, &return_true, &return_false);
6541            break;
6542          case kLessThanOrEqual:
6543            BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true, &return_false);
6544            break;
6545          case kGreaterThan:
6546            BranchIfSmiLessThan(rhs, lhs, &return_true, &return_false);
6547            break;
6548          case kGreaterThanOrEqual:
6549            BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true, &return_false);
6550            break;
6551        }
6552      }
6553
6554      Bind(&if_rhsisnotsmi);
6555      {
6556        // Load the map of {rhs}.
6557        Node* rhs_map = LoadMap(rhs);
6558
6559        // Check if the {rhs} is a HeapNumber.
6560        Label if_rhsisnumber(this), if_rhsisnotnumber(this, Label::kDeferred);
6561        Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber);
6562
6563        Bind(&if_rhsisnumber);
6564        {
6565          // Convert the {lhs} and {rhs} to floating point values, and
6566          // perform a floating point comparison.
6567          var_fcmp_lhs.Bind(SmiToFloat64(lhs));
6568          var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
6569          Goto(&do_fcmp);
6570        }
6571
6572        Bind(&if_rhsisnotnumber);
6573        {
6574          // Convert the {rhs} to a Number; we don't need to perform the
6575          // dedicated ToPrimitive(rhs, hint Number) operation, as the
6576          // ToNumber(rhs) will by itself already invoke ToPrimitive with
6577          // a Number hint.
6578          Callable callable = CodeFactory::NonNumberToNumber(isolate());
6579          var_rhs.Bind(CallStub(callable, context, rhs));
6580          Goto(&loop);
6581        }
6582      }
6583    }
6584
6585    Bind(&if_lhsisnotsmi);
6586    {
6587      // Load the map of {lhs}.
6588      Node* lhs_map = LoadMap(lhs);
6589
6590      // Check if {rhs} is a Smi or a HeapObject.
6591      Label if_rhsissmi(this), if_rhsisnotsmi(this);
6592      Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
6593
6594      Bind(&if_rhsissmi);
6595      {
6596        // Check if the {lhs} is a HeapNumber.
6597        Label if_lhsisnumber(this), if_lhsisnotnumber(this, Label::kDeferred);
6598        Branch(IsHeapNumberMap(lhs_map), &if_lhsisnumber, &if_lhsisnotnumber);
6599
6600        Bind(&if_lhsisnumber);
6601        {
6602          // Convert the {lhs} and {rhs} to floating point values, and
6603          // perform a floating point comparison.
6604          var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs));
6605          var_fcmp_rhs.Bind(SmiToFloat64(rhs));
6606          Goto(&do_fcmp);
6607        }
6608
6609        Bind(&if_lhsisnotnumber);
6610        {
6611          // Convert the {lhs} to a Number; we don't need to perform the
6612          // dedicated ToPrimitive(lhs, hint Number) operation, as the
6613          // ToNumber(lhs) will by itself already invoke ToPrimitive with
6614          // a Number hint.
6615          Callable callable = CodeFactory::NonNumberToNumber(isolate());
6616          var_lhs.Bind(CallStub(callable, context, lhs));
6617          Goto(&loop);
6618        }
6619      }
6620
6621      Bind(&if_rhsisnotsmi);
6622      {
6623        // Load the map of {rhs}.
6624        Node* rhs_map = LoadMap(rhs);
6625
6626        // Check if {lhs} is a HeapNumber.
6627        Label if_lhsisnumber(this), if_lhsisnotnumber(this);
6628        Branch(IsHeapNumberMap(lhs_map), &if_lhsisnumber, &if_lhsisnotnumber);
6629
6630        Bind(&if_lhsisnumber);
6631        {
6632          // Check if {rhs} is also a HeapNumber.
6633          Label if_rhsisnumber(this), if_rhsisnotnumber(this, Label::kDeferred);
6634          Branch(WordEqual(lhs_map, rhs_map), &if_rhsisnumber,
6635                 &if_rhsisnotnumber);
6636
6637          Bind(&if_rhsisnumber);
6638          {
6639            // Convert the {lhs} and {rhs} to floating point values, and
6640            // perform a floating point comparison.
6641            var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs));
6642            var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
6643            Goto(&do_fcmp);
6644          }
6645
6646          Bind(&if_rhsisnotnumber);
6647          {
6648            // Convert the {rhs} to a Number; we don't need to perform
6649            // dedicated ToPrimitive(rhs, hint Number) operation, as the
6650            // ToNumber(rhs) will by itself already invoke ToPrimitive with
6651            // a Number hint.
6652            Callable callable = CodeFactory::NonNumberToNumber(isolate());
6653            var_rhs.Bind(CallStub(callable, context, rhs));
6654            Goto(&loop);
6655          }
6656        }
6657
6658        Bind(&if_lhsisnotnumber);
6659        {
6660          // Load the instance type of {lhs}.
6661          Node* lhs_instance_type = LoadMapInstanceType(lhs_map);
6662
6663          // Check if {lhs} is a String.
6664          Label if_lhsisstring(this), if_lhsisnotstring(this, Label::kDeferred);
6665          Branch(IsStringInstanceType(lhs_instance_type), &if_lhsisstring,
6666                 &if_lhsisnotstring);
6667
6668          Bind(&if_lhsisstring);
6669          {
6670            // Load the instance type of {rhs}.
6671            Node* rhs_instance_type = LoadMapInstanceType(rhs_map);
6672
6673            // Check if {rhs} is also a String.
6674            Label if_rhsisstring(this, Label::kDeferred),
6675                if_rhsisnotstring(this, Label::kDeferred);
6676            Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring,
6677                   &if_rhsisnotstring);
6678
6679            Bind(&if_rhsisstring);
6680            {
6681              // Both {lhs} and {rhs} are strings.
6682              switch (mode) {
6683                case kLessThan:
6684                  result.Bind(CallStub(CodeFactory::StringLessThan(isolate()),
6685                                       context, lhs, rhs));
6686                  Goto(&end);
6687                  break;
6688                case kLessThanOrEqual:
6689                  result.Bind(
6690                      CallStub(CodeFactory::StringLessThanOrEqual(isolate()),
6691                               context, lhs, rhs));
6692                  Goto(&end);
6693                  break;
6694                case kGreaterThan:
6695                  result.Bind(
6696                      CallStub(CodeFactory::StringGreaterThan(isolate()),
6697                               context, lhs, rhs));
6698                  Goto(&end);
6699                  break;
6700                case kGreaterThanOrEqual:
6701                  result.Bind(
6702                      CallStub(CodeFactory::StringGreaterThanOrEqual(isolate()),
6703                               context, lhs, rhs));
6704                  Goto(&end);
6705                  break;
6706              }
6707            }
6708
6709            Bind(&if_rhsisnotstring);
6710            {
6711              // The {lhs} is a String, while {rhs} is neither a Number nor a
6712              // String, so we need to call ToPrimitive(rhs, hint Number) if
6713              // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the
6714              // other cases.
6715              STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
6716              Label if_rhsisreceiver(this, Label::kDeferred),
6717                  if_rhsisnotreceiver(this, Label::kDeferred);
6718              Branch(IsJSReceiverInstanceType(rhs_instance_type),
6719                     &if_rhsisreceiver, &if_rhsisnotreceiver);
6720
6721              Bind(&if_rhsisreceiver);
6722              {
6723                // Convert {rhs} to a primitive first passing Number hint.
6724                Callable callable = CodeFactory::NonPrimitiveToPrimitive(
6725                    isolate(), ToPrimitiveHint::kNumber);
6726                var_rhs.Bind(CallStub(callable, context, rhs));
6727                Goto(&loop);
6728              }
6729
6730              Bind(&if_rhsisnotreceiver);
6731              {
6732                // Convert both {lhs} and {rhs} to Number.
6733                Callable callable = CodeFactory::ToNumber(isolate());
6734                var_lhs.Bind(CallStub(callable, context, lhs));
6735                var_rhs.Bind(CallStub(callable, context, rhs));
6736                Goto(&loop);
6737              }
6738            }
6739          }
6740
6741          Bind(&if_lhsisnotstring);
6742          {
6743            // The {lhs} is neither a Number nor a String, so we need to call
6744            // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or
6745            // ToNumber(lhs) and ToNumber(rhs) in the other cases.
6746            STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
6747            Label if_lhsisreceiver(this, Label::kDeferred),
6748                if_lhsisnotreceiver(this, Label::kDeferred);
6749            Branch(IsJSReceiverInstanceType(lhs_instance_type),
6750                   &if_lhsisreceiver, &if_lhsisnotreceiver);
6751
6752            Bind(&if_lhsisreceiver);
6753            {
6754              // Convert {lhs} to a primitive first passing Number hint.
6755              Callable callable = CodeFactory::NonPrimitiveToPrimitive(
6756                  isolate(), ToPrimitiveHint::kNumber);
6757              var_lhs.Bind(CallStub(callable, context, lhs));
6758              Goto(&loop);
6759            }
6760
6761            Bind(&if_lhsisnotreceiver);
6762            {
6763              // Convert both {lhs} and {rhs} to Number.
6764              Callable callable = CodeFactory::ToNumber(isolate());
6765              var_lhs.Bind(CallStub(callable, context, lhs));
6766              var_rhs.Bind(CallStub(callable, context, rhs));
6767              Goto(&loop);
6768            }
6769          }
6770        }
6771      }
6772    }
6773  }
6774
6775  Bind(&do_fcmp);
6776  {
6777    // Load the {lhs} and {rhs} floating point values.
6778    Node* lhs = var_fcmp_lhs.value();
6779    Node* rhs = var_fcmp_rhs.value();
6780
6781    // Perform a fast floating point comparison.
6782    switch (mode) {
6783      case kLessThan:
6784        Branch(Float64LessThan(lhs, rhs), &return_true, &return_false);
6785        break;
6786      case kLessThanOrEqual:
6787        Branch(Float64LessThanOrEqual(lhs, rhs), &return_true, &return_false);
6788        break;
6789      case kGreaterThan:
6790        Branch(Float64GreaterThan(lhs, rhs), &return_true, &return_false);
6791        break;
6792      case kGreaterThanOrEqual:
6793        Branch(Float64GreaterThanOrEqual(lhs, rhs), &return_true,
6794               &return_false);
6795        break;
6796    }
6797  }
6798
6799  Bind(&return_true);
6800  {
6801    result.Bind(BooleanConstant(true));
6802    Goto(&end);
6803  }
6804
6805  Bind(&return_false);
6806  {
6807    result.Bind(BooleanConstant(false));
6808    Goto(&end);
6809  }
6810
6811  Bind(&end);
6812  return result.value();
6813}
6814
6815namespace {
6816
6817void GenerateEqual_Same(CodeStubAssembler* assembler, Node* value,
6818                        CodeStubAssembler::Label* if_equal,
6819                        CodeStubAssembler::Label* if_notequal) {
6820  // In case of abstract or strict equality checks, we need additional checks
6821  // for NaN values because they are not considered equal, even if both the
6822  // left and the right hand side reference exactly the same value.
6823
6824  typedef CodeStubAssembler::Label Label;
6825
6826  // Check if {value} is a Smi or a HeapObject.
6827  Label if_valueissmi(assembler), if_valueisnotsmi(assembler);
6828  assembler->Branch(assembler->TaggedIsSmi(value), &if_valueissmi,
6829                    &if_valueisnotsmi);
6830
6831  assembler->Bind(&if_valueisnotsmi);
6832  {
6833    // Load the map of {value}.
6834    Node* value_map = assembler->LoadMap(value);
6835
6836    // Check if {value} (and therefore {rhs}) is a HeapNumber.
6837    Label if_valueisnumber(assembler), if_valueisnotnumber(assembler);
6838    assembler->Branch(assembler->IsHeapNumberMap(value_map), &if_valueisnumber,
6839                      &if_valueisnotnumber);
6840
6841    assembler->Bind(&if_valueisnumber);
6842    {
6843      // Convert {value} (and therefore {rhs}) to floating point value.
6844      Node* value_value = assembler->LoadHeapNumberValue(value);
6845
6846      // Check if the HeapNumber value is a NaN.
6847      assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal);
6848    }
6849
6850    assembler->Bind(&if_valueisnotnumber);
6851    assembler->Goto(if_equal);
6852  }
6853
6854  assembler->Bind(&if_valueissmi);
6855  assembler->Goto(if_equal);
6856}
6857}  // namespace
6858
6859// ES6 section 7.2.12 Abstract Equality Comparison
6860Node* CodeStubAssembler::Equal(ResultMode mode, Node* lhs, Node* rhs,
6861                               Node* context) {
6862  // This is a slightly optimized version of Object::Equals represented as
6863  // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you
6864  // change something functionality wise in here, remember to update the
6865  // Object::Equals method as well.
6866
6867  Label if_equal(this), if_notequal(this),
6868      do_rhsstringtonumber(this, Label::kDeferred), end(this);
6869  Variable result(this, MachineRepresentation::kTagged);
6870
6871  // Shared entry for floating point comparison.
6872  Label do_fcmp(this);
6873  Variable var_fcmp_lhs(this, MachineRepresentation::kFloat64),
6874      var_fcmp_rhs(this, MachineRepresentation::kFloat64);
6875
6876  // We might need to loop several times due to ToPrimitive and/or ToNumber
6877  // conversions.
6878  Variable var_lhs(this, MachineRepresentation::kTagged, lhs),
6879      var_rhs(this, MachineRepresentation::kTagged, rhs);
6880  Variable* loop_vars[2] = {&var_lhs, &var_rhs};
6881  Label loop(this, 2, loop_vars);
6882  Goto(&loop);
6883  Bind(&loop);
6884  {
6885    // Load the current {lhs} and {rhs} values.
6886    lhs = var_lhs.value();
6887    rhs = var_rhs.value();
6888
6889    // Check if {lhs} and {rhs} refer to the same object.
6890    Label if_same(this), if_notsame(this);
6891    Branch(WordEqual(lhs, rhs), &if_same, &if_notsame);
6892
6893    Bind(&if_same);
6894    {
6895      // The {lhs} and {rhs} reference the exact same value, yet we need special
6896      // treatment for HeapNumber, as NaN is not equal to NaN.
6897      GenerateEqual_Same(this, lhs, &if_equal, &if_notequal);
6898    }
6899
6900    Bind(&if_notsame);
6901    {
6902      // Check if {lhs} is a Smi or a HeapObject.
6903      Label if_lhsissmi(this), if_lhsisnotsmi(this);
6904      Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
6905
6906      Bind(&if_lhsissmi);
6907      {
6908        // Check if {rhs} is a Smi or a HeapObject.
6909        Label if_rhsissmi(this), if_rhsisnotsmi(this);
6910        Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
6911
6912        Bind(&if_rhsissmi);
6913        // We have already checked for {lhs} and {rhs} being the same value, so
6914        // if both are Smis when we get here they must not be equal.
6915        Goto(&if_notequal);
6916
6917        Bind(&if_rhsisnotsmi);
6918        {
6919          // Load the map of {rhs}.
6920          Node* rhs_map = LoadMap(rhs);
6921
6922          // Check if {rhs} is a HeapNumber.
6923          Label if_rhsisnumber(this), if_rhsisnotnumber(this);
6924          Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber);
6925
6926          Bind(&if_rhsisnumber);
6927          {
6928            // Convert {lhs} and {rhs} to floating point values, and
6929            // perform a floating point comparison.
6930            var_fcmp_lhs.Bind(SmiToFloat64(lhs));
6931            var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
6932            Goto(&do_fcmp);
6933          }
6934
6935          Bind(&if_rhsisnotnumber);
6936          {
6937            // Load the instance type of the {rhs}.
6938            Node* rhs_instance_type = LoadMapInstanceType(rhs_map);
6939
6940            // Check if the {rhs} is a String.
6941            Label if_rhsisstring(this, Label::kDeferred),
6942                if_rhsisnotstring(this);
6943            Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring,
6944                   &if_rhsisnotstring);
6945
6946            Bind(&if_rhsisstring);
6947            {
6948              // The {rhs} is a String and the {lhs} is a Smi; we need
6949              // to convert the {rhs} to a Number and compare the output to
6950              // the Number on the {lhs}.
6951              Goto(&do_rhsstringtonumber);
6952            }
6953
6954            Bind(&if_rhsisnotstring);
6955            {
6956              // Check if the {rhs} is a Boolean.
6957              Label if_rhsisboolean(this), if_rhsisnotboolean(this);
6958              Branch(IsBooleanMap(rhs_map), &if_rhsisboolean,
6959                     &if_rhsisnotboolean);
6960
6961              Bind(&if_rhsisboolean);
6962              {
6963                // The {rhs} is a Boolean, load its number value.
6964                var_rhs.Bind(LoadObjectField(rhs, Oddball::kToNumberOffset));
6965                Goto(&loop);
6966              }
6967
6968              Bind(&if_rhsisnotboolean);
6969              {
6970                // Check if the {rhs} is a Receiver.
6971                STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
6972                Label if_rhsisreceiver(this, Label::kDeferred),
6973                    if_rhsisnotreceiver(this);
6974                Branch(IsJSReceiverInstanceType(rhs_instance_type),
6975                       &if_rhsisreceiver, &if_rhsisnotreceiver);
6976
6977                Bind(&if_rhsisreceiver);
6978                {
6979                  // Convert {rhs} to a primitive first (passing no hint).
6980                  Callable callable =
6981                      CodeFactory::NonPrimitiveToPrimitive(isolate());
6982                  var_rhs.Bind(CallStub(callable, context, rhs));
6983                  Goto(&loop);
6984                }
6985
6986                Bind(&if_rhsisnotreceiver);
6987                Goto(&if_notequal);
6988              }
6989            }
6990          }
6991        }
6992      }
6993
6994      Bind(&if_lhsisnotsmi);
6995      {
6996        // Check if {rhs} is a Smi or a HeapObject.
6997        Label if_rhsissmi(this), if_rhsisnotsmi(this);
6998        Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
6999
7000        Bind(&if_rhsissmi);
7001        {
7002          // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs}
7003          // and {rhs} is not observable and doesn't matter for the result, so
7004          // we can just swap them and use the Smi handling above (for {lhs}
7005          // being a Smi).
7006          var_lhs.Bind(rhs);
7007          var_rhs.Bind(lhs);
7008          Goto(&loop);
7009        }
7010
7011        Bind(&if_rhsisnotsmi);
7012        {
7013          Label if_lhsisstring(this), if_lhsisnumber(this),
7014              if_lhsissymbol(this), if_lhsisoddball(this),
7015              if_lhsisreceiver(this);
7016
7017          // Both {lhs} and {rhs} are HeapObjects, load their maps
7018          // and their instance types.
7019          Node* lhs_map = LoadMap(lhs);
7020          Node* rhs_map = LoadMap(rhs);
7021
7022          // Load the instance types of {lhs} and {rhs}.
7023          Node* lhs_instance_type = LoadMapInstanceType(lhs_map);
7024          Node* rhs_instance_type = LoadMapInstanceType(rhs_map);
7025
7026          // Dispatch based on the instance type of {lhs}.
7027          size_t const kNumCases = FIRST_NONSTRING_TYPE + 3;
7028          Label* case_labels[kNumCases];
7029          int32_t case_values[kNumCases];
7030          for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
7031            case_labels[i] = new Label(this);
7032            case_values[i] = i;
7033          }
7034          case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber;
7035          case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE;
7036          case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol;
7037          case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE;
7038          case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsisoddball;
7039          case_values[FIRST_NONSTRING_TYPE + 2] = ODDBALL_TYPE;
7040          Switch(lhs_instance_type, &if_lhsisreceiver, case_values, case_labels,
7041                 arraysize(case_values));
7042          for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
7043            Bind(case_labels[i]);
7044            Goto(&if_lhsisstring);
7045            delete case_labels[i];
7046          }
7047
7048          Bind(&if_lhsisstring);
7049          {
7050            // Check if {rhs} is also a String.
7051            Label if_rhsisstring(this, Label::kDeferred),
7052                if_rhsisnotstring(this);
7053            Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring,
7054                   &if_rhsisnotstring);
7055
7056            Bind(&if_rhsisstring);
7057            {
7058              // Both {lhs} and {rhs} are of type String, just do the
7059              // string comparison then.
7060              Callable callable = (mode == kDontNegateResult)
7061                                      ? CodeFactory::StringEqual(isolate())
7062                                      : CodeFactory::StringNotEqual(isolate());
7063              result.Bind(CallStub(callable, context, lhs, rhs));
7064              Goto(&end);
7065            }
7066
7067            Bind(&if_rhsisnotstring);
7068            {
7069              // The {lhs} is a String and the {rhs} is some other HeapObject.
7070              // Swapping {lhs} and {rhs} is not observable and doesn't matter
7071              // for the result, so we can just swap them and use the String
7072              // handling below (for {rhs} being a String).
7073              var_lhs.Bind(rhs);
7074              var_rhs.Bind(lhs);
7075              Goto(&loop);
7076            }
7077          }
7078
7079          Bind(&if_lhsisnumber);
7080          {
7081            // Check if {rhs} is also a HeapNumber.
7082            Label if_rhsisnumber(this), if_rhsisnotnumber(this);
7083            Branch(Word32Equal(lhs_instance_type, rhs_instance_type),
7084                   &if_rhsisnumber, &if_rhsisnotnumber);
7085
7086            Bind(&if_rhsisnumber);
7087            {
7088              // Convert {lhs} and {rhs} to floating point values, and
7089              // perform a floating point comparison.
7090              var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs));
7091              var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
7092              Goto(&do_fcmp);
7093            }
7094
7095            Bind(&if_rhsisnotnumber);
7096            {
7097              // The {lhs} is a Number, the {rhs} is some other HeapObject.
7098              Label if_rhsisstring(this, Label::kDeferred),
7099                  if_rhsisnotstring(this);
7100              Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring,
7101                     &if_rhsisnotstring);
7102
7103              Bind(&if_rhsisstring);
7104              {
7105                // The {rhs} is a String and the {lhs} is a HeapNumber; we need
7106                // to convert the {rhs} to a Number and compare the output to
7107                // the Number on the {lhs}.
7108                Goto(&do_rhsstringtonumber);
7109              }
7110
7111              Bind(&if_rhsisnotstring);
7112              {
7113                // Check if the {rhs} is a JSReceiver.
7114                Label if_rhsisreceiver(this), if_rhsisnotreceiver(this);
7115                STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
7116                Branch(IsJSReceiverInstanceType(rhs_instance_type),
7117                       &if_rhsisreceiver, &if_rhsisnotreceiver);
7118
7119                Bind(&if_rhsisreceiver);
7120                {
7121                  // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
7122                  // Swapping {lhs} and {rhs} is not observable and doesn't
7123                  // matter for the result, so we can just swap them and use
7124                  // the JSReceiver handling below (for {lhs} being a
7125                  // JSReceiver).
7126                  var_lhs.Bind(rhs);
7127                  var_rhs.Bind(lhs);
7128                  Goto(&loop);
7129                }
7130
7131                Bind(&if_rhsisnotreceiver);
7132                {
7133                  // Check if {rhs} is a Boolean.
7134                  Label if_rhsisboolean(this), if_rhsisnotboolean(this);
7135                  Branch(IsBooleanMap(rhs_map), &if_rhsisboolean,
7136                         &if_rhsisnotboolean);
7137
7138                  Bind(&if_rhsisboolean);
7139                  {
7140                    // The {rhs} is a Boolean, convert it to a Smi first.
7141                    var_rhs.Bind(
7142                        LoadObjectField(rhs, Oddball::kToNumberOffset));
7143                    Goto(&loop);
7144                  }
7145
7146                  Bind(&if_rhsisnotboolean);
7147                  Goto(&if_notequal);
7148                }
7149              }
7150            }
7151          }
7152
7153          Bind(&if_lhsisoddball);
7154          {
7155            // The {lhs} is an Oddball and {rhs} is some other HeapObject.
7156            Label if_lhsisboolean(this), if_lhsisnotboolean(this);
7157            Node* boolean_map = BooleanMapConstant();
7158            Branch(WordEqual(lhs_map, boolean_map), &if_lhsisboolean,
7159                   &if_lhsisnotboolean);
7160
7161            Bind(&if_lhsisboolean);
7162            {
7163              // The {lhs} is a Boolean, check if {rhs} is also a Boolean.
7164              Label if_rhsisboolean(this), if_rhsisnotboolean(this);
7165              Branch(WordEqual(rhs_map, boolean_map), &if_rhsisboolean,
7166                     &if_rhsisnotboolean);
7167
7168              Bind(&if_rhsisboolean);
7169              {
7170                // Both {lhs} and {rhs} are distinct Boolean values.
7171                Goto(&if_notequal);
7172              }
7173
7174              Bind(&if_rhsisnotboolean);
7175              {
7176                // Convert the {lhs} to a Number first.
7177                var_lhs.Bind(LoadObjectField(lhs, Oddball::kToNumberOffset));
7178                Goto(&loop);
7179              }
7180            }
7181
7182            Bind(&if_lhsisnotboolean);
7183            {
7184              // The {lhs} is either Null or Undefined; check if the {rhs} is
7185              // undetectable (i.e. either also Null or Undefined or some
7186              // undetectable JSReceiver).
7187              Node* rhs_bitfield = LoadMapBitField(rhs_map);
7188              Branch(Word32Equal(
7189                         Word32And(rhs_bitfield,
7190                                   Int32Constant(1 << Map::kIsUndetectable)),
7191                         Int32Constant(0)),
7192                     &if_notequal, &if_equal);
7193            }
7194          }
7195
7196          Bind(&if_lhsissymbol);
7197          {
7198            // Check if the {rhs} is a JSReceiver.
7199            Label if_rhsisreceiver(this), if_rhsisnotreceiver(this);
7200            STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
7201            Branch(IsJSReceiverInstanceType(rhs_instance_type),
7202                   &if_rhsisreceiver, &if_rhsisnotreceiver);
7203
7204            Bind(&if_rhsisreceiver);
7205            {
7206              // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
7207              // Swapping {lhs} and {rhs} is not observable and doesn't
7208              // matter for the result, so we can just swap them and use
7209              // the JSReceiver handling below (for {lhs} being a JSReceiver).
7210              var_lhs.Bind(rhs);
7211              var_rhs.Bind(lhs);
7212              Goto(&loop);
7213            }
7214
7215            Bind(&if_rhsisnotreceiver);
7216            {
7217              // The {rhs} is not a JSReceiver and also not the same Symbol
7218              // as the {lhs}, so this is equality check is considered false.
7219              Goto(&if_notequal);
7220            }
7221          }
7222
7223          Bind(&if_lhsisreceiver);
7224          {
7225            // Check if the {rhs} is also a JSReceiver.
7226            Label if_rhsisreceiver(this), if_rhsisnotreceiver(this);
7227            STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
7228            Branch(IsJSReceiverInstanceType(rhs_instance_type),
7229                   &if_rhsisreceiver, &if_rhsisnotreceiver);
7230
7231            Bind(&if_rhsisreceiver);
7232            {
7233              // Both {lhs} and {rhs} are different JSReceiver references, so
7234              // this cannot be considered equal.
7235              Goto(&if_notequal);
7236            }
7237
7238            Bind(&if_rhsisnotreceiver);
7239            {
7240              // Check if {rhs} is Null or Undefined (an undetectable check
7241              // is sufficient here, since we already know that {rhs} is not
7242              // a JSReceiver).
7243              Label if_rhsisundetectable(this),
7244                  if_rhsisnotundetectable(this, Label::kDeferred);
7245              Node* rhs_bitfield = LoadMapBitField(rhs_map);
7246              Branch(Word32Equal(
7247                         Word32And(rhs_bitfield,
7248                                   Int32Constant(1 << Map::kIsUndetectable)),
7249                         Int32Constant(0)),
7250                     &if_rhsisnotundetectable, &if_rhsisundetectable);
7251
7252              Bind(&if_rhsisundetectable);
7253              {
7254                // Check if {lhs} is an undetectable JSReceiver.
7255                Node* lhs_bitfield = LoadMapBitField(lhs_map);
7256                Branch(Word32Equal(
7257                           Word32And(lhs_bitfield,
7258                                     Int32Constant(1 << Map::kIsUndetectable)),
7259                           Int32Constant(0)),
7260                       &if_notequal, &if_equal);
7261              }
7262
7263              Bind(&if_rhsisnotundetectable);
7264              {
7265                // The {rhs} is some Primitive different from Null and
7266                // Undefined, need to convert {lhs} to Primitive first.
7267                Callable callable =
7268                    CodeFactory::NonPrimitiveToPrimitive(isolate());
7269                var_lhs.Bind(CallStub(callable, context, lhs));
7270                Goto(&loop);
7271              }
7272            }
7273          }
7274        }
7275      }
7276    }
7277
7278    Bind(&do_rhsstringtonumber);
7279    {
7280      Callable callable = CodeFactory::StringToNumber(isolate());
7281      var_rhs.Bind(CallStub(callable, context, rhs));
7282      Goto(&loop);
7283    }
7284  }
7285
7286  Bind(&do_fcmp);
7287  {
7288    // Load the {lhs} and {rhs} floating point values.
7289    Node* lhs = var_fcmp_lhs.value();
7290    Node* rhs = var_fcmp_rhs.value();
7291
7292    // Perform a fast floating point comparison.
7293    Branch(Float64Equal(lhs, rhs), &if_equal, &if_notequal);
7294  }
7295
7296  Bind(&if_equal);
7297  {
7298    result.Bind(BooleanConstant(mode == kDontNegateResult));
7299    Goto(&end);
7300  }
7301
7302  Bind(&if_notequal);
7303  {
7304    result.Bind(BooleanConstant(mode == kNegateResult));
7305    Goto(&end);
7306  }
7307
7308  Bind(&end);
7309  return result.value();
7310}
7311
7312Node* CodeStubAssembler::StrictEqual(ResultMode mode, Node* lhs, Node* rhs,
7313                                     Node* context) {
7314  // Here's pseudo-code for the algorithm below in case of kDontNegateResult
7315  // mode; for kNegateResult mode we properly negate the result.
7316  //
7317  // if (lhs == rhs) {
7318  //   if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN;
7319  //   return true;
7320  // }
7321  // if (!lhs->IsSmi()) {
7322  //   if (lhs->IsHeapNumber()) {
7323  //     if (rhs->IsSmi()) {
7324  //       return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value();
7325  //     } else if (rhs->IsHeapNumber()) {
7326  //       return HeapNumber::cast(rhs)->value() ==
7327  //       HeapNumber::cast(lhs)->value();
7328  //     } else {
7329  //       return false;
7330  //     }
7331  //   } else {
7332  //     if (rhs->IsSmi()) {
7333  //       return false;
7334  //     } else {
7335  //       if (lhs->IsString()) {
7336  //         if (rhs->IsString()) {
7337  //           return %StringEqual(lhs, rhs);
7338  //         } else {
7339  //           return false;
7340  //         }
7341  //       } else {
7342  //         return false;
7343  //       }
7344  //     }
7345  //   }
7346  // } else {
7347  //   if (rhs->IsSmi()) {
7348  //     return false;
7349  //   } else {
7350  //     if (rhs->IsHeapNumber()) {
7351  //       return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value();
7352  //     } else {
7353  //       return false;
7354  //     }
7355  //   }
7356  // }
7357
7358  Label if_equal(this), if_notequal(this), end(this);
7359  Variable result(this, MachineRepresentation::kTagged);
7360
7361  // Check if {lhs} and {rhs} refer to the same object.
7362  Label if_same(this), if_notsame(this);
7363  Branch(WordEqual(lhs, rhs), &if_same, &if_notsame);
7364
7365  Bind(&if_same);
7366  {
7367    // The {lhs} and {rhs} reference the exact same value, yet we need special
7368    // treatment for HeapNumber, as NaN is not equal to NaN.
7369    GenerateEqual_Same(this, lhs, &if_equal, &if_notequal);
7370  }
7371
7372  Bind(&if_notsame);
7373  {
7374    // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber
7375    // and String they can still be considered equal.
7376
7377    // Check if {lhs} is a Smi or a HeapObject.
7378    Label if_lhsissmi(this), if_lhsisnotsmi(this);
7379    Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
7380
7381    Bind(&if_lhsisnotsmi);
7382    {
7383      // Load the map of {lhs}.
7384      Node* lhs_map = LoadMap(lhs);
7385
7386      // Check if {lhs} is a HeapNumber.
7387      Label if_lhsisnumber(this), if_lhsisnotnumber(this);
7388      Branch(IsHeapNumberMap(lhs_map), &if_lhsisnumber, &if_lhsisnotnumber);
7389
7390      Bind(&if_lhsisnumber);
7391      {
7392        // Check if {rhs} is a Smi or a HeapObject.
7393        Label if_rhsissmi(this), if_rhsisnotsmi(this);
7394        Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
7395
7396        Bind(&if_rhsissmi);
7397        {
7398          // Convert {lhs} and {rhs} to floating point values.
7399          Node* lhs_value = LoadHeapNumberValue(lhs);
7400          Node* rhs_value = SmiToFloat64(rhs);
7401
7402          // Perform a floating point comparison of {lhs} and {rhs}.
7403          Branch(Float64Equal(lhs_value, rhs_value), &if_equal, &if_notequal);
7404        }
7405
7406        Bind(&if_rhsisnotsmi);
7407        {
7408          // Load the map of {rhs}.
7409          Node* rhs_map = LoadMap(rhs);
7410
7411          // Check if {rhs} is also a HeapNumber.
7412          Label if_rhsisnumber(this), if_rhsisnotnumber(this);
7413          Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber);
7414
7415          Bind(&if_rhsisnumber);
7416          {
7417            // Convert {lhs} and {rhs} to floating point values.
7418            Node* lhs_value = LoadHeapNumberValue(lhs);
7419            Node* rhs_value = LoadHeapNumberValue(rhs);
7420
7421            // Perform a floating point comparison of {lhs} and {rhs}.
7422            Branch(Float64Equal(lhs_value, rhs_value), &if_equal, &if_notequal);
7423          }
7424
7425          Bind(&if_rhsisnotnumber);
7426          Goto(&if_notequal);
7427        }
7428      }
7429
7430      Bind(&if_lhsisnotnumber);
7431      {
7432        // Check if {rhs} is a Smi or a HeapObject.
7433        Label if_rhsissmi(this), if_rhsisnotsmi(this);
7434        Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
7435
7436        Bind(&if_rhsissmi);
7437        Goto(&if_notequal);
7438
7439        Bind(&if_rhsisnotsmi);
7440        {
7441          // Load the instance type of {lhs}.
7442          Node* lhs_instance_type = LoadMapInstanceType(lhs_map);
7443
7444          // Check if {lhs} is a String.
7445          Label if_lhsisstring(this), if_lhsisnotstring(this);
7446          Branch(IsStringInstanceType(lhs_instance_type), &if_lhsisstring,
7447                 &if_lhsisnotstring);
7448
7449          Bind(&if_lhsisstring);
7450          {
7451            // Load the instance type of {rhs}.
7452            Node* rhs_instance_type = LoadInstanceType(rhs);
7453
7454            // Check if {rhs} is also a String.
7455            Label if_rhsisstring(this, Label::kDeferred),
7456                if_rhsisnotstring(this);
7457            Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring,
7458                   &if_rhsisnotstring);
7459
7460            Bind(&if_rhsisstring);
7461            {
7462              Callable callable = (mode == kDontNegateResult)
7463                                      ? CodeFactory::StringEqual(isolate())
7464                                      : CodeFactory::StringNotEqual(isolate());
7465              result.Bind(CallStub(callable, context, lhs, rhs));
7466              Goto(&end);
7467            }
7468
7469            Bind(&if_rhsisnotstring);
7470            Goto(&if_notequal);
7471          }
7472
7473          Bind(&if_lhsisnotstring);
7474          Goto(&if_notequal);
7475        }
7476      }
7477    }
7478
7479    Bind(&if_lhsissmi);
7480    {
7481      // We already know that {lhs} and {rhs} are not reference equal, and {lhs}
7482      // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a
7483      // HeapNumber with an equal floating point value.
7484
7485      // Check if {rhs} is a Smi or a HeapObject.
7486      Label if_rhsissmi(this), if_rhsisnotsmi(this);
7487      Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
7488
7489      Bind(&if_rhsissmi);
7490      Goto(&if_notequal);
7491
7492      Bind(&if_rhsisnotsmi);
7493      {
7494        // Load the map of the {rhs}.
7495        Node* rhs_map = LoadMap(rhs);
7496
7497        // The {rhs} could be a HeapNumber with the same value as {lhs}.
7498        Label if_rhsisnumber(this), if_rhsisnotnumber(this);
7499        Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber);
7500
7501        Bind(&if_rhsisnumber);
7502        {
7503          // Convert {lhs} and {rhs} to floating point values.
7504          Node* lhs_value = SmiToFloat64(lhs);
7505          Node* rhs_value = LoadHeapNumberValue(rhs);
7506
7507          // Perform a floating point comparison of {lhs} and {rhs}.
7508          Branch(Float64Equal(lhs_value, rhs_value), &if_equal, &if_notequal);
7509        }
7510
7511        Bind(&if_rhsisnotnumber);
7512        Goto(&if_notequal);
7513      }
7514    }
7515  }
7516
7517  Bind(&if_equal);
7518  {
7519    result.Bind(BooleanConstant(mode == kDontNegateResult));
7520    Goto(&end);
7521  }
7522
7523  Bind(&if_notequal);
7524  {
7525    result.Bind(BooleanConstant(mode == kNegateResult));
7526    Goto(&end);
7527  }
7528
7529  Bind(&end);
7530  return result.value();
7531}
7532
7533// ECMA#sec-samevalue
7534// This algorithm differs from the Strict Equality Comparison Algorithm in its
7535// treatment of signed zeroes and NaNs.
7536Node* CodeStubAssembler::SameValue(Node* lhs, Node* rhs, Node* context) {
7537  Variable var_result(this, MachineRepresentation::kWord32);
7538  Label strict_equal(this), out(this);
7539
7540  Node* const int_false = Int32Constant(0);
7541  Node* const int_true = Int32Constant(1);
7542
7543  Label if_equal(this), if_notequal(this);
7544  Branch(WordEqual(lhs, rhs), &if_equal, &if_notequal);
7545
7546  Bind(&if_equal);
7547  {
7548    // This covers the case when {lhs} == {rhs}. We can simply return true
7549    // because SameValue considers two NaNs to be equal.
7550
7551    var_result.Bind(int_true);
7552    Goto(&out);
7553  }
7554
7555  Bind(&if_notequal);
7556  {
7557    // This covers the case when {lhs} != {rhs}. We only handle numbers here
7558    // and defer to StrictEqual for the rest.
7559
7560    Node* const lhs_float = TryTaggedToFloat64(lhs, &strict_equal);
7561    Node* const rhs_float = TryTaggedToFloat64(rhs, &strict_equal);
7562
7563    Label if_lhsisnan(this), if_lhsnotnan(this);
7564    BranchIfFloat64IsNaN(lhs_float, &if_lhsisnan, &if_lhsnotnan);
7565
7566    Bind(&if_lhsisnan);
7567    {
7568      // Return true iff {rhs} is NaN.
7569
7570      Node* const result =
7571          SelectConstant(Float64Equal(rhs_float, rhs_float), int_false,
7572                         int_true, MachineRepresentation::kWord32);
7573      var_result.Bind(result);
7574      Goto(&out);
7575    }
7576
7577    Bind(&if_lhsnotnan);
7578    {
7579      Label if_floatisequal(this), if_floatnotequal(this);
7580      Branch(Float64Equal(lhs_float, rhs_float), &if_floatisequal,
7581             &if_floatnotequal);
7582
7583      Bind(&if_floatisequal);
7584      {
7585        // We still need to handle the case when {lhs} and {rhs} are -0.0 and
7586        // 0.0 (or vice versa). Compare the high word to
7587        // distinguish between the two.
7588
7589        Node* const lhs_hi_word = Float64ExtractHighWord32(lhs_float);
7590        Node* const rhs_hi_word = Float64ExtractHighWord32(rhs_float);
7591
7592        // If x is +0 and y is -0, return false.
7593        // If x is -0 and y is +0, return false.
7594
7595        Node* const result = Word32Equal(lhs_hi_word, rhs_hi_word);
7596        var_result.Bind(result);
7597        Goto(&out);
7598      }
7599
7600      Bind(&if_floatnotequal);
7601      {
7602        var_result.Bind(int_false);
7603        Goto(&out);
7604      }
7605    }
7606  }
7607
7608  Bind(&strict_equal);
7609  {
7610    Node* const is_equal = StrictEqual(kDontNegateResult, lhs, rhs, context);
7611    Node* const result = WordEqual(is_equal, TrueConstant());
7612    var_result.Bind(result);
7613    Goto(&out);
7614  }
7615
7616  Bind(&out);
7617  return var_result.value();
7618}
7619
7620Node* CodeStubAssembler::ForInFilter(Node* key, Node* object, Node* context) {
7621  Label return_undefined(this, Label::kDeferred), return_to_name(this),
7622      end(this);
7623
7624  Variable var_result(this, MachineRepresentation::kTagged);
7625
7626  Node* has_property =
7627      HasProperty(object, key, context, Runtime::kForInHasProperty);
7628
7629  Branch(WordEqual(has_property, BooleanConstant(true)), &return_to_name,
7630         &return_undefined);
7631
7632  Bind(&return_to_name);
7633  {
7634    var_result.Bind(ToName(context, key));
7635    Goto(&end);
7636  }
7637
7638  Bind(&return_undefined);
7639  {
7640    var_result.Bind(UndefinedConstant());
7641    Goto(&end);
7642  }
7643
7644  Bind(&end);
7645  return var_result.value();
7646}
7647
7648Node* CodeStubAssembler::HasProperty(
7649    Node* object, Node* key, Node* context,
7650    Runtime::FunctionId fallback_runtime_function_id) {
7651  Label call_runtime(this, Label::kDeferred), return_true(this),
7652      return_false(this), end(this);
7653
7654  CodeStubAssembler::LookupInHolder lookup_property_in_holder =
7655      [this, &return_true](Node* receiver, Node* holder, Node* holder_map,
7656                           Node* holder_instance_type, Node* unique_name,
7657                           Label* next_holder, Label* if_bailout) {
7658        TryHasOwnProperty(holder, holder_map, holder_instance_type, unique_name,
7659                          &return_true, next_holder, if_bailout);
7660      };
7661
7662  CodeStubAssembler::LookupInHolder lookup_element_in_holder =
7663      [this, &return_true](Node* receiver, Node* holder, Node* holder_map,
7664                           Node* holder_instance_type, Node* index,
7665                           Label* next_holder, Label* if_bailout) {
7666        TryLookupElement(holder, holder_map, holder_instance_type, index,
7667                         &return_true, next_holder, if_bailout);
7668      };
7669
7670  TryPrototypeChainLookup(object, key, lookup_property_in_holder,
7671                          lookup_element_in_holder, &return_false,
7672                          &call_runtime);
7673
7674  Variable result(this, MachineRepresentation::kTagged);
7675  Bind(&return_true);
7676  {
7677    result.Bind(BooleanConstant(true));
7678    Goto(&end);
7679  }
7680
7681  Bind(&return_false);
7682  {
7683    result.Bind(BooleanConstant(false));
7684    Goto(&end);
7685  }
7686
7687  Bind(&call_runtime);
7688  {
7689    result.Bind(
7690        CallRuntime(fallback_runtime_function_id, context, object, key));
7691    Goto(&end);
7692  }
7693
7694  Bind(&end);
7695  return result.value();
7696}
7697
7698Node* CodeStubAssembler::ClassOf(Node* value) {
7699  Variable var_result(this, MachineRepresentation::kTaggedPointer);
7700  Label if_function(this, Label::kDeferred), if_object(this, Label::kDeferred),
7701      if_primitive(this, Label::kDeferred), return_result(this);
7702
7703  // Check if {value} is a Smi.
7704  GotoIf(TaggedIsSmi(value), &if_primitive);
7705
7706  Node* value_map = LoadMap(value);
7707  Node* value_instance_type = LoadMapInstanceType(value_map);
7708
7709  // Check if {value} is a JSFunction or JSBoundFunction.
7710  STATIC_ASSERT(LAST_TYPE == LAST_FUNCTION_TYPE);
7711  GotoIf(Uint32LessThanOrEqual(Int32Constant(FIRST_FUNCTION_TYPE),
7712                               value_instance_type),
7713         &if_function);
7714
7715  // Check if {value} is a primitive HeapObject.
7716  STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
7717  GotoIf(Uint32LessThan(value_instance_type,
7718                        Int32Constant(FIRST_JS_RECEIVER_TYPE)),
7719         &if_primitive);
7720
7721  // Load the {value}s constructor, and check that it's a JSFunction.
7722  Node* constructor = LoadMapConstructor(value_map);
7723  GotoIfNot(IsJSFunction(constructor), &if_object);
7724
7725  // Return the instance class name for the {constructor}.
7726  Node* shared_info =
7727      LoadObjectField(constructor, JSFunction::kSharedFunctionInfoOffset);
7728  Node* instance_class_name = LoadObjectField(
7729      shared_info, SharedFunctionInfo::kInstanceClassNameOffset);
7730  var_result.Bind(instance_class_name);
7731  Goto(&return_result);
7732
7733  Bind(&if_function);
7734  var_result.Bind(LoadRoot(Heap::kFunction_stringRootIndex));
7735  Goto(&return_result);
7736
7737  Bind(&if_object);
7738  var_result.Bind(LoadRoot(Heap::kObject_stringRootIndex));
7739  Goto(&return_result);
7740
7741  Bind(&if_primitive);
7742  var_result.Bind(NullConstant());
7743  Goto(&return_result);
7744
7745  Bind(&return_result);
7746  return var_result.value();
7747}
7748
7749Node* CodeStubAssembler::Typeof(Node* value, Node* context) {
7750  Variable result_var(this, MachineRepresentation::kTagged);
7751
7752  Label return_number(this, Label::kDeferred), if_oddball(this),
7753      return_function(this), return_undefined(this), return_object(this),
7754      return_string(this), return_result(this);
7755
7756  GotoIf(TaggedIsSmi(value), &return_number);
7757
7758  Node* map = LoadMap(value);
7759
7760  GotoIf(IsHeapNumberMap(map), &return_number);
7761
7762  Node* instance_type = LoadMapInstanceType(map);
7763
7764  GotoIf(Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE)), &if_oddball);
7765
7766  Node* callable_or_undetectable_mask = Word32And(
7767      LoadMapBitField(map),
7768      Int32Constant(1 << Map::kIsCallable | 1 << Map::kIsUndetectable));
7769
7770  GotoIf(Word32Equal(callable_or_undetectable_mask,
7771                     Int32Constant(1 << Map::kIsCallable)),
7772         &return_function);
7773
7774  GotoIfNot(Word32Equal(callable_or_undetectable_mask, Int32Constant(0)),
7775            &return_undefined);
7776
7777  GotoIf(IsJSReceiverInstanceType(instance_type), &return_object);
7778
7779  GotoIf(IsStringInstanceType(instance_type), &return_string);
7780
7781  CSA_ASSERT(this, Word32Equal(instance_type, Int32Constant(SYMBOL_TYPE)));
7782  result_var.Bind(HeapConstant(isolate()->factory()->symbol_string()));
7783  Goto(&return_result);
7784
7785  Bind(&return_number);
7786  {
7787    result_var.Bind(HeapConstant(isolate()->factory()->number_string()));
7788    Goto(&return_result);
7789  }
7790
7791  Bind(&if_oddball);
7792  {
7793    Node* type = LoadObjectField(value, Oddball::kTypeOfOffset);
7794    result_var.Bind(type);
7795    Goto(&return_result);
7796  }
7797
7798  Bind(&return_function);
7799  {
7800    result_var.Bind(HeapConstant(isolate()->factory()->function_string()));
7801    Goto(&return_result);
7802  }
7803
7804  Bind(&return_undefined);
7805  {
7806    result_var.Bind(HeapConstant(isolate()->factory()->undefined_string()));
7807    Goto(&return_result);
7808  }
7809
7810  Bind(&return_object);
7811  {
7812    result_var.Bind(HeapConstant(isolate()->factory()->object_string()));
7813    Goto(&return_result);
7814  }
7815
7816  Bind(&return_string);
7817  {
7818    result_var.Bind(HeapConstant(isolate()->factory()->string_string()));
7819    Goto(&return_result);
7820  }
7821
7822  Bind(&return_result);
7823  return result_var.value();
7824}
7825
7826Node* CodeStubAssembler::GetSuperConstructor(Node* active_function,
7827                                             Node* context) {
7828  CSA_ASSERT(this, IsJSFunction(active_function));
7829
7830  Label is_not_constructor(this, Label::kDeferred), out(this);
7831  Variable result(this, MachineRepresentation::kTagged);
7832
7833  Node* map = LoadMap(active_function);
7834  Node* prototype = LoadMapPrototype(map);
7835  Node* prototype_map = LoadMap(prototype);
7836  GotoIfNot(IsConstructorMap(prototype_map), &is_not_constructor);
7837
7838  result.Bind(prototype);
7839  Goto(&out);
7840
7841  Bind(&is_not_constructor);
7842  {
7843    CallRuntime(Runtime::kThrowNotSuperConstructor, context, prototype,
7844                active_function);
7845    Unreachable();
7846  }
7847
7848  Bind(&out);
7849  return result.value();
7850}
7851
7852Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable,
7853                                    Node* context) {
7854  Variable var_result(this, MachineRepresentation::kTagged);
7855  Label if_notcallable(this, Label::kDeferred),
7856      if_notreceiver(this, Label::kDeferred), if_otherhandler(this),
7857      if_nohandler(this, Label::kDeferred), return_true(this),
7858      return_false(this), return_result(this, &var_result);
7859
7860  // Ensure that the {callable} is actually a JSReceiver.
7861  GotoIf(TaggedIsSmi(callable), &if_notreceiver);
7862  GotoIfNot(IsJSReceiver(callable), &if_notreceiver);
7863
7864  // Load the @@hasInstance property from {callable}.
7865  Node* inst_of_handler = CallStub(CodeFactory::GetProperty(isolate()), context,
7866                                   callable, HasInstanceSymbolConstant());
7867
7868  // Optimize for the likely case where {inst_of_handler} is the builtin
7869  // Function.prototype[@@hasInstance] method, and emit a direct call in
7870  // that case without any additional checking.
7871  Node* native_context = LoadNativeContext(context);
7872  Node* function_has_instance =
7873      LoadContextElement(native_context, Context::FUNCTION_HAS_INSTANCE_INDEX);
7874  GotoIfNot(WordEqual(inst_of_handler, function_has_instance),
7875            &if_otherhandler);
7876  {
7877    // Call to Function.prototype[@@hasInstance] directly.
7878    Callable builtin(isolate()->builtins()->FunctionPrototypeHasInstance(),
7879                     CallTrampolineDescriptor(isolate()));
7880    Node* result = CallJS(builtin, context, inst_of_handler, callable, object);
7881    var_result.Bind(result);
7882    Goto(&return_result);
7883  }
7884
7885  Bind(&if_otherhandler);
7886  {
7887    // Check if there's actually an {inst_of_handler}.
7888    GotoIf(IsNull(inst_of_handler), &if_nohandler);
7889    GotoIf(IsUndefined(inst_of_handler), &if_nohandler);
7890
7891    // Call the {inst_of_handler} for {callable} and {object}.
7892    Node* result = CallJS(
7893        CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
7894        context, inst_of_handler, callable, object);
7895
7896    // Convert the {result} to a Boolean.
7897    BranchIfToBooleanIsTrue(result, &return_true, &return_false);
7898  }
7899
7900  Bind(&if_nohandler);
7901  {
7902    // Ensure that the {callable} is actually Callable.
7903    GotoIfNot(IsCallable(callable), &if_notcallable);
7904
7905    // Use the OrdinaryHasInstance algorithm.
7906    Node* result = CallStub(CodeFactory::OrdinaryHasInstance(isolate()),
7907                            context, callable, object);
7908    var_result.Bind(result);
7909    Goto(&return_result);
7910  }
7911
7912  Bind(&if_notcallable);
7913  {
7914    CallRuntime(Runtime::kThrowNonCallableInInstanceOfCheck, context);
7915    Unreachable();
7916  }
7917
7918  Bind(&if_notreceiver);
7919  {
7920    CallRuntime(Runtime::kThrowNonObjectInInstanceOfCheck, context);
7921    Unreachable();
7922  }
7923
7924  Bind(&return_true);
7925  var_result.Bind(TrueConstant());
7926  Goto(&return_result);
7927
7928  Bind(&return_false);
7929  var_result.Bind(FalseConstant());
7930  Goto(&return_result);
7931
7932  Bind(&return_result);
7933  return var_result.value();
7934}
7935
7936Node* CodeStubAssembler::NumberInc(Node* value) {
7937  Variable var_result(this, MachineRepresentation::kTagged),
7938      var_finc_value(this, MachineRepresentation::kFloat64);
7939  Label if_issmi(this), if_isnotsmi(this), do_finc(this), end(this);
7940  Branch(TaggedIsSmi(value), &if_issmi, &if_isnotsmi);
7941
7942  Bind(&if_issmi);
7943  {
7944    // Try fast Smi addition first.
7945    Node* one = SmiConstant(Smi::FromInt(1));
7946    Node* pair = IntPtrAddWithOverflow(BitcastTaggedToWord(value),
7947                                       BitcastTaggedToWord(one));
7948    Node* overflow = Projection(1, pair);
7949
7950    // Check if the Smi addition overflowed.
7951    Label if_overflow(this), if_notoverflow(this);
7952    Branch(overflow, &if_overflow, &if_notoverflow);
7953
7954    Bind(&if_notoverflow);
7955    var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
7956    Goto(&end);
7957
7958    Bind(&if_overflow);
7959    {
7960      var_finc_value.Bind(SmiToFloat64(value));
7961      Goto(&do_finc);
7962    }
7963  }
7964
7965  Bind(&if_isnotsmi);
7966  {
7967    // Check if the value is a HeapNumber.
7968    CSA_ASSERT(this, IsHeapNumberMap(LoadMap(value)));
7969
7970    // Load the HeapNumber value.
7971    var_finc_value.Bind(LoadHeapNumberValue(value));
7972    Goto(&do_finc);
7973  }
7974
7975  Bind(&do_finc);
7976  {
7977    Node* finc_value = var_finc_value.value();
7978    Node* one = Float64Constant(1.0);
7979    Node* finc_result = Float64Add(finc_value, one);
7980    var_result.Bind(AllocateHeapNumberWithValue(finc_result));
7981    Goto(&end);
7982  }
7983
7984  Bind(&end);
7985  return var_result.value();
7986}
7987
7988void CodeStubAssembler::GotoIfNotNumber(Node* input, Label* is_not_number) {
7989  Label is_number(this);
7990  GotoIf(TaggedIsSmi(input), &is_number);
7991  Node* input_map = LoadMap(input);
7992  Branch(IsHeapNumberMap(input_map), &is_number, is_not_number);
7993  Bind(&is_number);
7994}
7995
7996void CodeStubAssembler::GotoIfNumber(Node* input, Label* is_number) {
7997  GotoIf(TaggedIsSmi(input), is_number);
7998  Node* input_map = LoadMap(input);
7999  GotoIf(IsHeapNumberMap(input_map), is_number);
8000}
8001
8002Node* CodeStubAssembler::CreateArrayIterator(Node* array, Node* array_map,
8003                                             Node* array_type, Node* context,
8004                                             IterationKind mode) {
8005  int kBaseMapIndex = 0;
8006  switch (mode) {
8007    case IterationKind::kKeys:
8008      kBaseMapIndex = Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX;
8009      break;
8010    case IterationKind::kValues:
8011      kBaseMapIndex = Context::UINT8_ARRAY_VALUE_ITERATOR_MAP_INDEX;
8012      break;
8013    case IterationKind::kEntries:
8014      kBaseMapIndex = Context::UINT8_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX;
8015      break;
8016  }
8017
8018  // Fast Array iterator map index:
8019  // (kBaseIndex + kFastIteratorOffset) + ElementsKind (for JSArrays)
8020  // kBaseIndex + (ElementsKind - UINT8_ELEMENTS) (for JSTypedArrays)
8021  const int kFastIteratorOffset =
8022      Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX -
8023      Context::UINT8_ARRAY_VALUE_ITERATOR_MAP_INDEX;
8024  STATIC_ASSERT(kFastIteratorOffset ==
8025                (Context::FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX -
8026                 Context::UINT8_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX));
8027
8028  // Slow Array iterator map index: (kBaseIndex + kSlowIteratorOffset)
8029  const int kSlowIteratorOffset =
8030      Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX -
8031      Context::UINT8_ARRAY_VALUE_ITERATOR_MAP_INDEX;
8032  STATIC_ASSERT(kSlowIteratorOffset ==
8033                (Context::GENERIC_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX -
8034                 Context::UINT8_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX));
8035
8036  // Assert: Type(array) is Object
8037  CSA_ASSERT(this, IsJSReceiverInstanceType(array_type));
8038
8039  Variable var_result(this, MachineRepresentation::kTagged);
8040  Variable var_map_index(this, MachineType::PointerRepresentation());
8041  Variable var_array_map(this, MachineRepresentation::kTagged);
8042
8043  Label return_result(this);
8044  Label allocate_iterator(this);
8045
8046  if (mode == IterationKind::kKeys) {
8047    // There are only two key iterator maps, branch depending on whether or not
8048    // the receiver is a TypedArray or not.
8049
8050    Label if_istypedarray(this), if_isgeneric(this);
8051
8052    Branch(Word32Equal(array_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
8053           &if_istypedarray, &if_isgeneric);
8054
8055    Bind(&if_isgeneric);
8056    {
8057      Label if_isfast(this), if_isslow(this);
8058      BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ,
8059                          &if_isfast, &if_isslow);
8060
8061      Bind(&if_isfast);
8062      {
8063        var_map_index.Bind(
8064            IntPtrConstant(Context::FAST_ARRAY_KEY_ITERATOR_MAP_INDEX));
8065        var_array_map.Bind(array_map);
8066        Goto(&allocate_iterator);
8067      }
8068
8069      Bind(&if_isslow);
8070      {
8071        var_map_index.Bind(
8072            IntPtrConstant(Context::GENERIC_ARRAY_KEY_ITERATOR_MAP_INDEX));
8073        var_array_map.Bind(UndefinedConstant());
8074        Goto(&allocate_iterator);
8075      }
8076    }
8077
8078    Bind(&if_istypedarray);
8079    {
8080      var_map_index.Bind(
8081          IntPtrConstant(Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX));
8082      var_array_map.Bind(UndefinedConstant());
8083      Goto(&allocate_iterator);
8084    }
8085  } else {
8086    Label if_istypedarray(this), if_isgeneric(this);
8087    Branch(Word32Equal(array_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
8088           &if_istypedarray, &if_isgeneric);
8089
8090    Bind(&if_isgeneric);
8091    {
8092      Label if_isfast(this), if_isslow(this);
8093      BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ,
8094                          &if_isfast, &if_isslow);
8095
8096      Bind(&if_isfast);
8097      {
8098        Label if_ispacked(this), if_isholey(this);
8099        Node* elements_kind = LoadMapElementsKind(array_map);
8100        Branch(IsHoleyFastElementsKind(elements_kind), &if_isholey,
8101               &if_ispacked);
8102
8103        Bind(&if_isholey);
8104        {
8105          // Fast holey JSArrays can treat the hole as undefined if the
8106          // protector cell is valid, and the prototype chain is unchanged from
8107          // its initial state (because the protector cell is only tracked for
8108          // initial the Array and Object prototypes). Check these conditions
8109          // here, and take the slow path if any fail.
8110          Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex);
8111          DCHECK(isolate()->heap()->array_protector()->IsPropertyCell());
8112          GotoIfNot(
8113              WordEqual(
8114                  LoadObjectField(protector_cell, PropertyCell::kValueOffset),
8115                  SmiConstant(Smi::FromInt(Isolate::kProtectorValid))),
8116              &if_isslow);
8117
8118          Node* native_context = LoadNativeContext(context);
8119
8120          Node* prototype = LoadMapPrototype(array_map);
8121          Node* array_prototype = LoadContextElement(
8122              native_context, Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
8123          GotoIfNot(WordEqual(prototype, array_prototype), &if_isslow);
8124
8125          Node* map = LoadMap(prototype);
8126          prototype = LoadMapPrototype(map);
8127          Node* object_prototype = LoadContextElement(
8128              native_context, Context::INITIAL_OBJECT_PROTOTYPE_INDEX);
8129          GotoIfNot(WordEqual(prototype, object_prototype), &if_isslow);
8130
8131          map = LoadMap(prototype);
8132          prototype = LoadMapPrototype(map);
8133          Branch(IsNull(prototype), &if_ispacked, &if_isslow);
8134        }
8135        Bind(&if_ispacked);
8136        {
8137          Node* map_index =
8138              IntPtrAdd(IntPtrConstant(kBaseMapIndex + kFastIteratorOffset),
8139                        ChangeUint32ToWord(LoadMapElementsKind(array_map)));
8140          CSA_ASSERT(this, IntPtrGreaterThanOrEqual(
8141                               map_index, IntPtrConstant(kBaseMapIndex +
8142                                                         kFastIteratorOffset)));
8143          CSA_ASSERT(this, IntPtrLessThan(map_index,
8144                                          IntPtrConstant(kBaseMapIndex +
8145                                                         kSlowIteratorOffset)));
8146
8147          var_map_index.Bind(map_index);
8148          var_array_map.Bind(array_map);
8149          Goto(&allocate_iterator);
8150        }
8151      }
8152
8153      Bind(&if_isslow);
8154      {
8155        Node* map_index = IntPtrAdd(IntPtrConstant(kBaseMapIndex),
8156                                    IntPtrConstant(kSlowIteratorOffset));
8157        var_map_index.Bind(map_index);
8158        var_array_map.Bind(UndefinedConstant());
8159        Goto(&allocate_iterator);
8160      }
8161    }
8162
8163    Bind(&if_istypedarray);
8164    {
8165      Node* map_index =
8166          IntPtrAdd(IntPtrConstant(kBaseMapIndex - UINT8_ELEMENTS),
8167                    ChangeUint32ToWord(LoadMapElementsKind(array_map)));
8168      CSA_ASSERT(
8169          this, IntPtrLessThan(map_index, IntPtrConstant(kBaseMapIndex +
8170                                                         kFastIteratorOffset)));
8171      CSA_ASSERT(this, IntPtrGreaterThanOrEqual(map_index,
8172                                                IntPtrConstant(kBaseMapIndex)));
8173      var_map_index.Bind(map_index);
8174      var_array_map.Bind(UndefinedConstant());
8175      Goto(&allocate_iterator);
8176    }
8177  }
8178
8179  Bind(&allocate_iterator);
8180  {
8181    Node* map = LoadFixedArrayElement(LoadNativeContext(context),
8182                                      var_map_index.value());
8183    var_result.Bind(AllocateJSArrayIterator(array, var_array_map.value(), map));
8184    Goto(&return_result);
8185  }
8186
8187  Bind(&return_result);
8188  return var_result.value();
8189}
8190
8191Node* CodeStubAssembler::AllocateJSArrayIterator(Node* array, Node* array_map,
8192                                                 Node* map) {
8193  Node* iterator = Allocate(JSArrayIterator::kSize);
8194  StoreMapNoWriteBarrier(iterator, map);
8195  StoreObjectFieldRoot(iterator, JSArrayIterator::kPropertiesOffset,
8196                       Heap::kEmptyFixedArrayRootIndex);
8197  StoreObjectFieldRoot(iterator, JSArrayIterator::kElementsOffset,
8198                       Heap::kEmptyFixedArrayRootIndex);
8199  StoreObjectFieldNoWriteBarrier(iterator,
8200                                 JSArrayIterator::kIteratedObjectOffset, array);
8201  StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset,
8202                                 SmiConstant(Smi::FromInt(0)));
8203  StoreObjectFieldNoWriteBarrier(
8204      iterator, JSArrayIterator::kIteratedObjectMapOffset, array_map);
8205  return iterator;
8206}
8207
8208Node* CodeStubAssembler::IsDetachedBuffer(Node* buffer) {
8209  CSA_ASSERT(this, HasInstanceType(buffer, JS_ARRAY_BUFFER_TYPE));
8210
8211  Node* buffer_bit_field = LoadObjectField(
8212      buffer, JSArrayBuffer::kBitFieldOffset, MachineType::Uint32());
8213  return IsSetWord32<JSArrayBuffer::WasNeutered>(buffer_bit_field);
8214}
8215
8216CodeStubArguments::CodeStubArguments(CodeStubAssembler* assembler, Node* argc,
8217                                     Node* fp,
8218                                     CodeStubAssembler::ParameterMode mode)
8219    : assembler_(assembler),
8220      argc_mode_(mode),
8221      argc_(argc),
8222      arguments_(nullptr),
8223      fp_(fp != nullptr ? fp : assembler->LoadFramePointer()) {
8224  Node* offset = assembler->ElementOffsetFromIndex(
8225      argc_, FAST_ELEMENTS, mode,
8226      (StandardFrameConstants::kFixedSlotCountAboveFp - 1) * kPointerSize);
8227  arguments_ = assembler_->IntPtrAdd(fp_, offset);
8228}
8229
8230Node* CodeStubArguments::GetReceiver() const {
8231  return assembler_->Load(MachineType::AnyTagged(), arguments_,
8232                          assembler_->IntPtrConstant(kPointerSize));
8233}
8234
8235Node* CodeStubArguments::AtIndexPtr(
8236    Node* index, CodeStubAssembler::ParameterMode mode) const {
8237  typedef compiler::Node Node;
8238  Node* negated_index = assembler_->IntPtrOrSmiSub(
8239      assembler_->IntPtrOrSmiConstant(0, mode), index, mode);
8240  Node* offset =
8241      assembler_->ElementOffsetFromIndex(negated_index, FAST_ELEMENTS, mode, 0);
8242  return assembler_->IntPtrAdd(arguments_, offset);
8243}
8244
8245Node* CodeStubArguments::AtIndex(Node* index,
8246                                 CodeStubAssembler::ParameterMode mode) const {
8247  DCHECK_EQ(argc_mode_, mode);
8248  CSA_ASSERT(assembler_,
8249             assembler_->UintPtrOrSmiLessThan(index, GetLength(), mode));
8250  return assembler_->Load(MachineType::AnyTagged(), AtIndexPtr(index, mode));
8251}
8252
8253Node* CodeStubArguments::AtIndex(int index) const {
8254  return AtIndex(assembler_->IntPtrConstant(index));
8255}
8256
8257void CodeStubArguments::ForEach(
8258    const CodeStubAssembler::VariableList& vars,
8259    const CodeStubArguments::ForEachBodyFunction& body, Node* first, Node* last,
8260    CodeStubAssembler::ParameterMode mode) {
8261  assembler_->Comment("CodeStubArguments::ForEach");
8262  if (first == nullptr) {
8263    first = assembler_->IntPtrOrSmiConstant(0, mode);
8264  }
8265  if (last == nullptr) {
8266    DCHECK_EQ(mode, argc_mode_);
8267    last = argc_;
8268  }
8269  Node* start = assembler_->IntPtrSub(
8270      arguments_,
8271      assembler_->ElementOffsetFromIndex(first, FAST_ELEMENTS, mode));
8272  Node* end = assembler_->IntPtrSub(
8273      arguments_,
8274      assembler_->ElementOffsetFromIndex(last, FAST_ELEMENTS, mode));
8275  assembler_->BuildFastLoop(vars, start, end,
8276                            [this, &body](Node* current) {
8277                              Node* arg = assembler_->Load(
8278                                  MachineType::AnyTagged(), current);
8279                              body(arg);
8280                            },
8281                            -kPointerSize, CodeStubAssembler::INTPTR_PARAMETERS,
8282                            CodeStubAssembler::IndexAdvanceMode::kPost);
8283}
8284
8285void CodeStubArguments::PopAndReturn(Node* value) {
8286  assembler_->PopAndReturn(
8287      assembler_->IntPtrAdd(argc_, assembler_->IntPtrConstant(1)), value);
8288}
8289
8290Node* CodeStubAssembler::IsFastElementsKind(Node* elements_kind) {
8291  return Uint32LessThanOrEqual(elements_kind,
8292                               Int32Constant(LAST_FAST_ELEMENTS_KIND));
8293}
8294
8295Node* CodeStubAssembler::IsHoleyFastElementsKind(Node* elements_kind) {
8296  CSA_ASSERT(this, IsFastElementsKind(elements_kind));
8297
8298  STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == (FAST_SMI_ELEMENTS | 1));
8299  STATIC_ASSERT(FAST_HOLEY_ELEMENTS == (FAST_ELEMENTS | 1));
8300  STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == (FAST_DOUBLE_ELEMENTS | 1));
8301
8302  // Check prototype chain if receiver does not have packed elements.
8303  Node* holey_elements = Word32And(elements_kind, Int32Constant(1));
8304  return Word32Equal(holey_elements, Int32Constant(1));
8305}
8306
8307Node* CodeStubAssembler::IsDebugActive() {
8308  Node* is_debug_active = Load(
8309      MachineType::Uint8(),
8310      ExternalConstant(ExternalReference::debug_is_active_address(isolate())));
8311  return Word32NotEqual(is_debug_active, Int32Constant(0));
8312}
8313
8314Node* CodeStubAssembler::IsPromiseHookEnabledOrDebugIsActive() {
8315  Node* const promise_hook_or_debug_is_active =
8316      Load(MachineType::Uint8(),
8317           ExternalConstant(
8318               ExternalReference::promise_hook_or_debug_is_active_address(
8319                   isolate())));
8320  return Word32NotEqual(promise_hook_or_debug_is_active, Int32Constant(0));
8321}
8322
8323Node* CodeStubAssembler::AllocateFunctionWithMapAndContext(Node* map,
8324                                                           Node* shared_info,
8325                                                           Node* context) {
8326  Node* const code = BitcastTaggedToWord(
8327      LoadObjectField(shared_info, SharedFunctionInfo::kCodeOffset));
8328  Node* const code_entry =
8329      IntPtrAdd(code, IntPtrConstant(Code::kHeaderSize - kHeapObjectTag));
8330
8331  Node* const fun = Allocate(JSFunction::kSize);
8332  StoreMapNoWriteBarrier(fun, map);
8333  StoreObjectFieldRoot(fun, JSObject::kPropertiesOffset,
8334                       Heap::kEmptyFixedArrayRootIndex);
8335  StoreObjectFieldRoot(fun, JSObject::kElementsOffset,
8336                       Heap::kEmptyFixedArrayRootIndex);
8337  StoreObjectFieldRoot(fun, JSFunction::kFeedbackVectorOffset,
8338                       Heap::kUndefinedCellRootIndex);
8339  StoreObjectFieldRoot(fun, JSFunction::kPrototypeOrInitialMapOffset,
8340                       Heap::kTheHoleValueRootIndex);
8341  StoreObjectFieldNoWriteBarrier(fun, JSFunction::kSharedFunctionInfoOffset,
8342                                 shared_info);
8343  StoreObjectFieldNoWriteBarrier(fun, JSFunction::kContextOffset, context);
8344  StoreObjectFieldNoWriteBarrier(fun, JSFunction::kCodeEntryOffset, code_entry,
8345                                 MachineType::PointerRepresentation());
8346  StoreObjectFieldRoot(fun, JSFunction::kNextFunctionLinkOffset,
8347                       Heap::kUndefinedValueRootIndex);
8348
8349  return fun;
8350}
8351
8352Node* CodeStubAssembler::AllocatePromiseReactionJobInfo(
8353    Node* value, Node* tasks, Node* deferred_promise, Node* deferred_on_resolve,
8354    Node* deferred_on_reject, Node* context) {
8355  Node* const result = Allocate(PromiseReactionJobInfo::kSize);
8356  StoreMapNoWriteBarrier(result, Heap::kPromiseReactionJobInfoMapRootIndex);
8357  StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kValueOffset,
8358                                 value);
8359  StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kTasksOffset,
8360                                 tasks);
8361  StoreObjectFieldNoWriteBarrier(
8362      result, PromiseReactionJobInfo::kDeferredPromiseOffset, deferred_promise);
8363  StoreObjectFieldNoWriteBarrier(
8364      result, PromiseReactionJobInfo::kDeferredOnResolveOffset,
8365      deferred_on_resolve);
8366  StoreObjectFieldNoWriteBarrier(
8367      result, PromiseReactionJobInfo::kDeferredOnRejectOffset,
8368      deferred_on_reject);
8369  StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kContextOffset,
8370                                 context);
8371  return result;
8372}
8373
8374Node* CodeStubAssembler::MarkerIsFrameType(Node* marker_or_function,
8375                                           StackFrame::Type frame_type) {
8376  return WordEqual(
8377      marker_or_function,
8378      IntPtrConstant(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
8379}
8380
8381Node* CodeStubAssembler::MarkerIsNotFrameType(Node* marker_or_function,
8382                                              StackFrame::Type frame_type) {
8383  return WordNotEqual(
8384      marker_or_function,
8385      IntPtrConstant(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
8386}
8387
8388void CodeStubAssembler::Print(const char* s) {
8389#ifdef DEBUG
8390  std::string formatted(s);
8391  formatted += "\n";
8392  Handle<String> string = isolate()->factory()->NewStringFromAsciiChecked(
8393      formatted.c_str(), TENURED);
8394  CallRuntime(Runtime::kGlobalPrint, NoContextConstant(), HeapConstant(string));
8395#endif
8396}
8397
8398void CodeStubAssembler::Print(const char* prefix, Node* tagged_value) {
8399#ifdef DEBUG
8400  if (prefix != nullptr) {
8401    std::string formatted(prefix);
8402    formatted += ": ";
8403    Handle<String> string = isolate()->factory()->NewStringFromAsciiChecked(
8404        formatted.c_str(), TENURED);
8405    CallRuntime(Runtime::kGlobalPrint, NoContextConstant(),
8406                HeapConstant(string));
8407  }
8408  CallRuntime(Runtime::kDebugPrint, NoContextConstant(), tagged_value);
8409#endif
8410}
8411
8412}  // namespace internal
8413}  // namespace v8
8414