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
5#include "src/code-stub-assembler.h"
6#include "src/code-factory.h"
7#include "src/frames-inl.h"
8#include "src/frames.h"
9#include "src/ic/stub-cache.h"
10
11namespace v8 {
12namespace internal {
13
14using compiler::Node;
15
16CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone,
17                                     const CallInterfaceDescriptor& descriptor,
18                                     Code::Flags flags, const char* name,
19                                     size_t result_size)
20    : compiler::CodeAssembler(isolate, zone, descriptor, flags, name,
21                              result_size) {}
22
23CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone,
24                                     int parameter_count, Code::Flags flags,
25                                     const char* name)
26    : compiler::CodeAssembler(isolate, zone, parameter_count, flags, name) {}
27
28void CodeStubAssembler::Assert(Node* condition) {
29#if defined(DEBUG)
30  Label ok(this);
31  Comment("[ Assert");
32  GotoIf(condition, &ok);
33  DebugBreak();
34  Goto(&ok);
35  Bind(&ok);
36  Comment("] Assert");
37#endif
38}
39
40Node* CodeStubAssembler::BooleanMapConstant() {
41  return HeapConstant(isolate()->factory()->boolean_map());
42}
43
44Node* CodeStubAssembler::EmptyStringConstant() {
45  return LoadRoot(Heap::kempty_stringRootIndex);
46}
47
48Node* CodeStubAssembler::HeapNumberMapConstant() {
49  return HeapConstant(isolate()->factory()->heap_number_map());
50}
51
52Node* CodeStubAssembler::NoContextConstant() {
53  return SmiConstant(Smi::FromInt(0));
54}
55
56Node* CodeStubAssembler::NullConstant() {
57  return LoadRoot(Heap::kNullValueRootIndex);
58}
59
60Node* CodeStubAssembler::UndefinedConstant() {
61  return LoadRoot(Heap::kUndefinedValueRootIndex);
62}
63
64Node* CodeStubAssembler::TheHoleConstant() {
65  return LoadRoot(Heap::kTheHoleValueRootIndex);
66}
67
68Node* CodeStubAssembler::HashSeed() {
69  return SmiToWord32(LoadRoot(Heap::kHashSeedRootIndex));
70}
71
72Node* CodeStubAssembler::StaleRegisterConstant() {
73  return LoadRoot(Heap::kStaleRegisterRootIndex);
74}
75
76Node* CodeStubAssembler::Float64Round(Node* x) {
77  Node* one = Float64Constant(1.0);
78  Node* one_half = Float64Constant(0.5);
79
80  Variable var_x(this, MachineRepresentation::kFloat64);
81  Label return_x(this);
82
83  // Round up {x} towards Infinity.
84  var_x.Bind(Float64Ceil(x));
85
86  GotoIf(Float64LessThanOrEqual(Float64Sub(var_x.value(), one_half), x),
87         &return_x);
88  var_x.Bind(Float64Sub(var_x.value(), one));
89  Goto(&return_x);
90
91  Bind(&return_x);
92  return var_x.value();
93}
94
95Node* CodeStubAssembler::Float64Ceil(Node* x) {
96  if (IsFloat64RoundUpSupported()) {
97    return Float64RoundUp(x);
98  }
99
100  Node* one = Float64Constant(1.0);
101  Node* zero = Float64Constant(0.0);
102  Node* two_52 = Float64Constant(4503599627370496.0E0);
103  Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
104
105  Variable var_x(this, MachineRepresentation::kFloat64);
106  Label return_x(this), return_minus_x(this);
107  var_x.Bind(x);
108
109  // Check if {x} is greater than zero.
110  Label if_xgreaterthanzero(this), if_xnotgreaterthanzero(this);
111  Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero,
112         &if_xnotgreaterthanzero);
113
114  Bind(&if_xgreaterthanzero);
115  {
116    // Just return {x} unless it's in the range ]0,2^52[.
117    GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x);
118
119    // Round positive {x} towards Infinity.
120    var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52));
121    GotoUnless(Float64LessThan(var_x.value(), x), &return_x);
122    var_x.Bind(Float64Add(var_x.value(), one));
123    Goto(&return_x);
124  }
125
126  Bind(&if_xnotgreaterthanzero);
127  {
128    // Just return {x} unless it's in the range ]-2^52,0[
129    GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x);
130    GotoUnless(Float64LessThan(x, zero), &return_x);
131
132    // Round negated {x} towards Infinity and return the result negated.
133    Node* minus_x = Float64Neg(x);
134    var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
135    GotoUnless(Float64GreaterThan(var_x.value(), minus_x), &return_minus_x);
136    var_x.Bind(Float64Sub(var_x.value(), one));
137    Goto(&return_minus_x);
138  }
139
140  Bind(&return_minus_x);
141  var_x.Bind(Float64Neg(var_x.value()));
142  Goto(&return_x);
143
144  Bind(&return_x);
145  return var_x.value();
146}
147
148Node* CodeStubAssembler::Float64Floor(Node* x) {
149  if (IsFloat64RoundDownSupported()) {
150    return Float64RoundDown(x);
151  }
152
153  Node* one = Float64Constant(1.0);
154  Node* zero = Float64Constant(0.0);
155  Node* two_52 = Float64Constant(4503599627370496.0E0);
156  Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
157
158  Variable var_x(this, MachineRepresentation::kFloat64);
159  Label return_x(this), return_minus_x(this);
160  var_x.Bind(x);
161
162  // Check if {x} is greater than zero.
163  Label if_xgreaterthanzero(this), if_xnotgreaterthanzero(this);
164  Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero,
165         &if_xnotgreaterthanzero);
166
167  Bind(&if_xgreaterthanzero);
168  {
169    // Just return {x} unless it's in the range ]0,2^52[.
170    GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x);
171
172    // Round positive {x} towards -Infinity.
173    var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52));
174    GotoUnless(Float64GreaterThan(var_x.value(), x), &return_x);
175    var_x.Bind(Float64Sub(var_x.value(), one));
176    Goto(&return_x);
177  }
178
179  Bind(&if_xnotgreaterthanzero);
180  {
181    // Just return {x} unless it's in the range ]-2^52,0[
182    GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x);
183    GotoUnless(Float64LessThan(x, zero), &return_x);
184
185    // Round negated {x} towards -Infinity and return the result negated.
186    Node* minus_x = Float64Neg(x);
187    var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
188    GotoUnless(Float64LessThan(var_x.value(), minus_x), &return_minus_x);
189    var_x.Bind(Float64Add(var_x.value(), one));
190    Goto(&return_minus_x);
191  }
192
193  Bind(&return_minus_x);
194  var_x.Bind(Float64Neg(var_x.value()));
195  Goto(&return_x);
196
197  Bind(&return_x);
198  return var_x.value();
199}
200
201Node* CodeStubAssembler::Float64Trunc(Node* x) {
202  if (IsFloat64RoundTruncateSupported()) {
203    return Float64RoundTruncate(x);
204  }
205
206  Node* one = Float64Constant(1.0);
207  Node* zero = Float64Constant(0.0);
208  Node* two_52 = Float64Constant(4503599627370496.0E0);
209  Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
210
211  Variable var_x(this, MachineRepresentation::kFloat64);
212  Label return_x(this), return_minus_x(this);
213  var_x.Bind(x);
214
215  // Check if {x} is greater than 0.
216  Label if_xgreaterthanzero(this), if_xnotgreaterthanzero(this);
217  Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero,
218         &if_xnotgreaterthanzero);
219
220  Bind(&if_xgreaterthanzero);
221  {
222    if (IsFloat64RoundDownSupported()) {
223      var_x.Bind(Float64RoundDown(x));
224    } else {
225      // Just return {x} unless it's in the range ]0,2^52[.
226      GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x);
227
228      // Round positive {x} towards -Infinity.
229      var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52));
230      GotoUnless(Float64GreaterThan(var_x.value(), x), &return_x);
231      var_x.Bind(Float64Sub(var_x.value(), one));
232    }
233    Goto(&return_x);
234  }
235
236  Bind(&if_xnotgreaterthanzero);
237  {
238    if (IsFloat64RoundUpSupported()) {
239      var_x.Bind(Float64RoundUp(x));
240      Goto(&return_x);
241    } else {
242      // Just return {x} unless its in the range ]-2^52,0[.
243      GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x);
244      GotoUnless(Float64LessThan(x, zero), &return_x);
245
246      // Round negated {x} towards -Infinity and return result negated.
247      Node* minus_x = Float64Neg(x);
248      var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
249      GotoUnless(Float64GreaterThan(var_x.value(), minus_x), &return_minus_x);
250      var_x.Bind(Float64Sub(var_x.value(), one));
251      Goto(&return_minus_x);
252    }
253  }
254
255  Bind(&return_minus_x);
256  var_x.Bind(Float64Neg(var_x.value()));
257  Goto(&return_x);
258
259  Bind(&return_x);
260  return var_x.value();
261}
262
263Node* CodeStubAssembler::SmiFromWord32(Node* value) {
264  value = ChangeInt32ToIntPtr(value);
265  return WordShl(value, SmiShiftBitsConstant());
266}
267
268Node* CodeStubAssembler::SmiTag(Node* value) {
269  int32_t constant_value;
270  if (ToInt32Constant(value, constant_value) && Smi::IsValid(constant_value)) {
271    return SmiConstant(Smi::FromInt(constant_value));
272  }
273  return WordShl(value, SmiShiftBitsConstant());
274}
275
276Node* CodeStubAssembler::SmiUntag(Node* value) {
277  return WordSar(value, SmiShiftBitsConstant());
278}
279
280Node* CodeStubAssembler::SmiToWord32(Node* value) {
281  Node* result = WordSar(value, SmiShiftBitsConstant());
282  if (Is64()) {
283    result = TruncateInt64ToInt32(result);
284  }
285  return result;
286}
287
288Node* CodeStubAssembler::SmiToFloat64(Node* value) {
289  return ChangeInt32ToFloat64(SmiToWord32(value));
290}
291
292Node* CodeStubAssembler::SmiAdd(Node* a, Node* b) { return IntPtrAdd(a, b); }
293
294Node* CodeStubAssembler::SmiAddWithOverflow(Node* a, Node* b) {
295  return IntPtrAddWithOverflow(a, b);
296}
297
298Node* CodeStubAssembler::SmiSub(Node* a, Node* b) { return IntPtrSub(a, b); }
299
300Node* CodeStubAssembler::SmiSubWithOverflow(Node* a, Node* b) {
301  return IntPtrSubWithOverflow(a, b);
302}
303
304Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); }
305
306Node* CodeStubAssembler::SmiAboveOrEqual(Node* a, Node* b) {
307  return UintPtrGreaterThanOrEqual(a, b);
308}
309
310Node* CodeStubAssembler::SmiLessThan(Node* a, Node* b) {
311  return IntPtrLessThan(a, b);
312}
313
314Node* CodeStubAssembler::SmiLessThanOrEqual(Node* a, Node* b) {
315  return IntPtrLessThanOrEqual(a, b);
316}
317
318Node* CodeStubAssembler::SmiMin(Node* a, Node* b) {
319  // TODO(bmeurer): Consider using Select once available.
320  Variable min(this, MachineRepresentation::kTagged);
321  Label if_a(this), if_b(this), join(this);
322  BranchIfSmiLessThan(a, b, &if_a, &if_b);
323  Bind(&if_a);
324  min.Bind(a);
325  Goto(&join);
326  Bind(&if_b);
327  min.Bind(b);
328  Goto(&join);
329  Bind(&join);
330  return min.value();
331}
332
333Node* CodeStubAssembler::WordIsSmi(Node* a) {
334  return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask)), IntPtrConstant(0));
335}
336
337Node* CodeStubAssembler::WordIsPositiveSmi(Node* a) {
338  return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask | kSmiSignMask)),
339                   IntPtrConstant(0));
340}
341
342Node* CodeStubAssembler::AllocateRawUnaligned(Node* size_in_bytes,
343                                              AllocationFlags flags,
344                                              Node* top_address,
345                                              Node* limit_address) {
346  Node* top = Load(MachineType::Pointer(), top_address);
347  Node* limit = Load(MachineType::Pointer(), limit_address);
348
349  // If there's not enough space, call the runtime.
350  Variable result(this, MachineRepresentation::kTagged);
351  Label runtime_call(this, Label::kDeferred), no_runtime_call(this);
352  Label merge_runtime(this, &result);
353
354  Node* new_top = IntPtrAdd(top, size_in_bytes);
355  Branch(UintPtrGreaterThanOrEqual(new_top, limit), &runtime_call,
356         &no_runtime_call);
357
358  Bind(&runtime_call);
359  // AllocateInTargetSpace does not use the context.
360  Node* context = SmiConstant(Smi::FromInt(0));
361
362  Node* runtime_result;
363  if (flags & kPretenured) {
364    Node* runtime_flags = SmiConstant(
365        Smi::FromInt(AllocateDoubleAlignFlag::encode(false) |
366                     AllocateTargetSpace::encode(AllocationSpace::OLD_SPACE)));
367    runtime_result = CallRuntime(Runtime::kAllocateInTargetSpace, context,
368                                 SmiTag(size_in_bytes), runtime_flags);
369  } else {
370    runtime_result = CallRuntime(Runtime::kAllocateInNewSpace, context,
371                                 SmiTag(size_in_bytes));
372  }
373  result.Bind(runtime_result);
374  Goto(&merge_runtime);
375
376  // When there is enough space, return `top' and bump it up.
377  Bind(&no_runtime_call);
378  Node* no_runtime_result = top;
379  StoreNoWriteBarrier(MachineType::PointerRepresentation(), top_address,
380                      new_top);
381  no_runtime_result = BitcastWordToTagged(
382      IntPtrAdd(no_runtime_result, IntPtrConstant(kHeapObjectTag)));
383  result.Bind(no_runtime_result);
384  Goto(&merge_runtime);
385
386  Bind(&merge_runtime);
387  return result.value();
388}
389
390Node* CodeStubAssembler::AllocateRawAligned(Node* size_in_bytes,
391                                            AllocationFlags flags,
392                                            Node* top_address,
393                                            Node* limit_address) {
394  Node* top = Load(MachineType::Pointer(), top_address);
395  Node* limit = Load(MachineType::Pointer(), limit_address);
396  Variable adjusted_size(this, MachineType::PointerRepresentation());
397  adjusted_size.Bind(size_in_bytes);
398  if (flags & kDoubleAlignment) {
399    // TODO(epertoso): Simd128 alignment.
400    Label aligned(this), not_aligned(this), merge(this, &adjusted_size);
401    Branch(WordAnd(top, IntPtrConstant(kDoubleAlignmentMask)), &not_aligned,
402           &aligned);
403
404    Bind(&not_aligned);
405    Node* not_aligned_size =
406        IntPtrAdd(size_in_bytes, IntPtrConstant(kPointerSize));
407    adjusted_size.Bind(not_aligned_size);
408    Goto(&merge);
409
410    Bind(&aligned);
411    Goto(&merge);
412
413    Bind(&merge);
414  }
415
416  Variable address(this, MachineRepresentation::kTagged);
417  address.Bind(AllocateRawUnaligned(adjusted_size.value(), kNone, top, limit));
418
419  Label needs_filler(this), doesnt_need_filler(this),
420      merge_address(this, &address);
421  Branch(IntPtrEqual(adjusted_size.value(), size_in_bytes), &doesnt_need_filler,
422         &needs_filler);
423
424  Bind(&needs_filler);
425  // Store a filler and increase the address by kPointerSize.
426  // TODO(epertoso): this code assumes that we only align to kDoubleSize. Change
427  // it when Simd128 alignment is supported.
428  StoreNoWriteBarrier(MachineType::PointerRepresentation(), top,
429                      LoadRoot(Heap::kOnePointerFillerMapRootIndex));
430  address.Bind(BitcastWordToTagged(
431      IntPtrAdd(address.value(), IntPtrConstant(kPointerSize))));
432  Goto(&merge_address);
433
434  Bind(&doesnt_need_filler);
435  Goto(&merge_address);
436
437  Bind(&merge_address);
438  // Update the top.
439  StoreNoWriteBarrier(MachineType::PointerRepresentation(), top_address,
440                      IntPtrAdd(top, adjusted_size.value()));
441  return address.value();
442}
443
444Node* CodeStubAssembler::Allocate(Node* size_in_bytes, AllocationFlags flags) {
445  bool const new_space = !(flags & kPretenured);
446  Node* top_address = ExternalConstant(
447      new_space
448          ? ExternalReference::new_space_allocation_top_address(isolate())
449          : ExternalReference::old_space_allocation_top_address(isolate()));
450  Node* limit_address = ExternalConstant(
451      new_space
452          ? ExternalReference::new_space_allocation_limit_address(isolate())
453          : ExternalReference::old_space_allocation_limit_address(isolate()));
454
455#ifdef V8_HOST_ARCH_32_BIT
456  if (flags & kDoubleAlignment) {
457    return AllocateRawAligned(size_in_bytes, flags, top_address, limit_address);
458  }
459#endif
460
461  return AllocateRawUnaligned(size_in_bytes, flags, top_address, limit_address);
462}
463
464Node* CodeStubAssembler::Allocate(int size_in_bytes, AllocationFlags flags) {
465  return CodeStubAssembler::Allocate(IntPtrConstant(size_in_bytes), flags);
466}
467
468Node* CodeStubAssembler::InnerAllocate(Node* previous, Node* offset) {
469  return BitcastWordToTagged(IntPtrAdd(previous, offset));
470}
471
472Node* CodeStubAssembler::InnerAllocate(Node* previous, int offset) {
473  return InnerAllocate(previous, IntPtrConstant(offset));
474}
475
476compiler::Node* CodeStubAssembler::LoadFromFrame(int offset, MachineType rep) {
477  Node* frame_pointer = LoadFramePointer();
478  return Load(rep, frame_pointer, IntPtrConstant(offset));
479}
480
481compiler::Node* CodeStubAssembler::LoadFromParentFrame(int offset,
482                                                       MachineType rep) {
483  Node* frame_pointer = LoadParentFramePointer();
484  return Load(rep, frame_pointer, IntPtrConstant(offset));
485}
486
487Node* CodeStubAssembler::LoadBufferObject(Node* buffer, int offset,
488                                          MachineType rep) {
489  return Load(rep, buffer, IntPtrConstant(offset));
490}
491
492Node* CodeStubAssembler::LoadObjectField(Node* object, int offset,
493                                         MachineType rep) {
494  return Load(rep, object, IntPtrConstant(offset - kHeapObjectTag));
495}
496
497Node* CodeStubAssembler::LoadObjectField(Node* object, Node* offset,
498                                         MachineType rep) {
499  return Load(rep, object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)));
500}
501
502Node* CodeStubAssembler::LoadHeapNumberValue(Node* object) {
503  return LoadObjectField(object, HeapNumber::kValueOffset,
504                         MachineType::Float64());
505}
506
507Node* CodeStubAssembler::LoadMap(Node* object) {
508  return LoadObjectField(object, HeapObject::kMapOffset);
509}
510
511Node* CodeStubAssembler::LoadInstanceType(Node* object) {
512  return LoadMapInstanceType(LoadMap(object));
513}
514
515void CodeStubAssembler::AssertInstanceType(Node* object,
516                                           InstanceType instance_type) {
517  Assert(Word32Equal(LoadInstanceType(object), Int32Constant(instance_type)));
518}
519
520Node* CodeStubAssembler::LoadProperties(Node* object) {
521  return LoadObjectField(object, JSObject::kPropertiesOffset);
522}
523
524Node* CodeStubAssembler::LoadElements(Node* object) {
525  return LoadObjectField(object, JSObject::kElementsOffset);
526}
527
528Node* CodeStubAssembler::LoadFixedArrayBaseLength(Node* array) {
529  return LoadObjectField(array, FixedArrayBase::kLengthOffset);
530}
531
532Node* CodeStubAssembler::LoadMapBitField(Node* map) {
533  return LoadObjectField(map, Map::kBitFieldOffset, MachineType::Uint8());
534}
535
536Node* CodeStubAssembler::LoadMapBitField2(Node* map) {
537  return LoadObjectField(map, Map::kBitField2Offset, MachineType::Uint8());
538}
539
540Node* CodeStubAssembler::LoadMapBitField3(Node* map) {
541  return LoadObjectField(map, Map::kBitField3Offset, MachineType::Uint32());
542}
543
544Node* CodeStubAssembler::LoadMapInstanceType(Node* map) {
545  return LoadObjectField(map, Map::kInstanceTypeOffset, MachineType::Uint8());
546}
547
548Node* CodeStubAssembler::LoadMapDescriptors(Node* map) {
549  return LoadObjectField(map, Map::kDescriptorsOffset);
550}
551
552Node* CodeStubAssembler::LoadMapPrototype(Node* map) {
553  return LoadObjectField(map, Map::kPrototypeOffset);
554}
555
556Node* CodeStubAssembler::LoadMapInstanceSize(Node* map) {
557  return LoadObjectField(map, Map::kInstanceSizeOffset, MachineType::Uint8());
558}
559
560Node* CodeStubAssembler::LoadMapInobjectProperties(Node* map) {
561  // See Map::GetInObjectProperties() for details.
562  STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
563  Assert(Int32GreaterThanOrEqual(LoadMapInstanceType(map),
564                                 Int32Constant(FIRST_JS_OBJECT_TYPE)));
565  return LoadObjectField(
566      map, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset,
567      MachineType::Uint8());
568}
569
570Node* CodeStubAssembler::LoadNameHashField(Node* name) {
571  return LoadObjectField(name, Name::kHashFieldOffset, MachineType::Uint32());
572}
573
574Node* CodeStubAssembler::LoadNameHash(Node* name, Label* if_hash_not_computed) {
575  Node* hash_field = LoadNameHashField(name);
576  if (if_hash_not_computed != nullptr) {
577    GotoIf(WordEqual(
578               Word32And(hash_field, Int32Constant(Name::kHashNotComputedMask)),
579               Int32Constant(0)),
580           if_hash_not_computed);
581  }
582  return Word32Shr(hash_field, Int32Constant(Name::kHashShift));
583}
584
585Node* CodeStubAssembler::LoadStringLength(Node* object) {
586  return LoadObjectField(object, String::kLengthOffset);
587}
588
589Node* CodeStubAssembler::LoadJSValueValue(Node* object) {
590  return LoadObjectField(object, JSValue::kValueOffset);
591}
592
593Node* CodeStubAssembler::LoadWeakCellValue(Node* weak_cell, Label* if_cleared) {
594  Node* value = LoadObjectField(weak_cell, WeakCell::kValueOffset);
595  if (if_cleared != nullptr) {
596    GotoIf(WordEqual(value, IntPtrConstant(0)), if_cleared);
597  }
598  return value;
599}
600
601Node* CodeStubAssembler::AllocateUninitializedFixedArray(Node* length) {
602  Node* header_size = IntPtrConstant(FixedArray::kHeaderSize);
603  Node* data_size = WordShl(length, IntPtrConstant(kPointerSizeLog2));
604  Node* total_size = IntPtrAdd(data_size, header_size);
605
606  Node* result = Allocate(total_size, kNone);
607  StoreMapNoWriteBarrier(result, LoadRoot(Heap::kFixedArrayMapRootIndex));
608  StoreObjectFieldNoWriteBarrier(result, FixedArray::kLengthOffset,
609      SmiTag(length));
610
611  return result;
612}
613
614Node* CodeStubAssembler::LoadFixedArrayElement(Node* object, Node* index_node,
615                                               int additional_offset,
616                                               ParameterMode parameter_mode) {
617  int32_t header_size =
618      FixedArray::kHeaderSize + additional_offset - kHeapObjectTag;
619  Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_ELEMENTS,
620                                        parameter_mode, header_size);
621  return Load(MachineType::AnyTagged(), object, offset);
622}
623
624Node* CodeStubAssembler::LoadFixedDoubleArrayElement(
625    Node* object, Node* index_node, MachineType machine_type,
626    int additional_offset, ParameterMode parameter_mode) {
627  int32_t header_size =
628      FixedDoubleArray::kHeaderSize + additional_offset - kHeapObjectTag;
629  Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_DOUBLE_ELEMENTS,
630                                        parameter_mode, header_size);
631  return Load(machine_type, object, offset);
632}
633
634Node* CodeStubAssembler::LoadNativeContext(Node* context) {
635  return LoadFixedArrayElement(context,
636                               Int32Constant(Context::NATIVE_CONTEXT_INDEX));
637}
638
639Node* CodeStubAssembler::LoadJSArrayElementsMap(ElementsKind kind,
640                                                Node* native_context) {
641  return LoadFixedArrayElement(native_context,
642                               Int32Constant(Context::ArrayMapIndex(kind)));
643}
644
645Node* CodeStubAssembler::StoreHeapNumberValue(Node* object, Node* value) {
646  return StoreNoWriteBarrier(
647      MachineRepresentation::kFloat64, object,
648      IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag), value);
649}
650
651Node* CodeStubAssembler::StoreObjectField(
652    Node* object, int offset, Node* value) {
653  return Store(MachineRepresentation::kTagged, object,
654               IntPtrConstant(offset - kHeapObjectTag), value);
655}
656
657Node* CodeStubAssembler::StoreObjectFieldNoWriteBarrier(
658    Node* object, int offset, Node* value, MachineRepresentation rep) {
659  return StoreNoWriteBarrier(rep, object,
660                             IntPtrConstant(offset - kHeapObjectTag), value);
661}
662
663Node* CodeStubAssembler::StoreMapNoWriteBarrier(Node* object, Node* map) {
664  return StoreNoWriteBarrier(
665      MachineRepresentation::kTagged, object,
666      IntPtrConstant(HeapNumber::kMapOffset - kHeapObjectTag), map);
667}
668
669Node* CodeStubAssembler::StoreFixedArrayElement(Node* object, Node* index_node,
670                                                Node* value,
671                                                WriteBarrierMode barrier_mode,
672                                                ParameterMode parameter_mode) {
673  DCHECK(barrier_mode == SKIP_WRITE_BARRIER ||
674         barrier_mode == UPDATE_WRITE_BARRIER);
675  Node* offset =
676      ElementOffsetFromIndex(index_node, FAST_HOLEY_ELEMENTS, parameter_mode,
677                             FixedArray::kHeaderSize - kHeapObjectTag);
678  MachineRepresentation rep = MachineRepresentation::kTagged;
679  if (barrier_mode == SKIP_WRITE_BARRIER) {
680    return StoreNoWriteBarrier(rep, object, offset, value);
681  } else {
682    return Store(rep, object, offset, value);
683  }
684}
685
686Node* CodeStubAssembler::StoreFixedDoubleArrayElement(
687    Node* object, Node* index_node, Node* value, ParameterMode parameter_mode) {
688  Node* offset =
689      ElementOffsetFromIndex(index_node, FAST_DOUBLE_ELEMENTS, parameter_mode,
690                             FixedArray::kHeaderSize - kHeapObjectTag);
691  MachineRepresentation rep = MachineRepresentation::kFloat64;
692  return StoreNoWriteBarrier(rep, object, offset, value);
693}
694
695Node* CodeStubAssembler::AllocateHeapNumber() {
696  Node* result = Allocate(HeapNumber::kSize, kNone);
697  StoreMapNoWriteBarrier(result, HeapNumberMapConstant());
698  return result;
699}
700
701Node* CodeStubAssembler::AllocateHeapNumberWithValue(Node* value) {
702  Node* result = AllocateHeapNumber();
703  StoreHeapNumberValue(result, value);
704  return result;
705}
706
707Node* CodeStubAssembler::AllocateSeqOneByteString(int length) {
708  Node* result = Allocate(SeqOneByteString::SizeFor(length));
709  StoreMapNoWriteBarrier(result, LoadRoot(Heap::kOneByteStringMapRootIndex));
710  StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset,
711                                 SmiConstant(Smi::FromInt(length)));
712  StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset,
713                                 IntPtrConstant(String::kEmptyHashField),
714                                 MachineRepresentation::kWord32);
715  return result;
716}
717
718Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length) {
719  Variable var_result(this, MachineRepresentation::kTagged);
720
721  // Compute the SeqOneByteString size and check if it fits into new space.
722  Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred),
723      if_join(this);
724  Node* size = WordAnd(
725      IntPtrAdd(
726          IntPtrAdd(length, IntPtrConstant(SeqOneByteString::kHeaderSize)),
727          IntPtrConstant(kObjectAlignmentMask)),
728      IntPtrConstant(~kObjectAlignmentMask));
729  Branch(IntPtrLessThanOrEqual(size,
730                               IntPtrConstant(Page::kMaxRegularHeapObjectSize)),
731         &if_sizeissmall, &if_notsizeissmall);
732
733  Bind(&if_sizeissmall);
734  {
735    // Just allocate the SeqOneByteString in new space.
736    Node* result = Allocate(size);
737    StoreMapNoWriteBarrier(result, LoadRoot(Heap::kOneByteStringMapRootIndex));
738    StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset,
739                                   SmiFromWord(length));
740    StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset,
741                                   IntPtrConstant(String::kEmptyHashField),
742                                   MachineRepresentation::kWord32);
743    var_result.Bind(result);
744    Goto(&if_join);
745  }
746
747  Bind(&if_notsizeissmall);
748  {
749    // We might need to allocate in large object space, go to the runtime.
750    Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context,
751                               SmiFromWord(length));
752    var_result.Bind(result);
753    Goto(&if_join);
754  }
755
756  Bind(&if_join);
757  return var_result.value();
758}
759
760Node* CodeStubAssembler::AllocateSeqTwoByteString(int length) {
761  Node* result = Allocate(SeqTwoByteString::SizeFor(length));
762  StoreMapNoWriteBarrier(result, LoadRoot(Heap::kStringMapRootIndex));
763  StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset,
764                                 SmiConstant(Smi::FromInt(length)));
765  StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset,
766                                 IntPtrConstant(String::kEmptyHashField),
767                                 MachineRepresentation::kWord32);
768  return result;
769}
770
771Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length) {
772  Variable var_result(this, MachineRepresentation::kTagged);
773
774  // Compute the SeqTwoByteString size and check if it fits into new space.
775  Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred),
776      if_join(this);
777  Node* size = WordAnd(
778      IntPtrAdd(IntPtrAdd(WordShl(length, 1),
779                          IntPtrConstant(SeqTwoByteString::kHeaderSize)),
780                IntPtrConstant(kObjectAlignmentMask)),
781      IntPtrConstant(~kObjectAlignmentMask));
782  Branch(IntPtrLessThanOrEqual(size,
783                               IntPtrConstant(Page::kMaxRegularHeapObjectSize)),
784         &if_sizeissmall, &if_notsizeissmall);
785
786  Bind(&if_sizeissmall);
787  {
788    // Just allocate the SeqTwoByteString in new space.
789    Node* result = Allocate(size);
790    StoreMapNoWriteBarrier(result, LoadRoot(Heap::kStringMapRootIndex));
791    StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset,
792                                   SmiFromWord(length));
793    StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset,
794                                   IntPtrConstant(String::kEmptyHashField),
795                                   MachineRepresentation::kWord32);
796    var_result.Bind(result);
797    Goto(&if_join);
798  }
799
800  Bind(&if_notsizeissmall);
801  {
802    // We might need to allocate in large object space, go to the runtime.
803    Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context,
804                               SmiFromWord(length));
805    var_result.Bind(result);
806    Goto(&if_join);
807  }
808
809  Bind(&if_join);
810  return var_result.value();
811}
812
813Node* CodeStubAssembler::AllocateJSArray(ElementsKind kind, Node* array_map,
814                                         Node* capacity_node, Node* length_node,
815                                         compiler::Node* allocation_site,
816                                         ParameterMode mode) {
817  bool is_double = IsFastDoubleElementsKind(kind);
818  int base_size = JSArray::kSize + FixedArray::kHeaderSize;
819  int elements_offset = JSArray::kSize;
820
821  Comment("begin allocation of JSArray");
822
823  if (allocation_site != nullptr) {
824    base_size += AllocationMemento::kSize;
825    elements_offset += AllocationMemento::kSize;
826  }
827
828  int32_t capacity;
829  bool constant_capacity = ToInt32Constant(capacity_node, capacity);
830  Node* total_size =
831      ElementOffsetFromIndex(capacity_node, kind, mode, base_size);
832
833  // Allocate both array and elements object, and initialize the JSArray.
834  Heap* heap = isolate()->heap();
835  Node* array = Allocate(total_size);
836  StoreMapNoWriteBarrier(array, array_map);
837  Node* empty_properties =
838      HeapConstant(Handle<HeapObject>(heap->empty_fixed_array()));
839  StoreObjectFieldNoWriteBarrier(array, JSArray::kPropertiesOffset,
840                                 empty_properties);
841  StoreObjectFieldNoWriteBarrier(
842      array, JSArray::kLengthOffset,
843      mode == SMI_PARAMETERS ? length_node : SmiTag(length_node));
844
845  if (allocation_site != nullptr) {
846    InitializeAllocationMemento(array, JSArray::kSize, allocation_site);
847  }
848
849  // Setup elements object.
850  Node* elements = InnerAllocate(array, elements_offset);
851  StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset, elements);
852  Handle<Map> elements_map(is_double ? heap->fixed_double_array_map()
853                                     : heap->fixed_array_map());
854  StoreMapNoWriteBarrier(elements, HeapConstant(elements_map));
855  StoreObjectFieldNoWriteBarrier(
856      elements, FixedArray::kLengthOffset,
857      mode == SMI_PARAMETERS ? capacity_node : SmiTag(capacity_node));
858
859  int const first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag;
860  Node* hole = HeapConstant(Handle<HeapObject>(heap->the_hole_value()));
861  Node* double_hole =
862      Is64() ? Int64Constant(kHoleNanInt64) : Int32Constant(kHoleNanLower32);
863  DCHECK_EQ(kHoleNanLower32, kHoleNanUpper32);
864  if (constant_capacity && capacity <= kElementLoopUnrollThreshold) {
865    for (int i = 0; i < capacity; ++i) {
866      if (is_double) {
867        Node* offset = ElementOffsetFromIndex(Int32Constant(i), kind, mode,
868                                              first_element_offset);
869        // Don't use doubles to store the hole double, since manipulating the
870        // signaling NaN used for the hole in C++, e.g. with bit_cast, will
871        // change its value on ia32 (the x87 stack is used to return values
872        // and stores to the stack silently clear the signalling bit).
873        //
874        // TODO(danno): When we have a Float32/Float64 wrapper class that
875        // preserves double bits during manipulation, remove this code/change
876        // this to an indexed Float64 store.
877        if (Is64()) {
878          StoreNoWriteBarrier(MachineRepresentation::kWord64, elements, offset,
879                              double_hole);
880        } else {
881          StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset,
882                              double_hole);
883          offset = ElementOffsetFromIndex(Int32Constant(i), kind, mode,
884                                          first_element_offset + kPointerSize);
885          StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset,
886                              double_hole);
887        }
888      } else {
889        StoreFixedArrayElement(elements, Int32Constant(i), hole,
890                               SKIP_WRITE_BARRIER);
891      }
892    }
893  } else {
894    Variable current(this, MachineRepresentation::kTagged);
895    Label test(this);
896    Label decrement(this, &current);
897    Label done(this);
898    Node* limit = IntPtrAdd(elements, IntPtrConstant(first_element_offset));
899    current.Bind(
900        IntPtrAdd(limit, ElementOffsetFromIndex(capacity_node, kind, mode, 0)));
901
902    Branch(WordEqual(current.value(), limit), &done, &decrement);
903
904    Bind(&decrement);
905    current.Bind(IntPtrSub(
906        current.value(),
907        Int32Constant(IsFastDoubleElementsKind(kind) ? kDoubleSize
908                                                     : kPointerSize)));
909    if (is_double) {
910      // Don't use doubles to store the hole double, since manipulating the
911      // signaling NaN used for the hole in C++, e.g. with bit_cast, will
912      // change its value on ia32 (the x87 stack is used to return values
913      // and stores to the stack silently clear the signalling bit).
914      //
915      // TODO(danno): When we have a Float32/Float64 wrapper class that
916      // preserves double bits during manipulation, remove this code/change
917      // this to an indexed Float64 store.
918      if (Is64()) {
919        StoreNoWriteBarrier(MachineRepresentation::kWord64, current.value(),
920                            double_hole);
921      } else {
922        StoreNoWriteBarrier(MachineRepresentation::kWord32, current.value(),
923                            double_hole);
924        StoreNoWriteBarrier(
925            MachineRepresentation::kWord32,
926            IntPtrAdd(current.value(), Int32Constant(kPointerSize)),
927            double_hole);
928      }
929    } else {
930      StoreNoWriteBarrier(MachineRepresentation::kTagged, current.value(),
931                          hole);
932    }
933    Node* compare = WordNotEqual(current.value(), limit);
934    Branch(compare, &decrement, &done);
935
936    Bind(&done);
937  }
938
939  return array;
940}
941
942void CodeStubAssembler::InitializeAllocationMemento(
943    compiler::Node* base_allocation, int base_allocation_size,
944    compiler::Node* allocation_site) {
945  StoreObjectFieldNoWriteBarrier(
946      base_allocation, AllocationMemento::kMapOffset + base_allocation_size,
947      HeapConstant(Handle<Map>(isolate()->heap()->allocation_memento_map())));
948  StoreObjectFieldNoWriteBarrier(
949      base_allocation,
950      AllocationMemento::kAllocationSiteOffset + base_allocation_size,
951      allocation_site);
952  if (FLAG_allocation_site_pretenuring) {
953    Node* count = LoadObjectField(allocation_site,
954                                  AllocationSite::kPretenureCreateCountOffset);
955    Node* incremented_count = IntPtrAdd(count, SmiConstant(Smi::FromInt(1)));
956    StoreObjectFieldNoWriteBarrier(allocation_site,
957                                   AllocationSite::kPretenureCreateCountOffset,
958                                   incremented_count);
959  }
960}
961
962Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) {
963  // We might need to loop once due to ToNumber conversion.
964  Variable var_value(this, MachineRepresentation::kTagged),
965      var_result(this, MachineRepresentation::kFloat64);
966  Label loop(this, &var_value), done_loop(this, &var_result);
967  var_value.Bind(value);
968  Goto(&loop);
969  Bind(&loop);
970  {
971    // Load the current {value}.
972    value = var_value.value();
973
974    // Check if the {value} is a Smi or a HeapObject.
975    Label if_valueissmi(this), if_valueisnotsmi(this);
976    Branch(WordIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
977
978    Bind(&if_valueissmi);
979    {
980      // Convert the Smi {value}.
981      var_result.Bind(SmiToFloat64(value));
982      Goto(&done_loop);
983    }
984
985    Bind(&if_valueisnotsmi);
986    {
987      // Check if {value} is a HeapNumber.
988      Label if_valueisheapnumber(this),
989          if_valueisnotheapnumber(this, Label::kDeferred);
990      Branch(WordEqual(LoadMap(value), HeapNumberMapConstant()),
991             &if_valueisheapnumber, &if_valueisnotheapnumber);
992
993      Bind(&if_valueisheapnumber);
994      {
995        // Load the floating point value.
996        var_result.Bind(LoadHeapNumberValue(value));
997        Goto(&done_loop);
998      }
999
1000      Bind(&if_valueisnotheapnumber);
1001      {
1002        // Convert the {value} to a Number first.
1003        Callable callable = CodeFactory::NonNumberToNumber(isolate());
1004        var_value.Bind(CallStub(callable, context, value));
1005        Goto(&loop);
1006      }
1007    }
1008  }
1009  Bind(&done_loop);
1010  return var_result.value();
1011}
1012
1013Node* CodeStubAssembler::TruncateTaggedToWord32(Node* context, Node* value) {
1014  // We might need to loop once due to ToNumber conversion.
1015  Variable var_value(this, MachineRepresentation::kTagged),
1016      var_result(this, MachineRepresentation::kWord32);
1017  Label loop(this, &var_value), done_loop(this, &var_result);
1018  var_value.Bind(value);
1019  Goto(&loop);
1020  Bind(&loop);
1021  {
1022    // Load the current {value}.
1023    value = var_value.value();
1024
1025    // Check if the {value} is a Smi or a HeapObject.
1026    Label if_valueissmi(this), if_valueisnotsmi(this);
1027    Branch(WordIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
1028
1029    Bind(&if_valueissmi);
1030    {
1031      // Convert the Smi {value}.
1032      var_result.Bind(SmiToWord32(value));
1033      Goto(&done_loop);
1034    }
1035
1036    Bind(&if_valueisnotsmi);
1037    {
1038      // Check if {value} is a HeapNumber.
1039      Label if_valueisheapnumber(this),
1040          if_valueisnotheapnumber(this, Label::kDeferred);
1041      Branch(WordEqual(LoadMap(value), HeapNumberMapConstant()),
1042             &if_valueisheapnumber, &if_valueisnotheapnumber);
1043
1044      Bind(&if_valueisheapnumber);
1045      {
1046        // Truncate the floating point value.
1047        var_result.Bind(TruncateHeapNumberValueToWord32(value));
1048        Goto(&done_loop);
1049      }
1050
1051      Bind(&if_valueisnotheapnumber);
1052      {
1053        // Convert the {value} to a Number first.
1054        Callable callable = CodeFactory::NonNumberToNumber(isolate());
1055        var_value.Bind(CallStub(callable, context, value));
1056        Goto(&loop);
1057      }
1058    }
1059  }
1060  Bind(&done_loop);
1061  return var_result.value();
1062}
1063
1064Node* CodeStubAssembler::TruncateHeapNumberValueToWord32(Node* object) {
1065  Node* value = LoadHeapNumberValue(object);
1066  return TruncateFloat64ToWord32(value);
1067}
1068
1069Node* CodeStubAssembler::ChangeFloat64ToTagged(Node* value) {
1070  Node* value32 = RoundFloat64ToInt32(value);
1071  Node* value64 = ChangeInt32ToFloat64(value32);
1072
1073  Label if_valueisint32(this), if_valueisheapnumber(this), if_join(this);
1074
1075  Label if_valueisequal(this), if_valueisnotequal(this);
1076  Branch(Float64Equal(value, value64), &if_valueisequal, &if_valueisnotequal);
1077  Bind(&if_valueisequal);
1078  {
1079    GotoUnless(Word32Equal(value32, Int32Constant(0)), &if_valueisint32);
1080    BranchIfInt32LessThan(Float64ExtractHighWord32(value), Int32Constant(0),
1081                          &if_valueisheapnumber, &if_valueisint32);
1082  }
1083  Bind(&if_valueisnotequal);
1084  Goto(&if_valueisheapnumber);
1085
1086  Variable var_result(this, MachineRepresentation::kTagged);
1087  Bind(&if_valueisint32);
1088  {
1089    if (Is64()) {
1090      Node* result = SmiTag(ChangeInt32ToInt64(value32));
1091      var_result.Bind(result);
1092      Goto(&if_join);
1093    } else {
1094      Node* pair = Int32AddWithOverflow(value32, value32);
1095      Node* overflow = Projection(1, pair);
1096      Label if_overflow(this, Label::kDeferred), if_notoverflow(this);
1097      Branch(overflow, &if_overflow, &if_notoverflow);
1098      Bind(&if_overflow);
1099      Goto(&if_valueisheapnumber);
1100      Bind(&if_notoverflow);
1101      {
1102        Node* result = Projection(0, pair);
1103        var_result.Bind(result);
1104        Goto(&if_join);
1105      }
1106    }
1107  }
1108  Bind(&if_valueisheapnumber);
1109  {
1110    Node* result = AllocateHeapNumberWithValue(value);
1111    var_result.Bind(result);
1112    Goto(&if_join);
1113  }
1114  Bind(&if_join);
1115  return var_result.value();
1116}
1117
1118Node* CodeStubAssembler::ChangeInt32ToTagged(Node* value) {
1119  if (Is64()) {
1120    return SmiTag(ChangeInt32ToInt64(value));
1121  }
1122  Variable var_result(this, MachineRepresentation::kTagged);
1123  Node* pair = Int32AddWithOverflow(value, value);
1124  Node* overflow = Projection(1, pair);
1125  Label if_overflow(this, Label::kDeferred), if_notoverflow(this),
1126      if_join(this);
1127  Branch(overflow, &if_overflow, &if_notoverflow);
1128  Bind(&if_overflow);
1129  {
1130    Node* value64 = ChangeInt32ToFloat64(value);
1131    Node* result = AllocateHeapNumberWithValue(value64);
1132    var_result.Bind(result);
1133  }
1134  Goto(&if_join);
1135  Bind(&if_notoverflow);
1136  {
1137    Node* result = Projection(0, pair);
1138    var_result.Bind(result);
1139  }
1140  Goto(&if_join);
1141  Bind(&if_join);
1142  return var_result.value();
1143}
1144
1145Node* CodeStubAssembler::ChangeUint32ToTagged(Node* value) {
1146  Label if_overflow(this, Label::kDeferred), if_not_overflow(this),
1147      if_join(this);
1148  Variable var_result(this, MachineRepresentation::kTagged);
1149  // If {value} > 2^31 - 1, we need to store it in a HeapNumber.
1150  Branch(Int32LessThan(value, Int32Constant(0)), &if_overflow,
1151         &if_not_overflow);
1152  Bind(&if_not_overflow);
1153  {
1154    if (Is64()) {
1155      var_result.Bind(SmiTag(ChangeUint32ToUint64(value)));
1156    } else {
1157      // If tagging {value} results in an overflow, we need to use a HeapNumber
1158      // to represent it.
1159      Node* pair = Int32AddWithOverflow(value, value);
1160      Node* overflow = Projection(1, pair);
1161      GotoIf(overflow, &if_overflow);
1162
1163      Node* result = Projection(0, pair);
1164      var_result.Bind(result);
1165    }
1166  }
1167  Goto(&if_join);
1168
1169  Bind(&if_overflow);
1170  {
1171    Node* float64_value = ChangeUint32ToFloat64(value);
1172    var_result.Bind(AllocateHeapNumberWithValue(float64_value));
1173  }
1174  Goto(&if_join);
1175
1176  Bind(&if_join);
1177  return var_result.value();
1178}
1179
1180Node* CodeStubAssembler::ToThisString(Node* context, Node* value,
1181                                      char const* method_name) {
1182  Variable var_value(this, MachineRepresentation::kTagged);
1183  var_value.Bind(value);
1184
1185  // Check if the {value} is a Smi or a HeapObject.
1186  Label if_valueissmi(this, Label::kDeferred), if_valueisnotsmi(this),
1187      if_valueisstring(this);
1188  Branch(WordIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
1189  Bind(&if_valueisnotsmi);
1190  {
1191    // Load the instance type of the {value}.
1192    Node* value_instance_type = LoadInstanceType(value);
1193
1194    // Check if the {value} is already String.
1195    Label if_valueisnotstring(this, Label::kDeferred);
1196    Branch(
1197        Int32LessThan(value_instance_type, Int32Constant(FIRST_NONSTRING_TYPE)),
1198        &if_valueisstring, &if_valueisnotstring);
1199    Bind(&if_valueisnotstring);
1200    {
1201      // Check if the {value} is null.
1202      Label if_valueisnullorundefined(this, Label::kDeferred),
1203          if_valueisnotnullorundefined(this, Label::kDeferred),
1204          if_valueisnotnull(this, Label::kDeferred);
1205      Branch(WordEqual(value, NullConstant()), &if_valueisnullorundefined,
1206             &if_valueisnotnull);
1207      Bind(&if_valueisnotnull);
1208      {
1209        // Check if the {value} is undefined.
1210        Branch(WordEqual(value, UndefinedConstant()),
1211               &if_valueisnullorundefined, &if_valueisnotnullorundefined);
1212        Bind(&if_valueisnotnullorundefined);
1213        {
1214          // Convert the {value} to a String.
1215          Callable callable = CodeFactory::ToString(isolate());
1216          var_value.Bind(CallStub(callable, context, value));
1217          Goto(&if_valueisstring);
1218        }
1219      }
1220
1221      Bind(&if_valueisnullorundefined);
1222      {
1223        // The {value} is either null or undefined.
1224        CallRuntime(Runtime::kThrowCalledOnNullOrUndefined, context,
1225                    HeapConstant(factory()->NewStringFromAsciiChecked(
1226                        method_name, TENURED)));
1227        Goto(&if_valueisstring);  // Never reached.
1228      }
1229    }
1230  }
1231  Bind(&if_valueissmi);
1232  {
1233    // The {value} is a Smi, convert it to a String.
1234    Callable callable = CodeFactory::NumberToString(isolate());
1235    var_value.Bind(CallStub(callable, context, value));
1236    Goto(&if_valueisstring);
1237  }
1238  Bind(&if_valueisstring);
1239  return var_value.value();
1240}
1241
1242Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index) {
1243  // Translate the {index} into a Word.
1244  index = SmiToWord(index);
1245
1246  // We may need to loop in case of cons or sliced strings.
1247  Variable var_index(this, MachineType::PointerRepresentation());
1248  Variable var_result(this, MachineRepresentation::kWord32);
1249  Variable var_string(this, MachineRepresentation::kTagged);
1250  Variable* loop_vars[] = {&var_index, &var_string};
1251  Label done_loop(this, &var_result), loop(this, 2, loop_vars);
1252  var_string.Bind(string);
1253  var_index.Bind(index);
1254  Goto(&loop);
1255  Bind(&loop);
1256  {
1257    // Load the current {index}.
1258    index = var_index.value();
1259
1260    // Load the current {string}.
1261    string = var_string.value();
1262
1263    // Load the instance type of the {string}.
1264    Node* string_instance_type = LoadInstanceType(string);
1265
1266    // Check if the {string} is a SeqString.
1267    Label if_stringissequential(this), if_stringisnotsequential(this);
1268    Branch(Word32Equal(Word32And(string_instance_type,
1269                                 Int32Constant(kStringRepresentationMask)),
1270                       Int32Constant(kSeqStringTag)),
1271           &if_stringissequential, &if_stringisnotsequential);
1272
1273    Bind(&if_stringissequential);
1274    {
1275      // Check if the {string} is a TwoByteSeqString or a OneByteSeqString.
1276      Label if_stringistwobyte(this), if_stringisonebyte(this);
1277      Branch(Word32Equal(Word32And(string_instance_type,
1278                                   Int32Constant(kStringEncodingMask)),
1279                         Int32Constant(kTwoByteStringTag)),
1280             &if_stringistwobyte, &if_stringisonebyte);
1281
1282      Bind(&if_stringisonebyte);
1283      {
1284        var_result.Bind(
1285            Load(MachineType::Uint8(), string,
1286                 IntPtrAdd(index, IntPtrConstant(SeqOneByteString::kHeaderSize -
1287                                                 kHeapObjectTag))));
1288        Goto(&done_loop);
1289      }
1290
1291      Bind(&if_stringistwobyte);
1292      {
1293        var_result.Bind(
1294            Load(MachineType::Uint16(), string,
1295                 IntPtrAdd(WordShl(index, IntPtrConstant(1)),
1296                           IntPtrConstant(SeqTwoByteString::kHeaderSize -
1297                                          kHeapObjectTag))));
1298        Goto(&done_loop);
1299      }
1300    }
1301
1302    Bind(&if_stringisnotsequential);
1303    {
1304      // Check if the {string} is a ConsString.
1305      Label if_stringiscons(this), if_stringisnotcons(this);
1306      Branch(Word32Equal(Word32And(string_instance_type,
1307                                   Int32Constant(kStringRepresentationMask)),
1308                         Int32Constant(kConsStringTag)),
1309             &if_stringiscons, &if_stringisnotcons);
1310
1311      Bind(&if_stringiscons);
1312      {
1313        // Check whether the right hand side is the empty string (i.e. if
1314        // this is really a flat string in a cons string). If that is not
1315        // the case we flatten the string first.
1316        Label if_rhsisempty(this), if_rhsisnotempty(this, Label::kDeferred);
1317        Node* rhs = LoadObjectField(string, ConsString::kSecondOffset);
1318        Branch(WordEqual(rhs, EmptyStringConstant()), &if_rhsisempty,
1319               &if_rhsisnotempty);
1320
1321        Bind(&if_rhsisempty);
1322        {
1323          // Just operate on the left hand side of the {string}.
1324          var_string.Bind(LoadObjectField(string, ConsString::kFirstOffset));
1325          Goto(&loop);
1326        }
1327
1328        Bind(&if_rhsisnotempty);
1329        {
1330          // Flatten the {string} and lookup in the resulting string.
1331          var_string.Bind(CallRuntime(Runtime::kFlattenString,
1332                                      NoContextConstant(), string));
1333          Goto(&loop);
1334        }
1335      }
1336
1337      Bind(&if_stringisnotcons);
1338      {
1339        // Check if the {string} is an ExternalString.
1340        Label if_stringisexternal(this), if_stringisnotexternal(this);
1341        Branch(Word32Equal(Word32And(string_instance_type,
1342                                     Int32Constant(kStringRepresentationMask)),
1343                           Int32Constant(kExternalStringTag)),
1344               &if_stringisexternal, &if_stringisnotexternal);
1345
1346        Bind(&if_stringisexternal);
1347        {
1348          // Check if the {string} is a short external string.
1349          Label if_stringisshort(this),
1350              if_stringisnotshort(this, Label::kDeferred);
1351          Branch(Word32Equal(Word32And(string_instance_type,
1352                                       Int32Constant(kShortExternalStringMask)),
1353                             Int32Constant(0)),
1354                 &if_stringisshort, &if_stringisnotshort);
1355
1356          Bind(&if_stringisshort);
1357          {
1358            // Load the actual resource data from the {string}.
1359            Node* string_resource_data =
1360                LoadObjectField(string, ExternalString::kResourceDataOffset,
1361                                MachineType::Pointer());
1362
1363            // Check if the {string} is a TwoByteExternalString or a
1364            // OneByteExternalString.
1365            Label if_stringistwobyte(this), if_stringisonebyte(this);
1366            Branch(Word32Equal(Word32And(string_instance_type,
1367                                         Int32Constant(kStringEncodingMask)),
1368                               Int32Constant(kTwoByteStringTag)),
1369                   &if_stringistwobyte, &if_stringisonebyte);
1370
1371            Bind(&if_stringisonebyte);
1372            {
1373              var_result.Bind(
1374                  Load(MachineType::Uint8(), string_resource_data, index));
1375              Goto(&done_loop);
1376            }
1377
1378            Bind(&if_stringistwobyte);
1379            {
1380              var_result.Bind(Load(MachineType::Uint16(), string_resource_data,
1381                                   WordShl(index, IntPtrConstant(1))));
1382              Goto(&done_loop);
1383            }
1384          }
1385
1386          Bind(&if_stringisnotshort);
1387          {
1388            // The {string} might be compressed, call the runtime.
1389            var_result.Bind(SmiToWord32(
1390                CallRuntime(Runtime::kExternalStringGetChar,
1391                            NoContextConstant(), string, SmiTag(index))));
1392            Goto(&done_loop);
1393          }
1394        }
1395
1396        Bind(&if_stringisnotexternal);
1397        {
1398          // The {string} is a SlicedString, continue with its parent.
1399          Node* string_offset =
1400              SmiToWord(LoadObjectField(string, SlicedString::kOffsetOffset));
1401          Node* string_parent =
1402              LoadObjectField(string, SlicedString::kParentOffset);
1403          var_index.Bind(IntPtrAdd(index, string_offset));
1404          var_string.Bind(string_parent);
1405          Goto(&loop);
1406        }
1407      }
1408    }
1409  }
1410
1411  Bind(&done_loop);
1412  return var_result.value();
1413}
1414
1415Node* CodeStubAssembler::StringFromCharCode(Node* code) {
1416  Variable var_result(this, MachineRepresentation::kTagged);
1417
1418  // Check if the {code} is a one-byte char code.
1419  Label if_codeisonebyte(this), if_codeistwobyte(this, Label::kDeferred),
1420      if_done(this);
1421  Branch(Int32LessThanOrEqual(code, Int32Constant(String::kMaxOneByteCharCode)),
1422         &if_codeisonebyte, &if_codeistwobyte);
1423  Bind(&if_codeisonebyte);
1424  {
1425    // Load the isolate wide single character string cache.
1426    Node* cache = LoadRoot(Heap::kSingleCharacterStringCacheRootIndex);
1427
1428    // Check if we have an entry for the {code} in the single character string
1429    // cache already.
1430    Label if_entryisundefined(this, Label::kDeferred),
1431        if_entryisnotundefined(this);
1432    Node* entry = LoadFixedArrayElement(cache, code);
1433    Branch(WordEqual(entry, UndefinedConstant()), &if_entryisundefined,
1434           &if_entryisnotundefined);
1435
1436    Bind(&if_entryisundefined);
1437    {
1438      // Allocate a new SeqOneByteString for {code} and store it in the {cache}.
1439      Node* result = AllocateSeqOneByteString(1);
1440      StoreNoWriteBarrier(
1441          MachineRepresentation::kWord8, result,
1442          IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag), code);
1443      StoreFixedArrayElement(cache, code, result);
1444      var_result.Bind(result);
1445      Goto(&if_done);
1446    }
1447
1448    Bind(&if_entryisnotundefined);
1449    {
1450      // Return the entry from the {cache}.
1451      var_result.Bind(entry);
1452      Goto(&if_done);
1453    }
1454  }
1455
1456  Bind(&if_codeistwobyte);
1457  {
1458    // Allocate a new SeqTwoByteString for {code}.
1459    Node* result = AllocateSeqTwoByteString(1);
1460    StoreNoWriteBarrier(
1461        MachineRepresentation::kWord16, result,
1462        IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code);
1463    var_result.Bind(result);
1464    Goto(&if_done);
1465  }
1466
1467  Bind(&if_done);
1468  return var_result.value();
1469}
1470
1471Node* CodeStubAssembler::BitFieldDecode(Node* word32, uint32_t shift,
1472                                        uint32_t mask) {
1473  return Word32Shr(Word32And(word32, Int32Constant(mask)),
1474                   Int32Constant(shift));
1475}
1476
1477void CodeStubAssembler::SetCounter(StatsCounter* counter, int value) {
1478  if (FLAG_native_code_counters && counter->Enabled()) {
1479    Node* counter_address = ExternalConstant(ExternalReference(counter));
1480    StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address,
1481                        Int32Constant(value));
1482  }
1483}
1484
1485void CodeStubAssembler::IncrementCounter(StatsCounter* counter, int delta) {
1486  DCHECK(delta > 0);
1487  if (FLAG_native_code_counters && counter->Enabled()) {
1488    Node* counter_address = ExternalConstant(ExternalReference(counter));
1489    Node* value = Load(MachineType::Int32(), counter_address);
1490    value = Int32Add(value, Int32Constant(delta));
1491    StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address, value);
1492  }
1493}
1494
1495void CodeStubAssembler::DecrementCounter(StatsCounter* counter, int delta) {
1496  DCHECK(delta > 0);
1497  if (FLAG_native_code_counters && counter->Enabled()) {
1498    Node* counter_address = ExternalConstant(ExternalReference(counter));
1499    Node* value = Load(MachineType::Int32(), counter_address);
1500    value = Int32Sub(value, Int32Constant(delta));
1501    StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address, value);
1502  }
1503}
1504
1505void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex,
1506                                  Variable* var_index, Label* if_keyisunique,
1507                                  Label* if_bailout) {
1508  DCHECK_EQ(MachineRepresentation::kWord32, var_index->rep());
1509  Comment("TryToName");
1510
1511  Label if_keyissmi(this), if_keyisnotsmi(this);
1512  Branch(WordIsSmi(key), &if_keyissmi, &if_keyisnotsmi);
1513  Bind(&if_keyissmi);
1514  {
1515    // Negative smi keys are named properties. Handle in the runtime.
1516    GotoUnless(WordIsPositiveSmi(key), if_bailout);
1517
1518    var_index->Bind(SmiToWord32(key));
1519    Goto(if_keyisindex);
1520  }
1521
1522  Bind(&if_keyisnotsmi);
1523
1524  Node* key_instance_type = LoadInstanceType(key);
1525  // Symbols are unique.
1526  GotoIf(Word32Equal(key_instance_type, Int32Constant(SYMBOL_TYPE)),
1527         if_keyisunique);
1528
1529  Label if_keyisinternalized(this);
1530  Node* bits =
1531      WordAnd(key_instance_type,
1532              Int32Constant(kIsNotStringMask | kIsNotInternalizedMask));
1533  Branch(Word32Equal(bits, Int32Constant(kStringTag | kInternalizedTag)),
1534         &if_keyisinternalized, if_bailout);
1535  Bind(&if_keyisinternalized);
1536
1537  // Check whether the key is an array index passed in as string. Handle
1538  // uniform with smi keys if so.
1539  // TODO(verwaest): Also support non-internalized strings.
1540  Node* hash = LoadNameHashField(key);
1541  Node* bit = Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask));
1542  GotoIf(Word32NotEqual(bit, Int32Constant(0)), if_keyisunique);
1543  // Key is an index. Check if it is small enough to be encoded in the
1544  // hash_field. Handle too big array index in runtime.
1545  bit = Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask));
1546  GotoIf(Word32NotEqual(bit, Int32Constant(0)), if_bailout);
1547  var_index->Bind(BitFieldDecode<Name::ArrayIndexValueBits>(hash));
1548  Goto(if_keyisindex);
1549}
1550
1551template <typename Dictionary>
1552Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) {
1553  Node* entry_index = Int32Mul(entry, Int32Constant(Dictionary::kEntrySize));
1554  return Int32Add(entry_index,
1555                  Int32Constant(Dictionary::kElementsStartIndex + field_index));
1556}
1557
1558template <typename Dictionary>
1559void CodeStubAssembler::NameDictionaryLookup(Node* dictionary,
1560                                             Node* unique_name, Label* if_found,
1561                                             Variable* var_name_index,
1562                                             Label* if_not_found,
1563                                             int inlined_probes) {
1564  DCHECK_EQ(MachineRepresentation::kWord32, var_name_index->rep());
1565  Comment("NameDictionaryLookup");
1566
1567  Node* capacity = SmiToWord32(LoadFixedArrayElement(
1568      dictionary, Int32Constant(Dictionary::kCapacityIndex)));
1569  Node* mask = Int32Sub(capacity, Int32Constant(1));
1570  Node* hash = LoadNameHash(unique_name);
1571
1572  // See Dictionary::FirstProbe().
1573  Node* count = Int32Constant(0);
1574  Node* entry = Word32And(hash, mask);
1575
1576  for (int i = 0; i < inlined_probes; i++) {
1577    Node* index = EntryToIndex<Dictionary>(entry);
1578    var_name_index->Bind(index);
1579
1580    Node* current = LoadFixedArrayElement(dictionary, index);
1581    GotoIf(WordEqual(current, unique_name), if_found);
1582
1583    // See Dictionary::NextProbe().
1584    count = Int32Constant(i + 1);
1585    entry = Word32And(Int32Add(entry, count), mask);
1586  }
1587
1588  Node* undefined = UndefinedConstant();
1589
1590  Variable var_count(this, MachineRepresentation::kWord32);
1591  Variable var_entry(this, MachineRepresentation::kWord32);
1592  Variable* loop_vars[] = {&var_count, &var_entry, var_name_index};
1593  Label loop(this, 3, loop_vars);
1594  var_count.Bind(count);
1595  var_entry.Bind(entry);
1596  Goto(&loop);
1597  Bind(&loop);
1598  {
1599    Node* count = var_count.value();
1600    Node* entry = var_entry.value();
1601
1602    Node* index = EntryToIndex<Dictionary>(entry);
1603    var_name_index->Bind(index);
1604
1605    Node* current = LoadFixedArrayElement(dictionary, index);
1606    GotoIf(WordEqual(current, undefined), if_not_found);
1607    GotoIf(WordEqual(current, unique_name), if_found);
1608
1609    // See Dictionary::NextProbe().
1610    count = Int32Add(count, Int32Constant(1));
1611    entry = Word32And(Int32Add(entry, count), mask);
1612
1613    var_count.Bind(count);
1614    var_entry.Bind(entry);
1615    Goto(&loop);
1616  }
1617}
1618
1619// Instantiate template methods to workaround GCC compilation issue.
1620template void CodeStubAssembler::NameDictionaryLookup<NameDictionary>(
1621    Node*, Node*, Label*, Variable*, Label*, int);
1622template void CodeStubAssembler::NameDictionaryLookup<GlobalDictionary>(
1623    Node*, Node*, Label*, Variable*, Label*, int);
1624
1625Node* CodeStubAssembler::ComputeIntegerHash(Node* key, Node* seed) {
1626  // See v8::internal::ComputeIntegerHash()
1627  Node* hash = key;
1628  hash = Word32Xor(hash, seed);
1629  hash = Int32Add(Word32Xor(hash, Int32Constant(0xffffffff)),
1630                  Word32Shl(hash, Int32Constant(15)));
1631  hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(12)));
1632  hash = Int32Add(hash, Word32Shl(hash, Int32Constant(2)));
1633  hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(4)));
1634  hash = Int32Mul(hash, Int32Constant(2057));
1635  hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(16)));
1636  return Word32And(hash, Int32Constant(0x3fffffff));
1637}
1638
1639template <typename Dictionary>
1640void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary, Node* key,
1641                                               Label* if_found,
1642                                               Variable* var_entry,
1643                                               Label* if_not_found) {
1644  DCHECK_EQ(MachineRepresentation::kWord32, var_entry->rep());
1645  Comment("NumberDictionaryLookup");
1646
1647  Node* capacity = SmiToWord32(LoadFixedArrayElement(
1648      dictionary, Int32Constant(Dictionary::kCapacityIndex)));
1649  Node* mask = Int32Sub(capacity, Int32Constant(1));
1650
1651  Node* seed;
1652  if (Dictionary::ShapeT::UsesSeed) {
1653    seed = HashSeed();
1654  } else {
1655    seed = Int32Constant(kZeroHashSeed);
1656  }
1657  Node* hash = ComputeIntegerHash(key, seed);
1658  Node* key_as_float64 = ChangeUint32ToFloat64(key);
1659
1660  // See Dictionary::FirstProbe().
1661  Node* count = Int32Constant(0);
1662  Node* entry = Word32And(hash, mask);
1663
1664  Node* undefined = UndefinedConstant();
1665  Node* the_hole = TheHoleConstant();
1666
1667  Variable var_count(this, MachineRepresentation::kWord32);
1668  Variable* loop_vars[] = {&var_count, var_entry};
1669  Label loop(this, 2, loop_vars);
1670  var_count.Bind(count);
1671  var_entry->Bind(entry);
1672  Goto(&loop);
1673  Bind(&loop);
1674  {
1675    Node* count = var_count.value();
1676    Node* entry = var_entry->value();
1677
1678    Node* index = EntryToIndex<Dictionary>(entry);
1679    Node* current = LoadFixedArrayElement(dictionary, index);
1680    GotoIf(WordEqual(current, undefined), if_not_found);
1681    Label next_probe(this);
1682    {
1683      Label if_currentissmi(this), if_currentisnotsmi(this);
1684      Branch(WordIsSmi(current), &if_currentissmi, &if_currentisnotsmi);
1685      Bind(&if_currentissmi);
1686      {
1687        Node* current_value = SmiToWord32(current);
1688        Branch(Word32Equal(current_value, key), if_found, &next_probe);
1689      }
1690      Bind(&if_currentisnotsmi);
1691      {
1692        GotoIf(WordEqual(current, the_hole), &next_probe);
1693        // Current must be the Number.
1694        Node* current_value = LoadHeapNumberValue(current);
1695        Branch(Float64Equal(current_value, key_as_float64), if_found,
1696               &next_probe);
1697      }
1698    }
1699
1700    Bind(&next_probe);
1701    // See Dictionary::NextProbe().
1702    count = Int32Add(count, Int32Constant(1));
1703    entry = Word32And(Int32Add(entry, count), mask);
1704
1705    var_count.Bind(count);
1706    var_entry->Bind(entry);
1707    Goto(&loop);
1708  }
1709}
1710
1711void CodeStubAssembler::TryLookupProperty(
1712    Node* object, Node* map, Node* instance_type, Node* unique_name,
1713    Label* if_found_fast, Label* if_found_dict, Label* if_found_global,
1714    Variable* var_meta_storage, Variable* var_name_index, Label* if_not_found,
1715    Label* if_bailout) {
1716  DCHECK_EQ(MachineRepresentation::kTagged, var_meta_storage->rep());
1717  DCHECK_EQ(MachineRepresentation::kWord32, var_name_index->rep());
1718
1719  Label if_objectisspecial(this);
1720  STATIC_ASSERT(JS_GLOBAL_OBJECT_TYPE <= LAST_SPECIAL_RECEIVER_TYPE);
1721  GotoIf(Int32LessThanOrEqual(instance_type,
1722                              Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
1723         &if_objectisspecial);
1724
1725  Node* bit_field = LoadMapBitField(map);
1726  Node* mask = Int32Constant(1 << Map::kHasNamedInterceptor |
1727                             1 << Map::kIsAccessCheckNeeded);
1728  Assert(Word32Equal(Word32And(bit_field, mask), Int32Constant(0)));
1729
1730  Node* bit_field3 = LoadMapBitField3(map);
1731  Node* bit = BitFieldDecode<Map::DictionaryMap>(bit_field3);
1732  Label if_isfastmap(this), if_isslowmap(this);
1733  Branch(Word32Equal(bit, Int32Constant(0)), &if_isfastmap, &if_isslowmap);
1734  Bind(&if_isfastmap);
1735  {
1736    Comment("DescriptorArrayLookup");
1737    Node* nof = BitFieldDecode<Map::NumberOfOwnDescriptorsBits>(bit_field3);
1738    // Bail out to the runtime for large numbers of own descriptors. The stub
1739    // only does linear search, which becomes too expensive in that case.
1740    {
1741      static const int32_t kMaxLinear = 210;
1742      GotoIf(Int32GreaterThan(nof, Int32Constant(kMaxLinear)), if_bailout);
1743    }
1744    Node* descriptors = LoadMapDescriptors(map);
1745    var_meta_storage->Bind(descriptors);
1746
1747    Variable var_descriptor(this, MachineRepresentation::kWord32);
1748    Label loop(this, &var_descriptor);
1749    var_descriptor.Bind(Int32Constant(0));
1750    Goto(&loop);
1751    Bind(&loop);
1752    {
1753      Node* index = var_descriptor.value();
1754      Node* name_offset = Int32Constant(DescriptorArray::ToKeyIndex(0));
1755      Node* factor = Int32Constant(DescriptorArray::kDescriptorSize);
1756      GotoIf(Word32Equal(index, nof), if_not_found);
1757
1758      Node* name_index = Int32Add(name_offset, Int32Mul(index, factor));
1759      Node* name = LoadFixedArrayElement(descriptors, name_index);
1760
1761      var_name_index->Bind(name_index);
1762      GotoIf(WordEqual(name, unique_name), if_found_fast);
1763
1764      var_descriptor.Bind(Int32Add(index, Int32Constant(1)));
1765      Goto(&loop);
1766    }
1767  }
1768  Bind(&if_isslowmap);
1769  {
1770    Node* dictionary = LoadProperties(object);
1771    var_meta_storage->Bind(dictionary);
1772
1773    NameDictionaryLookup<NameDictionary>(dictionary, unique_name, if_found_dict,
1774                                         var_name_index, if_not_found);
1775  }
1776  Bind(&if_objectisspecial);
1777  {
1778    // Handle global object here and other special objects in runtime.
1779    GotoUnless(Word32Equal(instance_type, Int32Constant(JS_GLOBAL_OBJECT_TYPE)),
1780               if_bailout);
1781
1782    // Handle interceptors and access checks in runtime.
1783    Node* bit_field = LoadMapBitField(map);
1784    Node* mask = Int32Constant(1 << Map::kHasNamedInterceptor |
1785                               1 << Map::kIsAccessCheckNeeded);
1786    GotoIf(Word32NotEqual(Word32And(bit_field, mask), Int32Constant(0)),
1787           if_bailout);
1788
1789    Node* dictionary = LoadProperties(object);
1790    var_meta_storage->Bind(dictionary);
1791
1792    NameDictionaryLookup<GlobalDictionary>(
1793        dictionary, unique_name, if_found_global, var_name_index, if_not_found);
1794  }
1795}
1796
1797void CodeStubAssembler::TryHasOwnProperty(compiler::Node* object,
1798                                          compiler::Node* map,
1799                                          compiler::Node* instance_type,
1800                                          compiler::Node* unique_name,
1801                                          Label* if_found, Label* if_not_found,
1802                                          Label* if_bailout) {
1803  Comment("TryHasOwnProperty");
1804  Variable var_meta_storage(this, MachineRepresentation::kTagged);
1805  Variable var_name_index(this, MachineRepresentation::kWord32);
1806
1807  Label if_found_global(this);
1808  TryLookupProperty(object, map, instance_type, unique_name, if_found, if_found,
1809                    &if_found_global, &var_meta_storage, &var_name_index,
1810                    if_not_found, if_bailout);
1811  Bind(&if_found_global);
1812  {
1813    Variable var_value(this, MachineRepresentation::kTagged);
1814    Variable var_details(this, MachineRepresentation::kWord32);
1815    // Check if the property cell is not deleted.
1816    LoadPropertyFromGlobalDictionary(var_meta_storage.value(),
1817                                     var_name_index.value(), &var_value,
1818                                     &var_details, if_not_found);
1819    Goto(if_found);
1820  }
1821}
1822
1823void CodeStubAssembler::LoadPropertyFromFastObject(Node* object, Node* map,
1824                                                   Node* descriptors,
1825                                                   Node* name_index,
1826                                                   Variable* var_details,
1827                                                   Variable* var_value) {
1828  DCHECK_EQ(MachineRepresentation::kWord32, var_details->rep());
1829  DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
1830  Comment("[ LoadPropertyFromFastObject");
1831
1832  const int name_to_details_offset =
1833      (DescriptorArray::kDescriptorDetails - DescriptorArray::kDescriptorKey) *
1834      kPointerSize;
1835  const int name_to_value_offset =
1836      (DescriptorArray::kDescriptorValue - DescriptorArray::kDescriptorKey) *
1837      kPointerSize;
1838
1839  Node* details = SmiToWord32(
1840      LoadFixedArrayElement(descriptors, name_index, name_to_details_offset));
1841  var_details->Bind(details);
1842
1843  Node* location = BitFieldDecode<PropertyDetails::LocationField>(details);
1844
1845  Label if_in_field(this), if_in_descriptor(this), done(this);
1846  Branch(Word32Equal(location, Int32Constant(kField)), &if_in_field,
1847         &if_in_descriptor);
1848  Bind(&if_in_field);
1849  {
1850    Node* field_index =
1851        BitFieldDecode<PropertyDetails::FieldIndexField>(details);
1852    Node* representation =
1853        BitFieldDecode<PropertyDetails::RepresentationField>(details);
1854
1855    Node* inobject_properties = LoadMapInobjectProperties(map);
1856
1857    Label if_inobject(this), if_backing_store(this);
1858    Variable var_double_value(this, MachineRepresentation::kFloat64);
1859    Label rebox_double(this, &var_double_value);
1860    BranchIfInt32LessThan(field_index, inobject_properties, &if_inobject,
1861                          &if_backing_store);
1862    Bind(&if_inobject);
1863    {
1864      Comment("if_inobject");
1865      Node* field_offset = ChangeInt32ToIntPtr(
1866          Int32Mul(Int32Sub(LoadMapInstanceSize(map),
1867                            Int32Sub(inobject_properties, field_index)),
1868                   Int32Constant(kPointerSize)));
1869
1870      Label if_double(this), if_tagged(this);
1871      BranchIfWord32NotEqual(representation,
1872                             Int32Constant(Representation::kDouble), &if_tagged,
1873                             &if_double);
1874      Bind(&if_tagged);
1875      {
1876        var_value->Bind(LoadObjectField(object, field_offset));
1877        Goto(&done);
1878      }
1879      Bind(&if_double);
1880      {
1881        if (FLAG_unbox_double_fields) {
1882          var_double_value.Bind(
1883              LoadObjectField(object, field_offset, MachineType::Float64()));
1884        } else {
1885          Node* mutable_heap_number = LoadObjectField(object, field_offset);
1886          var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
1887        }
1888        Goto(&rebox_double);
1889      }
1890    }
1891    Bind(&if_backing_store);
1892    {
1893      Comment("if_backing_store");
1894      Node* properties = LoadProperties(object);
1895      field_index = Int32Sub(field_index, inobject_properties);
1896      Node* value = LoadFixedArrayElement(properties, field_index);
1897
1898      Label if_double(this), if_tagged(this);
1899      BranchIfWord32NotEqual(representation,
1900                             Int32Constant(Representation::kDouble), &if_tagged,
1901                             &if_double);
1902      Bind(&if_tagged);
1903      {
1904        var_value->Bind(value);
1905        Goto(&done);
1906      }
1907      Bind(&if_double);
1908      {
1909        var_double_value.Bind(LoadHeapNumberValue(value));
1910        Goto(&rebox_double);
1911      }
1912    }
1913    Bind(&rebox_double);
1914    {
1915      Comment("rebox_double");
1916      Node* heap_number = AllocateHeapNumber();
1917      StoreHeapNumberValue(heap_number, var_double_value.value());
1918      var_value->Bind(heap_number);
1919      Goto(&done);
1920    }
1921  }
1922  Bind(&if_in_descriptor);
1923  {
1924    Node* value =
1925        LoadFixedArrayElement(descriptors, name_index, name_to_value_offset);
1926    var_value->Bind(value);
1927    Goto(&done);
1928  }
1929  Bind(&done);
1930
1931  Comment("] LoadPropertyFromFastObject");
1932}
1933
1934void CodeStubAssembler::LoadPropertyFromNameDictionary(Node* dictionary,
1935                                                       Node* name_index,
1936                                                       Variable* var_details,
1937                                                       Variable* var_value) {
1938  Comment("LoadPropertyFromNameDictionary");
1939
1940  const int name_to_details_offset =
1941      (NameDictionary::kEntryDetailsIndex - NameDictionary::kEntryKeyIndex) *
1942      kPointerSize;
1943  const int name_to_value_offset =
1944      (NameDictionary::kEntryValueIndex - NameDictionary::kEntryKeyIndex) *
1945      kPointerSize;
1946
1947  Node* details = SmiToWord32(
1948      LoadFixedArrayElement(dictionary, name_index, name_to_details_offset));
1949
1950  var_details->Bind(details);
1951  var_value->Bind(
1952      LoadFixedArrayElement(dictionary, name_index, name_to_value_offset));
1953
1954  Comment("] LoadPropertyFromNameDictionary");
1955}
1956
1957void CodeStubAssembler::LoadPropertyFromGlobalDictionary(Node* dictionary,
1958                                                         Node* name_index,
1959                                                         Variable* var_details,
1960                                                         Variable* var_value,
1961                                                         Label* if_deleted) {
1962  Comment("[ LoadPropertyFromGlobalDictionary");
1963
1964  const int name_to_value_offset =
1965      (GlobalDictionary::kEntryValueIndex - GlobalDictionary::kEntryKeyIndex) *
1966      kPointerSize;
1967
1968  Node* property_cell =
1969      LoadFixedArrayElement(dictionary, name_index, name_to_value_offset);
1970
1971  Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
1972  GotoIf(WordEqual(value, TheHoleConstant()), if_deleted);
1973
1974  var_value->Bind(value);
1975
1976  Node* details =
1977      SmiToWord32(LoadObjectField(property_cell, PropertyCell::kDetailsOffset));
1978  var_details->Bind(details);
1979
1980  Comment("] LoadPropertyFromGlobalDictionary");
1981}
1982
1983void CodeStubAssembler::TryGetOwnProperty(
1984    Node* context, Node* receiver, Node* object, Node* map, Node* instance_type,
1985    Node* unique_name, Label* if_found_value, Variable* var_value,
1986    Label* if_not_found, Label* if_bailout) {
1987  DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
1988  Comment("TryGetOwnProperty");
1989
1990  Variable var_meta_storage(this, MachineRepresentation::kTagged);
1991  Variable var_entry(this, MachineRepresentation::kWord32);
1992
1993  Label if_found_fast(this), if_found_dict(this), if_found_global(this);
1994
1995  Variable var_details(this, MachineRepresentation::kWord32);
1996  Variable* vars[] = {var_value, &var_details};
1997  Label if_found(this, 2, vars);
1998
1999  TryLookupProperty(object, map, instance_type, unique_name, &if_found_fast,
2000                    &if_found_dict, &if_found_global, &var_meta_storage,
2001                    &var_entry, if_not_found, if_bailout);
2002  Bind(&if_found_fast);
2003  {
2004    Node* descriptors = var_meta_storage.value();
2005    Node* name_index = var_entry.value();
2006
2007    LoadPropertyFromFastObject(object, map, descriptors, name_index,
2008                               &var_details, var_value);
2009    Goto(&if_found);
2010  }
2011  Bind(&if_found_dict);
2012  {
2013    Node* dictionary = var_meta_storage.value();
2014    Node* entry = var_entry.value();
2015    LoadPropertyFromNameDictionary(dictionary, entry, &var_details, var_value);
2016    Goto(&if_found);
2017  }
2018  Bind(&if_found_global);
2019  {
2020    Node* dictionary = var_meta_storage.value();
2021    Node* entry = var_entry.value();
2022
2023    LoadPropertyFromGlobalDictionary(dictionary, entry, &var_details, var_value,
2024                                     if_not_found);
2025    Goto(&if_found);
2026  }
2027  // Here we have details and value which could be an accessor.
2028  Bind(&if_found);
2029  {
2030    Node* details = var_details.value();
2031    Node* kind = BitFieldDecode<PropertyDetails::KindField>(details);
2032
2033    Label if_accessor(this);
2034    Branch(Word32Equal(kind, Int32Constant(kData)), if_found_value,
2035           &if_accessor);
2036    Bind(&if_accessor);
2037    {
2038      Node* accessor_pair = var_value->value();
2039      GotoIf(Word32Equal(LoadInstanceType(accessor_pair),
2040                         Int32Constant(ACCESSOR_INFO_TYPE)),
2041             if_bailout);
2042      AssertInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE);
2043      Node* getter =
2044          LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
2045      Node* getter_map = LoadMap(getter);
2046      Node* instance_type = LoadMapInstanceType(getter_map);
2047      // FunctionTemplateInfo getters are not supported yet.
2048      GotoIf(Word32Equal(instance_type,
2049                         Int32Constant(FUNCTION_TEMPLATE_INFO_TYPE)),
2050             if_bailout);
2051
2052      // Return undefined if the {getter} is not callable.
2053      var_value->Bind(UndefinedConstant());
2054      GotoIf(Word32Equal(Word32And(LoadMapBitField(getter_map),
2055                                   Int32Constant(1 << Map::kIsCallable)),
2056                         Int32Constant(0)),
2057             if_found_value);
2058
2059      // Call the accessor.
2060      Callable callable = CodeFactory::Call(isolate());
2061      Node* result = CallJS(callable, context, getter, receiver);
2062      var_value->Bind(result);
2063      Goto(if_found_value);
2064    }
2065  }
2066}
2067
2068void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
2069                                         Node* instance_type, Node* index,
2070                                         Label* if_found, Label* if_not_found,
2071                                         Label* if_bailout) {
2072  // Handle special objects in runtime.
2073  GotoIf(Int32LessThanOrEqual(instance_type,
2074                              Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
2075         if_bailout);
2076
2077  Node* bit_field2 = LoadMapBitField2(map);
2078  Node* elements_kind = BitFieldDecode<Map::ElementsKindBits>(bit_field2);
2079
2080  // TODO(verwaest): Support other elements kinds as well.
2081  Label if_isobjectorsmi(this), if_isdouble(this), if_isdictionary(this),
2082      if_isfaststringwrapper(this), if_isslowstringwrapper(this);
2083  // clang-format off
2084  int32_t values[] = {
2085      // Handled by {if_isobjectorsmi}.
2086      FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS,
2087          FAST_HOLEY_ELEMENTS,
2088      // Handled by {if_isdouble}.
2089      FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS,
2090      // Handled by {if_isdictionary}.
2091      DICTIONARY_ELEMENTS,
2092      // Handled by {if_isfaststringwrapper}.
2093      FAST_STRING_WRAPPER_ELEMENTS,
2094      // Handled by {if_isslowstringwrapper}.
2095      SLOW_STRING_WRAPPER_ELEMENTS,
2096      // Handled by {if_not_found}.
2097      NO_ELEMENTS,
2098  };
2099  Label* labels[] = {
2100      &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi,
2101          &if_isobjectorsmi,
2102      &if_isdouble, &if_isdouble,
2103      &if_isdictionary,
2104      &if_isfaststringwrapper,
2105      &if_isslowstringwrapper,
2106      if_not_found,
2107  };
2108  // clang-format on
2109  STATIC_ASSERT(arraysize(values) == arraysize(labels));
2110  Switch(elements_kind, if_bailout, values, labels, arraysize(values));
2111
2112  Bind(&if_isobjectorsmi);
2113  {
2114    Node* elements = LoadElements(object);
2115    Node* length = LoadFixedArrayBaseLength(elements);
2116
2117    GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found);
2118
2119    Node* element = LoadFixedArrayElement(elements, index);
2120    Node* the_hole = TheHoleConstant();
2121    Branch(WordEqual(element, the_hole), if_not_found, if_found);
2122  }
2123  Bind(&if_isdouble);
2124  {
2125    Node* elements = LoadElements(object);
2126    Node* length = LoadFixedArrayBaseLength(elements);
2127
2128    GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found);
2129
2130    if (kPointerSize == kDoubleSize) {
2131      Node* element =
2132          LoadFixedDoubleArrayElement(elements, index, MachineType::Uint64());
2133      Node* the_hole = Int64Constant(kHoleNanInt64);
2134      Branch(Word64Equal(element, the_hole), if_not_found, if_found);
2135    } else {
2136      Node* element_upper =
2137          LoadFixedDoubleArrayElement(elements, index, MachineType::Uint32(),
2138                                      kIeeeDoubleExponentWordOffset);
2139      Branch(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)),
2140             if_not_found, if_found);
2141    }
2142  }
2143  Bind(&if_isdictionary);
2144  {
2145    Variable var_entry(this, MachineRepresentation::kWord32);
2146    Node* elements = LoadElements(object);
2147    NumberDictionaryLookup<SeededNumberDictionary>(elements, index, if_found,
2148                                                   &var_entry, if_not_found);
2149  }
2150  Bind(&if_isfaststringwrapper);
2151  {
2152    AssertInstanceType(object, JS_VALUE_TYPE);
2153    Node* string = LoadJSValueValue(object);
2154    Assert(Int32LessThan(LoadInstanceType(string),
2155                         Int32Constant(FIRST_NONSTRING_TYPE)));
2156    Node* length = LoadStringLength(string);
2157    GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found);
2158    Goto(&if_isobjectorsmi);
2159  }
2160  Bind(&if_isslowstringwrapper);
2161  {
2162    AssertInstanceType(object, JS_VALUE_TYPE);
2163    Node* string = LoadJSValueValue(object);
2164    Assert(Int32LessThan(LoadInstanceType(string),
2165                         Int32Constant(FIRST_NONSTRING_TYPE)));
2166    Node* length = LoadStringLength(string);
2167    GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found);
2168    Goto(&if_isdictionary);
2169  }
2170}
2171
2172// Instantiate template methods to workaround GCC compilation issue.
2173template void CodeStubAssembler::NumberDictionaryLookup<SeededNumberDictionary>(
2174    Node*, Node*, Label*, Variable*, Label*);
2175template void CodeStubAssembler::NumberDictionaryLookup<
2176    UnseededNumberDictionary>(Node*, Node*, Label*, Variable*, Label*);
2177
2178Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
2179                                             Node* object) {
2180  Variable var_result(this, MachineRepresentation::kTagged);
2181  Label return_false(this), return_true(this),
2182      return_runtime(this, Label::kDeferred), return_result(this);
2183
2184  // Goto runtime if {object} is a Smi.
2185  GotoIf(WordIsSmi(object), &return_runtime);
2186
2187  // Load map of {object}.
2188  Node* object_map = LoadMap(object);
2189
2190  // Lookup the {callable} and {object} map in the global instanceof cache.
2191  // Note: This is safe because we clear the global instanceof cache whenever
2192  // we change the prototype of any object.
2193  Node* instanceof_cache_function =
2194      LoadRoot(Heap::kInstanceofCacheFunctionRootIndex);
2195  Node* instanceof_cache_map = LoadRoot(Heap::kInstanceofCacheMapRootIndex);
2196  {
2197    Label instanceof_cache_miss(this);
2198    GotoUnless(WordEqual(instanceof_cache_function, callable),
2199               &instanceof_cache_miss);
2200    GotoUnless(WordEqual(instanceof_cache_map, object_map),
2201               &instanceof_cache_miss);
2202    var_result.Bind(LoadRoot(Heap::kInstanceofCacheAnswerRootIndex));
2203    Goto(&return_result);
2204    Bind(&instanceof_cache_miss);
2205  }
2206
2207  // Goto runtime if {callable} is a Smi.
2208  GotoIf(WordIsSmi(callable), &return_runtime);
2209
2210  // Load map of {callable}.
2211  Node* callable_map = LoadMap(callable);
2212
2213  // Goto runtime if {callable} is not a JSFunction.
2214  Node* callable_instance_type = LoadMapInstanceType(callable_map);
2215  GotoUnless(
2216      Word32Equal(callable_instance_type, Int32Constant(JS_FUNCTION_TYPE)),
2217      &return_runtime);
2218
2219  // Goto runtime if {callable} is not a constructor or has
2220  // a non-instance "prototype".
2221  Node* callable_bitfield = LoadMapBitField(callable_map);
2222  GotoUnless(
2223      Word32Equal(Word32And(callable_bitfield,
2224                            Int32Constant((1 << Map::kHasNonInstancePrototype) |
2225                                          (1 << Map::kIsConstructor))),
2226                  Int32Constant(1 << Map::kIsConstructor)),
2227      &return_runtime);
2228
2229  // Get the "prototype" (or initial map) of the {callable}.
2230  Node* callable_prototype =
2231      LoadObjectField(callable, JSFunction::kPrototypeOrInitialMapOffset);
2232  {
2233    Variable var_callable_prototype(this, MachineRepresentation::kTagged);
2234    Label callable_prototype_valid(this);
2235    var_callable_prototype.Bind(callable_prototype);
2236
2237    // Resolve the "prototype" if the {callable} has an initial map.  Afterwards
2238    // the {callable_prototype} will be either the JSReceiver prototype object
2239    // or the hole value, which means that no instances of the {callable} were
2240    // created so far and hence we should return false.
2241    Node* callable_prototype_instance_type =
2242        LoadInstanceType(callable_prototype);
2243    GotoUnless(
2244        Word32Equal(callable_prototype_instance_type, Int32Constant(MAP_TYPE)),
2245        &callable_prototype_valid);
2246    var_callable_prototype.Bind(
2247        LoadObjectField(callable_prototype, Map::kPrototypeOffset));
2248    Goto(&callable_prototype_valid);
2249    Bind(&callable_prototype_valid);
2250    callable_prototype = var_callable_prototype.value();
2251  }
2252
2253  // Update the global instanceof cache with the current {object} map and
2254  // {callable}.  The cached answer will be set when it is known below.
2255  StoreRoot(Heap::kInstanceofCacheFunctionRootIndex, callable);
2256  StoreRoot(Heap::kInstanceofCacheMapRootIndex, object_map);
2257
2258  // Loop through the prototype chain looking for the {callable} prototype.
2259  Variable var_object_map(this, MachineRepresentation::kTagged);
2260  var_object_map.Bind(object_map);
2261  Label loop(this, &var_object_map);
2262  Goto(&loop);
2263  Bind(&loop);
2264  {
2265    Node* object_map = var_object_map.value();
2266
2267    // Check if the current {object} needs to be access checked.
2268    Node* object_bitfield = LoadMapBitField(object_map);
2269    GotoUnless(
2270        Word32Equal(Word32And(object_bitfield,
2271                              Int32Constant(1 << Map::kIsAccessCheckNeeded)),
2272                    Int32Constant(0)),
2273        &return_runtime);
2274
2275    // Check if the current {object} is a proxy.
2276    Node* object_instance_type = LoadMapInstanceType(object_map);
2277    GotoIf(Word32Equal(object_instance_type, Int32Constant(JS_PROXY_TYPE)),
2278           &return_runtime);
2279
2280    // Check the current {object} prototype.
2281    Node* object_prototype = LoadMapPrototype(object_map);
2282    GotoIf(WordEqual(object_prototype, NullConstant()), &return_false);
2283    GotoIf(WordEqual(object_prototype, callable_prototype), &return_true);
2284
2285    // Continue with the prototype.
2286    var_object_map.Bind(LoadMap(object_prototype));
2287    Goto(&loop);
2288  }
2289
2290  Bind(&return_true);
2291  StoreRoot(Heap::kInstanceofCacheAnswerRootIndex, BooleanConstant(true));
2292  var_result.Bind(BooleanConstant(true));
2293  Goto(&return_result);
2294
2295  Bind(&return_false);
2296  StoreRoot(Heap::kInstanceofCacheAnswerRootIndex, BooleanConstant(false));
2297  var_result.Bind(BooleanConstant(false));
2298  Goto(&return_result);
2299
2300  Bind(&return_runtime);
2301  {
2302    // Invalidate the global instanceof cache.
2303    StoreRoot(Heap::kInstanceofCacheFunctionRootIndex, SmiConstant(0));
2304    // Fallback to the runtime implementation.
2305    var_result.Bind(
2306        CallRuntime(Runtime::kOrdinaryHasInstance, context, callable, object));
2307  }
2308  Goto(&return_result);
2309
2310  Bind(&return_result);
2311  return var_result.value();
2312}
2313
2314compiler::Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node,
2315                                                          ElementsKind kind,
2316                                                          ParameterMode mode,
2317                                                          int base_size) {
2318  bool is_double = IsFastDoubleElementsKind(kind);
2319  int element_size_shift = is_double ? kDoubleSizeLog2 : kPointerSizeLog2;
2320  int element_size = 1 << element_size_shift;
2321  int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize;
2322  int32_t index = 0;
2323  bool constant_index = false;
2324  if (mode == SMI_PARAMETERS) {
2325    element_size_shift -= kSmiShiftBits;
2326    intptr_t temp = 0;
2327    constant_index = ToIntPtrConstant(index_node, temp);
2328    index = temp >> kSmiShiftBits;
2329  } else {
2330    constant_index = ToInt32Constant(index_node, index);
2331  }
2332  if (constant_index) {
2333    return IntPtrConstant(base_size + element_size * index);
2334  }
2335  if (Is64() && mode == INTEGER_PARAMETERS) {
2336    index_node = ChangeInt32ToInt64(index_node);
2337  }
2338  if (base_size == 0) {
2339    return (element_size_shift >= 0)
2340               ? WordShl(index_node, IntPtrConstant(element_size_shift))
2341               : WordShr(index_node, IntPtrConstant(-element_size_shift));
2342  }
2343  return IntPtrAdd(
2344      IntPtrConstant(base_size),
2345      (element_size_shift >= 0)
2346          ? WordShl(index_node, IntPtrConstant(element_size_shift))
2347          : WordShr(index_node, IntPtrConstant(-element_size_shift)));
2348}
2349
2350compiler::Node* CodeStubAssembler::LoadTypeFeedbackVectorForStub() {
2351  Node* function =
2352      LoadFromParentFrame(JavaScriptFrameConstants::kFunctionOffset);
2353  Node* literals = LoadObjectField(function, JSFunction::kLiteralsOffset);
2354  return LoadObjectField(literals, LiteralsArray::kFeedbackVectorOffset);
2355}
2356
2357compiler::Node* CodeStubAssembler::LoadReceiverMap(compiler::Node* receiver) {
2358  Variable var_receiver_map(this, MachineRepresentation::kTagged);
2359  // TODO(ishell): defer blocks when it works.
2360  Label load_smi_map(this /*, Label::kDeferred*/), load_receiver_map(this),
2361      if_result(this);
2362
2363  Branch(WordIsSmi(receiver), &load_smi_map, &load_receiver_map);
2364  Bind(&load_smi_map);
2365  {
2366    var_receiver_map.Bind(LoadRoot(Heap::kHeapNumberMapRootIndex));
2367    Goto(&if_result);
2368  }
2369  Bind(&load_receiver_map);
2370  {
2371    var_receiver_map.Bind(LoadMap(receiver));
2372    Goto(&if_result);
2373  }
2374  Bind(&if_result);
2375  return var_receiver_map.value();
2376}
2377
2378compiler::Node* CodeStubAssembler::TryMonomorphicCase(
2379    const LoadICParameters* p, compiler::Node* receiver_map, Label* if_handler,
2380    Variable* var_handler, Label* if_miss) {
2381  DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
2382
2383  // TODO(ishell): add helper class that hides offset computations for a series
2384  // of loads.
2385  int32_t header_size = FixedArray::kHeaderSize - kHeapObjectTag;
2386  Node* offset = ElementOffsetFromIndex(p->slot, FAST_HOLEY_ELEMENTS,
2387                                        SMI_PARAMETERS, header_size);
2388  Node* feedback = Load(MachineType::AnyTagged(), p->vector, offset);
2389
2390  // Try to quickly handle the monomorphic case without knowing for sure
2391  // if we have a weak cell in feedback. We do know it's safe to look
2392  // at WeakCell::kValueOffset.
2393  GotoUnless(WordEqual(receiver_map, LoadWeakCellValue(feedback)), if_miss);
2394
2395  Node* handler = Load(MachineType::AnyTagged(), p->vector,
2396                       IntPtrAdd(offset, IntPtrConstant(kPointerSize)));
2397
2398  var_handler->Bind(handler);
2399  Goto(if_handler);
2400  return feedback;
2401}
2402
2403void CodeStubAssembler::HandlePolymorphicCase(
2404    const LoadICParameters* p, compiler::Node* receiver_map,
2405    compiler::Node* feedback, Label* if_handler, Variable* var_handler,
2406    Label* if_miss, int unroll_count) {
2407  DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
2408
2409  // Iterate {feedback} array.
2410  const int kEntrySize = 2;
2411
2412  for (int i = 0; i < unroll_count; i++) {
2413    Label next_entry(this);
2414    Node* cached_map = LoadWeakCellValue(
2415        LoadFixedArrayElement(feedback, Int32Constant(i * kEntrySize)));
2416    GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
2417
2418    // Found, now call handler.
2419    Node* handler =
2420        LoadFixedArrayElement(feedback, Int32Constant(i * kEntrySize + 1));
2421    var_handler->Bind(handler);
2422    Goto(if_handler);
2423
2424    Bind(&next_entry);
2425  }
2426  Node* length = SmiToWord32(LoadFixedArrayBaseLength(feedback));
2427
2428  // Loop from {unroll_count}*kEntrySize to {length}.
2429  Variable var_index(this, MachineRepresentation::kWord32);
2430  Label loop(this, &var_index);
2431  var_index.Bind(Int32Constant(unroll_count * kEntrySize));
2432  Goto(&loop);
2433  Bind(&loop);
2434  {
2435    Node* index = var_index.value();
2436    GotoIf(Int32GreaterThanOrEqual(index, length), if_miss);
2437
2438    Node* cached_map =
2439        LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
2440
2441    Label next_entry(this);
2442    GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
2443
2444    // Found, now call handler.
2445    Node* handler = LoadFixedArrayElement(feedback, index, kPointerSize);
2446    var_handler->Bind(handler);
2447    Goto(if_handler);
2448
2449    Bind(&next_entry);
2450    var_index.Bind(Int32Add(index, Int32Constant(kEntrySize)));
2451    Goto(&loop);
2452  }
2453}
2454
2455compiler::Node* CodeStubAssembler::StubCachePrimaryOffset(compiler::Node* name,
2456                                                          Code::Flags flags,
2457                                                          compiler::Node* map) {
2458  // See v8::internal::StubCache::PrimaryOffset().
2459  STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift);
2460  // Compute the hash of the name (use entire hash field).
2461  Node* hash_field = LoadNameHashField(name);
2462  Assert(WordEqual(
2463      Word32And(hash_field, Int32Constant(Name::kHashNotComputedMask)),
2464      Int32Constant(0)));
2465
2466  // Using only the low bits in 64-bit mode is unlikely to increase the
2467  // risk of collision even if the heap is spread over an area larger than
2468  // 4Gb (and not at all if it isn't).
2469  Node* hash = Int32Add(hash_field, map);
2470  // We always set the in_loop bit to zero when generating the lookup code
2471  // so do it here too so the hash codes match.
2472  uint32_t iflags =
2473      (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
2474  // Base the offset on a simple combination of name, flags, and map.
2475  hash = Word32Xor(hash, Int32Constant(iflags));
2476  uint32_t mask = (StubCache::kPrimaryTableSize - 1)
2477                  << StubCache::kCacheIndexShift;
2478  return Word32And(hash, Int32Constant(mask));
2479}
2480
2481compiler::Node* CodeStubAssembler::StubCacheSecondaryOffset(
2482    compiler::Node* name, Code::Flags flags, compiler::Node* seed) {
2483  // See v8::internal::StubCache::SecondaryOffset().
2484
2485  // Use the seed from the primary cache in the secondary cache.
2486  Node* hash = Int32Sub(seed, name);
2487  // We always set the in_loop bit to zero when generating the lookup code
2488  // so do it here too so the hash codes match.
2489  uint32_t iflags =
2490      (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
2491  hash = Int32Add(hash, Int32Constant(iflags));
2492  int32_t mask = (StubCache::kSecondaryTableSize - 1)
2493                 << StubCache::kCacheIndexShift;
2494  return Word32And(hash, Int32Constant(mask));
2495}
2496
2497enum CodeStubAssembler::StubCacheTable : int {
2498  kPrimary = static_cast<int>(StubCache::kPrimary),
2499  kSecondary = static_cast<int>(StubCache::kSecondary)
2500};
2501
2502void CodeStubAssembler::TryProbeStubCacheTable(
2503    StubCache* stub_cache, StubCacheTable table_id,
2504    compiler::Node* entry_offset, compiler::Node* name, Code::Flags flags,
2505    compiler::Node* map, Label* if_handler, Variable* var_handler,
2506    Label* if_miss) {
2507  StubCache::Table table = static_cast<StubCache::Table>(table_id);
2508#ifdef DEBUG
2509  if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
2510    Goto(if_miss);
2511    return;
2512  } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
2513    Goto(if_miss);
2514    return;
2515  }
2516#endif
2517  // The {table_offset} holds the entry offset times four (due to masking
2518  // and shifting optimizations).
2519  const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift;
2520  entry_offset = Int32Mul(entry_offset, Int32Constant(kMultiplier));
2521
2522  // Check that the key in the entry matches the name.
2523  Node* key_base =
2524      ExternalConstant(ExternalReference(stub_cache->key_reference(table)));
2525  Node* entry_key = Load(MachineType::Pointer(), key_base, entry_offset);
2526  GotoIf(WordNotEqual(name, entry_key), if_miss);
2527
2528  // Get the map entry from the cache.
2529  DCHECK_EQ(kPointerSize * 2, stub_cache->map_reference(table).address() -
2530                                  stub_cache->key_reference(table).address());
2531  Node* entry_map =
2532      Load(MachineType::Pointer(), key_base,
2533           Int32Add(entry_offset, Int32Constant(kPointerSize * 2)));
2534  GotoIf(WordNotEqual(map, entry_map), if_miss);
2535
2536  // Check that the flags match what we're looking for.
2537  DCHECK_EQ(kPointerSize, stub_cache->value_reference(table).address() -
2538                              stub_cache->key_reference(table).address());
2539  Node* code = Load(MachineType::Pointer(), key_base,
2540                    Int32Add(entry_offset, Int32Constant(kPointerSize)));
2541
2542  Node* code_flags =
2543      LoadObjectField(code, Code::kFlagsOffset, MachineType::Uint32());
2544  GotoIf(Word32NotEqual(Int32Constant(flags),
2545                        Word32And(code_flags,
2546                                  Int32Constant(~Code::kFlagsNotUsedInLookup))),
2547         if_miss);
2548
2549  // We found the handler.
2550  var_handler->Bind(code);
2551  Goto(if_handler);
2552}
2553
2554void CodeStubAssembler::TryProbeStubCache(
2555    StubCache* stub_cache, Code::Flags flags, compiler::Node* receiver,
2556    compiler::Node* name, Label* if_handler, Variable* var_handler,
2557    Label* if_miss) {
2558  Label try_secondary(this), miss(this);
2559
2560  Counters* counters = isolate()->counters();
2561  IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
2562
2563  // Check that the {receiver} isn't a smi.
2564  GotoIf(WordIsSmi(receiver), &miss);
2565
2566  Node* receiver_map = LoadMap(receiver);
2567
2568  // Probe the primary table.
2569  Node* primary_offset = StubCachePrimaryOffset(name, flags, receiver_map);
2570  TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name, flags,
2571                         receiver_map, if_handler, var_handler, &try_secondary);
2572
2573  Bind(&try_secondary);
2574  {
2575    // Probe the secondary table.
2576    Node* secondary_offset =
2577        StubCacheSecondaryOffset(name, flags, primary_offset);
2578    TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name,
2579                           flags, receiver_map, if_handler, var_handler, &miss);
2580  }
2581
2582  Bind(&miss);
2583  {
2584    IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
2585    Goto(if_miss);
2586  }
2587}
2588
2589void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
2590  Variable var_handler(this, MachineRepresentation::kTagged);
2591  // TODO(ishell): defer blocks when it works.
2592  Label if_handler(this, &var_handler), try_polymorphic(this),
2593      try_megamorphic(this /*, Label::kDeferred*/),
2594      miss(this /*, Label::kDeferred*/);
2595
2596  Node* receiver_map = LoadReceiverMap(p->receiver);
2597
2598  // Check monomorphic case.
2599  Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler,
2600                                      &var_handler, &try_polymorphic);
2601  Bind(&if_handler);
2602  {
2603    LoadWithVectorDescriptor descriptor(isolate());
2604    TailCallStub(descriptor, var_handler.value(), p->context, p->receiver,
2605                 p->name, p->slot, p->vector);
2606  }
2607
2608  Bind(&try_polymorphic);
2609  {
2610    // Check polymorphic case.
2611    GotoUnless(
2612        WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
2613        &try_megamorphic);
2614    HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler,
2615                          &miss, 2);
2616  }
2617
2618  Bind(&try_megamorphic);
2619  {
2620    // Check megamorphic case.
2621    GotoUnless(
2622        WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
2623        &miss);
2624
2625    Code::Flags code_flags =
2626        Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(Code::LOAD_IC));
2627
2628    TryProbeStubCache(isolate()->stub_cache(), code_flags, p->receiver, p->name,
2629                      &if_handler, &var_handler, &miss);
2630  }
2631  Bind(&miss);
2632  {
2633    TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
2634                    p->slot, p->vector);
2635  }
2636}
2637
2638void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) {
2639  Label try_handler(this), miss(this);
2640  Node* weak_cell =
2641      LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS);
2642  AssertInstanceType(weak_cell, WEAK_CELL_TYPE);
2643
2644  // Load value or try handler case if the {weak_cell} is cleared.
2645  Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler);
2646  AssertInstanceType(property_cell, PROPERTY_CELL_TYPE);
2647
2648  Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
2649  GotoIf(WordEqual(value, TheHoleConstant()), &miss);
2650  Return(value);
2651
2652  Bind(&try_handler);
2653  {
2654    Node* handler =
2655        LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
2656    GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
2657           &miss);
2658
2659    // In this case {handler} must be a Code object.
2660    AssertInstanceType(handler, CODE_TYPE);
2661    LoadWithVectorDescriptor descriptor(isolate());
2662    Node* native_context = LoadNativeContext(p->context);
2663    Node* receiver = LoadFixedArrayElement(
2664        native_context, Int32Constant(Context::EXTENSION_INDEX));
2665    Node* fake_name = IntPtrConstant(0);
2666    TailCallStub(descriptor, handler, p->context, receiver, fake_name, p->slot,
2667                 p->vector);
2668  }
2669  Bind(&miss);
2670  {
2671    TailCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context, p->slot,
2672                    p->vector);
2673  }
2674}
2675
2676}  // namespace internal
2677}  // namespace v8
2678