• 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/ic/accessor-assembler.h"
6 
7 #include "src/ast/ast.h"
8 #include "src/base/optional.h"
9 #include "src/builtins/builtins-constructor-gen.h"
10 #include "src/codegen/code-factory.h"
11 #include "src/ic/handler-configuration.h"
12 #include "src/ic/ic.h"
13 #include "src/ic/keyed-store-generic.h"
14 #include "src/ic/stub-cache.h"
15 #include "src/logging/counters.h"
16 #include "src/objects/cell.h"
17 #include "src/objects/foreign.h"
18 #include "src/objects/heap-number.h"
19 #include "src/objects/module.h"
20 #include "src/objects/objects-inl.h"
21 #include "src/objects/property-details.h"
22 #include "src/objects/smi.h"
23 
24 namespace v8 {
25 namespace internal {
26 
27 using compiler::CodeAssemblerState;
28 using compiler::Node;
29 
30 //////////////////// Private helpers.
31 
32 // Loads dataX field from the DataHandler object.
LoadHandlerDataField(TNode<DataHandler> handler,int data_index)33 TNode<MaybeObject> AccessorAssembler::LoadHandlerDataField(
34     TNode<DataHandler> handler, int data_index) {
35 #ifdef DEBUG
36   TNode<Map> handler_map = LoadMap(handler);
37   TNode<Uint16T> instance_type = LoadMapInstanceType(handler_map);
38 #endif
39   CSA_ASSERT(this,
40              Word32Or(InstanceTypeEqual(instance_type, LOAD_HANDLER_TYPE),
41                       InstanceTypeEqual(instance_type, STORE_HANDLER_TYPE)));
42   int offset = 0;
43   int minimum_size = 0;
44   switch (data_index) {
45     case 1:
46       offset = DataHandler::kData1Offset;
47       minimum_size = DataHandler::kSizeWithData1;
48       break;
49     case 2:
50       offset = DataHandler::kData2Offset;
51       minimum_size = DataHandler::kSizeWithData2;
52       break;
53     case 3:
54       offset = DataHandler::kData3Offset;
55       minimum_size = DataHandler::kSizeWithData3;
56       break;
57     default:
58       UNREACHABLE();
59   }
60   USE(minimum_size);
61   CSA_ASSERT(this, UintPtrGreaterThanOrEqual(
62                        LoadMapInstanceSizeInWords(handler_map),
63                        IntPtrConstant(minimum_size / kTaggedSize)));
64   return LoadMaybeWeakObjectField(handler, offset);
65 }
66 
TryMonomorphicCase(TNode<TaggedIndex> slot,TNode<FeedbackVector> vector,TNode<Map> lookup_start_object_map,Label * if_handler,TVariable<MaybeObject> * var_handler,Label * if_miss)67 TNode<MaybeObject> AccessorAssembler::TryMonomorphicCase(
68     TNode<TaggedIndex> slot, TNode<FeedbackVector> vector,
69     TNode<Map> lookup_start_object_map, Label* if_handler,
70     TVariable<MaybeObject>* var_handler, Label* if_miss) {
71   Comment("TryMonomorphicCase");
72   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
73 
74   // TODO(ishell): add helper class that hides offset computations for a series
75   // of loads.
76   int32_t header_size =
77       FeedbackVector::kRawFeedbackSlotsOffset - kHeapObjectTag;
78   // Adding |header_size| with a separate IntPtrAdd rather than passing it
79   // into ElementOffsetFromIndex() allows it to be folded into a single
80   // [base, index, offset] indirect memory access on x64.
81   TNode<IntPtrT> offset = ElementOffsetFromIndex(slot, HOLEY_ELEMENTS);
82   TNode<MaybeObject> feedback = ReinterpretCast<MaybeObject>(
83       Load(MachineType::AnyTagged(), vector,
84            IntPtrAdd(offset, IntPtrConstant(header_size))));
85 
86   // Try to quickly handle the monomorphic case without knowing for sure
87   // if we have a weak reference in feedback.
88   GotoIfNot(IsWeakReferenceTo(feedback, lookup_start_object_map), if_miss);
89 
90   TNode<MaybeObject> handler = UncheckedCast<MaybeObject>(
91       Load(MachineType::AnyTagged(), vector,
92            IntPtrAdd(offset, IntPtrConstant(header_size + kTaggedSize))));
93 
94   *var_handler = handler;
95   Goto(if_handler);
96   return feedback;
97 }
98 
HandlePolymorphicCase(TNode<Map> lookup_start_object_map,TNode<WeakFixedArray> feedback,Label * if_handler,TVariable<MaybeObject> * var_handler,Label * if_miss)99 void AccessorAssembler::HandlePolymorphicCase(
100     TNode<Map> lookup_start_object_map, TNode<WeakFixedArray> feedback,
101     Label* if_handler, TVariable<MaybeObject>* var_handler, Label* if_miss) {
102   Comment("HandlePolymorphicCase");
103   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
104 
105   // Iterate {feedback} array.
106   const int kEntrySize = 2;
107 
108   // Load the {feedback} array length.
109   TNode<IntPtrT> length = LoadAndUntagWeakFixedArrayLength(feedback);
110   CSA_ASSERT(this, IntPtrLessThanOrEqual(IntPtrConstant(kEntrySize), length));
111 
112   // This is a hand-crafted loop that iterates backwards and only compares
113   // against zero at the end, since we already know that we will have at least a
114   // single entry in the {feedback} array anyways.
115   TVARIABLE(IntPtrT, var_index, IntPtrSub(length, IntPtrConstant(kEntrySize)));
116   Label loop(this, &var_index), loop_next(this);
117   Goto(&loop);
118   BIND(&loop);
119   {
120     TNode<MaybeObject> maybe_cached_map =
121         LoadWeakFixedArrayElement(feedback, var_index.value());
122     CSA_ASSERT(this, IsWeakOrCleared(maybe_cached_map));
123     GotoIfNot(IsWeakReferenceTo(maybe_cached_map, lookup_start_object_map),
124               &loop_next);
125 
126     // Found, now call handler.
127     TNode<MaybeObject> handler =
128         LoadWeakFixedArrayElement(feedback, var_index.value(), kTaggedSize);
129     *var_handler = handler;
130     Goto(if_handler);
131 
132     BIND(&loop_next);
133     var_index =
134         Signed(IntPtrSub(var_index.value(), IntPtrConstant(kEntrySize)));
135     Branch(IntPtrGreaterThanOrEqual(var_index.value(), IntPtrConstant(0)),
136            &loop, if_miss);
137   }
138 }
139 
HandleLoadICHandlerCase(const LazyLoadICParameters * p,TNode<Object> handler,Label * miss,ExitPoint * exit_point,ICMode ic_mode,OnNonExistent on_nonexistent,ElementSupport support_elements,LoadAccessMode access_mode)140 void AccessorAssembler::HandleLoadICHandlerCase(
141     const LazyLoadICParameters* p, TNode<Object> handler, Label* miss,
142     ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
143     ElementSupport support_elements, LoadAccessMode access_mode) {
144   Comment("have_handler");
145 
146   TVARIABLE(Object, var_holder, p->lookup_start_object());
147   TVARIABLE(Object, var_smi_handler, handler);
148 
149   Label if_smi_handler(this, {&var_holder, &var_smi_handler});
150   Label try_proto_handler(this, Label::kDeferred),
151       call_handler(this, Label::kDeferred);
152 
153   Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler);
154 
155   BIND(&try_proto_handler);
156   {
157     GotoIf(IsCodeMap(LoadMap(CAST(handler))), &call_handler);
158     HandleLoadICProtoHandler(p, CAST(handler), &var_holder, &var_smi_handler,
159                              &if_smi_handler, miss, exit_point, ic_mode,
160                              access_mode);
161   }
162 
163   // |handler| is a Smi, encoding what to do. See SmiHandler methods
164   // for the encoding format.
165   BIND(&if_smi_handler);
166   {
167     HandleLoadICSmiHandlerCase(
168         p, var_holder.value(), CAST(var_smi_handler.value()), handler, miss,
169         exit_point, ic_mode, on_nonexistent, support_elements, access_mode);
170   }
171 
172   BIND(&call_handler);
173   {
174     exit_point->ReturnCallStub(LoadWithVectorDescriptor{}, CAST(handler),
175                                p->context(), p->receiver(), p->name(),
176                                p->slot(), p->vector());
177   }
178 }
179 
HandleLoadCallbackProperty(const LazyLoadICParameters * p,TNode<JSObject> holder,TNode<WordT> handler_word,ExitPoint * exit_point)180 void AccessorAssembler::HandleLoadCallbackProperty(
181     const LazyLoadICParameters* p, TNode<JSObject> holder,
182     TNode<WordT> handler_word, ExitPoint* exit_point) {
183   Comment("native_data_property_load");
184   TNode<IntPtrT> descriptor =
185       Signed(DecodeWord<LoadHandler::DescriptorBits>(handler_word));
186 
187   Callable callable = CodeFactory::ApiGetter(isolate());
188   TNode<AccessorInfo> accessor_info =
189       CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
190 
191   exit_point->ReturnCallStub(callable, p->context(), p->receiver(), holder,
192                              accessor_info);
193 }
194 
HandleLoadAccessor(const LazyLoadICParameters * p,TNode<CallHandlerInfo> call_handler_info,TNode<WordT> handler_word,TNode<DataHandler> handler,TNode<IntPtrT> handler_kind,ExitPoint * exit_point)195 void AccessorAssembler::HandleLoadAccessor(
196     const LazyLoadICParameters* p, TNode<CallHandlerInfo> call_handler_info,
197     TNode<WordT> handler_word, TNode<DataHandler> handler,
198     TNode<IntPtrT> handler_kind, ExitPoint* exit_point) {
199   Comment("api_getter");
200   // Context is stored either in data2 or data3 field depending on whether
201   // the access check is enabled for this handler or not.
202   TNode<MaybeObject> maybe_context = Select<MaybeObject>(
203       IsSetWord<LoadHandler::DoAccessCheckOnLookupStartObjectBits>(
204           handler_word),
205       [=] { return LoadHandlerDataField(handler, 3); },
206       [=] { return LoadHandlerDataField(handler, 2); });
207 
208   CSA_ASSERT(this, IsWeakOrCleared(maybe_context));
209   CSA_CHECK(this, IsNotCleared(maybe_context));
210   TNode<HeapObject> context = GetHeapObjectAssumeWeak(maybe_context);
211 
212   TNode<Foreign> foreign = LoadObjectField<Foreign>(
213       call_handler_info, CallHandlerInfo::kJsCallbackOffset);
214   TNode<RawPtrT> callback = LoadForeignForeignAddressPtr(foreign);
215   TNode<Object> data =
216       LoadObjectField(call_handler_info, CallHandlerInfo::kDataOffset);
217 
218   TVARIABLE(HeapObject, api_holder, CAST(p->lookup_start_object()));
219   Label load(this);
220   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kApiGetter)),
221          &load);
222 
223   CSA_ASSERT(
224       this,
225       WordEqual(handler_kind,
226                 IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)));
227 
228   api_holder = LoadMapPrototype(LoadMap(CAST(p->lookup_start_object())));
229   Goto(&load);
230 
231   BIND(&load);
232   TNode<IntPtrT> argc = IntPtrConstant(0);
233   exit_point->Return(CallApiCallback(context, callback, argc, data,
234                                      api_holder.value(), p->receiver()));
235 }
236 
HandleLoadField(TNode<JSObject> holder,TNode<WordT> handler_word,TVariable<Float64T> * var_double_value,Label * rebox_double,Label * miss,ExitPoint * exit_point)237 void AccessorAssembler::HandleLoadField(TNode<JSObject> holder,
238                                         TNode<WordT> handler_word,
239                                         TVariable<Float64T>* var_double_value,
240                                         Label* rebox_double, Label* miss,
241                                         ExitPoint* exit_point) {
242   Comment("field_load");
243   TNode<IntPtrT> index =
244       Signed(DecodeWord<LoadHandler::FieldIndexBits>(handler_word));
245   TNode<IntPtrT> offset = IntPtrMul(index, IntPtrConstant(kTaggedSize));
246 
247   Label inobject(this), out_of_object(this);
248   Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject,
249          &out_of_object);
250 
251   BIND(&inobject);
252   {
253     Label is_double(this);
254     GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
255     exit_point->Return(LoadObjectField(holder, offset));
256 
257     BIND(&is_double);
258     if (FLAG_unbox_double_fields) {
259       *var_double_value = LoadObjectField<Float64T>(holder, offset);
260     } else {
261       TNode<Object> heap_number = LoadObjectField(holder, offset);
262       // This is not an "old" Smi value from before a Smi->Double transition.
263       // Rather, it's possible that since the last update of this IC, the Double
264       // field transitioned to a Tagged field, and was then assigned a Smi.
265       GotoIf(TaggedIsSmi(heap_number), miss);
266       GotoIfNot(IsHeapNumber(CAST(heap_number)), miss);
267       *var_double_value = LoadHeapNumberValue(CAST(heap_number));
268     }
269     Goto(rebox_double);
270   }
271 
272   BIND(&out_of_object);
273   {
274     Label is_double(this);
275     TNode<HeapObject> properties = LoadFastProperties(holder);
276     TNode<Object> value = LoadObjectField(properties, offset);
277     GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
278     exit_point->Return(value);
279 
280     BIND(&is_double);
281     if (!FLAG_unbox_double_fields) {
282       // This is not an "old" Smi value from before a Smi->Double transition.
283       // Rather, it's possible that since the last update of this IC, the Double
284       // field transitioned to a Tagged field, and was then assigned a Smi.
285       GotoIf(TaggedIsSmi(value), miss);
286       GotoIfNot(IsHeapNumber(CAST(value)), miss);
287     }
288     *var_double_value = LoadHeapNumberValue(CAST(value));
289     Goto(rebox_double);
290   }
291 }
292 
LoadDescriptorValue(TNode<Map> map,TNode<IntPtrT> descriptor_entry)293 TNode<Object> AccessorAssembler::LoadDescriptorValue(
294     TNode<Map> map, TNode<IntPtrT> descriptor_entry) {
295   return CAST(LoadDescriptorValueOrFieldType(map, descriptor_entry));
296 }
297 
LoadDescriptorValueOrFieldType(TNode<Map> map,TNode<IntPtrT> descriptor_entry)298 TNode<MaybeObject> AccessorAssembler::LoadDescriptorValueOrFieldType(
299     TNode<Map> map, TNode<IntPtrT> descriptor_entry) {
300   TNode<DescriptorArray> descriptors = LoadMapDescriptors(map);
301   return LoadFieldTypeByDescriptorEntry(descriptors, descriptor_entry);
302 }
303 
HandleLoadICSmiHandlerCase(const LazyLoadICParameters * p,TNode<Object> holder,TNode<Smi> smi_handler,TNode<Object> handler,Label * miss,ExitPoint * exit_point,ICMode ic_mode,OnNonExistent on_nonexistent,ElementSupport support_elements,LoadAccessMode access_mode)304 void AccessorAssembler::HandleLoadICSmiHandlerCase(
305     const LazyLoadICParameters* p, TNode<Object> holder, TNode<Smi> smi_handler,
306     TNode<Object> handler, Label* miss, ExitPoint* exit_point, ICMode ic_mode,
307     OnNonExistent on_nonexistent, ElementSupport support_elements,
308     LoadAccessMode access_mode) {
309   TVARIABLE(Float64T, var_double_value);
310   Label rebox_double(this, &var_double_value);
311 
312   TNode<IntPtrT> handler_word = SmiUntag(smi_handler);
313   TNode<IntPtrT> handler_kind =
314       Signed(DecodeWord<LoadHandler::KindBits>(handler_word));
315 
316   if (support_elements == kSupportElements) {
317     Label if_element(this), if_indexed_string(this), if_property(this),
318         if_hole(this), unimplemented_elements_kind(this),
319         if_oob(this, Label::kDeferred), try_string_to_array_index(this),
320         emit_element_load(this);
321     TVARIABLE(IntPtrT, var_intptr_index);
322     GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kElement)),
323            &if_element);
324 
325     if (access_mode == LoadAccessMode::kHas) {
326       CSA_ASSERT(this,
327                  WordNotEqual(handler_kind,
328                               IntPtrConstant(LoadHandler::kIndexedString)));
329       Goto(&if_property);
330     } else {
331       Branch(
332           WordEqual(handler_kind, IntPtrConstant(LoadHandler::kIndexedString)),
333           &if_indexed_string, &if_property);
334     }
335 
336     BIND(&if_element);
337     {
338       Comment("element_load");
339       TVARIABLE(Int32T, var_instance_type);
340       TNode<IntPtrT> intptr_index = TryToIntptr(
341           p->name(), &try_string_to_array_index, &var_instance_type);
342       var_intptr_index = intptr_index;
343       Goto(&emit_element_load);
344 
345       BIND(&try_string_to_array_index);
346       {
347         GotoIfNot(IsStringInstanceType(var_instance_type.value()), miss);
348 
349         TNode<ExternalReference> function = ExternalConstant(
350             ExternalReference::string_to_array_index_function());
351         TNode<Int32T> result = UncheckedCast<Int32T>(
352             CallCFunction(function, MachineType::Int32(),
353                           std::make_pair(MachineType::AnyTagged(), p->name())));
354         GotoIf(Word32Equal(Int32Constant(-1), result), miss);
355         CSA_ASSERT(this, Int32GreaterThanOrEqual(result, Int32Constant(0)));
356         var_intptr_index = ChangeInt32ToIntPtr(result);
357 
358         Goto(&emit_element_load);
359       }
360 
361       BIND(&emit_element_load);
362       {
363         TNode<BoolT> is_jsarray_condition =
364             IsSetWord<LoadHandler::IsJsArrayBits>(handler_word);
365         TNode<Uint32T> elements_kind =
366             DecodeWord32FromWord<LoadHandler::ElementsKindBits>(handler_word);
367         EmitElementLoad(CAST(holder), elements_kind, var_intptr_index.value(),
368                         is_jsarray_condition, &if_hole, &rebox_double,
369                         &var_double_value, &unimplemented_elements_kind,
370                         &if_oob, miss, exit_point, access_mode);
371       }
372     }
373 
374     BIND(&unimplemented_elements_kind);
375     {
376       // Smi handlers should only be installed for supported elements kinds.
377       // Crash if we get here.
378       DebugBreak();
379       Goto(miss);
380     }
381 
382     BIND(&if_oob);
383     {
384       Comment("out of bounds elements access");
385       Label return_undefined(this);
386 
387       // Check if we're allowed to handle OOB accesses.
388       TNode<BoolT> allow_out_of_bounds =
389           IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
390       GotoIfNot(allow_out_of_bounds, miss);
391 
392       // Negative indices aren't valid array indices (according to
393       // the ECMAScript specification), and are stored as properties
394       // in V8, not elements. So we cannot handle them here, except
395       // in case of typed arrays, where integer indexed properties
396       // aren't looked up in the prototype chain.
397       GotoIf(IsJSTypedArray(CAST(holder)), &return_undefined);
398       if (Is64()) {
399         GotoIfNot(
400             UintPtrLessThanOrEqual(var_intptr_index.value(),
401                                    IntPtrConstant(JSArray::kMaxArrayIndex)),
402             miss);
403       } else {
404         GotoIf(IntPtrLessThan(var_intptr_index.value(), IntPtrConstant(0)),
405                miss);
406       }
407 
408       // For all other receivers we need to check that the prototype chain
409       // doesn't contain any elements.
410       BranchIfPrototypesHaveNoElements(LoadMap(CAST(holder)), &return_undefined,
411                                        miss);
412 
413       BIND(&return_undefined);
414       exit_point->Return(access_mode == LoadAccessMode::kHas
415                              ? FalseConstant()
416                              : UndefinedConstant());
417     }
418 
419     BIND(&if_hole);
420     {
421       Comment("convert hole");
422 
423       GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
424       GotoIf(IsNoElementsProtectorCellInvalid(), miss);
425       exit_point->Return(access_mode == LoadAccessMode::kHas
426                              ? FalseConstant()
427                              : UndefinedConstant());
428     }
429 
430     if (access_mode != LoadAccessMode::kHas) {
431       BIND(&if_indexed_string);
432       {
433         Label if_oob(this, Label::kDeferred);
434 
435         Comment("indexed string");
436         TNode<String> string_holder = CAST(holder);
437         TNode<UintPtrT> index = Unsigned(TryToIntptr(p->name(), miss));
438         TNode<UintPtrT> length =
439             Unsigned(LoadStringLengthAsWord(string_holder));
440         GotoIf(UintPtrGreaterThanOrEqual(index, length), &if_oob);
441         TNode<Int32T> code = StringCharCodeAt(string_holder, index);
442         TNode<String> result = StringFromSingleCharCode(code);
443         Return(result);
444 
445         BIND(&if_oob);
446         TNode<BoolT> allow_out_of_bounds =
447             IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
448         GotoIfNot(allow_out_of_bounds, miss);
449         GotoIf(IsNoElementsProtectorCellInvalid(), miss);
450         Return(UndefinedConstant());
451       }
452     }
453 
454     BIND(&if_property);
455     Comment("property_load");
456   }
457 
458   if (access_mode == LoadAccessMode::kHas) {
459     HandleLoadICSmiHandlerHasNamedCase(p, holder, handler_kind, miss,
460                                        exit_point, ic_mode);
461   } else {
462     HandleLoadICSmiHandlerLoadNamedCase(
463         p, holder, handler_kind, handler_word, &rebox_double, &var_double_value,
464         handler, miss, exit_point, ic_mode, on_nonexistent, support_elements);
465   }
466 }
467 
HandleLoadICSmiHandlerLoadNamedCase(const LazyLoadICParameters * p,TNode<Object> holder,TNode<IntPtrT> handler_kind,TNode<WordT> handler_word,Label * rebox_double,TVariable<Float64T> * var_double_value,TNode<Object> handler,Label * miss,ExitPoint * exit_point,ICMode ic_mode,OnNonExistent on_nonexistent,ElementSupport support_elements)468 void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
469     const LazyLoadICParameters* p, TNode<Object> holder,
470     TNode<IntPtrT> handler_kind, TNode<WordT> handler_word, Label* rebox_double,
471     TVariable<Float64T>* var_double_value, TNode<Object> handler, Label* miss,
472     ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
473     ElementSupport support_elements) {
474   Label constant(this), field(this), normal(this, Label::kDeferred),
475       slow(this, Label::kDeferred), interceptor(this, Label::kDeferred),
476       nonexistent(this), accessor(this, Label::kDeferred),
477       global(this, Label::kDeferred), module_export(this, Label::kDeferred),
478       proxy(this, Label::kDeferred),
479       native_data_property(this, Label::kDeferred),
480       api_getter(this, Label::kDeferred);
481 
482   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field);
483 
484   GotoIf(WordEqual(handler_kind,
485                    IntPtrConstant(LoadHandler::kConstantFromPrototype)),
486          &constant);
487 
488   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)),
489          &nonexistent);
490 
491   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNormal)),
492          &normal);
493 
494   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kAccessor)),
495          &accessor);
496 
497   GotoIf(
498       WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNativeDataProperty)),
499       &native_data_property);
500 
501   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kApiGetter)),
502          &api_getter);
503 
504   GotoIf(WordEqual(handler_kind,
505                    IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)),
506          &api_getter);
507 
508   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)),
509          &global);
510 
511   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kSlow)), &slow);
512 
513   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kProxy)), &proxy);
514 
515   Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kModuleExport)),
516          &module_export, &interceptor);
517 
518   BIND(&field);
519   HandleLoadField(CAST(holder), handler_word, var_double_value, rebox_double,
520                   miss, exit_point);
521 
522   BIND(&nonexistent);
523   // This is a handler for a load of a non-existent value.
524   if (on_nonexistent == OnNonExistent::kThrowReferenceError) {
525     exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context(),
526                                   p->name());
527   } else {
528     DCHECK_EQ(OnNonExistent::kReturnUndefined, on_nonexistent);
529     exit_point->Return(UndefinedConstant());
530   }
531 
532   BIND(&constant);
533   {
534     Comment("constant_load");
535     exit_point->Return(holder);
536   }
537 
538   BIND(&normal);
539   {
540     Comment("load_normal");
541     TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(holder)));
542     TVARIABLE(IntPtrT, var_name_index);
543     Label found(this, &var_name_index);
544     NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()), &found,
545                                          &var_name_index, miss);
546     BIND(&found);
547     {
548       TVARIABLE(Uint32T, var_details);
549       TVARIABLE(Object, var_value);
550       LoadPropertyFromNameDictionary(properties, var_name_index.value(),
551                                      &var_details, &var_value);
552       TNode<Object> value = CallGetterIfAccessor(
553           var_value.value(), CAST(holder), var_details.value(), p->context(),
554           p->receiver(), miss);
555       exit_point->Return(value);
556     }
557   }
558 
559   BIND(&accessor);
560   {
561     Comment("accessor_load");
562     TNode<IntPtrT> descriptor =
563         Signed(DecodeWord<LoadHandler::DescriptorBits>(handler_word));
564     TNode<AccessorPair> accessor_pair =
565         CAST(LoadDescriptorValue(LoadMap(CAST(holder)), descriptor));
566     TNode<Object> getter =
567         LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
568     CSA_ASSERT(this, Word32BinaryNot(IsTheHole(getter)));
569 
570     exit_point->Return(Call(p->context(), getter, p->receiver()));
571   }
572 
573   BIND(&native_data_property);
574   HandleLoadCallbackProperty(p, CAST(holder), handler_word, exit_point);
575 
576   BIND(&api_getter);
577   HandleLoadAccessor(p, CAST(holder), handler_word, CAST(handler), handler_kind,
578                      exit_point);
579 
580   BIND(&proxy);
581   {
582     // TODO(mythria): LoadGlobals don't use this path. LoadGlobals need special
583     // handling with proxies which is currently not supported by builtins. So
584     // for such cases, we should install a slow path and never reach here. Fix
585     // it to not generate this for LoadGlobals.
586     CSA_ASSERT(this,
587                WordNotEqual(IntPtrConstant(static_cast<int>(on_nonexistent)),
588                             IntPtrConstant(static_cast<int>(
589                                 OnNonExistent::kThrowReferenceError))));
590     TVARIABLE(IntPtrT, var_index);
591     TVARIABLE(Name, var_unique);
592 
593     Label if_index(this), if_unique_name(this),
594         to_name_failed(this, Label::kDeferred);
595 
596     if (support_elements == kSupportElements) {
597       DCHECK_NE(on_nonexistent, OnNonExistent::kThrowReferenceError);
598 
599       TryToName(p->name(), &if_index, &var_index, &if_unique_name, &var_unique,
600                 &to_name_failed);
601 
602       BIND(&if_unique_name);
603       exit_point->ReturnCallStub(
604           Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
605           p->context(), holder, var_unique.value(), p->receiver(),
606           SmiConstant(on_nonexistent));
607 
608       BIND(&if_index);
609       // TODO(mslekova): introduce TryToName that doesn't try to compute
610       // the intptr index value
611       Goto(&to_name_failed);
612 
613       BIND(&to_name_failed);
614       // TODO(duongn): use GetPropertyWithReceiver builtin once
615       // |lookup_element_in_holder| supports elements.
616       exit_point->ReturnCallRuntime(Runtime::kGetPropertyWithReceiver,
617                                     p->context(), holder, p->name(),
618                                     p->receiver(), SmiConstant(on_nonexistent));
619     } else {
620       exit_point->ReturnCallStub(
621           Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
622           p->context(), holder, p->name(), p->receiver(),
623           SmiConstant(on_nonexistent));
624     }
625   }
626 
627   BIND(&global);
628   {
629     CSA_ASSERT(this, IsPropertyCell(CAST(holder)));
630     // Ensure the property cell doesn't contain the hole.
631     TNode<Object> value =
632         LoadObjectField(CAST(holder), PropertyCell::kValueOffset);
633     TNode<Uint32T> details = Unsigned(LoadAndUntagToWord32ObjectField(
634         CAST(holder), PropertyCell::kPropertyDetailsRawOffset));
635     GotoIf(IsTheHole(value), miss);
636 
637     exit_point->Return(CallGetterIfAccessor(value, CAST(holder), details,
638                                             p->context(), p->receiver(), miss));
639   }
640 
641   BIND(&interceptor);
642   {
643     Comment("load_interceptor");
644     exit_point->ReturnCallRuntime(Runtime::kLoadPropertyWithInterceptor,
645                                   p->context(), p->name(), p->receiver(),
646                                   holder, p->slot(), p->vector());
647   }
648   BIND(&slow);
649   {
650     Comment("load_slow");
651     if (ic_mode == ICMode::kGlobalIC) {
652       exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Slow, p->context(),
653                                     p->name(), p->slot(), p->vector());
654 
655     } else {
656       exit_point->ReturnCallRuntime(Runtime::kGetProperty, p->context(), holder,
657                                     p->name(), p->receiver());
658     }
659   }
660 
661   BIND(&module_export);
662   {
663     Comment("module export");
664     TNode<UintPtrT> index =
665         DecodeWord<LoadHandler::ExportsIndexBits>(handler_word);
666     TNode<Module> module = LoadObjectField<Module>(
667         CAST(p->receiver()), JSModuleNamespace::kModuleOffset);
668     TNode<ObjectHashTable> exports =
669         LoadObjectField<ObjectHashTable>(module, Module::kExportsOffset);
670     TNode<Cell> cell = CAST(LoadFixedArrayElement(exports, index));
671     // The handler is only installed for exports that exist.
672     TNode<Object> value = LoadCellValue(cell);
673     Label is_the_hole(this, Label::kDeferred);
674     GotoIf(IsTheHole(value), &is_the_hole);
675     exit_point->Return(value);
676 
677     BIND(&is_the_hole);
678     {
679       TNode<Smi> message = SmiConstant(MessageTemplate::kNotDefined);
680       exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context(),
681                                     message, p->name());
682     }
683   }
684 
685   BIND(rebox_double);
686   exit_point->Return(AllocateHeapNumberWithValue(var_double_value->value()));
687 }
688 
HandleLoadICSmiHandlerHasNamedCase(const LazyLoadICParameters * p,TNode<Object> holder,TNode<IntPtrT> handler_kind,Label * miss,ExitPoint * exit_point,ICMode ic_mode)689 void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
690     const LazyLoadICParameters* p, TNode<Object> holder,
691     TNode<IntPtrT> handler_kind, Label* miss, ExitPoint* exit_point,
692     ICMode ic_mode) {
693   Label return_true(this), return_false(this), return_lookup(this),
694       normal(this), global(this), slow(this);
695 
696   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)),
697          &return_true);
698 
699   GotoIf(WordEqual(handler_kind,
700                    IntPtrConstant(LoadHandler::kConstantFromPrototype)),
701          &return_true);
702 
703   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)),
704          &return_false);
705 
706   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNormal)),
707          &normal);
708 
709   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kAccessor)),
710          &return_true);
711 
712   GotoIf(
713       WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNativeDataProperty)),
714       &return_true);
715 
716   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kApiGetter)),
717          &return_true);
718 
719   GotoIf(WordEqual(handler_kind,
720                    IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)),
721          &return_true);
722 
723   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kSlow)), &slow);
724 
725   Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global,
726          &return_lookup);
727 
728   BIND(&return_true);
729   exit_point->Return(TrueConstant());
730 
731   BIND(&return_false);
732   exit_point->Return(FalseConstant());
733 
734   BIND(&return_lookup);
735   {
736     CSA_ASSERT(
737         this,
738         Word32Or(
739             WordEqual(handler_kind, IntPtrConstant(LoadHandler::kInterceptor)),
740             Word32Or(
741                 WordEqual(handler_kind, IntPtrConstant(LoadHandler::kProxy)),
742                 WordEqual(handler_kind,
743                           IntPtrConstant(LoadHandler::kModuleExport)))));
744     exit_point->ReturnCallStub(
745         Builtins::CallableFor(isolate(), Builtins::kHasProperty), p->context(),
746         p->receiver(), p->name());
747   }
748 
749   BIND(&normal);
750   {
751     Comment("has_normal");
752     TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(holder)));
753     TVARIABLE(IntPtrT, var_name_index);
754     Label found(this);
755     NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()), &found,
756                                          &var_name_index, miss);
757 
758     BIND(&found);
759     exit_point->Return(TrueConstant());
760   }
761 
762   BIND(&global);
763   {
764     CSA_ASSERT(this, IsPropertyCell(CAST(holder)));
765     // Ensure the property cell doesn't contain the hole.
766     TNode<Object> value =
767         LoadObjectField(CAST(holder), PropertyCell::kValueOffset);
768     GotoIf(IsTheHole(value), miss);
769 
770     exit_point->Return(TrueConstant());
771   }
772 
773   BIND(&slow);
774   {
775     Comment("load_slow");
776     if (ic_mode == ICMode::kGlobalIC) {
777       exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Slow, p->context(),
778                                     p->name(), p->slot(), p->vector());
779     } else {
780       exit_point->ReturnCallRuntime(Runtime::kHasProperty, p->context(),
781                                     p->receiver(), p->name());
782     }
783   }
784 }
785 
786 // Performs actions common to both load and store handlers:
787 // 1. Checks prototype validity cell.
788 // 2. If |on_code_handler| is provided, then it checks if the sub handler is
789 //    a smi or code and if it's a code then it calls |on_code_handler| to
790 //    generate a code that handles Code handlers.
791 //    If |on_code_handler| is not provided, then only smi sub handler are
792 //    expected.
793 // 3. Does access check on lookup start object if
794 //    ICHandler::DoAccessCheckOnLookupStartObjectBits bit is set in the smi
795 //    handler.
796 // 4. Does dictionary lookup on receiver if
797 //    ICHandler::LookupOnLookupStartObjectBits bit is set in the smi handler. If
798 //    |on_found_on_lookup_start_object| is provided then it calls it to
799 //    generate a code that handles the "found on receiver case" or just misses
800 //    if the |on_found_on_lookup_start_object| is not provided.
801 // 5. Falls through in a case of a smi handler which is returned from this
802 //    function (tagged!).
803 // TODO(ishell): Remove templatezation once we move common bits from
804 // Load/StoreHandler to the base class.
805 template <typename ICHandler, typename ICParameters>
HandleProtoHandler(const ICParameters * p,TNode<DataHandler> handler,const OnCodeHandler & on_code_handler,const OnFoundOnLookupStartObject & on_found_on_lookup_start_object,Label * miss,ICMode ic_mode)806 TNode<Object> AccessorAssembler::HandleProtoHandler(
807     const ICParameters* p, TNode<DataHandler> handler,
808     const OnCodeHandler& on_code_handler,
809     const OnFoundOnLookupStartObject& on_found_on_lookup_start_object,
810     Label* miss, ICMode ic_mode) {
811   //
812   // Check prototype validity cell.
813   //
814   {
815     TNode<Object> maybe_validity_cell =
816         LoadObjectField(handler, ICHandler::kValidityCellOffset);
817     CheckPrototypeValidityCell(maybe_validity_cell, miss);
818   }
819 
820   //
821   // Check smi handler bits.
822   //
823   {
824     TNode<Object> smi_or_code_handler =
825         LoadObjectField(handler, ICHandler::kSmiHandlerOffset);
826     if (on_code_handler) {
827       Label if_smi_handler(this);
828       GotoIf(TaggedIsSmi(smi_or_code_handler), &if_smi_handler);
829 
830       on_code_handler(CAST(smi_or_code_handler));
831 
832       BIND(&if_smi_handler);
833     }
834     TNode<IntPtrT> handler_flags = SmiUntag(CAST(smi_or_code_handler));
835 
836     // Lookup on receiver and access checks are not necessary for global ICs
837     // because in the former case the validity cell check guards modifications
838     // of the global object and the latter is not applicable to the global
839     // object.
840     int mask = ICHandler::LookupOnLookupStartObjectBits::kMask |
841                ICHandler::DoAccessCheckOnLookupStartObjectBits::kMask;
842     if (ic_mode == ICMode::kGlobalIC) {
843       CSA_ASSERT(this, IsClearWord(handler_flags, mask));
844     } else {
845       DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
846 
847       Label done(this), if_do_access_check(this),
848           if_lookup_on_lookup_start_object(this);
849       GotoIf(IsClearWord(handler_flags, mask), &done);
850       // Only one of the bits can be set at a time.
851       CSA_ASSERT(this,
852                  WordNotEqual(WordAnd(handler_flags, IntPtrConstant(mask)),
853                               IntPtrConstant(mask)));
854       Branch(
855           IsSetWord<typename ICHandler::DoAccessCheckOnLookupStartObjectBits>(
856               handler_flags),
857           &if_do_access_check, &if_lookup_on_lookup_start_object);
858 
859       BIND(&if_do_access_check);
860       {
861         TNode<MaybeObject> data2 = LoadHandlerDataField(handler, 2);
862         CSA_ASSERT(this, IsWeakOrCleared(data2));
863         TNode<Context> expected_native_context =
864             CAST(GetHeapObjectAssumeWeak(data2, miss));
865         EmitAccessCheck(expected_native_context, p->context(),
866                         p->lookup_start_object(), &done, miss);
867       }
868 
869       BIND(&if_lookup_on_lookup_start_object);
870       {
871         // Dictionary lookup on lookup start object is not necessary for
872         // Load/StoreGlobalIC (which is the only case when the
873         // lookup_start_object can be a JSGlobalObject) because prototype
874         // validity cell check already guards modifications of the global
875         // object.
876         CSA_ASSERT(this,
877                    Word32BinaryNot(HasInstanceType(
878                        CAST(p->lookup_start_object()), JS_GLOBAL_OBJECT_TYPE)));
879 
880         TNode<NameDictionary> properties =
881             CAST(LoadSlowProperties(CAST(p->lookup_start_object())));
882         TVARIABLE(IntPtrT, var_name_index);
883         Label found(this, &var_name_index);
884         NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()),
885                                              &found, &var_name_index, &done);
886         BIND(&found);
887         {
888           if (on_found_on_lookup_start_object) {
889             on_found_on_lookup_start_object(properties, var_name_index.value());
890           } else {
891             Goto(miss);
892           }
893         }
894       }
895 
896       BIND(&done);
897     }
898     return smi_or_code_handler;
899   }
900 }
901 
HandleLoadICProtoHandler(const LazyLoadICParameters * p,TNode<DataHandler> handler,TVariable<Object> * var_holder,TVariable<Object> * var_smi_handler,Label * if_smi_handler,Label * miss,ExitPoint * exit_point,ICMode ic_mode,LoadAccessMode access_mode)902 void AccessorAssembler::HandleLoadICProtoHandler(
903     const LazyLoadICParameters* p, TNode<DataHandler> handler,
904     TVariable<Object>* var_holder, TVariable<Object>* var_smi_handler,
905     Label* if_smi_handler, Label* miss, ExitPoint* exit_point, ICMode ic_mode,
906     LoadAccessMode access_mode) {
907   TNode<Smi> smi_handler = CAST(HandleProtoHandler<LoadHandler>(
908       p, handler,
909       // Code sub-handlers are not expected in LoadICs, so no |on_code_handler|.
910       nullptr,
911       // on_found_on_lookup_start_object
912       [=](TNode<NameDictionary> properties, TNode<IntPtrT> name_index) {
913         if (access_mode == LoadAccessMode::kHas) {
914           exit_point->Return(TrueConstant());
915         } else {
916           TVARIABLE(Uint32T, var_details);
917           TVARIABLE(Object, var_value);
918           LoadPropertyFromNameDictionary(properties, name_index, &var_details,
919                                          &var_value);
920           TNode<Object> value = CallGetterIfAccessor(
921               var_value.value(), CAST(var_holder->value()), var_details.value(),
922               p->context(), p->receiver(), miss);
923           exit_point->Return(value);
924         }
925       },
926       miss, ic_mode));
927 
928   TNode<MaybeObject> maybe_holder_or_constant =
929       LoadHandlerDataField(handler, 1);
930 
931   Label load_from_cached_holder(this), is_smi(this), done(this);
932 
933   GotoIf(TaggedIsSmi(maybe_holder_or_constant), &is_smi);
934   Branch(TaggedEqual(maybe_holder_or_constant, NullConstant()), &done,
935          &load_from_cached_holder);
936 
937   BIND(&is_smi);
938   {
939     CSA_ASSERT(
940         this,
941         WordEqual(
942             Signed(DecodeWord<LoadHandler::KindBits>(SmiUntag(smi_handler))),
943             IntPtrConstant(LoadHandler::kConstantFromPrototype)));
944     if (access_mode == LoadAccessMode::kHas) {
945       exit_point->Return(TrueConstant());
946     } else {
947       exit_point->Return(CAST(maybe_holder_or_constant));
948     }
949   }
950 
951   BIND(&load_from_cached_holder);
952   {
953     // For regular holders, having passed the receiver map check and
954     // the validity cell check implies that |holder| is
955     // alive. However, for global object receivers, |maybe_holder| may
956     // be cleared.
957     CSA_ASSERT(this, IsWeakOrCleared(maybe_holder_or_constant));
958     TNode<HeapObject> holder =
959         GetHeapObjectAssumeWeak(maybe_holder_or_constant, miss);
960     *var_holder = holder;
961     Goto(&done);
962   }
963 
964   BIND(&done);
965   {
966     *var_smi_handler = smi_handler;
967     Goto(if_smi_handler);
968   }
969 }
970 
EmitAccessCheck(TNode<Context> expected_native_context,TNode<Context> context,TNode<Object> receiver,Label * can_access,Label * miss)971 void AccessorAssembler::EmitAccessCheck(TNode<Context> expected_native_context,
972                                         TNode<Context> context,
973                                         TNode<Object> receiver,
974                                         Label* can_access, Label* miss) {
975   CSA_ASSERT(this, IsNativeContext(expected_native_context));
976 
977   TNode<NativeContext> native_context = LoadNativeContext(context);
978   GotoIf(TaggedEqual(expected_native_context, native_context), can_access);
979   // If the receiver is not a JSGlobalProxy then we miss.
980   GotoIfNot(IsJSGlobalProxy(CAST(receiver)), miss);
981   // For JSGlobalProxy receiver try to compare security tokens of current
982   // and expected native contexts.
983   TNode<Object> expected_token = LoadContextElement(
984       expected_native_context, Context::SECURITY_TOKEN_INDEX);
985   TNode<Object> current_token =
986       LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
987   Branch(TaggedEqual(expected_token, current_token), can_access, miss);
988 }
989 
JumpIfDataProperty(TNode<Uint32T> details,Label * writable,Label * readonly)990 void AccessorAssembler::JumpIfDataProperty(TNode<Uint32T> details,
991                                            Label* writable, Label* readonly) {
992   if (readonly) {
993     // Accessor properties never have the READ_ONLY attribute set.
994     GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
995            readonly);
996   } else {
997     CSA_ASSERT(this, IsNotSetWord32(details,
998                                     PropertyDetails::kAttributesReadOnlyMask));
999   }
1000   TNode<Uint32T> kind = DecodeWord32<PropertyDetails::KindField>(details);
1001   GotoIf(Word32Equal(kind, Int32Constant(kData)), writable);
1002   // Fall through if it's an accessor property.
1003 }
1004 
HandleStoreICNativeDataProperty(const StoreICParameters * p,TNode<HeapObject> holder,TNode<Word32T> handler_word)1005 void AccessorAssembler::HandleStoreICNativeDataProperty(
1006     const StoreICParameters* p, TNode<HeapObject> holder,
1007     TNode<Word32T> handler_word) {
1008   Comment("native_data_property_store");
1009   TNode<IntPtrT> descriptor =
1010       Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
1011   TNode<AccessorInfo> accessor_info =
1012       CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
1013 
1014   TailCallRuntime(Runtime::kStoreCallbackProperty, p->context(), p->receiver(),
1015                   holder, accessor_info, p->name(), p->value());
1016 }
1017 
HandleStoreICHandlerCase(const StoreICParameters * p,TNode<MaybeObject> handler,Label * miss,ICMode ic_mode,ElementSupport support_elements)1018 void AccessorAssembler::HandleStoreICHandlerCase(
1019     const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
1020     ICMode ic_mode, ElementSupport support_elements) {
1021   Label if_smi_handler(this), if_nonsmi_handler(this);
1022   Label if_proto_handler(this), call_handler(this),
1023       store_transition_or_global(this);
1024 
1025   Branch(TaggedIsSmi(handler), &if_smi_handler, &if_nonsmi_handler);
1026 
1027   // |handler| is a Smi, encoding what to do. See SmiHandler methods
1028   // for the encoding format.
1029   BIND(&if_smi_handler);
1030   {
1031     TNode<Object> holder = p->receiver();
1032     TNode<Int32T> handler_word = SmiToInt32(CAST(handler));
1033 
1034     Label if_fast_smi(this), if_proxy(this), if_interceptor(this),
1035         if_slow(this);
1036 
1037     STATIC_ASSERT(StoreHandler::kGlobalProxy + 1 == StoreHandler::kNormal);
1038     STATIC_ASSERT(StoreHandler::kNormal + 1 == StoreHandler::kInterceptor);
1039     STATIC_ASSERT(StoreHandler::kInterceptor + 1 == StoreHandler::kSlow);
1040     STATIC_ASSERT(StoreHandler::kSlow + 1 == StoreHandler::kProxy);
1041     STATIC_ASSERT(StoreHandler::kProxy + 1 == StoreHandler::kKindsNumber);
1042 
1043     TNode<Uint32T> handler_kind =
1044         DecodeWord32<StoreHandler::KindBits>(handler_word);
1045     GotoIf(
1046         Int32LessThan(handler_kind, Int32Constant(StoreHandler::kGlobalProxy)),
1047         &if_fast_smi);
1048     GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kProxy)),
1049            &if_proxy);
1050     GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kInterceptor)),
1051            &if_interceptor);
1052     GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kSlow)),
1053            &if_slow);
1054     CSA_ASSERT(this,
1055                Word32Equal(handler_kind, Int32Constant(StoreHandler::kNormal)));
1056     TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(holder)));
1057 
1058     TVARIABLE(IntPtrT, var_name_index);
1059     Label dictionary_found(this, &var_name_index);
1060     NameDictionaryLookup<NameDictionary>(
1061         properties, CAST(p->name()), &dictionary_found, &var_name_index, miss);
1062     BIND(&dictionary_found);
1063     {
1064       TNode<Uint32T> details =
1065           LoadDetailsByKeyIndex(properties, var_name_index.value());
1066       // Check that the property is a writable data property (no accessor).
1067       const int kTypeAndReadOnlyMask = PropertyDetails::KindField::kMask |
1068                                        PropertyDetails::kAttributesReadOnlyMask;
1069       STATIC_ASSERT(kData == 0);
1070       GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
1071 
1072       StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
1073                                            p->value());
1074       Return(p->value());
1075     }
1076 
1077     BIND(&if_fast_smi);
1078     {
1079       TNode<Uint32T> handler_kind =
1080           DecodeWord32<StoreHandler::KindBits>(handler_word);
1081 
1082       Label data(this), accessor(this), native_data_property(this);
1083       GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kAccessor)),
1084              &accessor);
1085       Branch(Word32Equal(handler_kind,
1086                          Int32Constant(StoreHandler::kNativeDataProperty)),
1087              &native_data_property, &data);
1088 
1089       BIND(&accessor);
1090       HandleStoreAccessor(p, CAST(holder), handler_word);
1091 
1092       BIND(&native_data_property);
1093       HandleStoreICNativeDataProperty(p, CAST(holder), handler_word);
1094 
1095       BIND(&data);
1096       // Handle non-transitioning field stores.
1097       HandleStoreICSmiHandlerCase(handler_word, CAST(holder), p->value(), miss);
1098     }
1099 
1100     BIND(&if_proxy);
1101     HandleStoreToProxy(p, CAST(holder), miss, support_elements);
1102 
1103     BIND(&if_interceptor);
1104     {
1105       Comment("store_interceptor");
1106       TailCallRuntime(Runtime::kStorePropertyWithInterceptor, p->context(),
1107                       p->value(), p->receiver(), p->name());
1108     }
1109 
1110     BIND(&if_slow);
1111     {
1112       Comment("store_slow");
1113       // The slow case calls into the runtime to complete the store without
1114       // causing an IC miss that would otherwise cause a transition to the
1115       // generic stub.
1116       if (ic_mode == ICMode::kGlobalIC) {
1117         TailCallRuntime(Runtime::kStoreGlobalIC_Slow, p->context(), p->value(),
1118                         p->slot(), p->vector(), p->receiver(), p->name());
1119       } else {
1120         TailCallRuntime(Runtime::kKeyedStoreIC_Slow, p->context(), p->value(),
1121                         p->receiver(), p->name());
1122       }
1123     }
1124   }
1125 
1126   BIND(&if_nonsmi_handler);
1127   {
1128     GotoIf(IsWeakOrCleared(handler), &store_transition_or_global);
1129     TNode<HeapObject> strong_handler = CAST(handler);
1130     TNode<Map> handler_map = LoadMap(strong_handler);
1131     Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler);
1132 
1133     BIND(&if_proto_handler);
1134     {
1135       HandleStoreICProtoHandler(p, CAST(strong_handler), miss, ic_mode,
1136                                 support_elements);
1137     }
1138 
1139     // |handler| is a heap object. Must be code, call it.
1140     BIND(&call_handler);
1141     {
1142       TailCallStub(StoreWithVectorDescriptor{}, CAST(strong_handler),
1143                    p->context(), p->receiver(), p->name(), p->value(),
1144                    p->slot(), p->vector());
1145     }
1146   }
1147 
1148   BIND(&store_transition_or_global);
1149   {
1150     // Load value or miss if the {handler} weak cell is cleared.
1151     CSA_ASSERT(this, IsWeakOrCleared(handler));
1152     TNode<HeapObject> map_or_property_cell =
1153         GetHeapObjectAssumeWeak(handler, miss);
1154 
1155     Label store_global(this), store_transition(this);
1156     Branch(IsMap(map_or_property_cell), &store_transition, &store_global);
1157 
1158     BIND(&store_global);
1159     {
1160       TNode<PropertyCell> property_cell = CAST(map_or_property_cell);
1161       ExitPoint direct_exit(this);
1162       StoreGlobalIC_PropertyCellCase(property_cell, p->value(), &direct_exit,
1163                                      miss);
1164     }
1165     BIND(&store_transition);
1166     {
1167       TNode<Map> map = CAST(map_or_property_cell);
1168       HandleStoreICTransitionMapHandlerCase(p, map, miss,
1169                                             kCheckPrototypeValidity);
1170       Return(p->value());
1171     }
1172   }
1173 }
1174 
HandleStoreICTransitionMapHandlerCase(const StoreICParameters * p,TNode<Map> transition_map,Label * miss,StoreTransitionMapFlags flags)1175 void AccessorAssembler::HandleStoreICTransitionMapHandlerCase(
1176     const StoreICParameters* p, TNode<Map> transition_map, Label* miss,
1177     StoreTransitionMapFlags flags) {
1178   DCHECK_EQ(0, flags & ~kStoreTransitionMapFlagsMask);
1179   if (flags & kCheckPrototypeValidity) {
1180     TNode<Object> maybe_validity_cell =
1181         LoadObjectField(transition_map, Map::kPrototypeValidityCellOffset);
1182     CheckPrototypeValidityCell(maybe_validity_cell, miss);
1183   }
1184 
1185   TNode<Uint32T> bitfield3 = LoadMapBitField3(transition_map);
1186   CSA_ASSERT(this, IsClearWord32<Map::Bits3::IsDictionaryMapBit>(bitfield3));
1187   GotoIf(IsSetWord32<Map::Bits3::IsDeprecatedBit>(bitfield3), miss);
1188 
1189   // Load last descriptor details.
1190   TNode<UintPtrT> nof =
1191       DecodeWordFromWord32<Map::Bits3::NumberOfOwnDescriptorsBits>(bitfield3);
1192   CSA_ASSERT(this, WordNotEqual(nof, IntPtrConstant(0)));
1193   TNode<DescriptorArray> descriptors = LoadMapDescriptors(transition_map);
1194 
1195   TNode<IntPtrT> factor = IntPtrConstant(DescriptorArray::kEntrySize);
1196   TNode<IntPtrT> last_key_index = UncheckedCast<IntPtrT>(IntPtrAdd(
1197       IntPtrConstant(DescriptorArray::ToKeyIndex(-1)), IntPtrMul(nof, factor)));
1198   if (flags & kValidateTransitionHandler) {
1199     TNode<Name> key = LoadKeyByKeyIndex(descriptors, last_key_index);
1200     GotoIf(TaggedNotEqual(key, p->name()), miss);
1201   } else {
1202     CSA_ASSERT(this, TaggedEqual(LoadKeyByKeyIndex(descriptors, last_key_index),
1203                                  p->name()));
1204   }
1205   TNode<Uint32T> details = LoadDetailsByKeyIndex(descriptors, last_key_index);
1206   if (flags & kValidateTransitionHandler) {
1207     // Follow transitions only in the following cases:
1208     // 1) name is a non-private symbol and attributes equal to NONE,
1209     // 2) name is a private symbol and attributes equal to DONT_ENUM.
1210     Label attributes_ok(this);
1211     const int kKindAndAttributesDontDeleteReadOnlyMask =
1212         PropertyDetails::KindField::kMask |
1213         PropertyDetails::kAttributesDontDeleteMask |
1214         PropertyDetails::kAttributesReadOnlyMask;
1215     STATIC_ASSERT(kData == 0);
1216     // Both DontDelete and ReadOnly attributes must not be set and it has to be
1217     // a kData property.
1218     GotoIf(IsSetWord32(details, kKindAndAttributesDontDeleteReadOnlyMask),
1219            miss);
1220 
1221     // DontEnum attribute is allowed only for private symbols and vice versa.
1222     Branch(Word32Equal(
1223                IsSetWord32(details, PropertyDetails::kAttributesDontEnumMask),
1224                IsPrivateSymbol(CAST(p->name()))),
1225            &attributes_ok, miss);
1226 
1227     BIND(&attributes_ok);
1228   }
1229 
1230   OverwriteExistingFastDataProperty(CAST(p->receiver()), transition_map,
1231                                     descriptors, last_key_index, details,
1232                                     p->value(), miss, true);
1233 }
1234 
CheckFieldType(TNode<DescriptorArray> descriptors,TNode<IntPtrT> name_index,TNode<Word32T> representation,TNode<Object> value,Label * bailout)1235 void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors,
1236                                        TNode<IntPtrT> name_index,
1237                                        TNode<Word32T> representation,
1238                                        TNode<Object> value, Label* bailout) {
1239   Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this);
1240   // Ignore FLAG_track_fields etc. and always emit code for all checks,
1241   // because this builtin is part of the snapshot and therefore should
1242   // be flag independent.
1243   GotoIf(Word32Equal(representation, Int32Constant(Representation::kSmi)),
1244          &r_smi);
1245   GotoIf(Word32Equal(representation, Int32Constant(Representation::kDouble)),
1246          &r_double);
1247   GotoIf(
1248       Word32Equal(representation, Int32Constant(Representation::kHeapObject)),
1249       &r_heapobject);
1250   GotoIf(Word32Equal(representation, Int32Constant(Representation::kNone)),
1251          bailout);
1252   CSA_ASSERT(this, Word32Equal(representation,
1253                                Int32Constant(Representation::kTagged)));
1254   Goto(&all_fine);
1255 
1256   BIND(&r_smi);
1257   { Branch(TaggedIsSmi(value), &all_fine, bailout); }
1258 
1259   BIND(&r_double);
1260   {
1261     GotoIf(TaggedIsSmi(value), &all_fine);
1262     Branch(IsHeapNumber(CAST(value)), &all_fine, bailout);
1263   }
1264 
1265   BIND(&r_heapobject);
1266   {
1267     GotoIf(TaggedIsSmi(value), bailout);
1268     TNode<MaybeObject> field_type =
1269         LoadFieldTypeByKeyIndex(descriptors, name_index);
1270     const Address kNoneType = FieldType::None().ptr();
1271     const Address kAnyType = FieldType::Any().ptr();
1272     DCHECK_NE(static_cast<uint32_t>(kNoneType), kClearedWeakHeapObjectLower32);
1273     DCHECK_NE(static_cast<uint32_t>(kAnyType), kClearedWeakHeapObjectLower32);
1274     // FieldType::None can't hold any value.
1275     GotoIf(
1276         TaggedEqual(field_type, BitcastWordToTagged(IntPtrConstant(kNoneType))),
1277         bailout);
1278     // FieldType::Any can hold any value.
1279     GotoIf(
1280         TaggedEqual(field_type, BitcastWordToTagged(IntPtrConstant(kAnyType))),
1281         &all_fine);
1282     // Cleared weak references count as FieldType::None, which can't hold any
1283     // value.
1284     TNode<Map> field_type_map =
1285         CAST(GetHeapObjectAssumeWeak(field_type, bailout));
1286     // FieldType::Class(...) performs a map check.
1287     Branch(TaggedEqual(LoadMap(CAST(value)), field_type_map), &all_fine,
1288            bailout);
1289   }
1290 
1291   BIND(&all_fine);
1292 }
1293 
IsPropertyDetailsConst(TNode<Uint32T> details)1294 TNode<BoolT> AccessorAssembler::IsPropertyDetailsConst(TNode<Uint32T> details) {
1295   return Word32Equal(DecodeWord32<PropertyDetails::ConstnessField>(details),
1296                      Int32Constant(static_cast<int32_t>(VariableMode::kConst)));
1297 }
1298 
OverwriteExistingFastDataProperty(TNode<HeapObject> object,TNode<Map> object_map,TNode<DescriptorArray> descriptors,TNode<IntPtrT> descriptor_name_index,TNode<Uint32T> details,TNode<Object> value,Label * slow,bool do_transitioning_store)1299 void AccessorAssembler::OverwriteExistingFastDataProperty(
1300     TNode<HeapObject> object, TNode<Map> object_map,
1301     TNode<DescriptorArray> descriptors, TNode<IntPtrT> descriptor_name_index,
1302     TNode<Uint32T> details, TNode<Object> value, Label* slow,
1303     bool do_transitioning_store) {
1304   Label done(this), if_field(this), if_descriptor(this);
1305 
1306   CSA_ASSERT(this,
1307              Word32Equal(DecodeWord32<PropertyDetails::KindField>(details),
1308                          Int32Constant(kData)));
1309 
1310   Branch(Word32Equal(DecodeWord32<PropertyDetails::LocationField>(details),
1311                      Int32Constant(kField)),
1312          &if_field, &if_descriptor);
1313 
1314   BIND(&if_field);
1315   {
1316     TNode<Uint32T> representation =
1317         DecodeWord32<PropertyDetails::RepresentationField>(details);
1318 
1319     CheckFieldType(descriptors, descriptor_name_index, representation, value,
1320                    slow);
1321 
1322     TNode<UintPtrT> field_index =
1323         DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
1324     field_index = Unsigned(
1325         IntPtrAdd(field_index,
1326                   Unsigned(LoadMapInobjectPropertiesStartInWords(object_map))));
1327     TNode<IntPtrT> instance_size_in_words =
1328         LoadMapInstanceSizeInWords(object_map);
1329 
1330     Label inobject(this), backing_store(this);
1331     Branch(UintPtrLessThan(field_index, instance_size_in_words), &inobject,
1332            &backing_store);
1333 
1334     BIND(&inobject);
1335     {
1336       TNode<IntPtrT> field_offset = Signed(TimesTaggedSize(field_index));
1337       Label tagged_rep(this), double_rep(this);
1338       Branch(
1339           Word32Equal(representation, Int32Constant(Representation::kDouble)),
1340           &double_rep, &tagged_rep);
1341       BIND(&double_rep);
1342       {
1343         TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value));
1344         if (FLAG_unbox_double_fields) {
1345           if (do_transitioning_store) {
1346             StoreMap(object, object_map);
1347           } else {
1348             Label store_value(this);
1349             GotoIfNot(IsPropertyDetailsConst(details), &store_value);
1350             TNode<Float64T> current_value =
1351                 LoadObjectField<Float64T>(object, field_offset);
1352             BranchIfSameNumberValue(current_value, double_value, &store_value,
1353                                     slow);
1354             BIND(&store_value);
1355           }
1356           StoreObjectFieldNoWriteBarrier(object, field_offset, double_value);
1357         } else {
1358           if (do_transitioning_store) {
1359             TNode<HeapNumber> heap_number =
1360                 AllocateHeapNumberWithValue(double_value);
1361             StoreMap(object, object_map);
1362             StoreObjectField(object, field_offset, heap_number);
1363           } else {
1364             TNode<HeapNumber> heap_number =
1365                 CAST(LoadObjectField(object, field_offset));
1366             Label store_value(this);
1367             GotoIfNot(IsPropertyDetailsConst(details), &store_value);
1368             TNode<Float64T> current_value = LoadHeapNumberValue(heap_number);
1369             BranchIfSameNumberValue(current_value, double_value, &store_value,
1370                                     slow);
1371             BIND(&store_value);
1372             StoreHeapNumberValue(heap_number, double_value);
1373           }
1374         }
1375         Goto(&done);
1376       }
1377 
1378       BIND(&tagged_rep);
1379       {
1380         if (do_transitioning_store) {
1381           StoreMap(object, object_map);
1382         } else {
1383           Label if_mutable(this);
1384           GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
1385           TNode<Object> current_value = LoadObjectField(object, field_offset);
1386           BranchIfSameValue(current_value, value, &done, slow,
1387                             SameValueMode::kNumbersOnly);
1388           BIND(&if_mutable);
1389         }
1390         StoreObjectField(object, field_offset, value);
1391         Goto(&done);
1392       }
1393     }
1394 
1395     BIND(&backing_store);
1396     {
1397       TNode<IntPtrT> backing_store_index =
1398           Signed(IntPtrSub(field_index, instance_size_in_words));
1399 
1400       if (do_transitioning_store) {
1401         // Allocate mutable heap number before extending properties backing
1402         // store to ensure that heap verifier will not see the heap in
1403         // inconsistent state.
1404         TVARIABLE(Object, var_value, value);
1405         {
1406           Label cont(this);
1407           GotoIf(Word32NotEqual(representation,
1408                                 Int32Constant(Representation::kDouble)),
1409                  &cont);
1410           {
1411             TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value));
1412             TNode<HeapNumber> heap_number =
1413                 AllocateHeapNumberWithValue(double_value);
1414             var_value = heap_number;
1415             Goto(&cont);
1416           }
1417           BIND(&cont);
1418         }
1419 
1420         TNode<PropertyArray> properties =
1421             ExtendPropertiesBackingStore(object, backing_store_index);
1422         StorePropertyArrayElement(properties, backing_store_index,
1423                                   var_value.value());
1424         StoreMap(object, object_map);
1425         Goto(&done);
1426 
1427       } else {
1428         Label tagged_rep(this), double_rep(this);
1429         TNode<PropertyArray> properties =
1430             CAST(LoadFastProperties(CAST(object)));
1431         Branch(
1432             Word32Equal(representation, Int32Constant(Representation::kDouble)),
1433             &double_rep, &tagged_rep);
1434         BIND(&double_rep);
1435         {
1436           TNode<HeapNumber> heap_number =
1437               CAST(LoadPropertyArrayElement(properties, backing_store_index));
1438           TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value));
1439 
1440           Label if_mutable(this);
1441           GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
1442           TNode<Float64T> current_value = LoadHeapNumberValue(heap_number);
1443           BranchIfSameNumberValue(current_value, double_value, &done, slow);
1444 
1445           BIND(&if_mutable);
1446           StoreHeapNumberValue(heap_number, double_value);
1447           Goto(&done);
1448         }
1449         BIND(&tagged_rep);
1450         {
1451           Label if_mutable(this);
1452           GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
1453           TNode<Object> current_value =
1454               LoadPropertyArrayElement(properties, backing_store_index);
1455           BranchIfSameValue(current_value, value, &done, slow,
1456                             SameValueMode::kNumbersOnly);
1457 
1458           BIND(&if_mutable);
1459           StorePropertyArrayElement(properties, backing_store_index, value);
1460           Goto(&done);
1461         }
1462       }
1463     }
1464   }
1465 
1466   BIND(&if_descriptor);
1467   {
1468     // Check that constant matches value.
1469     TNode<Object> constant =
1470         LoadValueByKeyIndex(descriptors, descriptor_name_index);
1471     GotoIf(TaggedNotEqual(value, constant), slow);
1472 
1473     if (do_transitioning_store) {
1474       StoreMap(object, object_map);
1475     }
1476     Goto(&done);
1477   }
1478   BIND(&done);
1479 }
1480 
CheckPrototypeValidityCell(TNode<Object> maybe_validity_cell,Label * miss)1481 void AccessorAssembler::CheckPrototypeValidityCell(
1482     TNode<Object> maybe_validity_cell, Label* miss) {
1483   Label done(this);
1484   GotoIf(
1485       TaggedEqual(maybe_validity_cell, SmiConstant(Map::kPrototypeChainValid)),
1486       &done);
1487   CSA_ASSERT(this, TaggedIsNotSmi(maybe_validity_cell));
1488 
1489   TNode<Object> cell_value =
1490       LoadObjectField(CAST(maybe_validity_cell), Cell::kValueOffset);
1491   Branch(TaggedEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)), &done,
1492          miss);
1493 
1494   BIND(&done);
1495 }
1496 
HandleStoreAccessor(const StoreICParameters * p,TNode<HeapObject> holder,TNode<Word32T> handler_word)1497 void AccessorAssembler::HandleStoreAccessor(const StoreICParameters* p,
1498                                             TNode<HeapObject> holder,
1499                                             TNode<Word32T> handler_word) {
1500   Comment("accessor_store");
1501   TNode<IntPtrT> descriptor =
1502       Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
1503   TNode<HeapObject> accessor_pair =
1504       CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
1505   CSA_ASSERT(this, IsAccessorPair(accessor_pair));
1506   TNode<Object> setter =
1507       LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
1508   CSA_ASSERT(this, Word32BinaryNot(IsTheHole(setter)));
1509 
1510   Callable callable = CodeFactory::Call(isolate());
1511   Return(Call(p->context(), setter, p->receiver(), p->value()));
1512 }
1513 
HandleStoreICProtoHandler(const StoreICParameters * p,TNode<StoreHandler> handler,Label * miss,ICMode ic_mode,ElementSupport support_elements)1514 void AccessorAssembler::HandleStoreICProtoHandler(
1515     const StoreICParameters* p, TNode<StoreHandler> handler, Label* miss,
1516     ICMode ic_mode, ElementSupport support_elements) {
1517   Comment("HandleStoreICProtoHandler");
1518 
1519   OnCodeHandler on_code_handler;
1520   if (support_elements == kSupportElements) {
1521     // Code sub-handlers are expected only in KeyedStoreICs.
1522     on_code_handler = [=](TNode<Code> code_handler) {
1523       // This is either element store or transitioning element store.
1524       Label if_element_store(this), if_transitioning_element_store(this);
1525       Branch(IsStoreHandler0Map(LoadMap(handler)), &if_element_store,
1526              &if_transitioning_element_store);
1527       BIND(&if_element_store);
1528       {
1529         TailCallStub(StoreWithVectorDescriptor{}, code_handler, p->context(),
1530                      p->receiver(), p->name(), p->value(), p->slot(),
1531                      p->vector());
1532       }
1533 
1534       BIND(&if_transitioning_element_store);
1535       {
1536         TNode<MaybeObject> maybe_transition_map =
1537             LoadHandlerDataField(handler, 1);
1538         TNode<Map> transition_map =
1539             CAST(GetHeapObjectAssumeWeak(maybe_transition_map, miss));
1540 
1541         GotoIf(IsDeprecatedMap(transition_map), miss);
1542 
1543         TailCallStub(StoreTransitionDescriptor{}, code_handler, p->context(),
1544                      p->receiver(), p->name(), transition_map, p->value(),
1545                      p->slot(), p->vector());
1546       }
1547     };
1548   }
1549 
1550   TNode<Object> smi_handler = HandleProtoHandler<StoreHandler>(
1551       p, handler, on_code_handler,
1552       // on_found_on_lookup_start_object
1553       [=](TNode<NameDictionary> properties, TNode<IntPtrT> name_index) {
1554         TNode<Uint32T> details = LoadDetailsByKeyIndex(properties, name_index);
1555         // Check that the property is a writable data property (no accessor).
1556         const int kTypeAndReadOnlyMask =
1557             PropertyDetails::KindField::kMask |
1558             PropertyDetails::kAttributesReadOnlyMask;
1559         STATIC_ASSERT(kData == 0);
1560         GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
1561 
1562         StoreValueByKeyIndex<NameDictionary>(properties, name_index,
1563                                              p->value());
1564         Return(p->value());
1565       },
1566       miss, ic_mode);
1567 
1568   {
1569     Label if_add_normal(this), if_store_global_proxy(this), if_api_setter(this),
1570         if_accessor(this), if_native_data_property(this), if_slow(this);
1571 
1572     CSA_ASSERT(this, TaggedIsSmi(smi_handler));
1573     TNode<Int32T> handler_word = SmiToInt32(CAST(smi_handler));
1574 
1575     TNode<Uint32T> handler_kind =
1576         DecodeWord32<StoreHandler::KindBits>(handler_word);
1577     GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kNormal)),
1578            &if_add_normal);
1579 
1580     GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kSlow)),
1581            &if_slow);
1582 
1583     TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
1584     CSA_ASSERT(this, IsWeakOrCleared(maybe_holder));
1585     TNode<HeapObject> holder = GetHeapObjectAssumeWeak(maybe_holder, miss);
1586 
1587     GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kGlobalProxy)),
1588            &if_store_global_proxy);
1589 
1590     GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kAccessor)),
1591            &if_accessor);
1592 
1593     GotoIf(Word32Equal(handler_kind,
1594                        Int32Constant(StoreHandler::kNativeDataProperty)),
1595            &if_native_data_property);
1596 
1597     GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kApiSetter)),
1598            &if_api_setter);
1599 
1600     GotoIf(
1601         Word32Equal(handler_kind,
1602                     Int32Constant(StoreHandler::kApiSetterHolderIsPrototype)),
1603         &if_api_setter);
1604 
1605     CSA_ASSERT(this,
1606                Word32Equal(handler_kind, Int32Constant(StoreHandler::kProxy)));
1607     HandleStoreToProxy(p, CAST(holder), miss, support_elements);
1608 
1609     BIND(&if_slow);
1610     {
1611       Comment("store_slow");
1612       // The slow case calls into the runtime to complete the store without
1613       // causing an IC miss that would otherwise cause a transition to the
1614       // generic stub.
1615       if (ic_mode == ICMode::kGlobalIC) {
1616         TailCallRuntime(Runtime::kStoreGlobalIC_Slow, p->context(), p->value(),
1617                         p->slot(), p->vector(), p->receiver(), p->name());
1618       } else {
1619         TailCallRuntime(Runtime::kKeyedStoreIC_Slow, p->context(), p->value(),
1620                         p->receiver(), p->name());
1621       }
1622     }
1623 
1624     BIND(&if_add_normal);
1625     {
1626       // This is a case of "transitioning store" to a dictionary mode object
1627       // when the property does not exist. The "existing property" case is
1628       // covered above by LookupOnLookupStartObject bit handling of the smi
1629       // handler.
1630       Label slow(this);
1631       TNode<Map> receiver_map = LoadMap(CAST(p->receiver()));
1632       InvalidateValidityCellIfPrototype(receiver_map);
1633 
1634       TNode<NameDictionary> properties =
1635           CAST(LoadSlowProperties(CAST(p->receiver())));
1636       Add<NameDictionary>(properties, CAST(p->name()), p->value(), &slow);
1637       Return(p->value());
1638 
1639       BIND(&slow);
1640       TailCallRuntime(Runtime::kAddDictionaryProperty, p->context(),
1641                       p->receiver(), p->name(), p->value());
1642     }
1643 
1644     BIND(&if_accessor);
1645     HandleStoreAccessor(p, holder, handler_word);
1646 
1647     BIND(&if_native_data_property);
1648     HandleStoreICNativeDataProperty(p, holder, handler_word);
1649 
1650     BIND(&if_api_setter);
1651     {
1652       Comment("api_setter");
1653       CSA_ASSERT(this, TaggedIsNotSmi(handler));
1654       TNode<CallHandlerInfo> call_handler_info = CAST(holder);
1655 
1656       // Context is stored either in data2 or data3 field depending on whether
1657       // the access check is enabled for this handler or not.
1658       TNode<MaybeObject> maybe_context = Select<MaybeObject>(
1659           IsSetWord32<StoreHandler::DoAccessCheckOnLookupStartObjectBits>(
1660               handler_word),
1661           [=] { return LoadHandlerDataField(handler, 3); },
1662           [=] { return LoadHandlerDataField(handler, 2); });
1663 
1664       CSA_ASSERT(this, IsWeakOrCleared(maybe_context));
1665       TNode<Object> context = Select<Object>(
1666           IsCleared(maybe_context), [=] { return SmiConstant(0); },
1667           [=] { return GetHeapObjectAssumeWeak(maybe_context); });
1668 
1669       TNode<Foreign> foreign = LoadObjectField<Foreign>(
1670           call_handler_info, CallHandlerInfo::kJsCallbackOffset);
1671       TNode<RawPtrT> callback = LoadForeignForeignAddressPtr(foreign);
1672       TNode<Object> data =
1673           LoadObjectField(call_handler_info, CallHandlerInfo::kDataOffset);
1674 
1675       TVARIABLE(Object, api_holder, p->receiver());
1676       Label store(this);
1677       GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kApiSetter)),
1678              &store);
1679 
1680       CSA_ASSERT(this,
1681                  Word32Equal(
1682                      handler_kind,
1683                      Int32Constant(StoreHandler::kApiSetterHolderIsPrototype)));
1684 
1685       api_holder = LoadMapPrototype(LoadMap(CAST(p->receiver())));
1686       Goto(&store);
1687 
1688       BIND(&store);
1689       TNode<IntPtrT> argc = IntPtrConstant(1);
1690       Return(CallApiCallback(context, callback, argc, data, api_holder.value(),
1691                              p->receiver(), p->value()));
1692     }
1693 
1694     BIND(&if_store_global_proxy);
1695     {
1696       ExitPoint direct_exit(this);
1697       StoreGlobalIC_PropertyCellCase(CAST(holder), p->value(), &direct_exit,
1698                                      miss);
1699     }
1700   }
1701 }
1702 
HandleStoreToProxy(const StoreICParameters * p,TNode<JSProxy> proxy,Label * miss,ElementSupport support_elements)1703 void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
1704                                            TNode<JSProxy> proxy, Label* miss,
1705                                            ElementSupport support_elements) {
1706   TVARIABLE(IntPtrT, var_index);
1707   TVARIABLE(Name, var_unique);
1708 
1709   Label if_index(this), if_unique_name(this),
1710       to_name_failed(this, Label::kDeferred);
1711 
1712   if (support_elements == kSupportElements) {
1713     TryToName(p->name(), &if_index, &var_index, &if_unique_name, &var_unique,
1714               &to_name_failed);
1715 
1716     BIND(&if_unique_name);
1717     CallBuiltin(Builtins::kProxySetProperty, p->context(), proxy,
1718                 var_unique.value(), p->value(), p->receiver());
1719     Return(p->value());
1720 
1721     // The index case is handled earlier by the runtime.
1722     BIND(&if_index);
1723     // TODO(mslekova): introduce TryToName that doesn't try to compute
1724     // the intptr index value
1725     Goto(&to_name_failed);
1726 
1727     BIND(&to_name_failed);
1728     TailCallRuntime(Runtime::kSetPropertyWithReceiver, p->context(), proxy,
1729                     p->name(), p->value(), p->receiver());
1730   } else {
1731     TNode<Object> name =
1732         CallBuiltin(Builtins::kToName, p->context(), p->name());
1733     TailCallBuiltin(Builtins::kProxySetProperty, p->context(), proxy, name,
1734                     p->value(), p->receiver());
1735   }
1736 }
1737 
HandleStoreICSmiHandlerCase(TNode<Word32T> handler_word,TNode<JSObject> holder,TNode<Object> value,Label * miss)1738 void AccessorAssembler::HandleStoreICSmiHandlerCase(TNode<Word32T> handler_word,
1739                                                     TNode<JSObject> holder,
1740                                                     TNode<Object> value,
1741                                                     Label* miss) {
1742   Comment("field store");
1743 #ifdef DEBUG
1744   TNode<Uint32T> handler_kind =
1745       DecodeWord32<StoreHandler::KindBits>(handler_word);
1746   CSA_ASSERT(
1747       this,
1748       Word32Or(
1749           Word32Equal(handler_kind, Int32Constant(StoreHandler::kField)),
1750           Word32Equal(handler_kind, Int32Constant(StoreHandler::kConstField))));
1751 #endif
1752 
1753   TNode<Uint32T> field_representation =
1754       DecodeWord32<StoreHandler::RepresentationBits>(handler_word);
1755 
1756   Label if_smi_field(this), if_double_field(this), if_heap_object_field(this),
1757       if_tagged_field(this);
1758 
1759   int32_t case_values[] = {Representation::kTagged, Representation::kHeapObject,
1760                            Representation::kSmi};
1761   Label* case_labels[] = {&if_tagged_field, &if_heap_object_field,
1762                           &if_smi_field};
1763 
1764   Switch(field_representation, &if_double_field, case_values, case_labels, 3);
1765 
1766   BIND(&if_tagged_field);
1767   {
1768     Comment("store tagged field");
1769     HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt,
1770                               Representation::Tagged(), miss);
1771   }
1772 
1773   BIND(&if_heap_object_field);
1774   {
1775     Comment("heap object field checks");
1776     CheckHeapObjectTypeMatchesDescriptor(handler_word, holder, value, miss);
1777 
1778     Comment("store heap object field");
1779     HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt,
1780                               Representation::HeapObject(), miss);
1781   }
1782 
1783   BIND(&if_smi_field);
1784   {
1785     Comment("smi field checks");
1786     GotoIfNot(TaggedIsSmi(value), miss);
1787 
1788     Comment("store smi field");
1789     HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt,
1790                               Representation::Smi(), miss);
1791   }
1792 
1793   BIND(&if_double_field);
1794   {
1795     CSA_ASSERT(this, Word32Equal(field_representation,
1796                                  Int32Constant(Representation::kDouble)));
1797     Comment("double field checks");
1798     TNode<Float64T> double_value = TryTaggedToFloat64(value, miss);
1799     CheckDescriptorConsidersNumbersMutable(handler_word, holder, miss);
1800 
1801     Comment("store double field");
1802     HandleStoreFieldAndReturn(handler_word, holder, value, double_value,
1803                               Representation::Double(), miss);
1804   }
1805 }
1806 
CheckHeapObjectTypeMatchesDescriptor(TNode<Word32T> handler_word,TNode<JSObject> holder,TNode<Object> value,Label * bailout)1807 void AccessorAssembler::CheckHeapObjectTypeMatchesDescriptor(
1808     TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value,
1809     Label* bailout) {
1810   GotoIf(TaggedIsSmi(value), bailout);
1811 
1812   Label done(this);
1813   // Skip field type check in favor of constant value check when storing
1814   // to constant field.
1815   GotoIf(Word32Equal(DecodeWord32<StoreHandler::KindBits>(handler_word),
1816                      Int32Constant(StoreHandler::kConstField)),
1817          &done);
1818   TNode<IntPtrT> descriptor =
1819       Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
1820   TNode<MaybeObject> maybe_field_type =
1821       LoadDescriptorValueOrFieldType(LoadMap(holder), descriptor);
1822 
1823   GotoIf(TaggedIsSmi(maybe_field_type), &done);
1824   // Check that value type matches the field type.
1825   {
1826     TNode<HeapObject> field_type =
1827         GetHeapObjectAssumeWeak(maybe_field_type, bailout);
1828     Branch(TaggedEqual(LoadMap(CAST(value)), field_type), &done, bailout);
1829   }
1830   BIND(&done);
1831 }
1832 
CheckDescriptorConsidersNumbersMutable(TNode<Word32T> handler_word,TNode<JSObject> holder,Label * bailout)1833 void AccessorAssembler::CheckDescriptorConsidersNumbersMutable(
1834     TNode<Word32T> handler_word, TNode<JSObject> holder, Label* bailout) {
1835   // We have to check that the representation is Double. Checking the value
1836   // (either in the field or being assigned) is not enough, as we could have
1837   // transitioned to Tagged but still be holding a HeapNumber, which would no
1838   // longer be allowed to be mutable.
1839 
1840   // TODO(leszeks): We could skip the representation check in favor of a
1841   // constant value check in HandleStoreFieldAndReturn here, but then
1842   // HandleStoreFieldAndReturn would need an IsHeapNumber check in case both the
1843   // representation changed and the value is no longer a HeapNumber.
1844   TNode<IntPtrT> descriptor_entry =
1845       Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
1846   TNode<DescriptorArray> descriptors = LoadMapDescriptors(LoadMap(holder));
1847   TNode<Uint32T> details =
1848       LoadDetailsByDescriptorEntry(descriptors, descriptor_entry);
1849 
1850   GotoIfNot(IsEqualInWord32<PropertyDetails::RepresentationField>(
1851                 details, Representation::kDouble),
1852             bailout);
1853 }
1854 
HandleStoreFieldAndReturn(TNode<Word32T> handler_word,TNode<JSObject> holder,TNode<Object> value,base::Optional<TNode<Float64T>> double_value,Representation representation,Label * miss)1855 void AccessorAssembler::HandleStoreFieldAndReturn(
1856     TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value,
1857     base::Optional<TNode<Float64T>> double_value, Representation representation,
1858     Label* miss) {
1859   Label done(this);
1860 
1861   bool store_value_as_double = representation.IsDouble();
1862 
1863   TNode<BoolT> is_inobject =
1864       IsSetWord32<StoreHandler::IsInobjectBits>(handler_word);
1865   TNode<HeapObject> property_storage = Select<HeapObject>(
1866       is_inobject, [&]() { return holder; },
1867       [&]() { return LoadFastProperties(holder); });
1868 
1869   TNode<UintPtrT> index =
1870       DecodeWordFromWord32<StoreHandler::FieldIndexBits>(handler_word);
1871   TNode<IntPtrT> offset = Signed(TimesTaggedSize(index));
1872 
1873   // For Double fields, we want to mutate the current double-value
1874   // field rather than changing it to point at a new HeapNumber.
1875   if (store_value_as_double) {
1876     TVARIABLE(HeapObject, actual_property_storage, property_storage);
1877     TVARIABLE(IntPtrT, actual_offset, offset);
1878 
1879     Label property_and_offset_ready(this);
1880 
1881     // If we are unboxing double fields, and this is an in-object field, the
1882     // property_storage and offset are already pointing to the double-valued
1883     // field.
1884     if (FLAG_unbox_double_fields) {
1885       GotoIf(is_inobject, &property_and_offset_ready);
1886     }
1887 
1888     // Store the double value directly into the mutable HeapNumber.
1889     TNode<Object> field = LoadObjectField(property_storage, offset);
1890     CSA_ASSERT(this, IsHeapNumber(CAST(field)));
1891     actual_property_storage = CAST(field);
1892     actual_offset = IntPtrConstant(HeapNumber::kValueOffset);
1893     Goto(&property_and_offset_ready);
1894 
1895     BIND(&property_and_offset_ready);
1896     property_storage = actual_property_storage.value();
1897     offset = actual_offset.value();
1898   }
1899 
1900   // Do constant value check if necessary.
1901   Label do_store(this);
1902   GotoIfNot(Word32Equal(DecodeWord32<StoreHandler::KindBits>(handler_word),
1903                         Int32Constant(StoreHandler::kConstField)),
1904             &do_store);
1905   {
1906     if (store_value_as_double) {
1907       Label done(this);
1908       TNode<Float64T> current_value =
1909           LoadObjectField<Float64T>(property_storage, offset);
1910       BranchIfSameNumberValue(current_value, *double_value, &done, miss);
1911       BIND(&done);
1912       Return(value);
1913     } else {
1914       TNode<Object> current_value = LoadObjectField(property_storage, offset);
1915       GotoIfNot(TaggedEqual(current_value, value), miss);
1916       Return(value);
1917     }
1918   }
1919 
1920   BIND(&do_store);
1921   // Do the store.
1922   if (store_value_as_double) {
1923     StoreObjectFieldNoWriteBarrier(property_storage, offset, *double_value);
1924   } else if (representation.IsSmi()) {
1925     TNode<Smi> value_smi = CAST(value);
1926     StoreObjectFieldNoWriteBarrier(property_storage, offset, value_smi);
1927   } else {
1928     StoreObjectField(property_storage, offset, value);
1929   }
1930 
1931   Return(value);
1932 }
1933 
ExtendPropertiesBackingStore(TNode<HeapObject> object,TNode<IntPtrT> index)1934 TNode<PropertyArray> AccessorAssembler::ExtendPropertiesBackingStore(
1935     TNode<HeapObject> object, TNode<IntPtrT> index) {
1936   Comment("[ Extend storage");
1937 
1938   TVARIABLE(HeapObject, var_properties);
1939   TVARIABLE(Int32T, var_encoded_hash);
1940   TVARIABLE(IntPtrT, var_length);
1941 
1942   TNode<Object> properties =
1943       LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
1944 
1945   Label if_smi_hash(this), if_property_array(this), extend_store(this);
1946   Branch(TaggedIsSmi(properties), &if_smi_hash, &if_property_array);
1947 
1948   BIND(&if_smi_hash);
1949   {
1950     TNode<Int32T> hash = SmiToInt32(CAST(properties));
1951     TNode<Int32T> encoded_hash =
1952         Word32Shl(hash, Int32Constant(PropertyArray::HashField::kShift));
1953     var_encoded_hash = encoded_hash;
1954     var_length = IntPtrConstant(0);
1955     var_properties = EmptyFixedArrayConstant();
1956     Goto(&extend_store);
1957   }
1958 
1959   BIND(&if_property_array);
1960   {
1961     var_properties = CAST(properties);
1962     TNode<Int32T> length_and_hash_int32 = LoadAndUntagToWord32ObjectField(
1963         var_properties.value(), PropertyArray::kLengthAndHashOffset);
1964     var_encoded_hash = Word32And(
1965         length_and_hash_int32, Int32Constant(PropertyArray::HashField::kMask));
1966     var_length = ChangeInt32ToIntPtr(
1967         Word32And(length_and_hash_int32,
1968                   Int32Constant(PropertyArray::LengthField::kMask)));
1969     Goto(&extend_store);
1970   }
1971 
1972   BIND(&extend_store);
1973   {
1974     TVARIABLE(HeapObject, var_new_properties, var_properties.value());
1975     Label done(this);
1976     // Previous property deletion could have left behind unused backing store
1977     // capacity even for a map that think it doesn't have any unused fields.
1978     // Perform a bounds check to see if we actually have to grow the array.
1979     GotoIf(UintPtrLessThan(index, ParameterToIntPtr(var_length.value())),
1980            &done);
1981 
1982     TNode<IntPtrT> delta = IntPtrConstant(JSObject::kFieldsAdded);
1983     TNode<IntPtrT> new_capacity = IntPtrAdd(var_length.value(), delta);
1984 
1985     // Grow properties array.
1986     DCHECK(kMaxNumberOfDescriptors + JSObject::kFieldsAdded <
1987            FixedArrayBase::GetMaxLengthForNewSpaceAllocation(PACKED_ELEMENTS));
1988     // The size of a new properties backing store is guaranteed to be small
1989     // enough that the new backing store will be allocated in new space.
1990     CSA_ASSERT(this, IntPtrLessThan(new_capacity,
1991                                     IntPtrConstant(kMaxNumberOfDescriptors +
1992                                                    JSObject::kFieldsAdded)));
1993 
1994     TNode<PropertyArray> new_properties = AllocatePropertyArray(new_capacity);
1995     var_new_properties = new_properties;
1996 
1997     FillPropertyArrayWithUndefined(new_properties, var_length.value(),
1998                                    new_capacity);
1999 
2000     // |new_properties| is guaranteed to be in new space, so we can skip
2001     // the write barrier.
2002     CopyPropertyArrayValues(var_properties.value(), new_properties,
2003                             var_length.value(), SKIP_WRITE_BARRIER,
2004                             DestroySource::kYes);
2005 
2006     TNode<Int32T> new_capacity_int32 = TruncateIntPtrToInt32(new_capacity);
2007     TNode<Int32T> new_length_and_hash_int32 =
2008         Word32Or(var_encoded_hash.value(), new_capacity_int32);
2009     StoreObjectField(new_properties, PropertyArray::kLengthAndHashOffset,
2010                      SmiFromInt32(new_length_and_hash_int32));
2011     StoreObjectField(object, JSObject::kPropertiesOrHashOffset, new_properties);
2012     Comment("] Extend storage");
2013     Goto(&done);
2014     BIND(&done);
2015     return CAST(var_new_properties.value());
2016   }
2017 }
2018 
EmitFastElementsBoundsCheck(TNode<JSObject> object,TNode<FixedArrayBase> elements,TNode<IntPtrT> intptr_index,TNode<BoolT> is_jsarray_condition,Label * miss)2019 void AccessorAssembler::EmitFastElementsBoundsCheck(
2020     TNode<JSObject> object, TNode<FixedArrayBase> elements,
2021     TNode<IntPtrT> intptr_index, TNode<BoolT> is_jsarray_condition,
2022     Label* miss) {
2023   TVARIABLE(IntPtrT, var_length);
2024   Comment("Fast elements bounds check");
2025   Label if_array(this), length_loaded(this, &var_length);
2026   GotoIf(is_jsarray_condition, &if_array);
2027   {
2028     var_length = SmiUntag(LoadFixedArrayBaseLength(elements));
2029     Goto(&length_loaded);
2030   }
2031   BIND(&if_array);
2032   {
2033     var_length = SmiUntag(LoadFastJSArrayLength(CAST(object)));
2034     Goto(&length_loaded);
2035   }
2036   BIND(&length_loaded);
2037   GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss);
2038 }
2039 
EmitElementLoad(TNode<HeapObject> object,TNode<Word32T> elements_kind,TNode<IntPtrT> intptr_index,TNode<BoolT> is_jsarray_condition,Label * if_hole,Label * rebox_double,TVariable<Float64T> * var_double_value,Label * unimplemented_elements_kind,Label * out_of_bounds,Label * miss,ExitPoint * exit_point,LoadAccessMode access_mode)2040 void AccessorAssembler::EmitElementLoad(
2041     TNode<HeapObject> object, TNode<Word32T> elements_kind,
2042     TNode<IntPtrT> intptr_index, TNode<BoolT> is_jsarray_condition,
2043     Label* if_hole, Label* rebox_double, TVariable<Float64T>* var_double_value,
2044     Label* unimplemented_elements_kind, Label* out_of_bounds, Label* miss,
2045     ExitPoint* exit_point, LoadAccessMode access_mode) {
2046   Label if_typed_array(this), if_fast(this), if_fast_packed(this),
2047       if_fast_holey(this), if_fast_double(this), if_fast_holey_double(this),
2048       if_nonfast(this), if_dictionary(this);
2049   Branch(Int32GreaterThan(elements_kind,
2050                           Int32Constant(LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND)),
2051          &if_nonfast, &if_fast);
2052 
2053   BIND(&if_fast);
2054   {
2055     TNode<FixedArrayBase> elements = LoadJSObjectElements(CAST(object));
2056     EmitFastElementsBoundsCheck(CAST(object), elements, intptr_index,
2057                                 is_jsarray_condition, out_of_bounds);
2058     int32_t kinds[] = {
2059         // Handled by if_fast_packed.
2060         PACKED_SMI_ELEMENTS, PACKED_ELEMENTS, PACKED_NONEXTENSIBLE_ELEMENTS,
2061         PACKED_SEALED_ELEMENTS, PACKED_FROZEN_ELEMENTS,
2062         // Handled by if_fast_holey.
2063         HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS, HOLEY_NONEXTENSIBLE_ELEMENTS,
2064         HOLEY_FROZEN_ELEMENTS, HOLEY_SEALED_ELEMENTS,
2065         // Handled by if_fast_double.
2066         PACKED_DOUBLE_ELEMENTS,
2067         // Handled by if_fast_holey_double.
2068         HOLEY_DOUBLE_ELEMENTS};
2069     Label* labels[] = {// FAST_{SMI,}_ELEMENTS
2070                        &if_fast_packed, &if_fast_packed, &if_fast_packed,
2071                        &if_fast_packed, &if_fast_packed,
2072                        // FAST_HOLEY_{SMI,}_ELEMENTS
2073                        &if_fast_holey, &if_fast_holey, &if_fast_holey,
2074                        &if_fast_holey, &if_fast_holey,
2075                        // PACKED_DOUBLE_ELEMENTS
2076                        &if_fast_double,
2077                        // HOLEY_DOUBLE_ELEMENTS
2078                        &if_fast_holey_double};
2079     Switch(elements_kind, unimplemented_elements_kind, kinds, labels,
2080            arraysize(kinds));
2081 
2082     BIND(&if_fast_packed);
2083     {
2084       Comment("fast packed elements");
2085       exit_point->Return(
2086           access_mode == LoadAccessMode::kHas
2087               ? TrueConstant()
2088               : UnsafeLoadFixedArrayElement(CAST(elements), intptr_index));
2089     }
2090 
2091     BIND(&if_fast_holey);
2092     {
2093       Comment("fast holey elements");
2094       TNode<Object> element =
2095           UnsafeLoadFixedArrayElement(CAST(elements), intptr_index);
2096       GotoIf(TaggedEqual(element, TheHoleConstant()), if_hole);
2097       exit_point->Return(access_mode == LoadAccessMode::kHas ? TrueConstant()
2098                                                              : element);
2099     }
2100 
2101     BIND(&if_fast_double);
2102     {
2103       Comment("packed double elements");
2104       if (access_mode == LoadAccessMode::kHas) {
2105         exit_point->Return(TrueConstant());
2106       } else {
2107         *var_double_value =
2108             LoadFixedDoubleArrayElement(CAST(elements), intptr_index);
2109         Goto(rebox_double);
2110       }
2111     }
2112 
2113     BIND(&if_fast_holey_double);
2114     {
2115       Comment("holey double elements");
2116       TNode<Float64T> value =
2117           LoadFixedDoubleArrayElement(CAST(elements), intptr_index, if_hole);
2118       if (access_mode == LoadAccessMode::kHas) {
2119         exit_point->Return(TrueConstant());
2120       } else {
2121         *var_double_value = value;
2122         Goto(rebox_double);
2123       }
2124     }
2125   }
2126 
2127   BIND(&if_nonfast);
2128   {
2129     STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
2130     GotoIf(Int32GreaterThanOrEqual(
2131                elements_kind,
2132                Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)),
2133            &if_typed_array);
2134     GotoIf(Word32Equal(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)),
2135            &if_dictionary);
2136     Goto(unimplemented_elements_kind);
2137 
2138     BIND(&if_dictionary);
2139     {
2140       Comment("dictionary elements");
2141       if (Is64()) {
2142         GotoIf(UintPtrLessThan(IntPtrConstant(JSArray::kMaxArrayIndex),
2143                                intptr_index),
2144                out_of_bounds);
2145       } else {
2146         GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds);
2147       }
2148 
2149       TNode<FixedArrayBase> elements = LoadJSObjectElements(CAST(object));
2150       TNode<Object> value = BasicLoadNumberDictionaryElement(
2151           CAST(elements), intptr_index, miss, if_hole);
2152       exit_point->Return(access_mode == LoadAccessMode::kHas ? TrueConstant()
2153                                                              : value);
2154     }
2155 
2156     BIND(&if_typed_array);
2157     {
2158       Comment("typed elements");
2159       // Check if buffer has been detached.
2160       TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(CAST(object));
2161       GotoIf(IsDetachedBuffer(buffer), miss);
2162 
2163       // Bounds check.
2164       TNode<UintPtrT> length = LoadJSTypedArrayLength(CAST(object));
2165       GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds);
2166       if (access_mode == LoadAccessMode::kHas) {
2167         exit_point->Return(TrueConstant());
2168       } else {
2169         TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(CAST(object));
2170 
2171         Label uint8_elements(this), int8_elements(this), uint16_elements(this),
2172             int16_elements(this), uint32_elements(this), int32_elements(this),
2173             float32_elements(this), float64_elements(this),
2174             bigint64_elements(this), biguint64_elements(this);
2175         Label* elements_kind_labels[] = {
2176             &uint8_elements,    &uint8_elements,    &int8_elements,
2177             &uint16_elements,   &int16_elements,    &uint32_elements,
2178             &int32_elements,    &float32_elements,  &float64_elements,
2179             &bigint64_elements, &biguint64_elements};
2180         int32_t elements_kinds[] = {
2181             UINT8_ELEMENTS,    UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
2182             UINT16_ELEMENTS,   INT16_ELEMENTS,         UINT32_ELEMENTS,
2183             INT32_ELEMENTS,    FLOAT32_ELEMENTS,       FLOAT64_ELEMENTS,
2184             BIGINT64_ELEMENTS, BIGUINT64_ELEMENTS};
2185         const size_t kTypedElementsKindCount =
2186             LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
2187             FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1;
2188         DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
2189         DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
2190         Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
2191                kTypedElementsKindCount);
2192         BIND(&uint8_elements);
2193         {
2194           Comment("UINT8_ELEMENTS");  // Handles UINT8_CLAMPED_ELEMENTS too.
2195           TNode<Int32T> element = Load<Uint8T>(data_ptr, intptr_index);
2196           exit_point->Return(SmiFromInt32(element));
2197         }
2198         BIND(&int8_elements);
2199         {
2200           Comment("INT8_ELEMENTS");
2201           TNode<Int32T> element = Load<Int8T>(data_ptr, intptr_index);
2202           exit_point->Return(SmiFromInt32(element));
2203         }
2204         BIND(&uint16_elements);
2205         {
2206           Comment("UINT16_ELEMENTS");
2207           TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
2208           TNode<Int32T> element = Load<Uint16T>(data_ptr, index);
2209           exit_point->Return(SmiFromInt32(element));
2210         }
2211         BIND(&int16_elements);
2212         {
2213           Comment("INT16_ELEMENTS");
2214           TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
2215           TNode<Int32T> element = Load<Int16T>(data_ptr, index);
2216           exit_point->Return(SmiFromInt32(element));
2217         }
2218         BIND(&uint32_elements);
2219         {
2220           Comment("UINT32_ELEMENTS");
2221           TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
2222           TNode<Uint32T> element = Load<Uint32T>(data_ptr, index);
2223           exit_point->Return(ChangeUint32ToTagged(element));
2224         }
2225         BIND(&int32_elements);
2226         {
2227           Comment("INT32_ELEMENTS");
2228           TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
2229           TNode<Int32T> element = Load<Int32T>(data_ptr, index);
2230           exit_point->Return(ChangeInt32ToTagged(element));
2231         }
2232         BIND(&float32_elements);
2233         {
2234           Comment("FLOAT32_ELEMENTS");
2235           TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
2236           TNode<Float32T> element = Load<Float32T>(data_ptr, index);
2237           *var_double_value = ChangeFloat32ToFloat64(element);
2238           Goto(rebox_double);
2239         }
2240         BIND(&float64_elements);
2241         {
2242           Comment("FLOAT64_ELEMENTS");
2243           TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(3));
2244           TNode<Float64T> element = Load<Float64T>(data_ptr, index);
2245           *var_double_value = element;
2246           Goto(rebox_double);
2247         }
2248         BIND(&bigint64_elements);
2249         {
2250           Comment("BIGINT64_ELEMENTS");
2251           exit_point->Return(LoadFixedTypedArrayElementAsTagged(
2252               data_ptr, Unsigned(intptr_index), BIGINT64_ELEMENTS));
2253         }
2254         BIND(&biguint64_elements);
2255         {
2256           Comment("BIGUINT64_ELEMENTS");
2257           exit_point->Return(LoadFixedTypedArrayElementAsTagged(
2258               data_ptr, Unsigned(intptr_index), BIGUINT64_ELEMENTS));
2259         }
2260       }
2261     }
2262   }
2263 }
2264 
InvalidateValidityCellIfPrototype(TNode<Map> map,base::Optional<TNode<Uint32T>> maybe_bitfield3)2265 void AccessorAssembler::InvalidateValidityCellIfPrototype(
2266     TNode<Map> map, base::Optional<TNode<Uint32T>> maybe_bitfield3) {
2267   Label is_prototype(this), cont(this);
2268   TNode<Uint32T> bitfield3;
2269   if (bitfield3) {
2270     bitfield3 = maybe_bitfield3.value();
2271   } else {
2272     bitfield3 = LoadMapBitField3(map);
2273   }
2274 
2275   Branch(IsSetWord32(bitfield3, Map::Bits3::IsPrototypeMapBit::kMask),
2276          &is_prototype, &cont);
2277 
2278   BIND(&is_prototype);
2279   {
2280     TNode<Object> maybe_prototype_info =
2281         LoadObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
2282     // If there's no prototype info then there's nothing to invalidate.
2283     GotoIf(TaggedIsSmi(maybe_prototype_info), &cont);
2284 
2285     TNode<ExternalReference> function = ExternalConstant(
2286         ExternalReference::invalidate_prototype_chains_function());
2287     CallCFunction(function, MachineType::AnyTagged(),
2288                   std::make_pair(MachineType::AnyTagged(), map));
2289     Goto(&cont);
2290   }
2291   BIND(&cont);
2292 }
2293 
GenericElementLoad(TNode<HeapObject> lookup_start_object,TNode<Map> lookup_start_object_map,TNode<Int32T> lookup_start_object_instance_type,TNode<IntPtrT> index,Label * slow)2294 void AccessorAssembler::GenericElementLoad(
2295     TNode<HeapObject> lookup_start_object, TNode<Map> lookup_start_object_map,
2296     TNode<Int32T> lookup_start_object_instance_type, TNode<IntPtrT> index,
2297     Label* slow) {
2298   Comment("integer index");
2299 
2300   ExitPoint direct_exit(this);
2301 
2302   Label if_custom(this), if_element_hole(this), if_oob(this);
2303   Label return_undefined(this);
2304   // Receivers requiring non-standard element accesses (interceptors, access
2305   // checks, strings and string wrappers, proxies) are handled in the runtime.
2306   GotoIf(
2307       IsCustomElementsReceiverInstanceType(lookup_start_object_instance_type),
2308       &if_custom);
2309   TNode<Int32T> elements_kind = LoadMapElementsKind(lookup_start_object_map);
2310   TNode<BoolT> is_jsarray_condition =
2311       IsJSArrayInstanceType(lookup_start_object_instance_type);
2312   TVARIABLE(Float64T, var_double_value);
2313   Label rebox_double(this, &var_double_value);
2314 
2315   // Unimplemented elements kinds fall back to a runtime call.
2316   Label* unimplemented_elements_kind = slow;
2317   IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
2318   EmitElementLoad(lookup_start_object, elements_kind, index,
2319                   is_jsarray_condition, &if_element_hole, &rebox_double,
2320                   &var_double_value, unimplemented_elements_kind, &if_oob, slow,
2321                   &direct_exit);
2322 
2323   BIND(&rebox_double);
2324   Return(AllocateHeapNumberWithValue(var_double_value.value()));
2325 
2326   BIND(&if_oob);
2327   {
2328     Comment("out of bounds");
2329     // On TypedArrays, all OOB loads (positive and negative) return undefined
2330     // without ever checking the prototype chain.
2331     GotoIf(IsJSTypedArrayInstanceType(lookup_start_object_instance_type),
2332            &return_undefined);
2333     // Positive OOB indices within JSArray index range are effectively the same
2334     // as hole loads. Larger keys and negative keys are named loads.
2335     if (Is64()) {
2336       Branch(UintPtrLessThanOrEqual(index,
2337                                     IntPtrConstant(JSArray::kMaxArrayIndex)),
2338              &if_element_hole, slow);
2339     } else {
2340       Branch(IntPtrLessThan(index, IntPtrConstant(0)), slow, &if_element_hole);
2341     }
2342   }
2343 
2344   BIND(&if_element_hole);
2345   {
2346     Comment("found the hole");
2347     BranchIfPrototypesHaveNoElements(lookup_start_object_map, &return_undefined,
2348                                      slow);
2349   }
2350 
2351   BIND(&if_custom);
2352   {
2353     Comment("check if string");
2354     GotoIfNot(IsStringInstanceType(lookup_start_object_instance_type), slow);
2355     Comment("load string character");
2356     TNode<IntPtrT> length = LoadStringLengthAsWord(CAST(lookup_start_object));
2357     GotoIfNot(UintPtrLessThan(index, length), slow);
2358     IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
2359     TailCallBuiltin(Builtins::kStringCharAt, NoContextConstant(),
2360                     lookup_start_object, index);
2361   }
2362 
2363   BIND(&return_undefined);
2364   Return(UndefinedConstant());
2365 }
2366 
GenericPropertyLoad(TNode<HeapObject> lookup_start_object,TNode<Map> lookup_start_object_map,TNode<Int32T> lookup_start_object_instance_type,const LoadICParameters * p,Label * slow,UseStubCache use_stub_cache)2367 void AccessorAssembler::GenericPropertyLoad(
2368     TNode<HeapObject> lookup_start_object, TNode<Map> lookup_start_object_map,
2369     TNode<Int32T> lookup_start_object_instance_type, const LoadICParameters* p,
2370     Label* slow, UseStubCache use_stub_cache) {
2371   DCHECK_EQ(lookup_start_object, p->lookup_start_object());
2372   ExitPoint direct_exit(this);
2373 
2374   Comment("key is unique name");
2375   Label if_found_on_lookup_start_object(this), if_property_dictionary(this),
2376       lookup_prototype_chain(this), special_receiver(this);
2377   TVARIABLE(Uint32T, var_details);
2378   TVARIABLE(Object, var_value);
2379 
2380   TNode<Name> name = CAST(p->name());
2381 
2382   // Receivers requiring non-standard accesses (interceptors, access
2383   // checks, strings and string wrappers) are handled in the runtime.
2384   GotoIf(IsSpecialReceiverInstanceType(lookup_start_object_instance_type),
2385          &special_receiver);
2386 
2387   // Check if the lookup_start_object has fast or slow properties.
2388   TNode<Uint32T> bitfield3 = LoadMapBitField3(lookup_start_object_map);
2389   GotoIf(IsSetWord32<Map::Bits3::IsDictionaryMapBit>(bitfield3),
2390          &if_property_dictionary);
2391 
2392   // Try looking up the property on the lookup_start_object; if unsuccessful,
2393   // look for a handler in the stub cache.
2394   TNode<DescriptorArray> descriptors =
2395       LoadMapDescriptors(lookup_start_object_map);
2396 
2397   Label if_descriptor_found(this), try_stub_cache(this);
2398   TVARIABLE(IntPtrT, var_name_index);
2399   Label* notfound = use_stub_cache == kUseStubCache ? &try_stub_cache
2400                                                     : &lookup_prototype_chain;
2401   DescriptorLookup(name, descriptors, bitfield3, &if_descriptor_found,
2402                    &var_name_index, notfound);
2403 
2404   BIND(&if_descriptor_found);
2405   {
2406     LoadPropertyFromFastObject(lookup_start_object, lookup_start_object_map,
2407                                descriptors, var_name_index.value(),
2408                                &var_details, &var_value);
2409     Goto(&if_found_on_lookup_start_object);
2410   }
2411 
2412   if (use_stub_cache == kUseStubCache) {
2413     DCHECK_EQ(lookup_start_object, p->receiver_and_lookup_start_object());
2414     Label stub_cache(this);
2415     BIND(&try_stub_cache);
2416     // When there is no feedback vector don't use stub cache.
2417     GotoIfNot(IsUndefined(p->vector()), &stub_cache);
2418     // Fall back to the slow path for private symbols.
2419     Branch(IsPrivateSymbol(name), slow, &lookup_prototype_chain);
2420 
2421     BIND(&stub_cache);
2422     Comment("stub cache probe for fast property load");
2423     TVARIABLE(MaybeObject, var_handler);
2424     Label found_handler(this, &var_handler), stub_cache_miss(this);
2425     TryProbeStubCache(isolate()->load_stub_cache(), lookup_start_object, name,
2426                       &found_handler, &var_handler, &stub_cache_miss);
2427     BIND(&found_handler);
2428     {
2429       LazyLoadICParameters lazy_p(p);
2430       HandleLoadICHandlerCase(&lazy_p, CAST(var_handler.value()),
2431                               &stub_cache_miss, &direct_exit);
2432     }
2433 
2434     BIND(&stub_cache_miss);
2435     {
2436       // TODO(jkummerow): Check if the property exists on the prototype
2437       // chain. If it doesn't, then there's no point in missing.
2438       Comment("KeyedLoadGeneric_miss");
2439       TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context(),
2440                       p->receiver_and_lookup_start_object(), name, p->slot(),
2441                       p->vector());
2442     }
2443   }
2444 
2445   BIND(&if_property_dictionary);
2446   {
2447     Comment("dictionary property load");
2448     // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
2449     // seeing global objects here (which would need special handling).
2450 
2451     TVARIABLE(IntPtrT, var_name_index);
2452     Label dictionary_found(this, &var_name_index);
2453     TNode<NameDictionary> properties =
2454         CAST(LoadSlowProperties(CAST(lookup_start_object)));
2455     NameDictionaryLookup<NameDictionary>(properties, name, &dictionary_found,
2456                                          &var_name_index,
2457                                          &lookup_prototype_chain);
2458     BIND(&dictionary_found);
2459     {
2460       LoadPropertyFromNameDictionary(properties, var_name_index.value(),
2461                                      &var_details, &var_value);
2462       Goto(&if_found_on_lookup_start_object);
2463     }
2464   }
2465 
2466   BIND(&if_found_on_lookup_start_object);
2467   {
2468     TNode<Object> value = CallGetterIfAccessor(
2469         var_value.value(), lookup_start_object, var_details.value(),
2470         p->context(), p->receiver(), slow);
2471     IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
2472     Return(value);
2473   }
2474 
2475   BIND(&lookup_prototype_chain);
2476   {
2477     TVARIABLE(Map, var_holder_map);
2478     TVARIABLE(Int32T, var_holder_instance_type);
2479     Label return_undefined(this), is_private_symbol(this);
2480     Label loop(this, {&var_holder_map, &var_holder_instance_type});
2481 
2482     var_holder_map = lookup_start_object_map;
2483     var_holder_instance_type = lookup_start_object_instance_type;
2484     GotoIf(IsPrivateSymbol(name), &is_private_symbol);
2485 
2486     Goto(&loop);
2487     BIND(&loop);
2488     {
2489       // Bailout if it can be an integer indexed exotic case.
2490       GotoIf(InstanceTypeEqual(var_holder_instance_type.value(),
2491                                JS_TYPED_ARRAY_TYPE),
2492              slow);
2493       TNode<HeapObject> proto = LoadMapPrototype(var_holder_map.value());
2494       GotoIf(TaggedEqual(proto, NullConstant()), &return_undefined);
2495       TNode<Map> proto_map = LoadMap(proto);
2496       TNode<Uint16T> proto_instance_type = LoadMapInstanceType(proto_map);
2497       var_holder_map = proto_map;
2498       var_holder_instance_type = proto_instance_type;
2499       Label next_proto(this), return_value(this, &var_value), goto_slow(this);
2500       TryGetOwnProperty(p->context(), p->receiver(), CAST(proto), proto_map,
2501                         proto_instance_type, name, &return_value, &var_value,
2502                         &next_proto, &goto_slow);
2503 
2504       // This trampoline and the next are required to appease Turbofan's
2505       // variable merging.
2506       BIND(&next_proto);
2507       Goto(&loop);
2508 
2509       BIND(&goto_slow);
2510       Goto(slow);
2511 
2512       BIND(&return_value);
2513       Return(var_value.value());
2514     }
2515 
2516     BIND(&is_private_symbol);
2517     {
2518       CSA_ASSERT(this, IsPrivateSymbol(name));
2519 
2520       // For private names that don't exist on the receiver, we bail
2521       // to the runtime to throw. For private symbols, we just return
2522       // undefined.
2523       Branch(IsPrivateName(CAST(name)), slow, &return_undefined);
2524     }
2525 
2526     BIND(&return_undefined);
2527     Return(UndefinedConstant());
2528   }
2529 
2530   BIND(&special_receiver);
2531   {
2532     // TODO(jkummerow): Consider supporting JSModuleNamespace.
2533     GotoIfNot(
2534         InstanceTypeEqual(lookup_start_object_instance_type, JS_PROXY_TYPE),
2535         slow);
2536 
2537     // Private field/symbol lookup is not supported.
2538     GotoIf(IsPrivateSymbol(name), slow);
2539 
2540     direct_exit.ReturnCallStub(
2541         Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
2542         p->context(), lookup_start_object, name, p->receiver(),
2543         SmiConstant(OnNonExistent::kReturnUndefined));
2544   }
2545 }
2546 
2547 //////////////////// Stub cache access helpers.
2548 
2549 enum AccessorAssembler::StubCacheTable : int {
2550   kPrimary = static_cast<int>(StubCache::kPrimary),
2551   kSecondary = static_cast<int>(StubCache::kSecondary)
2552 };
2553 
StubCachePrimaryOffset(TNode<Name> name,TNode<Map> map)2554 TNode<IntPtrT> AccessorAssembler::StubCachePrimaryOffset(TNode<Name> name,
2555                                                          TNode<Map> map) {
2556   // Compute the hash of the name (use entire hash field).
2557   TNode<Uint32T> hash_field = LoadNameHashField(name);
2558   CSA_ASSERT(this,
2559              Word32Equal(Word32And(hash_field,
2560                                    Int32Constant(Name::kHashNotComputedMask)),
2561                          Int32Constant(0)));
2562 
2563   // Using only the low bits in 64-bit mode is unlikely to increase the
2564   // risk of collision even if the heap is spread over an area larger than
2565   // 4Gb (and not at all if it isn't).
2566   TNode<IntPtrT> map_word = BitcastTaggedToWord(map);
2567 
2568   TNode<Int32T> map32 = TruncateIntPtrToInt32(UncheckedCast<IntPtrT>(
2569       WordXor(map_word, WordShr(map_word, StubCache::kMapKeyShift))));
2570   // Base the offset on a simple combination of name and map.
2571   TNode<Word32T> hash = Int32Add(hash_field, map32);
2572   uint32_t mask = (StubCache::kPrimaryTableSize - 1)
2573                   << StubCache::kCacheIndexShift;
2574   TNode<UintPtrT> result =
2575       ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
2576   return Signed(result);
2577 }
2578 
StubCacheSecondaryOffset(TNode<Name> name,TNode<IntPtrT> seed)2579 TNode<IntPtrT> AccessorAssembler::StubCacheSecondaryOffset(
2580     TNode<Name> name, TNode<IntPtrT> seed) {
2581   // See v8::internal::StubCache::SecondaryOffset().
2582 
2583   // Use the seed from the primary cache in the secondary cache.
2584   TNode<Int32T> name32 = TruncateIntPtrToInt32(BitcastTaggedToWord(name));
2585   TNode<Int32T> hash = Int32Sub(TruncateIntPtrToInt32(seed), name32);
2586   hash = Int32Add(hash, Int32Constant(StubCache::kSecondaryMagic));
2587   int32_t mask = (StubCache::kSecondaryTableSize - 1)
2588                  << StubCache::kCacheIndexShift;
2589   TNode<UintPtrT> result =
2590       ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
2591   return Signed(result);
2592 }
2593 
TryProbeStubCacheTable(StubCache * stub_cache,StubCacheTable table_id,TNode<IntPtrT> entry_offset,TNode<Object> name,TNode<Map> map,Label * if_handler,TVariable<MaybeObject> * var_handler,Label * if_miss)2594 void AccessorAssembler::TryProbeStubCacheTable(
2595     StubCache* stub_cache, StubCacheTable table_id, TNode<IntPtrT> entry_offset,
2596     TNode<Object> name, TNode<Map> map, Label* if_handler,
2597     TVariable<MaybeObject>* var_handler, Label* if_miss) {
2598   StubCache::Table table = static_cast<StubCache::Table>(table_id);
2599   // The {table_offset} holds the entry offset times four (due to masking
2600   // and shifting optimizations).
2601   const int kMultiplier =
2602       sizeof(StubCache::Entry) >> StubCache::kCacheIndexShift;
2603   entry_offset = IntPtrMul(entry_offset, IntPtrConstant(kMultiplier));
2604 
2605   TNode<ExternalReference> key_base = ExternalConstant(
2606       ExternalReference::Create(stub_cache->key_reference(table)));
2607 
2608   // Check that the key in the entry matches the name.
2609   DCHECK_EQ(0, offsetof(StubCache::Entry, key));
2610   TNode<HeapObject> cached_key =
2611       CAST(Load(MachineType::TaggedPointer(), key_base, entry_offset));
2612   GotoIf(TaggedNotEqual(name, cached_key), if_miss);
2613 
2614   // Check that the map in the entry matches.
2615   TNode<Object> cached_map = Load<Object>(
2616       key_base,
2617       IntPtrAdd(entry_offset, IntPtrConstant(offsetof(StubCache::Entry, map))));
2618   GotoIf(TaggedNotEqual(map, cached_map), if_miss);
2619 
2620   TNode<MaybeObject> handler = ReinterpretCast<MaybeObject>(
2621       Load(MachineType::AnyTagged(), key_base,
2622            IntPtrAdd(entry_offset,
2623                      IntPtrConstant(offsetof(StubCache::Entry, value)))));
2624 
2625   // We found the handler.
2626   *var_handler = handler;
2627   Goto(if_handler);
2628 }
2629 
TryProbeStubCache(StubCache * stub_cache,TNode<Object> lookup_start_object,TNode<Name> name,Label * if_handler,TVariable<MaybeObject> * var_handler,Label * if_miss)2630 void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache,
2631                                           TNode<Object> lookup_start_object,
2632                                           TNode<Name> name, Label* if_handler,
2633                                           TVariable<MaybeObject>* var_handler,
2634                                           Label* if_miss) {
2635   Label try_secondary(this), miss(this);
2636 
2637   Counters* counters = isolate()->counters();
2638   IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
2639 
2640   // Check that the {lookup_start_object} isn't a smi.
2641   GotoIf(TaggedIsSmi(lookup_start_object), &miss);
2642 
2643   TNode<Map> lookup_start_object_map = LoadMap(CAST(lookup_start_object));
2644 
2645   // Probe the primary table.
2646   TNode<IntPtrT> primary_offset =
2647       StubCachePrimaryOffset(name, lookup_start_object_map);
2648   TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name,
2649                          lookup_start_object_map, if_handler, var_handler,
2650                          &try_secondary);
2651 
2652   BIND(&try_secondary);
2653   {
2654     // Probe the secondary table.
2655     TNode<IntPtrT> secondary_offset =
2656         StubCacheSecondaryOffset(name, primary_offset);
2657     TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name,
2658                            lookup_start_object_map, if_handler, var_handler,
2659                            &miss);
2660   }
2661 
2662   BIND(&miss);
2663   {
2664     IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
2665     Goto(if_miss);
2666   }
2667 }
2668 
2669 //////////////////// Entry points into private implementation (one per stub).
2670 
LoadIC_BytecodeHandler(const LazyLoadICParameters * p,ExitPoint * exit_point)2671 void AccessorAssembler::LoadIC_BytecodeHandler(const LazyLoadICParameters* p,
2672                                                ExitPoint* exit_point) {
2673   // Must be kept in sync with LoadIC.
2674 
2675   // This function is hand-tuned to omit frame construction for common cases,
2676   // e.g.: monomorphic field and constant loads through smi handlers.
2677   // Polymorphic ICs with a hit in the first two entries also omit frames.
2678   // TODO(jgruber): Frame omission is fragile and can be affected by minor
2679   // changes in control flow and logic. We currently have no way of ensuring
2680   // that no frame is constructed, so it's easy to break this optimization by
2681   // accident.
2682   Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred),
2683       no_feedback(this, Label::kDeferred);
2684 
2685   GotoIf(IsUndefined(p->vector()), &no_feedback);
2686 
2687   TNode<Map> lookup_start_object_map =
2688       LoadReceiverMap(p->receiver_and_lookup_start_object());
2689   GotoIf(IsDeprecatedMap(lookup_start_object_map), &miss);
2690 
2691   // Inlined fast path.
2692   {
2693     Comment("LoadIC_BytecodeHandler_fast");
2694 
2695     TVARIABLE(MaybeObject, var_handler);
2696     Label try_polymorphic(this), if_handler(this, &var_handler);
2697 
2698     TNode<MaybeObject> feedback = TryMonomorphicCase(
2699         p->slot(), CAST(p->vector()), lookup_start_object_map, &if_handler,
2700         &var_handler, &try_polymorphic);
2701 
2702     BIND(&if_handler);
2703     HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, exit_point);
2704 
2705     BIND(&try_polymorphic);
2706     {
2707       TNode<HeapObject> strong_feedback =
2708           GetHeapObjectIfStrong(feedback, &miss);
2709       GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &stub_call);
2710       HandlePolymorphicCase(lookup_start_object_map, CAST(strong_feedback),
2711                             &if_handler, &var_handler, &miss);
2712     }
2713   }
2714 
2715   BIND(&stub_call);
2716   {
2717     Comment("LoadIC_BytecodeHandler_noninlined");
2718 
2719     // Call into the stub that implements the non-inlined parts of LoadIC.
2720     Callable ic =
2721         Builtins::CallableFor(isolate(), Builtins::kLoadIC_Noninlined);
2722     TNode<Code> code_target = HeapConstant(ic.code());
2723     exit_point->ReturnCallStub(ic.descriptor(), code_target, p->context(),
2724                                p->receiver_and_lookup_start_object(), p->name(),
2725                                p->slot(), p->vector());
2726   }
2727 
2728   BIND(&no_feedback);
2729   {
2730     Comment("LoadIC_BytecodeHandler_nofeedback");
2731     // Call into the stub that implements the non-inlined parts of LoadIC.
2732     exit_point->ReturnCallStub(
2733         Builtins::CallableFor(isolate(), Builtins::kLoadIC_NoFeedback),
2734         p->context(), p->receiver(), p->name(),
2735         SmiConstant(FeedbackSlotKind::kLoadProperty));
2736   }
2737 
2738   BIND(&miss);
2739   {
2740     Comment("LoadIC_BytecodeHandler_miss");
2741 
2742     exit_point->ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context(),
2743                                   p->receiver(), p->name(), p->slot(),
2744                                   p->vector());
2745   }
2746 }
2747 
LoadIC(const LoadICParameters * p)2748 void AccessorAssembler::LoadIC(const LoadICParameters* p) {
2749   // Must be kept in sync with LoadIC_BytecodeHandler.
2750 
2751   ExitPoint direct_exit(this);
2752 
2753   TVARIABLE(MaybeObject, var_handler);
2754   Label if_handler(this, &var_handler), non_inlined(this, Label::kDeferred),
2755       try_polymorphic(this), miss(this, Label::kDeferred);
2756 
2757   TNode<Map> lookup_start_object_map =
2758       LoadReceiverMap(p->receiver_and_lookup_start_object());
2759   GotoIf(IsDeprecatedMap(lookup_start_object_map), &miss);
2760 
2761   // Check monomorphic case.
2762   TNode<MaybeObject> feedback =
2763       TryMonomorphicCase(p->slot(), CAST(p->vector()), lookup_start_object_map,
2764                          &if_handler, &var_handler, &try_polymorphic);
2765   BIND(&if_handler);
2766   {
2767     LazyLoadICParameters lazy_p(p);
2768     HandleLoadICHandlerCase(&lazy_p, CAST(var_handler.value()), &miss,
2769                             &direct_exit);
2770   }
2771 
2772   BIND(&try_polymorphic);
2773   TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
2774   {
2775     // Check polymorphic case.
2776     Comment("LoadIC_try_polymorphic");
2777     GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &non_inlined);
2778     HandlePolymorphicCase(lookup_start_object_map, CAST(strong_feedback),
2779                           &if_handler, &var_handler, &miss);
2780   }
2781 
2782   BIND(&non_inlined);
2783   {
2784     LoadIC_Noninlined(p, lookup_start_object_map, strong_feedback, &var_handler,
2785                       &if_handler, &miss, &direct_exit);
2786   }
2787 
2788   BIND(&miss);
2789   direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context(),
2790                                 p->receiver_and_lookup_start_object(),
2791                                 p->name(), p->slot(), p->vector());
2792 }
2793 
LoadSuperIC(const LoadICParameters * p)2794 void AccessorAssembler::LoadSuperIC(const LoadICParameters* p) {
2795   ExitPoint direct_exit(this);
2796 
2797   TVARIABLE(MaybeObject, var_handler);
2798   Label if_handler(this, &var_handler), no_feedback(this),
2799       non_inlined(this, Label::kDeferred), try_polymorphic(this),
2800       miss(this, Label::kDeferred);
2801 
2802   GotoIf(IsUndefined(p->vector()), &no_feedback);
2803 
2804   // The lookup start object cannot be a SMI, since it's the home object's
2805   // prototype, and it's not possible to set SMIs as prototypes.
2806   TNode<Map> lookup_start_object_map =
2807       LoadReceiverMap(p->lookup_start_object());
2808   GotoIf(IsDeprecatedMap(lookup_start_object_map), &miss);
2809 
2810   TNode<MaybeObject> feedback =
2811       TryMonomorphicCase(p->slot(), CAST(p->vector()), lookup_start_object_map,
2812                          &if_handler, &var_handler, &try_polymorphic);
2813 
2814   BIND(&if_handler);
2815   {
2816     LazyLoadICParameters lazy_p(p);
2817     HandleLoadICHandlerCase(&lazy_p, CAST(var_handler.value()), &miss,
2818                             &direct_exit);
2819   }
2820 
2821   BIND(&no_feedback);
2822   { LoadSuperIC_NoFeedback(p); }
2823 
2824   BIND(&try_polymorphic);
2825   TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
2826   {
2827     Comment("LoadSuperIC_try_polymorphic");
2828     GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &non_inlined);
2829     HandlePolymorphicCase(lookup_start_object_map, CAST(strong_feedback),
2830                           &if_handler, &var_handler, &miss);
2831   }
2832 
2833   BIND(&non_inlined);
2834   {
2835     // LoadIC_Noninlined can be used here, since it handles the
2836     // lookup_start_object != receiver case gracefully.
2837     LoadIC_Noninlined(p, lookup_start_object_map, strong_feedback, &var_handler,
2838                       &if_handler, &miss, &direct_exit);
2839   }
2840 
2841   BIND(&miss);
2842   direct_exit.ReturnCallRuntime(Runtime::kLoadWithReceiverIC_Miss, p->context(),
2843                                 p->receiver(), p->lookup_start_object(),
2844                                 p->name(), p->slot(), p->vector());
2845 }
2846 
LoadIC_Noninlined(const LoadICParameters * p,TNode<Map> lookup_start_object_map,TNode<HeapObject> feedback,TVariable<MaybeObject> * var_handler,Label * if_handler,Label * miss,ExitPoint * exit_point)2847 void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
2848                                           TNode<Map> lookup_start_object_map,
2849                                           TNode<HeapObject> feedback,
2850                                           TVariable<MaybeObject>* var_handler,
2851                                           Label* if_handler, Label* miss,
2852                                           ExitPoint* exit_point) {
2853   // Neither deprecated map nor monomorphic. These cases are handled in the
2854   // bytecode handler.
2855   CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(lookup_start_object_map)));
2856   CSA_ASSERT(this, TaggedNotEqual(lookup_start_object_map, feedback));
2857   CSA_ASSERT(this, Word32BinaryNot(IsWeakFixedArrayMap(LoadMap(feedback))));
2858   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
2859 
2860   {
2861     // Check megamorphic case.
2862     GotoIfNot(TaggedEqual(feedback, MegamorphicSymbolConstant()), miss);
2863 
2864     TryProbeStubCache(isolate()->load_stub_cache(), p->lookup_start_object(),
2865                       CAST(p->name()), if_handler, var_handler, miss);
2866   }
2867 }
2868 
LoadIC_NoFeedback(const LoadICParameters * p,TNode<Smi> ic_kind)2869 void AccessorAssembler::LoadIC_NoFeedback(const LoadICParameters* p,
2870                                           TNode<Smi> ic_kind) {
2871   Label miss(this, Label::kDeferred);
2872   TNode<Object> lookup_start_object = p->receiver_and_lookup_start_object();
2873   GotoIf(TaggedIsSmi(lookup_start_object), &miss);
2874   TNode<Map> lookup_start_object_map = LoadMap(CAST(lookup_start_object));
2875   GotoIf(IsDeprecatedMap(lookup_start_object_map), &miss);
2876 
2877   TNode<Uint16T> instance_type = LoadMapInstanceType(lookup_start_object_map);
2878 
2879   {
2880     // Special case for Function.prototype load, because it's very common
2881     // for ICs that are only executed once (MyFunc.prototype.foo = ...).
2882     Label not_function_prototype(this, Label::kDeferred);
2883     GotoIfNot(InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE),
2884               &not_function_prototype);
2885     GotoIfNot(IsPrototypeString(p->name()), &not_function_prototype);
2886 
2887     GotoIfPrototypeRequiresRuntimeLookup(CAST(lookup_start_object),
2888                                          lookup_start_object_map,
2889                                          &not_function_prototype);
2890     Return(LoadJSFunctionPrototype(CAST(lookup_start_object), &miss));
2891     BIND(&not_function_prototype);
2892   }
2893 
2894   GenericPropertyLoad(CAST(lookup_start_object), lookup_start_object_map,
2895                       instance_type, p, &miss, kDontUseStubCache);
2896 
2897   BIND(&miss);
2898   {
2899     TailCallRuntime(Runtime::kLoadNoFeedbackIC_Miss, p->context(),
2900                     p->receiver(), p->name(), ic_kind);
2901   }
2902 }
2903 
LoadSuperIC_NoFeedback(const LoadICParameters * p)2904 void AccessorAssembler::LoadSuperIC_NoFeedback(const LoadICParameters* p) {
2905   Label miss(this, Label::kDeferred);
2906   TNode<Object> lookup_start_object = p->lookup_start_object();
2907 
2908   // The lookup start object cannot be a SMI, since it's the home object's
2909   // prototype, and it's not possible to set SMIs as prototypes.
2910   TNode<Map> lookup_start_object_map = LoadMap(CAST(lookup_start_object));
2911   GotoIf(IsDeprecatedMap(lookup_start_object_map), &miss);
2912 
2913   TNode<Uint16T> instance_type = LoadMapInstanceType(lookup_start_object_map);
2914 
2915   GenericPropertyLoad(CAST(lookup_start_object), lookup_start_object_map,
2916                       instance_type, p, &miss, kDontUseStubCache);
2917 
2918   BIND(&miss);
2919   {
2920     TailCallRuntime(Runtime::kLoadWithReceiverNoFeedbackIC_Miss, p->context(),
2921                     p->receiver(), p->lookup_start_object(), p->name());
2922   }
2923 }
2924 
LoadGlobalIC(TNode<HeapObject> maybe_feedback_vector,const LazyNode<TaggedIndex> & lazy_slot,const LazyNode<Context> & lazy_context,const LazyNode<Name> & lazy_name,TypeofMode typeof_mode,ExitPoint * exit_point)2925 void AccessorAssembler::LoadGlobalIC(TNode<HeapObject> maybe_feedback_vector,
2926                                      const LazyNode<TaggedIndex>& lazy_slot,
2927                                      const LazyNode<Context>& lazy_context,
2928                                      const LazyNode<Name>& lazy_name,
2929                                      TypeofMode typeof_mode,
2930                                      ExitPoint* exit_point) {
2931   Label try_handler(this, Label::kDeferred), miss(this, Label::kDeferred),
2932       no_feedback(this, Label::kDeferred);
2933 
2934   GotoIf(IsUndefined(maybe_feedback_vector), &no_feedback);
2935   {
2936     TNode<TaggedIndex> slot = lazy_slot();
2937 
2938     {
2939       TNode<FeedbackVector> vector = CAST(maybe_feedback_vector);
2940       LoadGlobalIC_TryPropertyCellCase(vector, slot, lazy_context, exit_point,
2941                                        &try_handler, &miss);
2942 
2943       BIND(&try_handler);
2944       LoadGlobalIC_TryHandlerCase(vector, slot, lazy_context, lazy_name,
2945                                   typeof_mode, exit_point, &miss);
2946     }
2947 
2948     BIND(&miss);
2949     {
2950       Comment("LoadGlobalIC_MissCase");
2951       TNode<Context> context = lazy_context();
2952       TNode<Name> name = lazy_name();
2953       exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, context, name,
2954                                     slot, maybe_feedback_vector,
2955                                     SmiConstant(typeof_mode));
2956     }
2957   }
2958 
2959   BIND(&no_feedback);
2960   {
2961     int ic_kind =
2962         static_cast<int>((typeof_mode == INSIDE_TYPEOF)
2963                              ? FeedbackSlotKind::kLoadGlobalInsideTypeof
2964                              : FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
2965     exit_point->ReturnCallStub(
2966         Builtins::CallableFor(isolate(), Builtins::kLoadGlobalIC_NoFeedback),
2967         lazy_context(), lazy_name(), SmiConstant(ic_kind));
2968   }
2969 }
2970 
LoadGlobalIC_TryPropertyCellCase(TNode<FeedbackVector> vector,TNode<TaggedIndex> slot,const LazyNode<Context> & lazy_context,ExitPoint * exit_point,Label * try_handler,Label * miss)2971 void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
2972     TNode<FeedbackVector> vector, TNode<TaggedIndex> slot,
2973     const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
2974     Label* try_handler, Label* miss) {
2975   Comment("LoadGlobalIC_TryPropertyCellCase");
2976 
2977   Label if_lexical_var(this), if_property_cell(this);
2978   TNode<MaybeObject> maybe_weak_ref = LoadFeedbackVectorSlot(vector, slot);
2979   Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_property_cell);
2980 
2981   BIND(&if_property_cell);
2982   {
2983     // Load value or try handler case if the weak reference is cleared.
2984     CSA_ASSERT(this, IsWeakOrCleared(maybe_weak_ref));
2985     TNode<PropertyCell> property_cell =
2986         CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, try_handler));
2987     TNode<Object> value =
2988         LoadObjectField(property_cell, PropertyCell::kValueOffset);
2989     GotoIf(TaggedEqual(value, TheHoleConstant()), miss);
2990     exit_point->Return(value);
2991   }
2992 
2993   BIND(&if_lexical_var);
2994   {
2995     Comment("Load lexical variable");
2996     TNode<IntPtrT> lexical_handler = SmiUntag(CAST(maybe_weak_ref));
2997     TNode<IntPtrT> context_index =
2998         Signed(DecodeWord<FeedbackNexus::ContextIndexBits>(lexical_handler));
2999     TNode<IntPtrT> slot_index =
3000         Signed(DecodeWord<FeedbackNexus::SlotIndexBits>(lexical_handler));
3001     TNode<Context> context = lazy_context();
3002     TNode<Context> script_context = LoadScriptContext(context, context_index);
3003     TNode<Object> result = LoadContextElement(script_context, slot_index);
3004     exit_point->Return(result);
3005   }
3006 }
3007 
LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector,TNode<TaggedIndex> slot,const LazyNode<Context> & lazy_context,const LazyNode<Name> & lazy_name,TypeofMode typeof_mode,ExitPoint * exit_point,Label * miss)3008 void AccessorAssembler::LoadGlobalIC_TryHandlerCase(
3009     TNode<FeedbackVector> vector, TNode<TaggedIndex> slot,
3010     const LazyNode<Context>& lazy_context, const LazyNode<Name>& lazy_name,
3011     TypeofMode typeof_mode, ExitPoint* exit_point, Label* miss) {
3012   Comment("LoadGlobalIC_TryHandlerCase");
3013 
3014   Label call_handler(this), non_smi(this);
3015 
3016   TNode<MaybeObject> feedback_element =
3017       LoadFeedbackVectorSlot(vector, slot, kTaggedSize);
3018   TNode<Object> handler = CAST(feedback_element);
3019   GotoIf(TaggedEqual(handler, UninitializedSymbolConstant()), miss);
3020 
3021   OnNonExistent on_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF
3022                                      ? OnNonExistent::kThrowReferenceError
3023                                      : OnNonExistent::kReturnUndefined;
3024 
3025   TNode<Context> context = lazy_context();
3026   TNode<NativeContext> native_context = LoadNativeContext(context);
3027   TNode<JSGlobalProxy> receiver =
3028       CAST(LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX));
3029   TNode<Object> global =
3030       LoadContextElement(native_context, Context::EXTENSION_INDEX);
3031 
3032   LazyLoadICParameters p([=] { return context; }, receiver, lazy_name,
3033                          [=] { return slot; }, vector, global);
3034 
3035   HandleLoadICHandlerCase(&p, handler, miss, exit_point, ICMode::kGlobalIC,
3036                           on_nonexistent);
3037 }
3038 
ScriptContextTableLookup(TNode<Name> name,TNode<NativeContext> native_context,Label * found_hole,Label * not_found)3039 void AccessorAssembler::ScriptContextTableLookup(
3040     TNode<Name> name, TNode<NativeContext> native_context, Label* found_hole,
3041     Label* not_found) {
3042   TNode<ScriptContextTable> script_context_table = CAST(
3043       LoadContextElement(native_context, Context::SCRIPT_CONTEXT_TABLE_INDEX));
3044   TVARIABLE(IntPtrT, context_index, IntPtrConstant(-1));
3045   Label loop(this, &context_index);
3046   TNode<IntPtrT> num_script_contexts = SmiUntag(CAST(LoadFixedArrayElement(
3047       script_context_table, ScriptContextTable::kUsedSlotIndex)));
3048   Goto(&loop);
3049 
3050   BIND(&loop);
3051   {
3052     context_index = IntPtrAdd(context_index.value(), IntPtrConstant(1));
3053     GotoIf(IntPtrGreaterThanOrEqual(context_index.value(), num_script_contexts),
3054            not_found);
3055 
3056     TNode<Context> script_context = CAST(LoadFixedArrayElement(
3057         script_context_table, context_index.value(),
3058         ScriptContextTable::kFirstContextSlotIndex * kTaggedSize));
3059     TNode<ScopeInfo> scope_info =
3060         CAST(LoadContextElement(script_context, Context::SCOPE_INFO_INDEX));
3061     TNode<IntPtrT> length = LoadAndUntagFixedArrayBaseLength(scope_info);
3062     GotoIf(IntPtrLessThanOrEqual(length, IntPtrConstant(0)), &loop);
3063 
3064     TVARIABLE(IntPtrT, scope_var_index,
3065               IntPtrConstant(ScopeInfo::kVariablePartIndex - 1));
3066     TNode<IntPtrT> num_scope_vars = SmiUntag(CAST(LoadFixedArrayElement(
3067         scope_info, IntPtrConstant(ScopeInfo::Fields::kContextLocalCount))));
3068     TNode<IntPtrT> end_index = IntPtrAdd(
3069         num_scope_vars, IntPtrConstant(ScopeInfo::kVariablePartIndex));
3070     Label loop_scope_info(this, &scope_var_index);
3071     Goto(&loop_scope_info);
3072 
3073     BIND(&loop_scope_info);
3074     {
3075       scope_var_index = IntPtrAdd(scope_var_index.value(), IntPtrConstant(1));
3076       GotoIf(IntPtrGreaterThanOrEqual(scope_var_index.value(), end_index),
3077              &loop);
3078 
3079       TNode<Object> var_name =
3080           LoadFixedArrayElement(scope_info, scope_var_index.value(), 0);
3081       GotoIf(TaggedNotEqual(var_name, name), &loop_scope_info);
3082 
3083       TNode<IntPtrT> var_index =
3084           IntPtrAdd(IntPtrConstant(Context::MIN_CONTEXT_SLOTS),
3085                     IntPtrSub(scope_var_index.value(),
3086                               IntPtrConstant(ScopeInfo::kVariablePartIndex)));
3087       TNode<Object> result = LoadContextElement(script_context, var_index);
3088       GotoIf(IsTheHole(result), found_hole);
3089       Return(result);
3090     }
3091   }
3092 }
3093 
LoadGlobalIC_NoFeedback(TNode<Context> context,TNode<Object> name,TNode<Smi> smi_typeof_mode)3094 void AccessorAssembler::LoadGlobalIC_NoFeedback(TNode<Context> context,
3095                                                 TNode<Object> name,
3096                                                 TNode<Smi> smi_typeof_mode) {
3097   TNode<NativeContext> native_context = LoadNativeContext(context);
3098   Label regular_load(this), throw_reference_error(this, Label::kDeferred);
3099 
3100   GotoIfNot(IsString(CAST(name)), &regular_load);
3101   ScriptContextTableLookup(CAST(name), native_context, &throw_reference_error,
3102                            &regular_load);
3103 
3104   BIND(&throw_reference_error);
3105   Return(CallRuntime(Runtime::kThrowReferenceError, context, name));
3106 
3107   BIND(&regular_load);
3108   TNode<JSGlobalObject> global_object =
3109       CAST(LoadContextElement(native_context, Context::EXTENSION_INDEX));
3110   TailCallStub(Builtins::CallableFor(isolate(), Builtins::kLoadIC_NoFeedback),
3111                context, global_object, name, smi_typeof_mode);
3112 }
3113 
KeyedLoadIC(const LoadICParameters * p,LoadAccessMode access_mode)3114 void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
3115                                     LoadAccessMode access_mode) {
3116   ExitPoint direct_exit(this);
3117 
3118   TVARIABLE(MaybeObject, var_handler);
3119   Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred),
3120       try_megamorphic(this, Label::kDeferred),
3121       try_uninitialized(this, Label::kDeferred),
3122       try_polymorphic_name(this, Label::kDeferred),
3123       miss(this, Label::kDeferred), generic(this, Label::kDeferred);
3124 
3125   TNode<Map> lookup_start_object_map =
3126       LoadReceiverMap(p->receiver_and_lookup_start_object());
3127   GotoIf(IsDeprecatedMap(lookup_start_object_map), &miss);
3128 
3129   GotoIf(IsUndefined(p->vector()), &generic);
3130 
3131   // Check monomorphic case.
3132   TNode<MaybeObject> feedback =
3133       TryMonomorphicCase(p->slot(), CAST(p->vector()), lookup_start_object_map,
3134                          &if_handler, &var_handler, &try_polymorphic);
3135   BIND(&if_handler);
3136   {
3137     LazyLoadICParameters lazy_p(p);
3138     HandleLoadICHandlerCase(&lazy_p, CAST(var_handler.value()), &miss,
3139                             &direct_exit, ICMode::kNonGlobalIC,
3140                             OnNonExistent::kReturnUndefined, kSupportElements,
3141                             access_mode);
3142   }
3143 
3144   BIND(&try_polymorphic);
3145   TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3146   {
3147     // Check polymorphic case.
3148     Comment("KeyedLoadIC_try_polymorphic");
3149     GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
3150     HandlePolymorphicCase(lookup_start_object_map, CAST(strong_feedback),
3151                           &if_handler, &var_handler, &miss);
3152   }
3153 
3154   BIND(&try_megamorphic);
3155   {
3156     // Check megamorphic case.
3157     Comment("KeyedLoadIC_try_megamorphic");
3158     Branch(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()), &generic,
3159            &try_uninitialized);
3160   }
3161 
3162   BIND(&generic);
3163   {
3164     // TODO(jkummerow): Inline this? Or some of it?
3165     TailCallBuiltin(access_mode == LoadAccessMode::kLoad
3166                         ? Builtins::kKeyedLoadIC_Megamorphic
3167                         : Builtins::kKeyedHasIC_Megamorphic,
3168                     p->context(), p->receiver(), p->name(), p->slot(),
3169                     p->vector());
3170   }
3171 
3172   BIND(&try_uninitialized);
3173   {
3174     // Check uninitialized case.
3175     Comment("KeyedLoadIC_try_uninitialized");
3176     Branch(TaggedEqual(strong_feedback, UninitializedSymbolConstant()), &miss,
3177            &try_polymorphic_name);
3178   }
3179 
3180   BIND(&try_polymorphic_name);
3181   {
3182     // We might have a name in feedback, and a weak fixed array in the next
3183     // slot.
3184     Comment("KeyedLoadIC_try_polymorphic_name");
3185     TVARIABLE(Name, var_name);
3186     TVARIABLE(IntPtrT, var_index);
3187     Label if_polymorphic_name(this), feedback_matches(this),
3188         if_internalized(this), if_notinternalized(this, Label::kDeferred);
3189 
3190     // Fast-case: The recorded {feedback} matches the {name}.
3191     GotoIf(TaggedEqual(strong_feedback, p->name()), &feedback_matches);
3192 
3193     // Try to internalize the {name} if it isn't already.
3194     TryToName(p->name(), &miss, &var_index, &if_internalized, &var_name, &miss,
3195               &if_notinternalized);
3196 
3197     BIND(&if_internalized);
3198     {
3199       // The {var_name} now contains a unique name.
3200       Branch(TaggedEqual(strong_feedback, var_name.value()),
3201              &if_polymorphic_name, &miss);
3202     }
3203 
3204     BIND(&if_notinternalized);
3205     {
3206       TVARIABLE(IntPtrT, var_index);
3207       TryInternalizeString(CAST(p->name()), &miss, &var_index, &if_internalized,
3208                            &var_name, &miss, &miss);
3209     }
3210 
3211     BIND(&feedback_matches);
3212     {
3213       var_name = CAST(p->name());
3214       Goto(&if_polymorphic_name);
3215     }
3216 
3217     BIND(&if_polymorphic_name);
3218     {
3219       // If the name comparison succeeded, we know we have a weak fixed array
3220       // with at least one map/handler pair.
3221       TailCallBuiltin(access_mode == LoadAccessMode::kLoad
3222                           ? Builtins::kKeyedLoadIC_PolymorphicName
3223                           : Builtins::kKeyedHasIC_PolymorphicName,
3224                       p->context(), p->receiver(), var_name.value(), p->slot(),
3225                       p->vector());
3226     }
3227   }
3228 
3229   BIND(&miss);
3230   {
3231     Comment("KeyedLoadIC_miss");
3232     TailCallRuntime(
3233         access_mode == LoadAccessMode::kLoad ? Runtime::kKeyedLoadIC_Miss
3234                                              : Runtime::kKeyedHasIC_Miss,
3235         p->context(), p->receiver(), p->name(), p->slot(), p->vector());
3236   }
3237 }
3238 
KeyedLoadICGeneric(const LoadICParameters * p)3239 void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
3240   TVARIABLE(Object, var_name, p->name());
3241 
3242   Label if_runtime(this, Label::kDeferred);
3243   TNode<Object> lookup_start_object = p->lookup_start_object();
3244   GotoIf(TaggedIsSmi(lookup_start_object), &if_runtime);
3245   GotoIf(IsNullOrUndefined(lookup_start_object), &if_runtime);
3246 
3247   {
3248     TVARIABLE(IntPtrT, var_index);
3249     TVARIABLE(Name, var_unique);
3250     Label if_index(this), if_unique_name(this, &var_name), if_notunique(this),
3251         if_other(this, Label::kDeferred);
3252 
3253     TryToName(var_name.value(), &if_index, &var_index, &if_unique_name,
3254               &var_unique, &if_other, &if_notunique);
3255 
3256     BIND(&if_unique_name);
3257     {
3258       LoadICParameters pp(p, var_unique.value());
3259       TNode<Map> lookup_start_object_map = LoadMap(CAST(lookup_start_object));
3260       GenericPropertyLoad(CAST(lookup_start_object), lookup_start_object_map,
3261                           LoadMapInstanceType(lookup_start_object_map), &pp,
3262                           &if_runtime);
3263     }
3264 
3265     BIND(&if_other);
3266     {
3267       var_name = CallBuiltin(Builtins::kToName, p->context(), var_name.value());
3268       TryToName(var_name.value(), &if_index, &var_index, &if_unique_name,
3269                 &var_unique, &if_runtime, &if_notunique);
3270     }
3271 
3272     BIND(&if_notunique);
3273     {
3274       if (FLAG_internalize_on_the_fly) {
3275         // Ideally we could return undefined directly here if the name is not
3276         // found in the string table, i.e. it was never internalized, but that
3277         // invariant doesn't hold with named property interceptors (at this
3278         // point), so we take the {if_runtime} path instead.
3279         Label if_in_string_table(this);
3280         TryInternalizeString(CAST(var_name.value()), &if_index, &var_index,
3281                              &if_in_string_table, &var_unique, &if_runtime,
3282                              &if_runtime);
3283 
3284         BIND(&if_in_string_table);
3285         {
3286           // TODO(bmeurer): We currently use a version of GenericPropertyLoad
3287           // here, where we don't try to probe the megamorphic stub cache
3288           // after successfully internalizing the incoming string. Past
3289           // experiments with this have shown that it causes too much traffic
3290           // on the stub cache. We may want to re-evaluate that in the future.
3291           LoadICParameters pp(p, var_unique.value());
3292           TNode<Map> lookup_start_object_map =
3293               LoadMap(CAST(lookup_start_object));
3294           GenericPropertyLoad(CAST(lookup_start_object),
3295                               lookup_start_object_map,
3296                               LoadMapInstanceType(lookup_start_object_map), &pp,
3297                               &if_runtime, kDontUseStubCache);
3298         }
3299       } else {
3300         Goto(&if_runtime);
3301       }
3302     }
3303 
3304     BIND(&if_index);
3305     {
3306       TNode<Map> lookup_start_object_map = LoadMap(CAST(lookup_start_object));
3307       GenericElementLoad(CAST(lookup_start_object), lookup_start_object_map,
3308                          LoadMapInstanceType(lookup_start_object_map),
3309                          var_index.value(), &if_runtime);
3310     }
3311   }
3312 
3313   BIND(&if_runtime);
3314   {
3315     Comment("KeyedLoadGeneric_slow");
3316     IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1);
3317     // TODO(jkummerow): Should we use the GetProperty TF stub instead?
3318     TailCallRuntime(Runtime::kGetProperty, p->context(),
3319                     p->receiver_and_lookup_start_object(), var_name.value());
3320   }
3321 }
3322 
KeyedLoadICPolymorphicName(const LoadICParameters * p,LoadAccessMode access_mode)3323 void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p,
3324                                                    LoadAccessMode access_mode) {
3325   TVARIABLE(MaybeObject, var_handler);
3326   Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
3327 
3328   TNode<Object> lookup_start_object = p->lookup_start_object();
3329   TNode<Map> lookup_start_object_map = LoadReceiverMap(lookup_start_object);
3330   TNode<Name> name = CAST(p->name());
3331   TNode<FeedbackVector> vector = CAST(p->vector());
3332   TNode<TaggedIndex> slot = p->slot();
3333   TNode<Context> context = p->context();
3334 
3335   // When we get here, we know that the {name} matches the recorded
3336   // feedback name in the {vector} and can safely be used for the
3337   // LoadIC handler logic below.
3338   CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(lookup_start_object_map)));
3339   CSA_ASSERT(this, TaggedEqual(name, LoadFeedbackVectorSlot(vector, slot)),
3340              name, vector);
3341 
3342   // Check if we have a matching handler for the {lookup_start_object_map}.
3343   TNode<MaybeObject> feedback_element =
3344       LoadFeedbackVectorSlot(vector, slot, kTaggedSize);
3345   TNode<WeakFixedArray> array = CAST(feedback_element);
3346   HandlePolymorphicCase(lookup_start_object_map, array, &if_handler,
3347                         &var_handler, &miss);
3348 
3349   BIND(&if_handler);
3350   {
3351     ExitPoint direct_exit(this);
3352     LazyLoadICParameters lazy_p(p);
3353     HandleLoadICHandlerCase(&lazy_p, CAST(var_handler.value()), &miss,
3354                             &direct_exit, ICMode::kNonGlobalIC,
3355                             OnNonExistent::kReturnUndefined, kOnlyProperties,
3356                             access_mode);
3357   }
3358 
3359   BIND(&miss);
3360   {
3361     Comment("KeyedLoadIC_miss");
3362     TailCallRuntime(
3363         access_mode == LoadAccessMode::kLoad ? Runtime::kKeyedLoadIC_Miss
3364                                              : Runtime::kKeyedHasIC_Miss,
3365         context, p->receiver_and_lookup_start_object(), name, slot, vector);
3366   }
3367 }
3368 
StoreIC(const StoreICParameters * p)3369 void AccessorAssembler::StoreIC(const StoreICParameters* p) {
3370   TVARIABLE(MaybeObject, var_handler,
3371             ReinterpretCast<MaybeObject>(SmiConstant(0)));
3372 
3373   Label if_handler(this, &var_handler),
3374       if_handler_from_stub_cache(this, &var_handler, Label::kDeferred),
3375       try_polymorphic(this, Label::kDeferred),
3376       try_megamorphic(this, Label::kDeferred), miss(this, Label::kDeferred),
3377       no_feedback(this, Label::kDeferred);
3378 
3379   TNode<Map> receiver_map = LoadReceiverMap(p->receiver());
3380   GotoIf(IsDeprecatedMap(receiver_map), &miss);
3381 
3382   GotoIf(IsUndefined(p->vector()), &no_feedback);
3383 
3384   // Check monomorphic case.
3385   TNode<MaybeObject> feedback =
3386       TryMonomorphicCase(p->slot(), CAST(p->vector()), receiver_map,
3387                          &if_handler, &var_handler, &try_polymorphic);
3388   BIND(&if_handler);
3389   {
3390     Comment("StoreIC_if_handler");
3391     HandleStoreICHandlerCase(p, var_handler.value(), &miss,
3392                              ICMode::kNonGlobalIC);
3393   }
3394 
3395   BIND(&try_polymorphic);
3396   TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3397   {
3398     // Check polymorphic case.
3399     Comment("StoreIC_try_polymorphic");
3400     GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
3401     HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
3402                           &var_handler, &miss);
3403   }
3404 
3405   BIND(&try_megamorphic);
3406   {
3407     // Check megamorphic case.
3408     GotoIfNot(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()), &miss);
3409 
3410     TryProbeStubCache(isolate()->store_stub_cache(), p->receiver(),
3411                       CAST(p->name()), &if_handler, &var_handler, &miss);
3412   }
3413 
3414   BIND(&no_feedback);
3415   {
3416     TailCallBuiltin(Builtins::kStoreIC_NoFeedback, p->context(), p->receiver(),
3417                     p->name(), p->value(), p->slot());
3418   }
3419 
3420   BIND(&miss);
3421   {
3422     TailCallRuntime(Runtime::kStoreIC_Miss, p->context(), p->value(), p->slot(),
3423                     p->vector(), p->receiver(), p->name());
3424   }
3425 }
3426 
StoreGlobalIC(const StoreICParameters * pp)3427 void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
3428   Label if_lexical_var(this), if_heapobject(this);
3429   TNode<MaybeObject> maybe_weak_ref =
3430       LoadFeedbackVectorSlot(CAST(pp->vector()), pp->slot());
3431   Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_heapobject);
3432 
3433   BIND(&if_heapobject);
3434   {
3435     Label try_handler(this), miss(this, Label::kDeferred);
3436 
3437     CSA_ASSERT(this, IsWeakOrCleared(maybe_weak_ref));
3438     TNode<PropertyCell> property_cell =
3439         CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, &try_handler));
3440 
3441     ExitPoint direct_exit(this);
3442     StoreGlobalIC_PropertyCellCase(property_cell, pp->value(), &direct_exit,
3443                                    &miss);
3444 
3445     BIND(&try_handler);
3446     {
3447       Comment("StoreGlobalIC_try_handler");
3448       TNode<MaybeObject> handler =
3449           LoadFeedbackVectorSlot(CAST(pp->vector()), pp->slot(), kTaggedSize);
3450 
3451       GotoIf(TaggedEqual(handler, UninitializedSymbolConstant()), &miss);
3452 
3453       DCHECK(pp->receiver_is_null());
3454       TNode<NativeContext> native_context = LoadNativeContext(pp->context());
3455       StoreICParameters p(
3456           pp->context(),
3457           LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX),
3458           pp->name(), pp->value(), pp->slot(), pp->vector());
3459 
3460       HandleStoreICHandlerCase(&p, handler, &miss, ICMode::kGlobalIC);
3461     }
3462 
3463     BIND(&miss);
3464     {
3465       TailCallRuntime(Runtime::kStoreGlobalIC_Miss, pp->context(), pp->value(),
3466                       pp->slot(), pp->vector(), pp->name());
3467     }
3468   }
3469 
3470   BIND(&if_lexical_var);
3471   {
3472     Comment("Store lexical variable");
3473     TNode<IntPtrT> lexical_handler = SmiUntag(CAST(maybe_weak_ref));
3474     TNode<IntPtrT> context_index =
3475         Signed(DecodeWord<FeedbackNexus::ContextIndexBits>(lexical_handler));
3476     TNode<IntPtrT> slot_index =
3477         Signed(DecodeWord<FeedbackNexus::SlotIndexBits>(lexical_handler));
3478     TNode<Context> script_context =
3479         LoadScriptContext(pp->context(), context_index);
3480     StoreContextElement(script_context, slot_index, pp->value());
3481     Return(pp->value());
3482   }
3483 }
3484 
StoreGlobalIC_PropertyCellCase(TNode<PropertyCell> property_cell,TNode<Object> value,ExitPoint * exit_point,Label * miss)3485 void AccessorAssembler::StoreGlobalIC_PropertyCellCase(
3486     TNode<PropertyCell> property_cell, TNode<Object> value,
3487     ExitPoint* exit_point, Label* miss) {
3488   Comment("StoreGlobalIC_TryPropertyCellCase");
3489 
3490   // Load the payload of the global parameter cell. A hole indicates that
3491   // the cell has been invalidated and that the store must be handled by the
3492   // runtime.
3493   TNode<Object> cell_contents =
3494       LoadObjectField(property_cell, PropertyCell::kValueOffset);
3495   TNode<Int32T> details = LoadAndUntagToWord32ObjectField(
3496       property_cell, PropertyCell::kPropertyDetailsRawOffset);
3497   GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), miss);
3498   CSA_ASSERT(this,
3499              Word32Equal(DecodeWord32<PropertyDetails::KindField>(details),
3500                          Int32Constant(kData)));
3501 
3502   TNode<Uint32T> type =
3503       DecodeWord32<PropertyDetails::PropertyCellTypeField>(details);
3504 
3505   Label constant(this), store(this), not_smi(this);
3506 
3507   GotoIf(Word32Equal(type, Int32Constant(
3508                                static_cast<int>(PropertyCellType::kConstant))),
3509          &constant);
3510 
3511   GotoIf(IsTheHole(cell_contents), miss);
3512 
3513   GotoIf(Word32Equal(
3514              type, Int32Constant(static_cast<int>(PropertyCellType::kMutable))),
3515          &store);
3516   CSA_ASSERT(this,
3517              Word32Or(Word32Equal(type, Int32Constant(static_cast<int>(
3518                                             PropertyCellType::kConstantType))),
3519                       Word32Equal(type, Int32Constant(static_cast<int>(
3520                                             PropertyCellType::kUndefined)))));
3521 
3522   GotoIfNot(TaggedIsSmi(cell_contents), &not_smi);
3523   GotoIfNot(TaggedIsSmi(value), miss);
3524   Goto(&store);
3525 
3526   BIND(&not_smi);
3527   {
3528     GotoIf(TaggedIsSmi(value), miss);
3529     TNode<Map> expected_map = LoadMap(CAST(cell_contents));
3530     TNode<Map> map = LoadMap(CAST(value));
3531     GotoIfNot(TaggedEqual(expected_map, map), miss);
3532     Goto(&store);
3533   }
3534 
3535   BIND(&store);
3536   {
3537     StoreObjectField(property_cell, PropertyCell::kValueOffset, value);
3538     exit_point->Return(value);
3539   }
3540 
3541   BIND(&constant);
3542   {
3543     GotoIfNot(TaggedEqual(cell_contents, value), miss);
3544     exit_point->Return(value);
3545   }
3546 }
3547 
KeyedStoreIC(const StoreICParameters * p)3548 void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
3549   Label miss(this, Label::kDeferred);
3550   {
3551     TVARIABLE(MaybeObject, var_handler);
3552 
3553     Label if_handler(this, &var_handler),
3554         try_polymorphic(this, Label::kDeferred),
3555         try_megamorphic(this, Label::kDeferred),
3556         no_feedback(this, Label::kDeferred),
3557         try_polymorphic_name(this, Label::kDeferred);
3558 
3559     TNode<Map> receiver_map = LoadReceiverMap(p->receiver());
3560     GotoIf(IsDeprecatedMap(receiver_map), &miss);
3561 
3562     GotoIf(IsUndefined(p->vector()), &no_feedback);
3563 
3564     // Check monomorphic case.
3565     TNode<MaybeObject> feedback =
3566         TryMonomorphicCase(p->slot(), CAST(p->vector()), receiver_map,
3567                            &if_handler, &var_handler, &try_polymorphic);
3568     BIND(&if_handler);
3569     {
3570       Comment("KeyedStoreIC_if_handler");
3571       HandleStoreICHandlerCase(p, var_handler.value(), &miss,
3572                                ICMode::kNonGlobalIC, kSupportElements);
3573     }
3574 
3575     BIND(&try_polymorphic);
3576     TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3577     {
3578       // CheckPolymorphic case.
3579       Comment("KeyedStoreIC_try_polymorphic");
3580       GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
3581                 &try_megamorphic);
3582       HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
3583                             &var_handler, &miss);
3584     }
3585 
3586     BIND(&try_megamorphic);
3587     {
3588       // Check megamorphic case.
3589       Comment("KeyedStoreIC_try_megamorphic");
3590       Branch(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()),
3591              &no_feedback, &try_polymorphic_name);
3592     }
3593 
3594     BIND(&no_feedback);
3595     {
3596       TailCallBuiltin(Builtins::kKeyedStoreIC_Megamorphic, p->context(),
3597                       p->receiver(), p->name(), p->value(), p->slot());
3598     }
3599 
3600     BIND(&try_polymorphic_name);
3601     {
3602       // We might have a name in feedback, and a fixed array in the next slot.
3603       Comment("KeyedStoreIC_try_polymorphic_name");
3604       GotoIfNot(TaggedEqual(strong_feedback, p->name()), &miss);
3605       // If the name comparison succeeded, we know we have a feedback vector
3606       // with at least one map/handler pair.
3607       TNode<MaybeObject> feedback_element =
3608           LoadFeedbackVectorSlot(CAST(p->vector()), p->slot(), kTaggedSize);
3609       TNode<WeakFixedArray> array = CAST(feedback_element);
3610       HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler,
3611                             &miss);
3612     }
3613   }
3614   BIND(&miss);
3615   {
3616     Comment("KeyedStoreIC_miss");
3617     TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context(), p->value(),
3618                     p->slot(), p->vector(), p->receiver(), p->name());
3619   }
3620 }
3621 
StoreInArrayLiteralIC(const StoreICParameters * p)3622 void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
3623   Label miss(this, Label::kDeferred), no_feedback(this, Label::kDeferred);
3624   {
3625     TVARIABLE(MaybeObject, var_handler);
3626 
3627     Label if_handler(this, &var_handler),
3628         try_polymorphic(this, Label::kDeferred),
3629         try_megamorphic(this, Label::kDeferred);
3630 
3631     TNode<Map> array_map = LoadReceiverMap(p->receiver());
3632     GotoIf(IsDeprecatedMap(array_map), &miss);
3633 
3634     GotoIf(IsUndefined(p->vector()), &no_feedback);
3635 
3636     TNode<MaybeObject> feedback =
3637         TryMonomorphicCase(p->slot(), CAST(p->vector()), array_map, &if_handler,
3638                            &var_handler, &try_polymorphic);
3639 
3640     BIND(&if_handler);
3641     {
3642       Comment("StoreInArrayLiteralIC_if_handler");
3643       // This is a stripped-down version of HandleStoreICHandlerCase.
3644       Label if_transitioning_element_store(this), if_smi_handler(this);
3645 
3646       // Check used to identify the Slow case.
3647       // Currently only the Slow case uses a Smi handler.
3648       GotoIf(TaggedIsSmi(var_handler.value()), &if_smi_handler);
3649 
3650       TNode<HeapObject> handler = CAST(var_handler.value());
3651       GotoIfNot(IsCode(handler), &if_transitioning_element_store);
3652       TailCallStub(StoreWithVectorDescriptor{}, CAST(handler), p->context(),
3653                    p->receiver(), p->name(), p->value(), p->slot(),
3654                    p->vector());
3655 
3656       BIND(&if_transitioning_element_store);
3657       {
3658         TNode<MaybeObject> maybe_transition_map =
3659             LoadHandlerDataField(CAST(handler), 1);
3660         TNode<Map> transition_map =
3661             CAST(GetHeapObjectAssumeWeak(maybe_transition_map, &miss));
3662         GotoIf(IsDeprecatedMap(transition_map), &miss);
3663         TNode<Code> code =
3664             CAST(LoadObjectField(handler, StoreHandler::kSmiHandlerOffset));
3665         TailCallStub(StoreTransitionDescriptor{}, code, p->context(),
3666                      p->receiver(), p->name(), transition_map, p->value(),
3667                      p->slot(), p->vector());
3668       }
3669 
3670       BIND(&if_smi_handler);
3671       {
3672 #ifdef DEBUG
3673         // A check to ensure that no other Smi handler uses this path.
3674         TNode<Int32T> handler_word = SmiToInt32(CAST(var_handler.value()));
3675         TNode<Uint32T> handler_kind =
3676             DecodeWord32<StoreHandler::KindBits>(handler_word);
3677         CSA_ASSERT(this, Word32Equal(handler_kind,
3678                                      Int32Constant(StoreHandler::kSlow)));
3679 #endif
3680 
3681         Comment("StoreInArrayLiteralIC_Slow");
3682         TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context(),
3683                         p->value(), p->receiver(), p->name());
3684       }
3685     }
3686 
3687     BIND(&try_polymorphic);
3688     TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3689     {
3690       Comment("StoreInArrayLiteralIC_try_polymorphic");
3691       GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
3692                 &try_megamorphic);
3693       HandlePolymorphicCase(array_map, CAST(strong_feedback), &if_handler,
3694                             &var_handler, &miss);
3695     }
3696 
3697     BIND(&try_megamorphic);
3698     {
3699       Comment("StoreInArrayLiteralIC_try_megamorphic");
3700       CSA_ASSERT(
3701           this,
3702           Word32Or(TaggedEqual(strong_feedback, UninitializedSymbolConstant()),
3703                    TaggedEqual(strong_feedback, MegamorphicSymbolConstant())));
3704       GotoIfNot(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()),
3705                 &miss);
3706       TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context(),
3707                       p->value(), p->receiver(), p->name());
3708     }
3709   }
3710 
3711   BIND(&no_feedback);
3712   {
3713     Comment("StoreInArrayLiteralIC_NoFeedback");
3714     TailCallBuiltin(Builtins::kSetPropertyInLiteral, p->context(),
3715                     p->receiver(), p->name(), p->value());
3716   }
3717 
3718   BIND(&miss);
3719   {
3720     Comment("StoreInArrayLiteralIC_miss");
3721     TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Miss, p->context(),
3722                     p->value(), p->slot(), p->vector(), p->receiver(),
3723                     p->name());
3724   }
3725 }
3726 
3727 //////////////////// Public methods.
3728 
GenerateLoadIC()3729 void AccessorAssembler::GenerateLoadIC() {
3730   using Descriptor = LoadWithVectorDescriptor;
3731 
3732   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3733   auto name = Parameter<Object>(Descriptor::kName);
3734   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3735   auto vector = Parameter<HeapObject>(Descriptor::kVector);
3736   auto context = Parameter<Context>(Descriptor::kContext);
3737 
3738   LoadICParameters p(context, receiver, name, slot, vector);
3739   LoadIC(&p);
3740 }
3741 
GenerateLoadIC_Megamorphic()3742 void AccessorAssembler::GenerateLoadIC_Megamorphic() {
3743   using Descriptor = LoadWithVectorDescriptor;
3744 
3745   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3746   auto name = Parameter<Object>(Descriptor::kName);
3747   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3748   auto vector = Parameter<HeapObject>(Descriptor::kVector);
3749   auto context = Parameter<Context>(Descriptor::kContext);
3750 
3751   ExitPoint direct_exit(this);
3752   TVARIABLE(MaybeObject, var_handler);
3753   Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
3754 
3755   CSA_ASSERT(this, TaggedEqual(LoadFeedbackVectorSlot(CAST(vector), slot),
3756                                MegamorphicSymbolConstant()));
3757 
3758   TryProbeStubCache(isolate()->load_stub_cache(), receiver, CAST(name),
3759                     &if_handler, &var_handler, &miss);
3760 
3761   BIND(&if_handler);
3762   LazyLoadICParameters p(
3763       // lazy_context
3764       [=] { return context; }, receiver,
3765       // lazy_name
3766       [=] { return name; },
3767       // lazy_slot
3768       [=] { return slot; }, vector);
3769   HandleLoadICHandlerCase(&p, CAST(var_handler.value()), &miss, &direct_exit);
3770 
3771   BIND(&miss);
3772   direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name,
3773                                 slot, vector);
3774 }
3775 
GenerateLoadIC_Noninlined()3776 void AccessorAssembler::GenerateLoadIC_Noninlined() {
3777   using Descriptor = LoadWithVectorDescriptor;
3778 
3779   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3780   auto name = Parameter<Object>(Descriptor::kName);
3781   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3782   auto vector = Parameter<FeedbackVector>(Descriptor::kVector);
3783   auto context = Parameter<Context>(Descriptor::kContext);
3784 
3785   ExitPoint direct_exit(this);
3786   TVARIABLE(MaybeObject, var_handler);
3787   Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
3788 
3789   TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot(vector, slot);
3790   TNode<HeapObject> feedback = CAST(feedback_element);
3791 
3792   LoadICParameters p(context, receiver, name, slot, vector);
3793   TNode<Map> lookup_start_object_map = LoadReceiverMap(p.lookup_start_object());
3794   LoadIC_Noninlined(&p, lookup_start_object_map, feedback, &var_handler,
3795                     &if_handler, &miss, &direct_exit);
3796 
3797   BIND(&if_handler);
3798   {
3799     LazyLoadICParameters lazy_p(&p);
3800     HandleLoadICHandlerCase(&lazy_p, CAST(var_handler.value()), &miss,
3801                             &direct_exit);
3802   }
3803 
3804   BIND(&miss);
3805   direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name,
3806                                 slot, vector);
3807 }
3808 
GenerateLoadIC_NoFeedback()3809 void AccessorAssembler::GenerateLoadIC_NoFeedback() {
3810   using Descriptor = LoadNoFeedbackDescriptor;
3811 
3812   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3813   auto name = Parameter<Object>(Descriptor::kName);
3814   auto context = Parameter<Context>(Descriptor::kContext);
3815   auto ic_kind = Parameter<Smi>(Descriptor::kICKind);
3816 
3817   LoadICParameters p(context, receiver, name,
3818                      TaggedIndexConstant(FeedbackSlot::Invalid().ToInt()),
3819                      UndefinedConstant());
3820   LoadIC_NoFeedback(&p, ic_kind);
3821 }
3822 
GenerateLoadICTrampoline()3823 void AccessorAssembler::GenerateLoadICTrampoline() {
3824   using Descriptor = LoadDescriptor;
3825 
3826   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3827   auto name = Parameter<Object>(Descriptor::kName);
3828   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3829   auto context = Parameter<Context>(Descriptor::kContext);
3830   TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
3831 
3832   TailCallBuiltin(Builtins::kLoadIC, context, receiver, name, slot, vector);
3833 }
3834 
GenerateLoadICTrampoline_Megamorphic()3835 void AccessorAssembler::GenerateLoadICTrampoline_Megamorphic() {
3836   using Descriptor = LoadDescriptor;
3837 
3838   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3839   auto name = Parameter<Object>(Descriptor::kName);
3840   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3841   auto context = Parameter<Context>(Descriptor::kContext);
3842   TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
3843 
3844   TailCallBuiltin(Builtins::kLoadIC_Megamorphic, context, receiver, name, slot,
3845                   vector);
3846 }
3847 
GenerateLoadSuperIC()3848 void AccessorAssembler::GenerateLoadSuperIC() {
3849   using Descriptor = LoadWithReceiverAndVectorDescriptor;
3850 
3851   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3852   auto lookup_start_object = Parameter<Object>(Descriptor::kLookupStartObject);
3853   auto name = Parameter<Object>(Descriptor::kName);
3854   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3855   auto vector = Parameter<HeapObject>(Descriptor::kVector);
3856   auto context = Parameter<Context>(Descriptor::kContext);
3857 
3858   LoadICParameters p(context, receiver, name, slot, vector,
3859                      lookup_start_object);
3860   LoadSuperIC(&p);
3861 }
3862 
GenerateLoadGlobalIC_NoFeedback()3863 void AccessorAssembler::GenerateLoadGlobalIC_NoFeedback() {
3864   using Descriptor = LoadGlobalNoFeedbackDescriptor;
3865 
3866   auto name = Parameter<Object>(Descriptor::kName);
3867   auto context = Parameter<Context>(Descriptor::kContext);
3868   auto ic_kind = Parameter<Smi>(Descriptor::kICKind);
3869 
3870   LoadGlobalIC_NoFeedback(context, name, ic_kind);
3871 }
3872 
GenerateLoadGlobalIC(TypeofMode typeof_mode)3873 void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
3874   using Descriptor = LoadGlobalWithVectorDescriptor;
3875 
3876   auto name = Parameter<Name>(Descriptor::kName);
3877   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3878   auto vector = Parameter<HeapObject>(Descriptor::kVector);
3879   auto context = Parameter<Context>(Descriptor::kContext);
3880 
3881   ExitPoint direct_exit(this);
3882   LoadGlobalIC(
3883       vector,
3884       // lazy_slot
3885       [=] { return slot; },
3886       // lazy_context
3887       [=] { return context; },
3888       // lazy_name
3889       [=] { return name; }, typeof_mode, &direct_exit);
3890 }
3891 
GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode)3892 void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) {
3893   using Descriptor = LoadGlobalDescriptor;
3894 
3895   auto name = Parameter<Object>(Descriptor::kName);
3896   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3897   auto context = Parameter<Context>(Descriptor::kContext);
3898   TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
3899 
3900   Callable callable =
3901       CodeFactory::LoadGlobalICInOptimizedCode(isolate(), typeof_mode);
3902   TailCallStub(callable, context, name, slot, vector);
3903 }
3904 
GenerateKeyedLoadIC()3905 void AccessorAssembler::GenerateKeyedLoadIC() {
3906   using Descriptor = LoadWithVectorDescriptor;
3907 
3908   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3909   auto name = Parameter<Object>(Descriptor::kName);
3910   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3911   auto vector = Parameter<HeapObject>(Descriptor::kVector);
3912   auto context = Parameter<Context>(Descriptor::kContext);
3913 
3914   LoadICParameters p(context, receiver, name, slot, vector);
3915   KeyedLoadIC(&p, LoadAccessMode::kLoad);
3916 }
3917 
GenerateKeyedLoadIC_Megamorphic()3918 void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
3919   using Descriptor = LoadWithVectorDescriptor;
3920 
3921   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3922   auto name = Parameter<Object>(Descriptor::kName);
3923   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3924   auto vector = Parameter<HeapObject>(Descriptor::kVector);
3925   auto context = Parameter<Context>(Descriptor::kContext);
3926 
3927   LoadICParameters p(context, receiver, name, slot, vector);
3928   KeyedLoadICGeneric(&p);
3929 }
3930 
GenerateKeyedLoadICTrampoline()3931 void AccessorAssembler::GenerateKeyedLoadICTrampoline() {
3932   using Descriptor = LoadDescriptor;
3933 
3934   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3935   auto name = Parameter<Object>(Descriptor::kName);
3936   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3937   auto context = Parameter<Context>(Descriptor::kContext);
3938   TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
3939 
3940   TailCallBuiltin(Builtins::kKeyedLoadIC, context, receiver, name, slot,
3941                   vector);
3942 }
3943 
GenerateKeyedLoadICTrampoline_Megamorphic()3944 void AccessorAssembler::GenerateKeyedLoadICTrampoline_Megamorphic() {
3945   using Descriptor = LoadDescriptor;
3946 
3947   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3948   auto name = Parameter<Object>(Descriptor::kName);
3949   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3950   auto context = Parameter<Context>(Descriptor::kContext);
3951   TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
3952 
3953   TailCallBuiltin(Builtins::kKeyedLoadIC_Megamorphic, context, receiver, name,
3954                   slot, vector);
3955 }
3956 
GenerateKeyedLoadIC_PolymorphicName()3957 void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() {
3958   using Descriptor = LoadWithVectorDescriptor;
3959 
3960   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3961   auto name = Parameter<Object>(Descriptor::kName);
3962   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3963   auto vector = Parameter<FeedbackVector>(Descriptor::kVector);
3964   auto context = Parameter<Context>(Descriptor::kContext);
3965 
3966   LoadICParameters p(context, receiver, name, slot, vector);
3967   KeyedLoadICPolymorphicName(&p, LoadAccessMode::kLoad);
3968 }
3969 
GenerateStoreGlobalIC()3970 void AccessorAssembler::GenerateStoreGlobalIC() {
3971   using Descriptor = StoreGlobalWithVectorDescriptor;
3972 
3973   auto name = Parameter<Object>(Descriptor::kName);
3974   auto value = Parameter<Object>(Descriptor::kValue);
3975   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3976   auto vector = Parameter<HeapObject>(Descriptor::kVector);
3977   auto context = Parameter<Context>(Descriptor::kContext);
3978 
3979   StoreICParameters p(context, base::nullopt, name, value, slot, vector);
3980   StoreGlobalIC(&p);
3981 }
3982 
GenerateStoreGlobalICTrampoline()3983 void AccessorAssembler::GenerateStoreGlobalICTrampoline() {
3984   using Descriptor = StoreGlobalDescriptor;
3985 
3986   auto name = Parameter<Object>(Descriptor::kName);
3987   auto value = Parameter<Object>(Descriptor::kValue);
3988   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
3989   auto context = Parameter<Context>(Descriptor::kContext);
3990   TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
3991 
3992   TailCallBuiltin(Builtins::kStoreGlobalIC, context, name, value, slot, vector);
3993 }
3994 
GenerateStoreIC()3995 void AccessorAssembler::GenerateStoreIC() {
3996   using Descriptor = StoreWithVectorDescriptor;
3997 
3998   auto receiver = Parameter<Object>(Descriptor::kReceiver);
3999   auto name = Parameter<Object>(Descriptor::kName);
4000   auto value = Parameter<Object>(Descriptor::kValue);
4001   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4002   auto vector = Parameter<HeapObject>(Descriptor::kVector);
4003   auto context = Parameter<Context>(Descriptor::kContext);
4004 
4005   StoreICParameters p(context, receiver, name, value, slot, vector);
4006   StoreIC(&p);
4007 }
4008 
GenerateStoreICTrampoline()4009 void AccessorAssembler::GenerateStoreICTrampoline() {
4010   using Descriptor = StoreDescriptor;
4011 
4012   auto receiver = Parameter<Object>(Descriptor::kReceiver);
4013   auto name = Parameter<Object>(Descriptor::kName);
4014   auto value = Parameter<Object>(Descriptor::kValue);
4015   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4016   auto context = Parameter<Context>(Descriptor::kContext);
4017   TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
4018 
4019   TailCallBuiltin(Builtins::kStoreIC, context, receiver, name, value, slot,
4020                   vector);
4021 }
4022 
GenerateKeyedStoreIC()4023 void AccessorAssembler::GenerateKeyedStoreIC() {
4024   using Descriptor = StoreWithVectorDescriptor;
4025 
4026   auto receiver = Parameter<Object>(Descriptor::kReceiver);
4027   auto name = Parameter<Object>(Descriptor::kName);
4028   auto value = Parameter<Object>(Descriptor::kValue);
4029   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4030   auto vector = Parameter<HeapObject>(Descriptor::kVector);
4031   auto context = Parameter<Context>(Descriptor::kContext);
4032 
4033   StoreICParameters p(context, receiver, name, value, slot, vector);
4034   KeyedStoreIC(&p);
4035 }
4036 
GenerateKeyedStoreICTrampoline()4037 void AccessorAssembler::GenerateKeyedStoreICTrampoline() {
4038   using Descriptor = StoreDescriptor;
4039 
4040   auto receiver = Parameter<Object>(Descriptor::kReceiver);
4041   auto name = Parameter<Object>(Descriptor::kName);
4042   auto value = Parameter<Object>(Descriptor::kValue);
4043   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4044   auto context = Parameter<Context>(Descriptor::kContext);
4045   TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
4046 
4047   TailCallBuiltin(Builtins::kKeyedStoreIC, context, receiver, name, value, slot,
4048                   vector);
4049 }
4050 
GenerateStoreInArrayLiteralIC()4051 void AccessorAssembler::GenerateStoreInArrayLiteralIC() {
4052   using Descriptor = StoreWithVectorDescriptor;
4053 
4054   auto array = Parameter<Object>(Descriptor::kReceiver);
4055   auto index = Parameter<Object>(Descriptor::kName);
4056   auto value = Parameter<Object>(Descriptor::kValue);
4057   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4058   auto vector = Parameter<HeapObject>(Descriptor::kVector);
4059   auto context = Parameter<Context>(Descriptor::kContext);
4060 
4061   StoreICParameters p(context, array, index, value, slot, vector);
4062   StoreInArrayLiteralIC(&p);
4063 }
4064 
GenerateCloneObjectIC_Slow()4065 void AccessorAssembler::GenerateCloneObjectIC_Slow() {
4066   using Descriptor = CloneObjectWithVectorDescriptor;
4067   auto source = Parameter<Object>(Descriptor::kSource);
4068   auto flags = Parameter<Smi>(Descriptor::kFlags);
4069   auto context = Parameter<Context>(Descriptor::kContext);
4070 
4071   // The Slow case uses the same call interface as CloneObjectIC, so that it
4072   // can be tail called from it. However, the feedback slot and vector are not
4073   // used.
4074 
4075   TNode<NativeContext> native_context = LoadNativeContext(context);
4076   TNode<Map> initial_map = LoadObjectFunctionInitialMap(native_context);
4077   TNode<JSObject> result = AllocateJSObjectFromMap(initial_map);
4078 
4079   {
4080     Label did_set_proto_if_needed(this);
4081     TNode<BoolT> is_null_proto = SmiNotEqual(
4082         SmiAnd(flags, SmiConstant(ObjectLiteral::kHasNullPrototype)),
4083         SmiConstant(Smi::zero()));
4084     GotoIfNot(is_null_proto, &did_set_proto_if_needed);
4085 
4086     CallRuntime(Runtime::kInternalSetPrototype, context, result,
4087                 NullConstant());
4088 
4089     Goto(&did_set_proto_if_needed);
4090     BIND(&did_set_proto_if_needed);
4091   }
4092 
4093   ReturnIf(IsNullOrUndefined(source), result);
4094   source = ToObject_Inline(context, source);
4095 
4096   Label call_runtime(this, Label::kDeferred), done(this);
4097 
4098   TNode<Map> source_map = LoadMap(CAST(source));
4099   GotoIfNot(IsJSObjectMap(source_map), &call_runtime);
4100   GotoIfNot(IsEmptyFixedArray(LoadElements(CAST(source))), &call_runtime);
4101 
4102   ForEachEnumerableOwnProperty(
4103       context, source_map, CAST(source), kPropertyAdditionOrder,
4104       [=](TNode<Name> key, TNode<Object> value) {
4105         SetPropertyInLiteral(context, result, key, value);
4106       },
4107       &call_runtime);
4108   Goto(&done);
4109 
4110   BIND(&call_runtime);
4111   CallRuntime(Runtime::kCopyDataProperties, context, result, source);
4112 
4113   Goto(&done);
4114   BIND(&done);
4115   Return(result);
4116 }
4117 
GenerateCloneObjectIC()4118 void AccessorAssembler::GenerateCloneObjectIC() {
4119   using Descriptor = CloneObjectWithVectorDescriptor;
4120   auto source = Parameter<Object>(Descriptor::kSource);
4121   auto flags = Parameter<Smi>(Descriptor::kFlags);
4122   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4123   auto maybe_vector = Parameter<HeapObject>(Descriptor::kVector);
4124   auto context = Parameter<Context>(Descriptor::kContext);
4125   TVARIABLE(MaybeObject, var_handler);
4126   Label if_handler(this, &var_handler), miss(this, Label::kDeferred),
4127       try_polymorphic(this, Label::kDeferred),
4128       try_megamorphic(this, Label::kDeferred), slow(this, Label::kDeferred);
4129 
4130   TNode<Map> source_map = LoadReceiverMap(source);
4131   GotoIf(IsDeprecatedMap(source_map), &miss);
4132 
4133   GotoIf(IsUndefined(maybe_vector), &slow);
4134 
4135   TNode<MaybeObject> feedback =
4136       TryMonomorphicCase(slot, CAST(maybe_vector), source_map, &if_handler,
4137                          &var_handler, &try_polymorphic);
4138 
4139   BIND(&if_handler);
4140   {
4141     Comment("CloneObjectIC_if_handler");
4142 
4143     // Handlers for the CloneObjectIC stub are weak references to the Map of
4144     // a result object.
4145     TNode<Map> result_map = CAST(var_handler.value());
4146     TVARIABLE(HeapObject, var_properties, EmptyFixedArrayConstant());
4147     TVARIABLE(FixedArray, var_elements, EmptyFixedArrayConstant());
4148 
4149     Label allocate_object(this);
4150     GotoIf(IsNullOrUndefined(source), &allocate_object);
4151     CSA_SLOW_ASSERT(this, IsJSObjectMap(source_map));
4152     CSA_SLOW_ASSERT(this, IsJSObjectMap(result_map));
4153 
4154     // The IC fast case should only be taken if the result map a compatible
4155     // elements kind with the source object.
4156     TNode<FixedArrayBase> source_elements = LoadElements(CAST(source));
4157 
4158     auto flags = ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW;
4159     var_elements = CAST(CloneFixedArray(source_elements, flags));
4160 
4161     // Copy the PropertyArray backing store. The source PropertyArray must be
4162     // either an Smi, or a PropertyArray.
4163     // FIXME: Make a CSA macro for this
4164     TNode<Object> source_properties =
4165         LoadObjectField(CAST(source), JSObject::kPropertiesOrHashOffset);
4166     {
4167       GotoIf(TaggedIsSmi(source_properties), &allocate_object);
4168       GotoIf(IsEmptyFixedArray(source_properties), &allocate_object);
4169 
4170       // This IC requires that the source object has fast properties.
4171       TNode<PropertyArray> source_property_array = CAST(source_properties);
4172 
4173       TNode<IntPtrT> length = LoadPropertyArrayLength(source_property_array);
4174       GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &allocate_object);
4175 
4176       TNode<PropertyArray> property_array = AllocatePropertyArray(length);
4177       FillPropertyArrayWithUndefined(property_array, IntPtrConstant(0), length);
4178       CopyPropertyArrayValues(source_property_array, property_array, length,
4179                               SKIP_WRITE_BARRIER, DestroySource::kNo);
4180       var_properties = property_array;
4181     }
4182 
4183     Goto(&allocate_object);
4184     BIND(&allocate_object);
4185     TNode<JSObject> object = UncheckedCast<JSObject>(AllocateJSObjectFromMap(
4186         result_map, var_properties.value(), var_elements.value()));
4187     ReturnIf(IsNullOrUndefined(source), object);
4188 
4189     // Lastly, clone any in-object properties.
4190     TNode<IntPtrT> source_start =
4191         LoadMapInobjectPropertiesStartInWords(source_map);
4192     TNode<IntPtrT> source_size = LoadMapInstanceSizeInWords(source_map);
4193     TNode<IntPtrT> result_start =
4194         LoadMapInobjectPropertiesStartInWords(result_map);
4195     TNode<IntPtrT> field_offset_difference =
4196         TimesTaggedSize(IntPtrSub(result_start, source_start));
4197 
4198     // Just copy the fields as raw data (pretending that there are no mutable
4199     // HeapNumbers). This doesn't need write barriers.
4200     BuildFastLoop<IntPtrT>(
4201         source_start, source_size,
4202         [=](TNode<IntPtrT> field_index) {
4203           TNode<IntPtrT> field_offset = TimesTaggedSize(field_index);
4204           TNode<TaggedT> field =
4205               LoadObjectField<TaggedT>(CAST(source), field_offset);
4206           TNode<IntPtrT> result_offset =
4207               IntPtrAdd(field_offset, field_offset_difference);
4208           StoreObjectFieldNoWriteBarrier(object, result_offset, field);
4209         },
4210         1, IndexAdvanceMode::kPost);
4211 
4212     // If mutable HeapNumbers can occur, we need to go through the {object}
4213     // again here and properly clone them. We use a second loop here to
4214     // ensure that the GC (and heap verifier) always sees properly initialized
4215     // objects, i.e. never hits undefined values in double fields.
4216     if (!FLAG_unbox_double_fields) {
4217       TNode<IntPtrT> start_offset = TimesTaggedSize(result_start);
4218       TNode<IntPtrT> end_offset =
4219           IntPtrAdd(TimesTaggedSize(source_size), field_offset_difference);
4220       ConstructorBuiltinsAssembler(state()).CopyMutableHeapNumbersInObject(
4221           object, start_offset, end_offset);
4222     }
4223 
4224     Return(object);
4225   }
4226 
4227   BIND(&try_polymorphic);
4228   TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
4229   {
4230     Comment("CloneObjectIC_try_polymorphic");
4231     GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
4232     HandlePolymorphicCase(source_map, CAST(strong_feedback), &if_handler,
4233                           &var_handler, &miss);
4234   }
4235 
4236   BIND(&try_megamorphic);
4237   {
4238     Comment("CloneObjectIC_try_megamorphic");
4239     CSA_ASSERT(
4240         this,
4241         Word32Or(TaggedEqual(strong_feedback, UninitializedSymbolConstant()),
4242                  TaggedEqual(strong_feedback, MegamorphicSymbolConstant())));
4243     GotoIfNot(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()), &miss);
4244     Goto(&slow);
4245   }
4246 
4247   BIND(&slow);
4248   {
4249     TailCallBuiltin(Builtins::kCloneObjectIC_Slow, context, source, flags, slot,
4250                     maybe_vector);
4251   }
4252 
4253   BIND(&miss);
4254   {
4255     Comment("CloneObjectIC_miss");
4256     TNode<HeapObject> map_or_result =
4257         CAST(CallRuntime(Runtime::kCloneObjectIC_Miss, context, source, flags,
4258                          slot, maybe_vector));
4259     var_handler = UncheckedCast<MaybeObject>(map_or_result);
4260     GotoIf(IsMap(map_or_result), &if_handler);
4261     CSA_ASSERT(this, IsJSObject(map_or_result));
4262     Return(map_or_result);
4263   }
4264 }
4265 
GenerateKeyedHasIC()4266 void AccessorAssembler::GenerateKeyedHasIC() {
4267   using Descriptor = LoadWithVectorDescriptor;
4268 
4269   auto receiver = Parameter<Object>(Descriptor::kReceiver);
4270   auto name = Parameter<Object>(Descriptor::kName);
4271   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4272   auto vector = Parameter<HeapObject>(Descriptor::kVector);
4273   auto context = Parameter<Context>(Descriptor::kContext);
4274 
4275   LoadICParameters p(context, receiver, name, slot, vector);
4276   KeyedLoadIC(&p, LoadAccessMode::kHas);
4277 }
4278 
GenerateKeyedHasIC_Megamorphic()4279 void AccessorAssembler::GenerateKeyedHasIC_Megamorphic() {
4280   using Descriptor = LoadWithVectorDescriptor;
4281 
4282   auto receiver = Parameter<Object>(Descriptor::kReceiver);
4283   auto name = Parameter<Object>(Descriptor::kName);
4284   auto context = Parameter<Context>(Descriptor::kContext);
4285   // TODO(magardn): implement HasProperty handling in KeyedLoadICGeneric
4286   Return(HasProperty(context, receiver, name,
4287                      HasPropertyLookupMode::kHasProperty));
4288 }
4289 
GenerateKeyedHasIC_PolymorphicName()4290 void AccessorAssembler::GenerateKeyedHasIC_PolymorphicName() {
4291   using Descriptor = LoadWithVectorDescriptor;
4292 
4293   auto receiver = Parameter<Object>(Descriptor::kReceiver);
4294   auto name = Parameter<Object>(Descriptor::kName);
4295   auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4296   auto vector = Parameter<HeapObject>(Descriptor::kVector);
4297   auto context = Parameter<Context>(Descriptor::kContext);
4298 
4299   LoadICParameters p(context, receiver, name, slot, vector);
4300   KeyedLoadICPolymorphicName(&p, LoadAccessMode::kHas);
4301 }
4302 
BranchIfPrototypesHaveNoElements(TNode<Map> receiver_map,Label * definitely_no_elements,Label * possibly_elements)4303 void AccessorAssembler::BranchIfPrototypesHaveNoElements(
4304     TNode<Map> receiver_map, Label* definitely_no_elements,
4305     Label* possibly_elements) {
4306   TVARIABLE(Map, var_map, receiver_map);
4307   Label loop_body(this, &var_map);
4308   TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
4309   TNode<NumberDictionary> empty_slow_element_dictionary =
4310       EmptySlowElementDictionaryConstant();
4311   Goto(&loop_body);
4312 
4313   BIND(&loop_body);
4314   {
4315     TNode<Map> map = var_map.value();
4316     TNode<HeapObject> prototype = LoadMapPrototype(map);
4317     GotoIf(IsNull(prototype), definitely_no_elements);
4318     TNode<Map> prototype_map = LoadMap(prototype);
4319     TNode<Uint16T> prototype_instance_type = LoadMapInstanceType(prototype_map);
4320 
4321     // Pessimistically assume elements if a Proxy, Special API Object,
4322     // or JSPrimitiveWrapper wrapper is found on the prototype chain. After this
4323     // instance type check, it's not necessary to check for interceptors or
4324     // access checks.
4325     Label if_custom(this, Label::kDeferred), if_notcustom(this);
4326     Branch(IsCustomElementsReceiverInstanceType(prototype_instance_type),
4327            &if_custom, &if_notcustom);
4328 
4329     BIND(&if_custom);
4330     {
4331       // For string JSPrimitiveWrapper wrappers we still support the checks as
4332       // long as they wrap the empty string.
4333       GotoIfNot(
4334           InstanceTypeEqual(prototype_instance_type, JS_PRIMITIVE_WRAPPER_TYPE),
4335           possibly_elements);
4336       TNode<Object> prototype_value =
4337           LoadJSPrimitiveWrapperValue(CAST(prototype));
4338       Branch(IsEmptyString(prototype_value), &if_notcustom, possibly_elements);
4339     }
4340 
4341     BIND(&if_notcustom);
4342     {
4343       TNode<FixedArrayBase> prototype_elements = LoadElements(CAST(prototype));
4344       var_map = prototype_map;
4345       GotoIf(TaggedEqual(prototype_elements, empty_fixed_array), &loop_body);
4346       Branch(TaggedEqual(prototype_elements, empty_slow_element_dictionary),
4347              &loop_body, possibly_elements);
4348     }
4349   }
4350 }
4351 
4352 }  // namespace internal
4353 }  // namespace v8
4354