• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
11 namespace v8 {
12 namespace internal {
13 
14 using compiler::Node;
15 
CodeStubAssembler(Isolate * isolate,Zone * zone,const CallInterfaceDescriptor & descriptor,Code::Flags flags,const char * name,size_t result_size)16 CodeStubAssembler::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 
CodeStubAssembler(Isolate * isolate,Zone * zone,int parameter_count,Code::Flags flags,const char * name)23 CodeStubAssembler::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 
Assert(Node * condition)28 void 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 
BooleanMapConstant()40 Node* CodeStubAssembler::BooleanMapConstant() {
41   return HeapConstant(isolate()->factory()->boolean_map());
42 }
43 
EmptyStringConstant()44 Node* CodeStubAssembler::EmptyStringConstant() {
45   return LoadRoot(Heap::kempty_stringRootIndex);
46 }
47 
HeapNumberMapConstant()48 Node* CodeStubAssembler::HeapNumberMapConstant() {
49   return HeapConstant(isolate()->factory()->heap_number_map());
50 }
51 
NoContextConstant()52 Node* CodeStubAssembler::NoContextConstant() {
53   return SmiConstant(Smi::FromInt(0));
54 }
55 
NullConstant()56 Node* CodeStubAssembler::NullConstant() {
57   return LoadRoot(Heap::kNullValueRootIndex);
58 }
59 
UndefinedConstant()60 Node* CodeStubAssembler::UndefinedConstant() {
61   return LoadRoot(Heap::kUndefinedValueRootIndex);
62 }
63 
TheHoleConstant()64 Node* CodeStubAssembler::TheHoleConstant() {
65   return LoadRoot(Heap::kTheHoleValueRootIndex);
66 }
67 
HashSeed()68 Node* CodeStubAssembler::HashSeed() {
69   return SmiToWord32(LoadRoot(Heap::kHashSeedRootIndex));
70 }
71 
StaleRegisterConstant()72 Node* CodeStubAssembler::StaleRegisterConstant() {
73   return LoadRoot(Heap::kStaleRegisterRootIndex);
74 }
75 
Float64Round(Node * x)76 Node* 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 
Float64Ceil(Node * x)95 Node* 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 
Float64Floor(Node * x)148 Node* 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 
Float64Trunc(Node * x)201 Node* 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 
SmiFromWord32(Node * value)263 Node* CodeStubAssembler::SmiFromWord32(Node* value) {
264   value = ChangeInt32ToIntPtr(value);
265   return WordShl(value, SmiShiftBitsConstant());
266 }
267 
SmiTag(Node * value)268 Node* 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 
SmiUntag(Node * value)276 Node* CodeStubAssembler::SmiUntag(Node* value) {
277   return WordSar(value, SmiShiftBitsConstant());
278 }
279 
SmiToWord32(Node * value)280 Node* CodeStubAssembler::SmiToWord32(Node* value) {
281   Node* result = WordSar(value, SmiShiftBitsConstant());
282   if (Is64()) {
283     result = TruncateInt64ToInt32(result);
284   }
285   return result;
286 }
287 
SmiToFloat64(Node * value)288 Node* CodeStubAssembler::SmiToFloat64(Node* value) {
289   return ChangeInt32ToFloat64(SmiToWord32(value));
290 }
291 
SmiAdd(Node * a,Node * b)292 Node* CodeStubAssembler::SmiAdd(Node* a, Node* b) { return IntPtrAdd(a, b); }
293 
SmiAddWithOverflow(Node * a,Node * b)294 Node* CodeStubAssembler::SmiAddWithOverflow(Node* a, Node* b) {
295   return IntPtrAddWithOverflow(a, b);
296 }
297 
SmiSub(Node * a,Node * b)298 Node* CodeStubAssembler::SmiSub(Node* a, Node* b) { return IntPtrSub(a, b); }
299 
SmiSubWithOverflow(Node * a,Node * b)300 Node* CodeStubAssembler::SmiSubWithOverflow(Node* a, Node* b) {
301   return IntPtrSubWithOverflow(a, b);
302 }
303 
SmiEqual(Node * a,Node * b)304 Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); }
305 
SmiAboveOrEqual(Node * a,Node * b)306 Node* CodeStubAssembler::SmiAboveOrEqual(Node* a, Node* b) {
307   return UintPtrGreaterThanOrEqual(a, b);
308 }
309 
SmiLessThan(Node * a,Node * b)310 Node* CodeStubAssembler::SmiLessThan(Node* a, Node* b) {
311   return IntPtrLessThan(a, b);
312 }
313 
SmiLessThanOrEqual(Node * a,Node * b)314 Node* CodeStubAssembler::SmiLessThanOrEqual(Node* a, Node* b) {
315   return IntPtrLessThanOrEqual(a, b);
316 }
317 
SmiMin(Node * a,Node * b)318 Node* 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 
WordIsSmi(Node * a)333 Node* CodeStubAssembler::WordIsSmi(Node* a) {
334   return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask)), IntPtrConstant(0));
335 }
336 
WordIsPositiveSmi(Node * a)337 Node* CodeStubAssembler::WordIsPositiveSmi(Node* a) {
338   return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask | kSmiSignMask)),
339                    IntPtrConstant(0));
340 }
341 
AllocateRawUnaligned(Node * size_in_bytes,AllocationFlags flags,Node * top_address,Node * limit_address)342 Node* 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 
AllocateRawAligned(Node * size_in_bytes,AllocationFlags flags,Node * top_address,Node * limit_address)390 Node* 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 
Allocate(Node * size_in_bytes,AllocationFlags flags)444 Node* 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 
Allocate(int size_in_bytes,AllocationFlags flags)464 Node* CodeStubAssembler::Allocate(int size_in_bytes, AllocationFlags flags) {
465   return CodeStubAssembler::Allocate(IntPtrConstant(size_in_bytes), flags);
466 }
467 
InnerAllocate(Node * previous,Node * offset)468 Node* CodeStubAssembler::InnerAllocate(Node* previous, Node* offset) {
469   return BitcastWordToTagged(IntPtrAdd(previous, offset));
470 }
471 
InnerAllocate(Node * previous,int offset)472 Node* CodeStubAssembler::InnerAllocate(Node* previous, int offset) {
473   return InnerAllocate(previous, IntPtrConstant(offset));
474 }
475 
LoadFromFrame(int offset,MachineType rep)476 compiler::Node* CodeStubAssembler::LoadFromFrame(int offset, MachineType rep) {
477   Node* frame_pointer = LoadFramePointer();
478   return Load(rep, frame_pointer, IntPtrConstant(offset));
479 }
480 
LoadFromParentFrame(int offset,MachineType rep)481 compiler::Node* CodeStubAssembler::LoadFromParentFrame(int offset,
482                                                        MachineType rep) {
483   Node* frame_pointer = LoadParentFramePointer();
484   return Load(rep, frame_pointer, IntPtrConstant(offset));
485 }
486 
LoadBufferObject(Node * buffer,int offset,MachineType rep)487 Node* CodeStubAssembler::LoadBufferObject(Node* buffer, int offset,
488                                           MachineType rep) {
489   return Load(rep, buffer, IntPtrConstant(offset));
490 }
491 
LoadObjectField(Node * object,int offset,MachineType rep)492 Node* CodeStubAssembler::LoadObjectField(Node* object, int offset,
493                                          MachineType rep) {
494   return Load(rep, object, IntPtrConstant(offset - kHeapObjectTag));
495 }
496 
LoadObjectField(Node * object,Node * offset,MachineType rep)497 Node* CodeStubAssembler::LoadObjectField(Node* object, Node* offset,
498                                          MachineType rep) {
499   return Load(rep, object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)));
500 }
501 
LoadHeapNumberValue(Node * object)502 Node* CodeStubAssembler::LoadHeapNumberValue(Node* object) {
503   return LoadObjectField(object, HeapNumber::kValueOffset,
504                          MachineType::Float64());
505 }
506 
LoadMap(Node * object)507 Node* CodeStubAssembler::LoadMap(Node* object) {
508   return LoadObjectField(object, HeapObject::kMapOffset);
509 }
510 
LoadInstanceType(Node * object)511 Node* CodeStubAssembler::LoadInstanceType(Node* object) {
512   return LoadMapInstanceType(LoadMap(object));
513 }
514 
AssertInstanceType(Node * object,InstanceType instance_type)515 void CodeStubAssembler::AssertInstanceType(Node* object,
516                                            InstanceType instance_type) {
517   Assert(Word32Equal(LoadInstanceType(object), Int32Constant(instance_type)));
518 }
519 
LoadProperties(Node * object)520 Node* CodeStubAssembler::LoadProperties(Node* object) {
521   return LoadObjectField(object, JSObject::kPropertiesOffset);
522 }
523 
LoadElements(Node * object)524 Node* CodeStubAssembler::LoadElements(Node* object) {
525   return LoadObjectField(object, JSObject::kElementsOffset);
526 }
527 
LoadFixedArrayBaseLength(Node * array)528 Node* CodeStubAssembler::LoadFixedArrayBaseLength(Node* array) {
529   return LoadObjectField(array, FixedArrayBase::kLengthOffset);
530 }
531 
LoadMapBitField(Node * map)532 Node* CodeStubAssembler::LoadMapBitField(Node* map) {
533   return LoadObjectField(map, Map::kBitFieldOffset, MachineType::Uint8());
534 }
535 
LoadMapBitField2(Node * map)536 Node* CodeStubAssembler::LoadMapBitField2(Node* map) {
537   return LoadObjectField(map, Map::kBitField2Offset, MachineType::Uint8());
538 }
539 
LoadMapBitField3(Node * map)540 Node* CodeStubAssembler::LoadMapBitField3(Node* map) {
541   return LoadObjectField(map, Map::kBitField3Offset, MachineType::Uint32());
542 }
543 
LoadMapInstanceType(Node * map)544 Node* CodeStubAssembler::LoadMapInstanceType(Node* map) {
545   return LoadObjectField(map, Map::kInstanceTypeOffset, MachineType::Uint8());
546 }
547 
LoadMapDescriptors(Node * map)548 Node* CodeStubAssembler::LoadMapDescriptors(Node* map) {
549   return LoadObjectField(map, Map::kDescriptorsOffset);
550 }
551 
LoadMapPrototype(Node * map)552 Node* CodeStubAssembler::LoadMapPrototype(Node* map) {
553   return LoadObjectField(map, Map::kPrototypeOffset);
554 }
555 
LoadMapInstanceSize(Node * map)556 Node* CodeStubAssembler::LoadMapInstanceSize(Node* map) {
557   return LoadObjectField(map, Map::kInstanceSizeOffset, MachineType::Uint8());
558 }
559 
LoadMapInobjectProperties(Node * map)560 Node* 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 
LoadNameHashField(Node * name)570 Node* CodeStubAssembler::LoadNameHashField(Node* name) {
571   return LoadObjectField(name, Name::kHashFieldOffset, MachineType::Uint32());
572 }
573 
LoadNameHash(Node * name,Label * if_hash_not_computed)574 Node* 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 
LoadStringLength(Node * object)585 Node* CodeStubAssembler::LoadStringLength(Node* object) {
586   return LoadObjectField(object, String::kLengthOffset);
587 }
588 
LoadJSValueValue(Node * object)589 Node* CodeStubAssembler::LoadJSValueValue(Node* object) {
590   return LoadObjectField(object, JSValue::kValueOffset);
591 }
592 
LoadWeakCellValue(Node * weak_cell,Label * if_cleared)593 Node* 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 
AllocateUninitializedFixedArray(Node * length)601 Node* 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 
LoadFixedArrayElement(Node * object,Node * index_node,int additional_offset,ParameterMode parameter_mode)614 Node* 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 
LoadFixedDoubleArrayElement(Node * object,Node * index_node,MachineType machine_type,int additional_offset,ParameterMode parameter_mode)624 Node* 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 
LoadNativeContext(Node * context)634 Node* CodeStubAssembler::LoadNativeContext(Node* context) {
635   return LoadFixedArrayElement(context,
636                                Int32Constant(Context::NATIVE_CONTEXT_INDEX));
637 }
638 
LoadJSArrayElementsMap(ElementsKind kind,Node * native_context)639 Node* CodeStubAssembler::LoadJSArrayElementsMap(ElementsKind kind,
640                                                 Node* native_context) {
641   return LoadFixedArrayElement(native_context,
642                                Int32Constant(Context::ArrayMapIndex(kind)));
643 }
644 
StoreHeapNumberValue(Node * object,Node * value)645 Node* CodeStubAssembler::StoreHeapNumberValue(Node* object, Node* value) {
646   return StoreNoWriteBarrier(
647       MachineRepresentation::kFloat64, object,
648       IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag), value);
649 }
650 
StoreObjectField(Node * object,int offset,Node * value)651 Node* CodeStubAssembler::StoreObjectField(
652     Node* object, int offset, Node* value) {
653   return Store(MachineRepresentation::kTagged, object,
654                IntPtrConstant(offset - kHeapObjectTag), value);
655 }
656 
StoreObjectFieldNoWriteBarrier(Node * object,int offset,Node * value,MachineRepresentation rep)657 Node* CodeStubAssembler::StoreObjectFieldNoWriteBarrier(
658     Node* object, int offset, Node* value, MachineRepresentation rep) {
659   return StoreNoWriteBarrier(rep, object,
660                              IntPtrConstant(offset - kHeapObjectTag), value);
661 }
662 
StoreMapNoWriteBarrier(Node * object,Node * map)663 Node* CodeStubAssembler::StoreMapNoWriteBarrier(Node* object, Node* map) {
664   return StoreNoWriteBarrier(
665       MachineRepresentation::kTagged, object,
666       IntPtrConstant(HeapNumber::kMapOffset - kHeapObjectTag), map);
667 }
668 
StoreFixedArrayElement(Node * object,Node * index_node,Node * value,WriteBarrierMode barrier_mode,ParameterMode parameter_mode)669 Node* 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 
StoreFixedDoubleArrayElement(Node * object,Node * index_node,Node * value,ParameterMode parameter_mode)686 Node* 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 
AllocateHeapNumber()695 Node* CodeStubAssembler::AllocateHeapNumber() {
696   Node* result = Allocate(HeapNumber::kSize, kNone);
697   StoreMapNoWriteBarrier(result, HeapNumberMapConstant());
698   return result;
699 }
700 
AllocateHeapNumberWithValue(Node * value)701 Node* CodeStubAssembler::AllocateHeapNumberWithValue(Node* value) {
702   Node* result = AllocateHeapNumber();
703   StoreHeapNumberValue(result, value);
704   return result;
705 }
706 
AllocateSeqOneByteString(int length)707 Node* 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 
AllocateSeqOneByteString(Node * context,Node * length)718 Node* 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 
AllocateSeqTwoByteString(int length)760 Node* 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 
AllocateSeqTwoByteString(Node * context,Node * length)771 Node* 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 
AllocateJSArray(ElementsKind kind,Node * array_map,Node * capacity_node,Node * length_node,compiler::Node * allocation_site,ParameterMode mode)813 Node* 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 
InitializeAllocationMemento(compiler::Node * base_allocation,int base_allocation_size,compiler::Node * allocation_site)942 void 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 
TruncateTaggedToFloat64(Node * context,Node * value)962 Node* 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 
TruncateTaggedToWord32(Node * context,Node * value)1013 Node* 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 
TruncateHeapNumberValueToWord32(Node * object)1064 Node* CodeStubAssembler::TruncateHeapNumberValueToWord32(Node* object) {
1065   Node* value = LoadHeapNumberValue(object);
1066   return TruncateFloat64ToWord32(value);
1067 }
1068 
ChangeFloat64ToTagged(Node * value)1069 Node* 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 
ChangeInt32ToTagged(Node * value)1118 Node* 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 
ChangeUint32ToTagged(Node * value)1145 Node* 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 
ToThisString(Node * context,Node * value,char const * method_name)1180 Node* 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 
StringCharCodeAt(Node * string,Node * index)1242 Node* 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 
StringFromCharCode(Node * code)1415 Node* 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 
BitFieldDecode(Node * word32,uint32_t shift,uint32_t mask)1471 Node* CodeStubAssembler::BitFieldDecode(Node* word32, uint32_t shift,
1472                                         uint32_t mask) {
1473   return Word32Shr(Word32And(word32, Int32Constant(mask)),
1474                    Int32Constant(shift));
1475 }
1476 
SetCounter(StatsCounter * counter,int value)1477 void 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 
IncrementCounter(StatsCounter * counter,int delta)1485 void 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 
DecrementCounter(StatsCounter * counter,int delta)1495 void 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 
TryToName(Node * key,Label * if_keyisindex,Variable * var_index,Label * if_keyisunique,Label * if_bailout)1505 void 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 
1551 template <typename Dictionary>
EntryToIndex(Node * entry,int field_index)1552 Node* 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 
1558 template <typename Dictionary>
NameDictionaryLookup(Node * dictionary,Node * unique_name,Label * if_found,Variable * var_name_index,Label * if_not_found,int inlined_probes)1559 void 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.
1620 template void CodeStubAssembler::NameDictionaryLookup<NameDictionary>(
1621     Node*, Node*, Label*, Variable*, Label*, int);
1622 template void CodeStubAssembler::NameDictionaryLookup<GlobalDictionary>(
1623     Node*, Node*, Label*, Variable*, Label*, int);
1624 
ComputeIntegerHash(Node * key,Node * seed)1625 Node* 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 
1639 template <typename Dictionary>
NumberDictionaryLookup(Node * dictionary,Node * key,Label * if_found,Variable * var_entry,Label * if_not_found)1640 void 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 
TryLookupProperty(Node * object,Node * map,Node * instance_type,Node * unique_name,Label * if_found_fast,Label * if_found_dict,Label * if_found_global,Variable * var_meta_storage,Variable * var_name_index,Label * if_not_found,Label * if_bailout)1711 void 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 
TryHasOwnProperty(compiler::Node * object,compiler::Node * map,compiler::Node * instance_type,compiler::Node * unique_name,Label * if_found,Label * if_not_found,Label * if_bailout)1797 void 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 
LoadPropertyFromFastObject(Node * object,Node * map,Node * descriptors,Node * name_index,Variable * var_details,Variable * var_value)1823 void 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 
LoadPropertyFromNameDictionary(Node * dictionary,Node * name_index,Variable * var_details,Variable * var_value)1934 void 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 
LoadPropertyFromGlobalDictionary(Node * dictionary,Node * name_index,Variable * var_details,Variable * var_value,Label * if_deleted)1957 void 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 
TryGetOwnProperty(Node * context,Node * receiver,Node * object,Node * map,Node * instance_type,Node * unique_name,Label * if_found_value,Variable * var_value,Label * if_not_found,Label * if_bailout)1983 void 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 
TryLookupElement(Node * object,Node * map,Node * instance_type,Node * index,Label * if_found,Label * if_not_found,Label * if_bailout)2068 void 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.
2173 template void CodeStubAssembler::NumberDictionaryLookup<SeededNumberDictionary>(
2174     Node*, Node*, Label*, Variable*, Label*);
2175 template void CodeStubAssembler::NumberDictionaryLookup<
2176     UnseededNumberDictionary>(Node*, Node*, Label*, Variable*, Label*);
2177 
OrdinaryHasInstance(Node * context,Node * callable,Node * object)2178 Node* 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 
ElementOffsetFromIndex(Node * index_node,ElementsKind kind,ParameterMode mode,int base_size)2314 compiler::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 
LoadTypeFeedbackVectorForStub()2350 compiler::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 
LoadReceiverMap(compiler::Node * receiver)2357 compiler::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 
TryMonomorphicCase(const LoadICParameters * p,compiler::Node * receiver_map,Label * if_handler,Variable * var_handler,Label * if_miss)2378 compiler::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 
HandlePolymorphicCase(const LoadICParameters * p,compiler::Node * receiver_map,compiler::Node * feedback,Label * if_handler,Variable * var_handler,Label * if_miss,int unroll_count)2403 void 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 
StubCachePrimaryOffset(compiler::Node * name,Code::Flags flags,compiler::Node * map)2455 compiler::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 
StubCacheSecondaryOffset(compiler::Node * name,Code::Flags flags,compiler::Node * seed)2481 compiler::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 
2497 enum CodeStubAssembler::StubCacheTable : int {
2498   kPrimary = static_cast<int>(StubCache::kPrimary),
2499   kSecondary = static_cast<int>(StubCache::kSecondary)
2500 };
2501 
TryProbeStubCacheTable(StubCache * stub_cache,StubCacheTable table_id,compiler::Node * entry_offset,compiler::Node * name,Code::Flags flags,compiler::Node * map,Label * if_handler,Variable * var_handler,Label * if_miss)2502 void 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 
TryProbeStubCache(StubCache * stub_cache,Code::Flags flags,compiler::Node * receiver,compiler::Node * name,Label * if_handler,Variable * var_handler,Label * if_miss)2554 void 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 
LoadIC(const LoadICParameters * p)2589 void 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 
LoadGlobalIC(const LoadICParameters * p)2638 void 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