• 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/code-factory.h"
8 #include "src/code-stubs.h"
9 #include "src/counters.h"
10 #include "src/ic/handler-configuration.h"
11 #include "src/ic/ic.h"
12 #include "src/ic/stub-cache.h"
13 #include "src/objects-inl.h"
14 #include "src/objects/module.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 using compiler::CodeAssemblerState;
20 using compiler::Node;
21 template <typename T>
22 using TNode = compiler::TNode<T>;
23 template <typename T>
24 using SloppyTNode = compiler::SloppyTNode<T>;
25 
26 //////////////////// Private helpers.
27 
28 // Loads dataX field from the DataHandler object.
LoadHandlerDataField(SloppyTNode<DataHandler> handler,int data_index)29 TNode<MaybeObject> AccessorAssembler::LoadHandlerDataField(
30     SloppyTNode<DataHandler> handler, int data_index) {
31 #ifdef DEBUG
32   TNode<Map> handler_map = LoadMap(handler);
33   TNode<Int32T> instance_type = LoadMapInstanceType(handler_map);
34 #endif
35   CSA_ASSERT(this,
36              Word32Or(InstanceTypeEqual(instance_type, LOAD_HANDLER_TYPE),
37                       InstanceTypeEqual(instance_type, STORE_HANDLER_TYPE)));
38   int offset = 0;
39   int minimum_size = 0;
40   switch (data_index) {
41     case 1:
42       offset = DataHandler::kData1Offset;
43       minimum_size = DataHandler::kSizeWithData1;
44       break;
45     case 2:
46       offset = DataHandler::kData2Offset;
47       minimum_size = DataHandler::kSizeWithData2;
48       break;
49     case 3:
50       offset = DataHandler::kData3Offset;
51       minimum_size = DataHandler::kSizeWithData3;
52       break;
53     default:
54       UNREACHABLE();
55       break;
56   }
57   USE(minimum_size);
58   CSA_ASSERT(this, UintPtrGreaterThanOrEqual(
59                        LoadMapInstanceSizeInWords(handler_map),
60                        IntPtrConstant(minimum_size / kPointerSize)));
61   return LoadMaybeWeakObjectField(handler, offset);
62 }
63 
TryMonomorphicCase(Node * slot,Node * vector,Node * receiver_map,Label * if_handler,TVariable<MaybeObject> * var_handler,Label * if_miss)64 TNode<MaybeObject> AccessorAssembler::TryMonomorphicCase(
65     Node* slot, Node* vector, Node* receiver_map, Label* if_handler,
66     TVariable<MaybeObject>* var_handler, Label* if_miss) {
67   Comment("TryMonomorphicCase");
68   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
69 
70   // TODO(ishell): add helper class that hides offset computations for a series
71   // of loads.
72   CSA_ASSERT(this, IsFeedbackVector(vector), vector);
73   int32_t header_size = FeedbackVector::kFeedbackSlotsOffset - kHeapObjectTag;
74   // Adding |header_size| with a separate IntPtrAdd rather than passing it
75   // into ElementOffsetFromIndex() allows it to be folded into a single
76   // [base, index, offset] indirect memory access on x64.
77   Node* offset = ElementOffsetFromIndex(slot, HOLEY_ELEMENTS, SMI_PARAMETERS);
78   TNode<MaybeObject> feedback = ReinterpretCast<MaybeObject>(
79       Load(MachineType::AnyTagged(), vector,
80            IntPtrAdd(offset, IntPtrConstant(header_size))));
81 
82   // Try to quickly handle the monomorphic case without knowing for sure
83   // if we have a weak reference in feedback.
84   GotoIf(IsNotWeakReferenceTo(feedback, CAST(receiver_map)), if_miss);
85 
86   TNode<MaybeObject> handler = UncheckedCast<MaybeObject>(
87       Load(MachineType::AnyTagged(), vector,
88            IntPtrAdd(offset, IntPtrConstant(header_size + kPointerSize))));
89 
90   *var_handler = handler;
91   Goto(if_handler);
92   return feedback;
93 }
94 
HandlePolymorphicCase(Node * receiver_map,TNode<WeakFixedArray> feedback,Label * if_handler,TVariable<MaybeObject> * var_handler,Label * if_miss,int min_feedback_capacity)95 void AccessorAssembler::HandlePolymorphicCase(
96     Node* receiver_map, TNode<WeakFixedArray> feedback, Label* if_handler,
97     TVariable<MaybeObject>* var_handler, Label* if_miss,
98     int min_feedback_capacity) {
99   Comment("HandlePolymorphicCase");
100   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
101 
102   // Deferred so the unrolled case can omit frame construction in bytecode
103   // handler.
104   Label loop(this, Label::kDeferred);
105 
106   // Iterate {feedback} array.
107   const int kEntrySize = 2;
108 
109   // Loading feedback's length is delayed until we need it when looking past
110   // the first {min_feedback_capacity} (map, handler) pairs.
111   Node* length = nullptr;
112   CSA_ASSERT(this, SmiGreaterThanOrEqual(
113                        LoadWeakFixedArrayLength(feedback),
114                        SmiConstant(min_feedback_capacity * kEntrySize)));
115 
116   const int kUnrolledIterations = IC::kMaxPolymorphicMapCount;
117   for (int i = 0; i < kUnrolledIterations; i++) {
118     int map_index = i * kEntrySize;
119     int handler_index = i * kEntrySize + 1;
120 
121     if (i >= min_feedback_capacity) {
122       if (length == nullptr) length = LoadWeakFixedArrayLength(feedback);
123       GotoIf(SmiGreaterThanOrEqual(SmiConstant(handler_index), CAST(length)),
124              if_miss);
125     }
126 
127     Label next_entry(this);
128     TNode<MaybeObject> maybe_cached_map =
129         LoadWeakFixedArrayElement(feedback, map_index);
130     CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_cached_map));
131     GotoIf(IsNotWeakReferenceTo(maybe_cached_map, CAST(receiver_map)),
132            &next_entry);
133 
134     // Found, now call handler.
135     TNode<MaybeObject> handler =
136         LoadWeakFixedArrayElement(feedback, handler_index);
137     *var_handler = handler;
138     Goto(if_handler);
139 
140     BIND(&next_entry);
141   }
142   Goto(&loop);
143 
144   // Loop from {kUnrolledIterations}*kEntrySize to {length}.
145   BIND(&loop);
146   Node* start_index = IntPtrConstant(kUnrolledIterations * kEntrySize);
147   Node* end_index = LoadAndUntagWeakFixedArrayLength(feedback);
148   BuildFastLoop(
149       start_index, end_index,
150       [this, receiver_map, feedback, if_handler, var_handler](Node* index) {
151         Label next_entry(this);
152         TNode<MaybeObject> maybe_cached_map =
153             LoadWeakFixedArrayElement(feedback, index);
154         CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_cached_map));
155         GotoIf(IsNotWeakReferenceTo(maybe_cached_map, CAST(receiver_map)),
156                &next_entry);
157 
158         // Found, now call handler.
159         TNode<MaybeObject> handler =
160             LoadWeakFixedArrayElement(feedback, index, kPointerSize);
161         *var_handler = handler;
162         Goto(if_handler);
163 
164         BIND(&next_entry);
165       },
166       kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
167   // The loop falls through if no handler was found.
168   Goto(if_miss);
169 }
170 
HandleLoadICHandlerCase(const LoadICParameters * p,TNode<Object> handler,Label * miss,ExitPoint * exit_point,ICMode ic_mode,OnNonExistent on_nonexistent,ElementSupport support_elements)171 void AccessorAssembler::HandleLoadICHandlerCase(
172     const LoadICParameters* p, TNode<Object> handler, Label* miss,
173     ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
174     ElementSupport support_elements) {
175   Comment("have_handler");
176 
177   VARIABLE(var_holder, MachineRepresentation::kTagged, p->holder);
178   VARIABLE(var_smi_handler, MachineRepresentation::kTagged, handler);
179 
180   Variable* vars[] = {&var_holder, &var_smi_handler};
181   Label if_smi_handler(this, 2, vars);
182   Label try_proto_handler(this, Label::kDeferred),
183       call_handler(this, Label::kDeferred);
184 
185   Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler);
186 
187   // |handler| is a Smi, encoding what to do. See SmiHandler methods
188   // for the encoding format.
189   BIND(&if_smi_handler);
190   {
191     HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
192                                handler, miss, exit_point, on_nonexistent,
193                                support_elements);
194   }
195 
196   BIND(&try_proto_handler);
197   {
198     GotoIf(IsCodeMap(LoadMap(CAST(handler))), &call_handler);
199     HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler,
200                              &if_smi_handler, miss, exit_point, ic_mode);
201   }
202 
203   BIND(&call_handler);
204   {
205     exit_point->ReturnCallStub(LoadWithVectorDescriptor{}, handler, p->context,
206                                p->receiver, p->name, p->slot, p->vector);
207   }
208 }
209 
HandleLoadCallbackProperty(const LoadICParameters * p,TNode<JSObject> holder,TNode<WordT> handler_word,ExitPoint * exit_point)210 void AccessorAssembler::HandleLoadCallbackProperty(const LoadICParameters* p,
211                                                    TNode<JSObject> holder,
212                                                    TNode<WordT> handler_word,
213                                                    ExitPoint* exit_point) {
214   Comment("native_data_property_load");
215   Node* descriptor = DecodeWord<LoadHandler::DescriptorBits>(handler_word);
216 
217   Label runtime(this, Label::kDeferred);
218   Callable callable = CodeFactory::ApiGetter(isolate());
219   TNode<AccessorInfo> accessor_info =
220       CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
221 
222   GotoIf(IsRuntimeCallStatsEnabled(), &runtime);
223   exit_point->ReturnCallStub(callable, p->context, p->receiver, holder,
224                              accessor_info);
225 
226   BIND(&runtime);
227   exit_point->ReturnCallRuntime(Runtime::kLoadCallbackProperty, p->context,
228                                 p->receiver, holder, accessor_info, p->name);
229 }
230 
HandleLoadAccessor(const LoadICParameters * p,TNode<CallHandlerInfo> call_handler_info,TNode<WordT> handler_word,TNode<DataHandler> handler,TNode<IntPtrT> handler_kind,ExitPoint * exit_point)231 void AccessorAssembler::HandleLoadAccessor(
232     const LoadICParameters* p, TNode<CallHandlerInfo> call_handler_info,
233     TNode<WordT> handler_word, TNode<DataHandler> handler,
234     TNode<IntPtrT> handler_kind, ExitPoint* exit_point) {
235   Comment("api_getter");
236   Label runtime(this, Label::kDeferred);
237   // Context is stored either in data2 or data3 field depending on whether
238   // the access check is enabled for this handler or not.
239   TNode<MaybeObject> maybe_context = Select<MaybeObject>(
240       IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word),
241       [=] { return LoadHandlerDataField(handler, 3); },
242       [=] { return LoadHandlerDataField(handler, 2); });
243 
244   CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_context));
245   CSA_CHECK(this, IsNotClearedWeakHeapObject(maybe_context));
246   TNode<Object> context = ToWeakHeapObject(maybe_context);
247 
248   GotoIf(IsRuntimeCallStatsEnabled(), &runtime);
249   {
250     TNode<Foreign> foreign = CAST(
251         LoadObjectField(call_handler_info, CallHandlerInfo::kJsCallbackOffset));
252     TNode<WordT> callback = TNode<WordT>::UncheckedCast(LoadObjectField(
253         foreign, Foreign::kForeignAddressOffset, MachineType::Pointer()));
254     TNode<Object> data =
255         LoadObjectField(call_handler_info, CallHandlerInfo::kDataOffset);
256 
257     VARIABLE(api_holder, MachineRepresentation::kTagged, p->receiver);
258     Label load(this);
259     GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kApiGetter)),
260            &load);
261 
262     CSA_ASSERT(
263         this,
264         WordEqual(handler_kind,
265                   IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)));
266 
267     api_holder.Bind(LoadMapPrototype(LoadMap(p->receiver)));
268     Goto(&load);
269 
270     BIND(&load);
271     Callable callable = CodeFactory::CallApiCallback(isolate(), 0);
272     exit_point->Return(CallStub(callable, nullptr, context, data,
273                                 api_holder.value(), callback, p->receiver));
274   }
275 
276   BIND(&runtime);
277   exit_point->ReturnCallRuntime(Runtime::kLoadAccessorProperty, context,
278                                 p->receiver, SmiTag(handler_kind),
279                                 call_handler_info);
280 }
281 
HandleLoadField(Node * holder,Node * handler_word,Variable * var_double_value,Label * rebox_double,ExitPoint * exit_point)282 void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word,
283                                         Variable* var_double_value,
284                                         Label* rebox_double,
285                                         ExitPoint* exit_point) {
286   Comment("field_load");
287   Node* index = DecodeWord<LoadHandler::FieldIndexBits>(handler_word);
288   Node* offset = IntPtrMul(index, IntPtrConstant(kPointerSize));
289 
290   Label inobject(this), out_of_object(this);
291   Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject,
292          &out_of_object);
293 
294   BIND(&inobject);
295   {
296     Label is_double(this);
297     GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
298     exit_point->Return(LoadObjectField(holder, offset));
299 
300     BIND(&is_double);
301     if (FLAG_unbox_double_fields) {
302       var_double_value->Bind(
303           LoadObjectField(holder, offset, MachineType::Float64()));
304     } else {
305       Node* mutable_heap_number = LoadObjectField(holder, offset);
306       var_double_value->Bind(LoadHeapNumberValue(mutable_heap_number));
307     }
308     Goto(rebox_double);
309   }
310 
311   BIND(&out_of_object);
312   {
313     Label is_double(this);
314     Node* properties = LoadFastProperties(holder);
315     Node* value = LoadObjectField(properties, offset);
316     GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
317     exit_point->Return(value);
318 
319     BIND(&is_double);
320     var_double_value->Bind(LoadHeapNumberValue(value));
321     Goto(rebox_double);
322   }
323 }
324 
LoadDescriptorValue(TNode<Map> map,Node * descriptor)325 TNode<Object> AccessorAssembler::LoadDescriptorValue(TNode<Map> map,
326                                                      Node* descriptor) {
327   return CAST(LoadDescriptorValueOrFieldType(map, descriptor));
328 }
329 
LoadDescriptorValueOrFieldType(TNode<Map> map,SloppyTNode<IntPtrT> descriptor)330 TNode<MaybeObject> AccessorAssembler::LoadDescriptorValueOrFieldType(
331     TNode<Map> map, SloppyTNode<IntPtrT> descriptor) {
332   TNode<DescriptorArray> descriptors = LoadMapDescriptors(map);
333   TNode<IntPtrT> scaled_descriptor =
334       IntPtrMul(descriptor, IntPtrConstant(DescriptorArray::kEntrySize));
335   TNode<IntPtrT> value_index = IntPtrAdd(
336       scaled_descriptor, IntPtrConstant(DescriptorArray::kFirstIndex +
337                                         DescriptorArray::kEntryValueIndex));
338   CSA_ASSERT(this, UintPtrLessThan(descriptor, LoadAndUntagWeakFixedArrayLength(
339                                                    descriptors)));
340   return LoadWeakFixedArrayElement(descriptors, value_index);
341 }
342 
HandleLoadICSmiHandlerCase(const LoadICParameters * p,Node * holder,SloppyTNode<Smi> smi_handler,SloppyTNode<Object> handler,Label * miss,ExitPoint * exit_point,OnNonExistent on_nonexistent,ElementSupport support_elements)343 void AccessorAssembler::HandleLoadICSmiHandlerCase(
344     const LoadICParameters* p, Node* holder, SloppyTNode<Smi> smi_handler,
345     SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point,
346     OnNonExistent on_nonexistent, ElementSupport support_elements) {
347   VARIABLE(var_double_value, MachineRepresentation::kFloat64);
348   Label rebox_double(this, &var_double_value);
349 
350   TNode<WordT> handler_word = SmiUntag(smi_handler);
351   TNode<IntPtrT> handler_kind =
352       Signed(DecodeWord<LoadHandler::KindBits>(handler_word));
353   if (support_elements == kSupportElements) {
354     Label if_element(this), if_indexed_string(this), if_property(this);
355     GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kElement)),
356            &if_element);
357     Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kIndexedString)),
358            &if_indexed_string, &if_property);
359 
360     BIND(&if_element);
361     Comment("element_load");
362     Node* intptr_index = TryToIntptr(p->name, miss);
363     Node* elements = LoadElements(holder);
364     Node* is_jsarray_condition =
365         IsSetWord<LoadHandler::IsJsArrayBits>(handler_word);
366     Node* elements_kind =
367         DecodeWord32FromWord<LoadHandler::ElementsKindBits>(handler_word);
368     Label if_hole(this), unimplemented_elements_kind(this),
369         if_oob(this, Label::kDeferred);
370     EmitElementLoad(holder, elements, elements_kind, intptr_index,
371                     is_jsarray_condition, &if_hole, &rebox_double,
372                     &var_double_value, &unimplemented_elements_kind, &if_oob,
373                     miss, exit_point);
374 
375     BIND(&unimplemented_elements_kind);
376     {
377       // Smi handlers should only be installed for supported elements kinds.
378       // Crash if we get here.
379       DebugBreak();
380       Goto(miss);
381     }
382 
383     BIND(&if_oob);
384     {
385       Comment("out of bounds elements access");
386       Label return_undefined(this);
387 
388       // Check if we're allowed to handle OOB accesses.
389       Node* allow_out_of_bounds =
390           IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
391       GotoIfNot(allow_out_of_bounds, miss);
392 
393       // Negative indices aren't valid array indices (according to
394       // the ECMAScript specification), and are stored as properties
395       // in V8, not elements. So we cannot handle them here, except
396       // in case of typed arrays, where integer indexed properties
397       // aren't looked up in the prototype chain.
398       GotoIf(IsJSTypedArray(holder), &return_undefined);
399       GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), miss);
400 
401       // For all other receivers we need to check that the prototype chain
402       // doesn't contain any elements.
403       BranchIfPrototypesHaveNoElements(LoadMap(holder), &return_undefined,
404                                        miss);
405 
406       BIND(&return_undefined);
407       exit_point->Return(UndefinedConstant());
408     }
409 
410     BIND(&if_hole);
411     {
412       Comment("convert hole");
413       GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
414       GotoIf(IsNoElementsProtectorCellInvalid(), miss);
415       exit_point->Return(UndefinedConstant());
416     }
417 
418     BIND(&if_indexed_string);
419     {
420       Label if_oob(this, Label::kDeferred);
421 
422       Comment("indexed string");
423       Node* intptr_index = TryToIntptr(p->name, miss);
424       Node* length = LoadStringLengthAsWord(holder);
425       GotoIf(UintPtrGreaterThanOrEqual(intptr_index, length), &if_oob);
426       TNode<Int32T> code = StringCharCodeAt(holder, intptr_index);
427       TNode<String> result = StringFromSingleCharCode(code);
428       Return(result);
429 
430       BIND(&if_oob);
431       Node* allow_out_of_bounds =
432           IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
433       GotoIfNot(allow_out_of_bounds, miss);
434       GotoIf(IsNoElementsProtectorCellInvalid(), miss);
435       Return(UndefinedConstant());
436     }
437 
438     BIND(&if_property);
439     Comment("property_load");
440   }
441 
442   Label constant(this), field(this), normal(this, Label::kDeferred),
443       interceptor(this, Label::kDeferred), nonexistent(this),
444       accessor(this, Label::kDeferred), global(this, Label::kDeferred),
445       module_export(this, Label::kDeferred), proxy(this, Label::kDeferred),
446       native_data_property(this), api_getter(this);
447   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field);
448 
449   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
450          &constant);
451 
452   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)),
453          &nonexistent);
454 
455   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNormal)),
456          &normal);
457 
458   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kAccessor)),
459          &accessor);
460 
461   GotoIf(
462       WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNativeDataProperty)),
463       &native_data_property);
464 
465   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kApiGetter)),
466          &api_getter);
467 
468   GotoIf(WordEqual(handler_kind,
469                    IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)),
470          &api_getter);
471 
472   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)),
473          &global);
474 
475   GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kProxy)), &proxy);
476 
477   Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kModuleExport)),
478          &module_export, &interceptor);
479 
480   BIND(&field);
481   HandleLoadField(holder, handler_word, &var_double_value, &rebox_double,
482                   exit_point);
483 
484   BIND(&nonexistent);
485   // This is a handler for a load of a non-existent value.
486   if (on_nonexistent == OnNonExistent::kThrowReferenceError) {
487     exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context,
488                                   p->name);
489   } else {
490     DCHECK_EQ(OnNonExistent::kReturnUndefined, on_nonexistent);
491     exit_point->Return(UndefinedConstant());
492   }
493 
494   BIND(&constant);
495   {
496     Comment("constant_load");
497     Node* descriptor = DecodeWord<LoadHandler::DescriptorBits>(handler_word);
498     Node* value = LoadDescriptorValue(LoadMap(holder), descriptor);
499 
500     exit_point->Return(value);
501   }
502 
503   BIND(&normal);
504   {
505     Comment("load_normal");
506     TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder));
507     TVARIABLE(IntPtrT, var_name_index);
508     Label found(this, &var_name_index);
509     NameDictionaryLookup<NameDictionary>(properties, CAST(p->name), &found,
510                                          &var_name_index, miss);
511     BIND(&found);
512     {
513       VARIABLE(var_details, MachineRepresentation::kWord32);
514       VARIABLE(var_value, MachineRepresentation::kTagged);
515       LoadPropertyFromNameDictionary(properties, var_name_index.value(),
516                                      &var_details, &var_value);
517       Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
518                                          p->context, p->receiver, miss);
519       exit_point->Return(value);
520     }
521   }
522 
523   BIND(&accessor);
524   {
525     Comment("accessor_load");
526     Node* descriptor = DecodeWord<LoadHandler::DescriptorBits>(handler_word);
527     Node* accessor_pair = LoadDescriptorValue(LoadMap(holder), descriptor);
528     CSA_ASSERT(this, IsAccessorPair(accessor_pair));
529     Node* getter = LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
530     CSA_ASSERT(this, Word32BinaryNot(IsTheHole(getter)));
531 
532     Callable callable = CodeFactory::Call(isolate());
533     exit_point->Return(CallJS(callable, p->context, getter, p->receiver));
534   }
535 
536   BIND(&native_data_property);
537   HandleLoadCallbackProperty(p, CAST(holder), handler_word, exit_point);
538 
539   BIND(&api_getter);
540   HandleLoadAccessor(p, CAST(holder), handler_word, CAST(handler), handler_kind,
541                      exit_point);
542 
543   BIND(&proxy);
544   {
545     VARIABLE(var_index, MachineType::PointerRepresentation());
546     VARIABLE(var_unique, MachineRepresentation::kTagged);
547 
548     Label if_index(this), if_unique_name(this),
549         to_name_failed(this, Label::kDeferred);
550 
551     if (support_elements == kSupportElements) {
552       DCHECK_NE(on_nonexistent, OnNonExistent::kThrowReferenceError);
553 
554       TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
555                 &to_name_failed);
556 
557       BIND(&if_unique_name);
558       exit_point->ReturnCallStub(
559           Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
560           p->context, holder, var_unique.value(), p->receiver,
561           SmiConstant(on_nonexistent));
562 
563       BIND(&if_index);
564       // TODO(mslekova): introduce TryToName that doesn't try to compute
565       // the intptr index value
566       Goto(&to_name_failed);
567 
568       BIND(&to_name_failed);
569       exit_point->ReturnCallRuntime(Runtime::kGetPropertyWithReceiver,
570                                     p->context, holder, p->name, p->receiver,
571                                     SmiConstant(on_nonexistent));
572     } else {
573       exit_point->ReturnCallStub(
574           Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
575           p->context, holder, p->name, p->receiver,
576           SmiConstant(on_nonexistent));
577     }
578   }
579 
580   BIND(&global);
581   {
582     CSA_ASSERT(this, IsPropertyCell(holder));
583     // Ensure the property cell doesn't contain the hole.
584     Node* value = LoadObjectField(holder, PropertyCell::kValueOffset);
585     Node* details =
586         LoadAndUntagToWord32ObjectField(holder, PropertyCell::kDetailsOffset);
587     GotoIf(IsTheHole(value), miss);
588 
589     exit_point->Return(
590         CallGetterIfAccessor(value, details, p->context, p->receiver, miss));
591   }
592 
593   BIND(&interceptor);
594   {
595     Comment("load_interceptor");
596     exit_point->ReturnCallRuntime(Runtime::kLoadPropertyWithInterceptor,
597                                   p->context, p->name, p->receiver, holder,
598                                   p->slot, p->vector);
599   }
600 
601   BIND(&module_export);
602   {
603     Comment("module export");
604     Node* index = DecodeWord<LoadHandler::ExportsIndexBits>(handler_word);
605     Node* module =
606         LoadObjectField(p->receiver, JSModuleNamespace::kModuleOffset,
607                         MachineType::TaggedPointer());
608     TNode<ObjectHashTable> exports = CAST(LoadObjectField(
609         module, Module::kExportsOffset, MachineType::TaggedPointer()));
610     Node* cell = LoadFixedArrayElement(exports, index);
611     // The handler is only installed for exports that exist.
612     CSA_ASSERT(this, IsCell(cell));
613     Node* value = LoadCellValue(cell);
614     Label is_the_hole(this, Label::kDeferred);
615     GotoIf(IsTheHole(value), &is_the_hole);
616     exit_point->Return(value);
617 
618     BIND(&is_the_hole);
619     {
620       Node* message = SmiConstant(MessageTemplate::kNotDefined);
621       exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context,
622                                     message, p->name);
623     }
624   }
625 
626   BIND(&rebox_double);
627   exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value()));
628 }
629 
630 // Performs actions common to both load and store handlers:
631 // 1. Checks prototype validity cell.
632 // 2. If |on_code_handler| is provided, then it checks if the sub handler is
633 //    a smi or code and if it's a code then it calls |on_code_handler| to
634 //    generate a code that handles Code handlers.
635 //    If |on_code_handler| is not provided, then only smi sub handler are
636 //    expected.
637 // 3. Does access check on receiver if ICHandler::DoAccessCheckOnReceiverBits
638 //    bit is set in the smi handler.
639 // 4. Does dictionary lookup on receiver if ICHandler::LookupOnReceiverBits bit
640 //    is set in the smi handler. If |on_found_on_receiver| is provided then
641 //    it calls it to generate a code that handles the "found on receiver case"
642 //    or just misses if the |on_found_on_receiver| is not provided.
643 // 5. Falls through in a case of a smi handler which is returned from this
644 //    function (tagged!).
645 // TODO(ishell): Remove templatezation once we move common bits from
646 // Load/StoreHandler to the base class.
647 template <typename ICHandler, typename ICParameters>
HandleProtoHandler(const ICParameters * p,Node * handler,const OnCodeHandler & on_code_handler,const OnFoundOnReceiver & on_found_on_receiver,Label * miss,ICMode ic_mode)648 Node* AccessorAssembler::HandleProtoHandler(
649     const ICParameters* p, Node* handler, const OnCodeHandler& on_code_handler,
650     const OnFoundOnReceiver& on_found_on_receiver, Label* miss,
651     ICMode ic_mode) {
652   //
653   // Check prototype validity cell.
654   //
655   {
656     Node* maybe_validity_cell =
657         LoadObjectField(handler, ICHandler::kValidityCellOffset);
658     CheckPrototypeValidityCell(maybe_validity_cell, miss);
659   }
660 
661   //
662   // Check smi handler bits.
663   //
664   {
665     Node* smi_or_code_handler =
666         LoadObjectField(handler, ICHandler::kSmiHandlerOffset);
667     if (on_code_handler) {
668       Label if_smi_handler(this);
669       GotoIf(TaggedIsSmi(smi_or_code_handler), &if_smi_handler);
670 
671       CSA_ASSERT(this, IsCodeMap(LoadMap(smi_or_code_handler)));
672       on_code_handler(smi_or_code_handler);
673 
674       BIND(&if_smi_handler);
675     } else {
676       CSA_ASSERT(this, TaggedIsSmi(smi_or_code_handler));
677     }
678     Node* handler_flags = SmiUntag(smi_or_code_handler);
679 
680     // Lookup on receiver and access checks are not necessary for global ICs
681     // because in the former case the validity cell check guards modifications
682     // of the global object and the latter is not applicable to the global
683     // object.
684     int mask = ICHandler::LookupOnReceiverBits::kMask |
685                ICHandler::DoAccessCheckOnReceiverBits::kMask;
686     if (ic_mode == ICMode::kGlobalIC) {
687       CSA_ASSERT(this, IsClearWord(handler_flags, mask));
688     } else {
689       DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
690 
691       Label done(this), if_do_access_check(this), if_lookup_on_receiver(this);
692       GotoIf(IsClearWord(handler_flags, mask), &done);
693       // Only one of the bits can be set at a time.
694       CSA_ASSERT(this,
695                  WordNotEqual(WordAnd(handler_flags, IntPtrConstant(mask)),
696                               IntPtrConstant(mask)));
697       Branch(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
698              &if_do_access_check, &if_lookup_on_receiver);
699 
700       BIND(&if_do_access_check);
701       {
702         TNode<MaybeObject> data2 = LoadHandlerDataField(handler, 2);
703         CSA_ASSERT(this, IsWeakOrClearedHeapObject(data2));
704         TNode<Object> expected_native_context = ToWeakHeapObject(data2, miss);
705         EmitAccessCheck(expected_native_context, p->context, p->receiver, &done,
706                         miss);
707       }
708 
709       // Dictionary lookup on receiver is not necessary for Load/StoreGlobalIC
710       // because prototype validity cell check already guards modifications of
711       // the global object.
712       BIND(&if_lookup_on_receiver);
713       {
714         DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
715         CSA_ASSERT(this, Word32BinaryNot(HasInstanceType(
716                              p->receiver, JS_GLOBAL_OBJECT_TYPE)));
717 
718         TNode<NameDictionary> properties =
719             CAST(LoadSlowProperties(p->receiver));
720         TVARIABLE(IntPtrT, var_name_index);
721         Label found(this, &var_name_index);
722         NameDictionaryLookup<NameDictionary>(properties, CAST(p->name), &found,
723                                              &var_name_index, &done);
724         BIND(&found);
725         {
726           if (on_found_on_receiver) {
727             on_found_on_receiver(properties, var_name_index.value());
728           } else {
729             Goto(miss);
730           }
731         }
732       }
733 
734       BIND(&done);
735     }
736     return smi_or_code_handler;
737   }
738 }
739 
HandleLoadICProtoHandler(const LoadICParameters * p,Node * handler,Variable * var_holder,Variable * var_smi_handler,Label * if_smi_handler,Label * miss,ExitPoint * exit_point,ICMode ic_mode)740 void AccessorAssembler::HandleLoadICProtoHandler(
741     const LoadICParameters* p, Node* handler, Variable* var_holder,
742     Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
743     ExitPoint* exit_point, ICMode ic_mode) {
744   DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
745   DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
746 
747   Node* smi_handler = HandleProtoHandler<LoadHandler>(
748       p, handler,
749       // Code sub-handlers are not expected in LoadICs, so no |on_code_handler|.
750       nullptr,
751       // on_found_on_receiver
752       [=](Node* properties, Node* name_index) {
753         VARIABLE(var_details, MachineRepresentation::kWord32);
754         VARIABLE(var_value, MachineRepresentation::kTagged);
755         LoadPropertyFromNameDictionary(properties, name_index, &var_details,
756                                        &var_value);
757         Node* value =
758             CallGetterIfAccessor(var_value.value(), var_details.value(),
759                                  p->context, p->receiver, miss);
760         exit_point->Return(value);
761       },
762       miss, ic_mode);
763 
764   TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
765 
766   Label load_from_cached_holder(this), done(this);
767 
768   Branch(IsStrongReferenceTo(maybe_holder, NullConstant()), &done,
769          &load_from_cached_holder);
770 
771   BIND(&load_from_cached_holder);
772   {
773     // For regular holders, having passed the receiver map check and the
774     // validity cell check implies that |holder| is alive. However, for global
775     // object receivers, |maybe_holder| may be cleared.
776     CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_holder));
777     Node* holder = ToWeakHeapObject(maybe_holder, miss);
778 
779     var_holder->Bind(holder);
780     Goto(&done);
781   }
782 
783   BIND(&done);
784   {
785     var_smi_handler->Bind(smi_handler);
786     Goto(if_smi_handler);
787   }
788 }
789 
EmitAccessCheck(Node * expected_native_context,Node * context,Node * receiver,Label * can_access,Label * miss)790 void AccessorAssembler::EmitAccessCheck(Node* expected_native_context,
791                                         Node* context, Node* receiver,
792                                         Label* can_access, Label* miss) {
793   CSA_ASSERT(this, IsNativeContext(expected_native_context));
794 
795   Node* native_context = LoadNativeContext(context);
796   GotoIf(WordEqual(expected_native_context, native_context), can_access);
797   // If the receiver is not a JSGlobalProxy then we miss.
798   GotoIfNot(IsJSGlobalProxy(receiver), miss);
799   // For JSGlobalProxy receiver try to compare security tokens of current
800   // and expected native contexts.
801   Node* expected_token = LoadContextElement(expected_native_context,
802                                             Context::SECURITY_TOKEN_INDEX);
803   Node* current_token =
804       LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
805   Branch(WordEqual(expected_token, current_token), can_access, miss);
806 }
807 
JumpIfDataProperty(Node * details,Label * writable,Label * readonly)808 void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable,
809                                            Label* readonly) {
810   // Accessor properties never have the READ_ONLY attribute set.
811   GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
812          readonly);
813   Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
814   GotoIf(Word32Equal(kind, Int32Constant(kData)), writable);
815   // Fall through if it's an accessor property.
816 }
817 
HandleStoreICNativeDataProperty(const StoreICParameters * p,Node * holder,Node * handler_word)818 void AccessorAssembler::HandleStoreICNativeDataProperty(
819     const StoreICParameters* p, Node* holder, Node* handler_word) {
820   Comment("native_data_property_store");
821   Node* descriptor = DecodeWord<StoreHandler::DescriptorBits>(handler_word);
822   Node* accessor_info = LoadDescriptorValue(LoadMap(holder), descriptor);
823   CSA_CHECK(this, IsAccessorInfo(accessor_info));
824 
825   Node* language_mode = GetLanguageMode(p->vector, p->slot);
826 
827   TailCallRuntime(Runtime::kStoreCallbackProperty, p->context, p->receiver,
828                   holder, accessor_info, p->name, p->value, language_mode);
829 }
830 
HandleStoreICHandlerCase(const StoreICParameters * p,TNode<MaybeObject> handler,Label * miss,ICMode ic_mode,ElementSupport support_elements)831 void AccessorAssembler::HandleStoreICHandlerCase(
832     const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
833     ICMode ic_mode, ElementSupport support_elements) {
834   Label if_smi_handler(this), if_nonsmi_handler(this);
835   Label if_proto_handler(this), if_element_handler(this), call_handler(this),
836       store_transition_or_global(this);
837 
838   Branch(TaggedIsSmi(handler), &if_smi_handler, &if_nonsmi_handler);
839 
840   // |handler| is a Smi, encoding what to do. See SmiHandler methods
841   // for the encoding format.
842   BIND(&if_smi_handler);
843   {
844     Node* holder = p->receiver;
845     Node* handler_word = SmiUntag(CAST(handler));
846 
847     Label if_fast_smi(this), if_proxy(this);
848 
849     STATIC_ASSERT(StoreHandler::kGlobalProxy + 1 == StoreHandler::kNormal);
850     STATIC_ASSERT(StoreHandler::kNormal + 1 == StoreHandler::kProxy);
851     STATIC_ASSERT(StoreHandler::kProxy + 1 == StoreHandler::kKindsNumber);
852 
853     Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
854     GotoIf(IntPtrLessThan(handler_kind,
855                           IntPtrConstant(StoreHandler::kGlobalProxy)),
856            &if_fast_smi);
857     GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)),
858            &if_proxy);
859     CSA_ASSERT(this,
860                WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)));
861     TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder));
862 
863     TVARIABLE(IntPtrT, var_name_index);
864     Label dictionary_found(this, &var_name_index);
865     NameDictionaryLookup<NameDictionary>(
866         properties, CAST(p->name), &dictionary_found, &var_name_index, miss);
867     BIND(&dictionary_found);
868     {
869       Node* details = LoadDetailsByKeyIndex<NameDictionary>(
870           properties, var_name_index.value());
871       // Check that the property is a writable data property (no accessor).
872       const int kTypeAndReadOnlyMask = PropertyDetails::KindField::kMask |
873                                        PropertyDetails::kAttributesReadOnlyMask;
874       STATIC_ASSERT(kData == 0);
875       GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
876 
877       StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
878                                            p->value);
879       Return(p->value);
880     }
881 
882     BIND(&if_fast_smi);
883     {
884       Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
885 
886       Label data(this), accessor(this), native_data_property(this);
887       GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)),
888              &accessor);
889       Branch(WordEqual(handler_kind,
890                        IntPtrConstant(StoreHandler::kNativeDataProperty)),
891              &native_data_property, &data);
892 
893       BIND(&accessor);
894       HandleStoreAccessor(p, holder, handler_word);
895 
896       BIND(&native_data_property);
897       HandleStoreICNativeDataProperty(p, holder, handler_word);
898 
899       BIND(&data);
900       // Handle non-transitioning field stores.
901       HandleStoreICSmiHandlerCase(handler_word, holder, p->value, miss);
902     }
903 
904     BIND(&if_proxy);
905     HandleStoreToProxy(p, holder, miss, support_elements);
906   }
907 
908   BIND(&if_nonsmi_handler);
909   {
910     GotoIf(IsWeakOrClearedHeapObject(handler), &store_transition_or_global);
911     TNode<HeapObject> strong_handler = CAST(handler);
912     TNode<Map> handler_map = LoadMap(strong_handler);
913     Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler);
914 
915     BIND(&if_proto_handler);
916     {
917       HandleStoreICProtoHandler(p, CAST(strong_handler), miss, ic_mode,
918                                 support_elements);
919     }
920 
921     // |handler| is a heap object. Must be code, call it.
922     BIND(&call_handler);
923     {
924       TailCallStub(StoreWithVectorDescriptor{}, CAST(strong_handler),
925                    CAST(p->context), p->receiver, p->name, p->value, p->slot,
926                    p->vector);
927     }
928   }
929 
930   BIND(&store_transition_or_global);
931   {
932     // Load value or miss if the {handler} weak cell is cleared.
933     CSA_ASSERT(this, IsWeakOrClearedHeapObject(handler));
934     TNode<HeapObject> map_or_property_cell = ToWeakHeapObject(handler, miss);
935 
936     Label store_global(this), store_transition(this);
937     Branch(IsMap(map_or_property_cell), &store_transition, &store_global);
938 
939     BIND(&store_global);
940     {
941       TNode<PropertyCell> property_cell = CAST(map_or_property_cell);
942       ExitPoint direct_exit(this);
943       StoreGlobalIC_PropertyCellCase(property_cell, p->value, &direct_exit,
944                                      miss);
945     }
946     BIND(&store_transition);
947     {
948       TNode<Map> map = CAST(map_or_property_cell);
949       HandleStoreICTransitionMapHandlerCase(p, map, miss, false);
950       Return(p->value);
951     }
952   }
953 }
954 
HandleStoreICTransitionMapHandlerCase(const StoreICParameters * p,TNode<Map> transition_map,Label * miss,bool validate_transition_handler)955 void AccessorAssembler::HandleStoreICTransitionMapHandlerCase(
956     const StoreICParameters* p, TNode<Map> transition_map, Label* miss,
957     bool validate_transition_handler) {
958   Node* maybe_validity_cell =
959       LoadObjectField(transition_map, Map::kPrototypeValidityCellOffset);
960   CheckPrototypeValidityCell(maybe_validity_cell, miss);
961 
962   TNode<Uint32T> bitfield3 = LoadMapBitField3(transition_map);
963   CSA_ASSERT(this, IsClearWord32<Map::IsDictionaryMapBit>(bitfield3));
964   GotoIf(IsSetWord32<Map::IsDeprecatedBit>(bitfield3), miss);
965 
966   // Load last descriptor details.
967   Node* nof = DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3);
968   CSA_ASSERT(this, WordNotEqual(nof, IntPtrConstant(0)));
969   TNode<DescriptorArray> descriptors = LoadMapDescriptors(transition_map);
970 
971   Node* factor = IntPtrConstant(DescriptorArray::kEntrySize);
972   TNode<IntPtrT> last_key_index = UncheckedCast<IntPtrT>(IntPtrAdd(
973       IntPtrConstant(DescriptorArray::ToKeyIndex(-1)), IntPtrMul(nof, factor)));
974   if (validate_transition_handler) {
975     Node* key = LoadWeakFixedArrayElement(descriptors, last_key_index);
976     GotoIf(WordNotEqual(key, p->name), miss);
977   } else {
978     CSA_ASSERT(this,
979                WordEqual(BitcastMaybeObjectToWord(LoadWeakFixedArrayElement(
980                              descriptors, last_key_index)),
981                          p->name));
982   }
983   Node* details = LoadDetailsByKeyIndex(descriptors, last_key_index);
984   if (validate_transition_handler) {
985     // Follow transitions only in the following cases:
986     // 1) name is a non-private symbol and attributes equal to NONE,
987     // 2) name is a private symbol and attributes equal to DONT_ENUM.
988     Label attributes_ok(this);
989     const int kAttributesDontDeleteReadOnlyMask =
990         PropertyDetails::kAttributesDontDeleteMask |
991         PropertyDetails::kAttributesReadOnlyMask;
992     // Both DontDelete and ReadOnly attributes must not be set.
993     GotoIf(IsSetWord32(details, kAttributesDontDeleteReadOnlyMask), miss);
994 
995     // DontEnum attribute is allowed only for private symbols and vice versa.
996     Branch(Word32Equal(
997                IsSetWord32(details, PropertyDetails::kAttributesDontEnumMask),
998                IsPrivateSymbol(p->name)),
999            &attributes_ok, miss);
1000 
1001     BIND(&attributes_ok);
1002   }
1003 
1004   OverwriteExistingFastDataProperty(p->receiver, transition_map, descriptors,
1005                                     last_key_index, details, p->value, miss,
1006                                     true);
1007 }
1008 
CheckFieldType(TNode<DescriptorArray> descriptors,Node * name_index,Node * representation,Node * value,Label * bailout)1009 void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors,
1010                                        Node* name_index, Node* representation,
1011                                        Node* value, Label* bailout) {
1012   Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this);
1013   // Ignore FLAG_track_fields etc. and always emit code for all checks,
1014   // because this builtin is part of the snapshot and therefore should
1015   // be flag independent.
1016   GotoIf(Word32Equal(representation, Int32Constant(Representation::kSmi)),
1017          &r_smi);
1018   GotoIf(Word32Equal(representation, Int32Constant(Representation::kDouble)),
1019          &r_double);
1020   GotoIf(
1021       Word32Equal(representation, Int32Constant(Representation::kHeapObject)),
1022       &r_heapobject);
1023   GotoIf(Word32Equal(representation, Int32Constant(Representation::kNone)),
1024          bailout);
1025   CSA_ASSERT(this, Word32Equal(representation,
1026                                Int32Constant(Representation::kTagged)));
1027   Goto(&all_fine);
1028 
1029   BIND(&r_smi);
1030   { Branch(TaggedIsSmi(value), &all_fine, bailout); }
1031 
1032   BIND(&r_double);
1033   {
1034     GotoIf(TaggedIsSmi(value), &all_fine);
1035     Node* value_map = LoadMap(value);
1036     // While supporting mutable HeapNumbers would be straightforward, such
1037     // objects should not end up here anyway.
1038     CSA_ASSERT(this,
1039                WordNotEqual(value_map,
1040                             LoadRoot(Heap::kMutableHeapNumberMapRootIndex)));
1041     Branch(IsHeapNumberMap(value_map), &all_fine, bailout);
1042   }
1043 
1044   BIND(&r_heapobject);
1045   {
1046     GotoIf(TaggedIsSmi(value), bailout);
1047     TNode<MaybeObject> field_type = LoadFieldTypeByKeyIndex(
1048         descriptors, UncheckedCast<IntPtrT>(name_index));
1049     intptr_t kNoneType = reinterpret_cast<intptr_t>(FieldType::None());
1050     intptr_t kAnyType = reinterpret_cast<intptr_t>(FieldType::Any());
1051     DCHECK_NE(kNoneType, kClearedWeakHeapObject);
1052     DCHECK_NE(kAnyType, kClearedWeakHeapObject);
1053     // FieldType::None can't hold any value.
1054     GotoIf(WordEqual(BitcastMaybeObjectToWord(field_type),
1055                      IntPtrConstant(kNoneType)),
1056            bailout);
1057     // FieldType::Any can hold any value.
1058     GotoIf(WordEqual(BitcastMaybeObjectToWord(field_type),
1059                      IntPtrConstant(kAnyType)),
1060            &all_fine);
1061     // Cleared weak references count as FieldType::None, which can't hold any
1062     // value.
1063     TNode<Map> field_type_map = CAST(ToWeakHeapObject(field_type, bailout));
1064     // FieldType::Class(...) performs a map check.
1065     Branch(WordEqual(LoadMap(value), field_type_map), &all_fine, bailout);
1066   }
1067 
1068   BIND(&all_fine);
1069 }
1070 
OverwriteExistingFastDataProperty(Node * object,Node * object_map,Node * descriptors,Node * descriptor_name_index,Node * details,Node * value,Label * slow,bool do_transitioning_store)1071 void AccessorAssembler::OverwriteExistingFastDataProperty(
1072     Node* object, Node* object_map, Node* descriptors,
1073     Node* descriptor_name_index, Node* details, Node* value, Label* slow,
1074     bool do_transitioning_store) {
1075   Label done(this), if_field(this), if_descriptor(this);
1076 
1077   CSA_ASSERT(this,
1078              Word32Equal(DecodeWord32<PropertyDetails::KindField>(details),
1079                          Int32Constant(kData)));
1080 
1081   Branch(Word32Equal(DecodeWord32<PropertyDetails::LocationField>(details),
1082                      Int32Constant(kField)),
1083          &if_field, &if_descriptor);
1084 
1085   BIND(&if_field);
1086   {
1087     if (FLAG_track_constant_fields && !do_transitioning_store) {
1088       // TODO(ishell): Taking the slow path is not necessary if new and old
1089       // values are identical.
1090       GotoIf(Word32Equal(
1091                  DecodeWord32<PropertyDetails::ConstnessField>(details),
1092                  Int32Constant(static_cast<int32_t>(VariableMode::kConst))),
1093              slow);
1094     }
1095 
1096     Node* representation =
1097         DecodeWord32<PropertyDetails::RepresentationField>(details);
1098 
1099     CheckFieldType(CAST(descriptors), descriptor_name_index, representation,
1100                    value, slow);
1101 
1102     Node* field_index =
1103         DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
1104     field_index = IntPtrAdd(field_index,
1105                             LoadMapInobjectPropertiesStartInWords(object_map));
1106     Node* instance_size_in_words = LoadMapInstanceSizeInWords(object_map);
1107 
1108     Label inobject(this), backing_store(this);
1109     Branch(UintPtrLessThan(field_index, instance_size_in_words), &inobject,
1110            &backing_store);
1111 
1112     BIND(&inobject);
1113     {
1114       Node* field_offset = TimesPointerSize(field_index);
1115       Label tagged_rep(this), double_rep(this);
1116       Branch(
1117           Word32Equal(representation, Int32Constant(Representation::kDouble)),
1118           &double_rep, &tagged_rep);
1119       BIND(&double_rep);
1120       {
1121         Node* double_value = ChangeNumberToFloat64(value);
1122         if (FLAG_unbox_double_fields) {
1123           if (do_transitioning_store) {
1124             StoreMap(object, object_map);
1125           }
1126           StoreObjectFieldNoWriteBarrier(object, field_offset, double_value,
1127                                          MachineRepresentation::kFloat64);
1128         } else {
1129           if (do_transitioning_store) {
1130             Node* mutable_heap_number =
1131                 AllocateMutableHeapNumberWithValue(double_value);
1132             StoreMap(object, object_map);
1133             StoreObjectField(object, field_offset, mutable_heap_number);
1134           } else {
1135             Node* mutable_heap_number = LoadObjectField(object, field_offset);
1136             StoreHeapNumberValue(mutable_heap_number, double_value);
1137           }
1138         }
1139         Goto(&done);
1140       }
1141 
1142       BIND(&tagged_rep);
1143       {
1144         if (do_transitioning_store) {
1145           StoreMap(object, object_map);
1146         }
1147         StoreObjectField(object, field_offset, value);
1148         Goto(&done);
1149       }
1150     }
1151 
1152     BIND(&backing_store);
1153     {
1154       Node* backing_store_index =
1155           IntPtrSub(field_index, instance_size_in_words);
1156 
1157       if (do_transitioning_store) {
1158         // Allocate mutable heap number before extending properties backing
1159         // store to ensure that heap verifier will not see the heap in
1160         // inconsistent state.
1161         VARIABLE(var_value, MachineRepresentation::kTagged, value);
1162         {
1163           Label cont(this);
1164           GotoIf(Word32NotEqual(representation,
1165                                 Int32Constant(Representation::kDouble)),
1166                  &cont);
1167           {
1168             Node* double_value = ChangeNumberToFloat64(value);
1169             Node* mutable_heap_number =
1170                 AllocateMutableHeapNumberWithValue(double_value);
1171             var_value.Bind(mutable_heap_number);
1172             Goto(&cont);
1173           }
1174           BIND(&cont);
1175         }
1176 
1177         TNode<PropertyArray> properties =
1178             CAST(ExtendPropertiesBackingStore(object, backing_store_index));
1179         StorePropertyArrayElement(properties, backing_store_index,
1180                                   var_value.value());
1181         StoreMap(object, object_map);
1182         Goto(&done);
1183 
1184       } else {
1185         Label tagged_rep(this), double_rep(this);
1186         TNode<PropertyArray> properties = CAST(LoadFastProperties(object));
1187         Branch(
1188             Word32Equal(representation, Int32Constant(Representation::kDouble)),
1189             &double_rep, &tagged_rep);
1190         BIND(&double_rep);
1191         {
1192           Node* mutable_heap_number =
1193               LoadPropertyArrayElement(properties, backing_store_index);
1194           Node* double_value = ChangeNumberToFloat64(value);
1195           StoreHeapNumberValue(mutable_heap_number, double_value);
1196           Goto(&done);
1197         }
1198         BIND(&tagged_rep);
1199         {
1200           StorePropertyArrayElement(properties, backing_store_index, value);
1201           Goto(&done);
1202         }
1203       }
1204     }
1205   }
1206 
1207   BIND(&if_descriptor);
1208   {
1209     // Check that constant matches value.
1210     Node* constant = LoadValueByKeyIndex(
1211         CAST(descriptors), UncheckedCast<IntPtrT>(descriptor_name_index));
1212     GotoIf(WordNotEqual(value, constant), slow);
1213 
1214     if (do_transitioning_store) {
1215       StoreMap(object, object_map);
1216     }
1217     Goto(&done);
1218   }
1219   BIND(&done);
1220 }
1221 
CheckPrototypeValidityCell(Node * maybe_validity_cell,Label * miss)1222 void AccessorAssembler::CheckPrototypeValidityCell(Node* maybe_validity_cell,
1223                                                    Label* miss) {
1224   Label done(this);
1225   GotoIf(WordEqual(maybe_validity_cell, SmiConstant(Map::kPrototypeChainValid)),
1226          &done);
1227   CSA_ASSERT(this, TaggedIsNotSmi(maybe_validity_cell));
1228 
1229   Node* cell_value = LoadObjectField(maybe_validity_cell, Cell::kValueOffset);
1230   Branch(WordEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)), &done,
1231          miss);
1232 
1233   BIND(&done);
1234 }
1235 
HandleStoreAccessor(const StoreICParameters * p,Node * holder,Node * handler_word)1236 void AccessorAssembler::HandleStoreAccessor(const StoreICParameters* p,
1237                                             Node* holder, Node* handler_word) {
1238   Comment("accessor_store");
1239   Node* descriptor = DecodeWord<StoreHandler::DescriptorBits>(handler_word);
1240   Node* accessor_pair = LoadDescriptorValue(LoadMap(holder), descriptor);
1241   CSA_ASSERT(this, IsAccessorPair(accessor_pair));
1242   Node* setter = LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
1243   CSA_ASSERT(this, Word32BinaryNot(IsTheHole(setter)));
1244 
1245   Callable callable = CodeFactory::Call(isolate());
1246   Return(CallJS(callable, p->context, setter, p->receiver, p->value));
1247 }
1248 
HandleStoreICProtoHandler(const StoreICParameters * p,TNode<StoreHandler> handler,Label * miss,ICMode ic_mode,ElementSupport support_elements)1249 void AccessorAssembler::HandleStoreICProtoHandler(
1250     const StoreICParameters* p, TNode<StoreHandler> handler, Label* miss,
1251     ICMode ic_mode, ElementSupport support_elements) {
1252   Comment("HandleStoreICProtoHandler");
1253 
1254   OnCodeHandler on_code_handler;
1255   if (support_elements == kSupportElements) {
1256     // Code sub-handlers are expected only in KeyedStoreICs.
1257     on_code_handler = [=](Node* code_handler) {
1258       // This is either element store or transitioning element store.
1259       Label if_element_store(this), if_transitioning_element_store(this);
1260       Branch(IsStoreHandler0Map(LoadMap(handler)), &if_element_store,
1261              &if_transitioning_element_store);
1262       BIND(&if_element_store);
1263       {
1264         TailCallStub(StoreWithVectorDescriptor{}, code_handler, p->context,
1265                      p->receiver, p->name, p->value, p->slot, p->vector);
1266       }
1267 
1268       BIND(&if_transitioning_element_store);
1269       {
1270         TNode<MaybeObject> maybe_transition_map =
1271             LoadHandlerDataField(handler, 1);
1272         TNode<Map> transition_map =
1273             CAST(ToWeakHeapObject(maybe_transition_map, miss));
1274 
1275         GotoIf(IsDeprecatedMap(transition_map), miss);
1276 
1277         TailCallStub(StoreTransitionDescriptor{}, code_handler, p->context,
1278                      p->receiver, p->name, transition_map, p->value, p->slot,
1279                      p->vector);
1280       }
1281     };
1282   }
1283 
1284   Node* smi_handler = HandleProtoHandler<StoreHandler>(
1285       p, handler, on_code_handler,
1286       // on_found_on_receiver
1287       [=](Node* properties, Node* name_index) {
1288         Node* details =
1289             LoadDetailsByKeyIndex<NameDictionary>(properties, name_index);
1290         // Check that the property is a writable data property (no accessor).
1291         const int kTypeAndReadOnlyMask =
1292             PropertyDetails::KindField::kMask |
1293             PropertyDetails::kAttributesReadOnlyMask;
1294         STATIC_ASSERT(kData == 0);
1295         GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
1296 
1297         StoreValueByKeyIndex<NameDictionary>(
1298             CAST(properties), UncheckedCast<IntPtrT>(name_index), p->value);
1299         Return(p->value);
1300       },
1301       miss, ic_mode);
1302 
1303   {
1304     Label if_add_normal(this), if_store_global_proxy(this), if_api_setter(this),
1305         if_accessor(this), if_native_data_property(this);
1306 
1307     CSA_ASSERT(this, TaggedIsSmi(smi_handler));
1308     Node* handler_word = SmiUntag(smi_handler);
1309 
1310     Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
1311     GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)),
1312            &if_add_normal);
1313 
1314     TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
1315     CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_holder));
1316     TNode<Object> holder = ToWeakHeapObject(maybe_holder, miss);
1317 
1318     GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kGlobalProxy)),
1319            &if_store_global_proxy);
1320 
1321     GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)),
1322            &if_accessor);
1323 
1324     GotoIf(WordEqual(handler_kind,
1325                      IntPtrConstant(StoreHandler::kNativeDataProperty)),
1326            &if_native_data_property);
1327 
1328     GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kApiSetter)),
1329            &if_api_setter);
1330 
1331     GotoIf(WordEqual(handler_kind,
1332                      IntPtrConstant(StoreHandler::kApiSetterHolderIsPrototype)),
1333            &if_api_setter);
1334 
1335     CSA_ASSERT(this,
1336                WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)));
1337     HandleStoreToProxy(p, holder, miss, support_elements);
1338 
1339     BIND(&if_add_normal);
1340     {
1341       // This is a case of "transitioning store" to a dictionary mode object
1342       // when the property is still does not exist. The "existing property"
1343       // case is covered above by LookupOnReceiver bit handling of the smi
1344       // handler.
1345       Label slow(this);
1346       TNode<Map> receiver_map = LoadMap(p->receiver);
1347       InvalidateValidityCellIfPrototype(receiver_map);
1348 
1349       TNode<NameDictionary> properties = CAST(LoadSlowProperties(p->receiver));
1350       Add<NameDictionary>(properties, CAST(p->name), p->value, &slow);
1351       Return(p->value);
1352 
1353       BIND(&slow);
1354       TailCallRuntime(Runtime::kAddDictionaryProperty, p->context, p->receiver,
1355                       p->name, p->value);
1356     }
1357 
1358     BIND(&if_accessor);
1359     HandleStoreAccessor(p, holder, handler_word);
1360 
1361     BIND(&if_native_data_property);
1362     HandleStoreICNativeDataProperty(p, holder, handler_word);
1363 
1364     BIND(&if_api_setter);
1365     {
1366       Comment("api_setter");
1367       CSA_ASSERT(this, TaggedIsNotSmi(handler));
1368       Node* call_handler_info = holder;
1369 
1370       // Context is stored either in data2 or data3 field depending on whether
1371       // the access check is enabled for this handler or not.
1372       TNode<MaybeObject> maybe_context = Select<MaybeObject>(
1373           IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word),
1374           [=] { return LoadHandlerDataField(handler, 3); },
1375           [=] { return LoadHandlerDataField(handler, 2); });
1376 
1377       CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_context));
1378       TNode<Object> context =
1379           Select<Object>(IsClearedWeakHeapObject(maybe_context),
1380                          [=] { return SmiConstant(0); },
1381                          [=] { return ToWeakHeapObject(maybe_context); });
1382 
1383       Node* foreign = LoadObjectField(call_handler_info,
1384                                       CallHandlerInfo::kJsCallbackOffset);
1385       Node* callback = LoadObjectField(foreign, Foreign::kForeignAddressOffset,
1386                                        MachineType::Pointer());
1387       Node* data =
1388           LoadObjectField(call_handler_info, CallHandlerInfo::kDataOffset);
1389 
1390       VARIABLE(api_holder, MachineRepresentation::kTagged, p->receiver);
1391       Label store(this);
1392       GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kApiSetter)),
1393              &store);
1394 
1395       CSA_ASSERT(
1396           this,
1397           WordEqual(handler_kind,
1398                     IntPtrConstant(StoreHandler::kApiSetterHolderIsPrototype)));
1399 
1400       api_holder.Bind(LoadMapPrototype(LoadMap(p->receiver)));
1401       Goto(&store);
1402 
1403       BIND(&store);
1404       Callable callable = CodeFactory::CallApiCallback(isolate(), 1);
1405       Return(CallStub(callable, nullptr, context, data, api_holder.value(),
1406                       callback, p->receiver, p->value));
1407     }
1408 
1409     BIND(&if_store_global_proxy);
1410     {
1411       ExitPoint direct_exit(this);
1412       StoreGlobalIC_PropertyCellCase(holder, p->value, &direct_exit, miss);
1413     }
1414   }
1415 }
1416 
GetLanguageMode(Node * vector,Node * slot)1417 Node* AccessorAssembler::GetLanguageMode(Node* vector, Node* slot) {
1418   VARIABLE(var_language_mode, MachineRepresentation::kTaggedSigned,
1419            SmiConstant(LanguageMode::kStrict));
1420   Label language_mode_determined(this);
1421   BranchIfStrictMode(vector, slot, &language_mode_determined);
1422   var_language_mode.Bind(SmiConstant(LanguageMode::kSloppy));
1423   Goto(&language_mode_determined);
1424   BIND(&language_mode_determined);
1425   return var_language_mode.value();
1426 }
1427 
HandleStoreToProxy(const StoreICParameters * p,Node * proxy,Label * miss,ElementSupport support_elements)1428 void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
1429                                            Node* proxy, Label* miss,
1430                                            ElementSupport support_elements) {
1431   VARIABLE(var_index, MachineType::PointerRepresentation());
1432   VARIABLE(var_unique, MachineRepresentation::kTagged);
1433 
1434   Label if_index(this), if_unique_name(this),
1435       to_name_failed(this, Label::kDeferred);
1436 
1437   Node* language_mode = GetLanguageMode(p->vector, p->slot);
1438 
1439   if (support_elements == kSupportElements) {
1440     TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
1441               &to_name_failed);
1442 
1443     BIND(&if_unique_name);
1444     CallBuiltin(Builtins::kProxySetProperty, p->context, proxy,
1445                 var_unique.value(), p->value, p->receiver, language_mode);
1446     Return(p->value);
1447 
1448     // The index case is handled earlier by the runtime.
1449     BIND(&if_index);
1450     // TODO(mslekova): introduce TryToName that doesn't try to compute
1451     // the intptr index value
1452     Goto(&to_name_failed);
1453 
1454     BIND(&to_name_failed);
1455     TailCallRuntime(Runtime::kSetPropertyWithReceiver, p->context, proxy,
1456                     p->name, p->value, p->receiver, language_mode);
1457   } else {
1458     Node* name = ToName(p->context, p->name);
1459     TailCallBuiltin(Builtins::kProxySetProperty, p->context, proxy, name,
1460                     p->value, p->receiver, language_mode);
1461   }
1462 }
1463 
HandleStoreICSmiHandlerCase(Node * handler_word,Node * holder,Node * value,Label * miss)1464 void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
1465                                                     Node* holder, Node* value,
1466                                                     Label* miss) {
1467   Comment("field store");
1468 #ifdef DEBUG
1469   Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
1470   if (FLAG_track_constant_fields) {
1471     CSA_ASSERT(
1472         this,
1473         Word32Or(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kField)),
1474                  WordEqual(handler_kind,
1475                            IntPtrConstant(StoreHandler::kConstField))));
1476   } else {
1477     CSA_ASSERT(this,
1478                WordEqual(handler_kind, IntPtrConstant(StoreHandler::kField)));
1479   }
1480 #endif
1481 
1482   Node* field_representation =
1483       DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word);
1484 
1485   Label if_smi_field(this), if_double_field(this), if_heap_object_field(this),
1486       if_tagged_field(this);
1487 
1488   GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)),
1489          &if_tagged_field);
1490   GotoIf(WordEqual(field_representation,
1491                    IntPtrConstant(StoreHandler::kHeapObject)),
1492          &if_heap_object_field);
1493   GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)),
1494          &if_double_field);
1495   CSA_ASSERT(this, WordEqual(field_representation,
1496                              IntPtrConstant(StoreHandler::kSmi)));
1497   Goto(&if_smi_field);
1498 
1499   BIND(&if_tagged_field);
1500   {
1501     Comment("store tagged field");
1502     HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(),
1503                               value, miss);
1504   }
1505 
1506   BIND(&if_double_field);
1507   {
1508     Comment("store double field");
1509     HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(),
1510                               value, miss);
1511   }
1512 
1513   BIND(&if_heap_object_field);
1514   {
1515     Comment("store heap object field");
1516     HandleStoreFieldAndReturn(handler_word, holder,
1517                               Representation::HeapObject(), value, miss);
1518   }
1519 
1520   BIND(&if_smi_field);
1521   {
1522     Comment("store smi field");
1523     HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(),
1524                               value, miss);
1525   }
1526 }
1527 
HandleStoreFieldAndReturn(Node * handler_word,Node * holder,Representation representation,Node * value,Label * miss)1528 void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
1529                                                   Node* holder,
1530                                                   Representation representation,
1531                                                   Node* value, Label* miss) {
1532   Node* prepared_value =
1533       PrepareValueForStore(handler_word, holder, representation, value, miss);
1534 
1535   Label if_inobject(this), if_out_of_object(this);
1536   Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject,
1537          &if_out_of_object);
1538 
1539   BIND(&if_inobject);
1540   {
1541     StoreNamedField(handler_word, holder, true, representation, prepared_value,
1542                     miss);
1543     Return(value);
1544   }
1545 
1546   BIND(&if_out_of_object);
1547   {
1548     StoreNamedField(handler_word, holder, false, representation, prepared_value,
1549                     miss);
1550     Return(value);
1551   }
1552 }
1553 
PrepareValueForStore(Node * handler_word,Node * holder,Representation representation,Node * value,Label * bailout)1554 Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
1555                                               Representation representation,
1556                                               Node* value, Label* bailout) {
1557   if (representation.IsDouble()) {
1558     value = TryTaggedToFloat64(value, bailout);
1559 
1560   } else if (representation.IsHeapObject()) {
1561     GotoIf(TaggedIsSmi(value), bailout);
1562 
1563     Label done(this);
1564     if (FLAG_track_constant_fields) {
1565       // Skip field type check in favor of constant value check when storing
1566       // to constant field.
1567       GotoIf(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
1568                        IntPtrConstant(StoreHandler::kConstField)),
1569              &done);
1570     }
1571     Node* descriptor = DecodeWord<StoreHandler::DescriptorBits>(handler_word);
1572     TNode<MaybeObject> maybe_field_type =
1573         LoadDescriptorValueOrFieldType(LoadMap(holder), descriptor);
1574 
1575     GotoIf(TaggedIsSmi(maybe_field_type), &done);
1576     // Check that value type matches the field type.
1577     {
1578       Node* field_type = ToWeakHeapObject(maybe_field_type, bailout);
1579       Branch(WordEqual(LoadMap(value), field_type), &done, bailout);
1580     }
1581     BIND(&done);
1582 
1583   } else if (representation.IsSmi()) {
1584     GotoIfNot(TaggedIsSmi(value), bailout);
1585 
1586   } else {
1587     DCHECK(representation.IsTagged());
1588   }
1589   return value;
1590 }
1591 
ExtendPropertiesBackingStore(Node * object,Node * index)1592 Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
1593                                                       Node* index) {
1594   Comment("[ Extend storage");
1595 
1596   ParameterMode mode = OptimalParameterMode();
1597 
1598   // TODO(gsathya): Clean up the type conversions by creating smarter
1599   // helpers that do the correct op based on the mode.
1600   VARIABLE(var_properties, MachineRepresentation::kTaggedPointer);
1601   VARIABLE(var_encoded_hash, MachineRepresentation::kWord32);
1602   VARIABLE(var_length, ParameterRepresentation(mode));
1603 
1604   Node* properties = LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
1605   var_properties.Bind(properties);
1606 
1607   Label if_smi_hash(this), if_property_array(this), extend_store(this);
1608   Branch(TaggedIsSmi(properties), &if_smi_hash, &if_property_array);
1609 
1610   BIND(&if_smi_hash);
1611   {
1612     Node* hash = SmiToInt32(properties);
1613     Node* encoded_hash =
1614         Word32Shl(hash, Int32Constant(PropertyArray::HashField::kShift));
1615     var_encoded_hash.Bind(encoded_hash);
1616     var_length.Bind(IntPtrOrSmiConstant(0, mode));
1617     var_properties.Bind(EmptyFixedArrayConstant());
1618     Goto(&extend_store);
1619   }
1620 
1621   BIND(&if_property_array);
1622   {
1623     Node* length_and_hash_int32 = LoadAndUntagToWord32ObjectField(
1624         var_properties.value(), PropertyArray::kLengthAndHashOffset);
1625     var_encoded_hash.Bind(Word32And(
1626         length_and_hash_int32, Int32Constant(PropertyArray::HashField::kMask)));
1627     Node* length_intptr = ChangeInt32ToIntPtr(
1628         Word32And(length_and_hash_int32,
1629                   Int32Constant(PropertyArray::LengthField::kMask)));
1630     Node* length = IntPtrToParameter(length_intptr, mode);
1631     var_length.Bind(length);
1632     Goto(&extend_store);
1633   }
1634 
1635   BIND(&extend_store);
1636   {
1637     VARIABLE(var_new_properties, MachineRepresentation::kTaggedPointer,
1638              var_properties.value());
1639     Label done(this);
1640     // Previous property deletion could have left behind unused backing store
1641     // capacity even for a map that think it doesn't have any unused fields.
1642     // Perform a bounds check to see if we actually have to grow the array.
1643     GotoIf(UintPtrLessThan(index, ParameterToIntPtr(var_length.value(), mode)),
1644            &done);
1645 
1646     Node* delta = IntPtrOrSmiConstant(JSObject::kFieldsAdded, mode);
1647     Node* new_capacity = IntPtrOrSmiAdd(var_length.value(), delta, mode);
1648 
1649     // Grow properties array.
1650     DCHECK(kMaxNumberOfDescriptors + JSObject::kFieldsAdded <
1651            FixedArrayBase::GetMaxLengthForNewSpaceAllocation(PACKED_ELEMENTS));
1652     // The size of a new properties backing store is guaranteed to be small
1653     // enough that the new backing store will be allocated in new space.
1654     CSA_ASSERT(this,
1655                UintPtrOrSmiLessThan(
1656                    new_capacity,
1657                    IntPtrOrSmiConstant(
1658                        kMaxNumberOfDescriptors + JSObject::kFieldsAdded, mode),
1659                    mode));
1660 
1661     Node* new_properties = AllocatePropertyArray(new_capacity, mode);
1662     var_new_properties.Bind(new_properties);
1663 
1664     FillPropertyArrayWithUndefined(new_properties, var_length.value(),
1665                                    new_capacity, mode);
1666 
1667     // |new_properties| is guaranteed to be in new space, so we can skip
1668     // the write barrier.
1669     CopyPropertyArrayValues(var_properties.value(), new_properties,
1670                             var_length.value(), SKIP_WRITE_BARRIER, mode);
1671 
1672     // TODO(gsathya): Clean up the type conversions by creating smarter
1673     // helpers that do the correct op based on the mode.
1674     Node* new_capacity_int32 =
1675         TruncateIntPtrToInt32(ParameterToIntPtr(new_capacity, mode));
1676     Node* new_length_and_hash_int32 =
1677         Word32Or(var_encoded_hash.value(), new_capacity_int32);
1678     StoreObjectField(new_properties, PropertyArray::kLengthAndHashOffset,
1679                      SmiFromInt32(new_length_and_hash_int32));
1680     StoreObjectField(object, JSObject::kPropertiesOrHashOffset, new_properties);
1681     Comment("] Extend storage");
1682     Goto(&done);
1683     BIND(&done);
1684     return var_new_properties.value();
1685   }
1686 }
1687 
StoreNamedField(Node * handler_word,Node * object,bool is_inobject,Representation representation,Node * value,Label * bailout)1688 void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
1689                                         bool is_inobject,
1690                                         Representation representation,
1691                                         Node* value, Label* bailout) {
1692   bool store_value_as_double = representation.IsDouble();
1693   Node* property_storage = object;
1694   if (!is_inobject) {
1695     property_storage = LoadFastProperties(object);
1696   }
1697 
1698   Node* index = DecodeWord<StoreHandler::FieldIndexBits>(handler_word);
1699   Node* offset = IntPtrMul(index, IntPtrConstant(kPointerSize));
1700   if (representation.IsDouble()) {
1701     if (!FLAG_unbox_double_fields || !is_inobject) {
1702       // Load the mutable heap number.
1703       property_storage = LoadObjectField(property_storage, offset);
1704       // Store the double value into it.
1705       offset = IntPtrConstant(HeapNumber::kValueOffset);
1706     }
1707   }
1708 
1709   // Do constant value check if necessary.
1710   if (FLAG_track_constant_fields) {
1711     Label done(this);
1712     GotoIfNot(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
1713                         IntPtrConstant(StoreHandler::kConstField)),
1714               &done);
1715     {
1716       if (store_value_as_double) {
1717         Node* current_value =
1718             LoadObjectField(property_storage, offset, MachineType::Float64());
1719         GotoIfNot(Float64Equal(current_value, value), bailout);
1720       } else {
1721         Node* current_value = LoadObjectField(property_storage, offset);
1722         GotoIfNot(WordEqual(current_value, value), bailout);
1723       }
1724       Goto(&done);
1725     }
1726     BIND(&done);
1727   }
1728 
1729   // Do the store.
1730   if (store_value_as_double) {
1731     StoreObjectFieldNoWriteBarrier(property_storage, offset, value,
1732                                    MachineRepresentation::kFloat64);
1733   } else if (representation.IsSmi()) {
1734     StoreObjectFieldNoWriteBarrier(property_storage, offset, value);
1735   } else {
1736     StoreObjectField(property_storage, offset, value);
1737   }
1738 }
1739 
EmitFastElementsBoundsCheck(Node * object,Node * elements,Node * intptr_index,Node * is_jsarray_condition,Label * miss)1740 void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
1741                                                     Node* elements,
1742                                                     Node* intptr_index,
1743                                                     Node* is_jsarray_condition,
1744                                                     Label* miss) {
1745   VARIABLE(var_length, MachineType::PointerRepresentation());
1746   Comment("Fast elements bounds check");
1747   Label if_array(this), length_loaded(this, &var_length);
1748   GotoIf(is_jsarray_condition, &if_array);
1749   {
1750     var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements)));
1751     Goto(&length_loaded);
1752   }
1753   BIND(&if_array);
1754   {
1755     var_length.Bind(SmiUntag(LoadFastJSArrayLength(object)));
1756     Goto(&length_loaded);
1757   }
1758   BIND(&length_loaded);
1759   GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss);
1760 }
1761 
EmitElementLoad(Node * object,Node * elements,Node * elements_kind,SloppyTNode<IntPtrT> intptr_index,Node * is_jsarray_condition,Label * if_hole,Label * rebox_double,Variable * var_double_value,Label * unimplemented_elements_kind,Label * out_of_bounds,Label * miss,ExitPoint * exit_point)1762 void AccessorAssembler::EmitElementLoad(
1763     Node* object, Node* elements, Node* elements_kind,
1764     SloppyTNode<IntPtrT> intptr_index, Node* is_jsarray_condition,
1765     Label* if_hole, Label* rebox_double, Variable* var_double_value,
1766     Label* unimplemented_elements_kind, Label* out_of_bounds, Label* miss,
1767     ExitPoint* exit_point) {
1768   Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this),
1769       if_fast_double(this), if_fast_holey_double(this), if_nonfast(this),
1770       if_dictionary(this);
1771   GotoIf(
1772       Int32GreaterThan(elements_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
1773       &if_nonfast);
1774 
1775   EmitFastElementsBoundsCheck(object, elements, intptr_index,
1776                               is_jsarray_condition, out_of_bounds);
1777   int32_t kinds[] = {// Handled by if_fast_packed.
1778                      PACKED_SMI_ELEMENTS, PACKED_ELEMENTS,
1779                      // Handled by if_fast_holey.
1780                      HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS,
1781                      // Handled by if_fast_double.
1782                      PACKED_DOUBLE_ELEMENTS,
1783                      // Handled by if_fast_holey_double.
1784                      HOLEY_DOUBLE_ELEMENTS};
1785   Label* labels[] = {// FAST_{SMI,}_ELEMENTS
1786                      &if_fast_packed, &if_fast_packed,
1787                      // FAST_HOLEY_{SMI,}_ELEMENTS
1788                      &if_fast_holey, &if_fast_holey,
1789                      // PACKED_DOUBLE_ELEMENTS
1790                      &if_fast_double,
1791                      // HOLEY_DOUBLE_ELEMENTS
1792                      &if_fast_holey_double};
1793   Switch(elements_kind, unimplemented_elements_kind, kinds, labels,
1794          arraysize(kinds));
1795 
1796   BIND(&if_fast_packed);
1797   {
1798     Comment("fast packed elements");
1799     exit_point->Return(LoadFixedArrayElement(CAST(elements), intptr_index));
1800   }
1801 
1802   BIND(&if_fast_holey);
1803   {
1804     Comment("fast holey elements");
1805     Node* element = LoadFixedArrayElement(CAST(elements), intptr_index);
1806     GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
1807     exit_point->Return(element);
1808   }
1809 
1810   BIND(&if_fast_double);
1811   {
1812     Comment("packed double elements");
1813     var_double_value->Bind(LoadFixedDoubleArrayElement(elements, intptr_index,
1814                                                        MachineType::Float64()));
1815     Goto(rebox_double);
1816   }
1817 
1818   BIND(&if_fast_holey_double);
1819   {
1820     Comment("holey double elements");
1821     Node* value = LoadFixedDoubleArrayElement(elements, intptr_index,
1822                                               MachineType::Float64(), 0,
1823                                               INTPTR_PARAMETERS, if_hole);
1824     var_double_value->Bind(value);
1825     Goto(rebox_double);
1826   }
1827 
1828   BIND(&if_nonfast);
1829   {
1830     STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
1831     GotoIf(Int32GreaterThanOrEqual(
1832                elements_kind,
1833                Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)),
1834            &if_typed_array);
1835     GotoIf(Word32Equal(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)),
1836            &if_dictionary);
1837     Goto(unimplemented_elements_kind);
1838   }
1839 
1840   BIND(&if_dictionary);
1841   {
1842     Comment("dictionary elements");
1843     GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds);
1844 
1845     TNode<Object> value = BasicLoadNumberDictionaryElement(
1846         CAST(elements), intptr_index, miss, if_hole);
1847     exit_point->Return(value);
1848   }
1849 
1850   BIND(&if_typed_array);
1851   {
1852     Comment("typed elements");
1853     // Check if buffer has been neutered.
1854     Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset);
1855     GotoIf(IsDetachedBuffer(buffer), miss);
1856 
1857     // Bounds check.
1858     Node* length = SmiUntag(LoadTypedArrayLength(CAST(object)));
1859     GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds);
1860 
1861     Node* backing_store = LoadFixedTypedArrayBackingStore(CAST(elements));
1862 
1863     Label uint8_elements(this), int8_elements(this), uint16_elements(this),
1864         int16_elements(this), uint32_elements(this), int32_elements(this),
1865         float32_elements(this), float64_elements(this), bigint64_elements(this),
1866         biguint64_elements(this);
1867     Label* elements_kind_labels[] = {
1868         &uint8_elements,    &uint8_elements,    &int8_elements,
1869         &uint16_elements,   &int16_elements,    &uint32_elements,
1870         &int32_elements,    &float32_elements,  &float64_elements,
1871         &bigint64_elements, &biguint64_elements};
1872     int32_t elements_kinds[] = {
1873         UINT8_ELEMENTS,    UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
1874         UINT16_ELEMENTS,   INT16_ELEMENTS,         UINT32_ELEMENTS,
1875         INT32_ELEMENTS,    FLOAT32_ELEMENTS,       FLOAT64_ELEMENTS,
1876         BIGINT64_ELEMENTS, BIGUINT64_ELEMENTS};
1877     const size_t kTypedElementsKindCount =
1878         LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
1879         FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1;
1880     DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
1881     DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
1882     Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
1883            kTypedElementsKindCount);
1884     BIND(&uint8_elements);
1885     {
1886       Comment("UINT8_ELEMENTS");  // Handles UINT8_CLAMPED_ELEMENTS too.
1887       Node* element = Load(MachineType::Uint8(), backing_store, intptr_index);
1888       exit_point->Return(SmiFromInt32(element));
1889     }
1890     BIND(&int8_elements);
1891     {
1892       Comment("INT8_ELEMENTS");
1893       Node* element = Load(MachineType::Int8(), backing_store, intptr_index);
1894       exit_point->Return(SmiFromInt32(element));
1895     }
1896     BIND(&uint16_elements);
1897     {
1898       Comment("UINT16_ELEMENTS");
1899       Node* index = WordShl(intptr_index, IntPtrConstant(1));
1900       Node* element = Load(MachineType::Uint16(), backing_store, index);
1901       exit_point->Return(SmiFromInt32(element));
1902     }
1903     BIND(&int16_elements);
1904     {
1905       Comment("INT16_ELEMENTS");
1906       Node* index = WordShl(intptr_index, IntPtrConstant(1));
1907       Node* element = Load(MachineType::Int16(), backing_store, index);
1908       exit_point->Return(SmiFromInt32(element));
1909     }
1910     BIND(&uint32_elements);
1911     {
1912       Comment("UINT32_ELEMENTS");
1913       Node* index = WordShl(intptr_index, IntPtrConstant(2));
1914       Node* element = Load(MachineType::Uint32(), backing_store, index);
1915       exit_point->Return(ChangeUint32ToTagged(element));
1916     }
1917     BIND(&int32_elements);
1918     {
1919       Comment("INT32_ELEMENTS");
1920       Node* index = WordShl(intptr_index, IntPtrConstant(2));
1921       Node* element = Load(MachineType::Int32(), backing_store, index);
1922       exit_point->Return(ChangeInt32ToTagged(element));
1923     }
1924     BIND(&float32_elements);
1925     {
1926       Comment("FLOAT32_ELEMENTS");
1927       Node* index = WordShl(intptr_index, IntPtrConstant(2));
1928       Node* element = Load(MachineType::Float32(), backing_store, index);
1929       var_double_value->Bind(ChangeFloat32ToFloat64(element));
1930       Goto(rebox_double);
1931     }
1932     BIND(&float64_elements);
1933     {
1934       Comment("FLOAT64_ELEMENTS");
1935       Node* index = WordShl(intptr_index, IntPtrConstant(3));
1936       Node* element = Load(MachineType::Float64(), backing_store, index);
1937       var_double_value->Bind(element);
1938       Goto(rebox_double);
1939     }
1940     BIND(&bigint64_elements);
1941     {
1942       Comment("BIGINT64_ELEMENTS");
1943       exit_point->Return(LoadFixedTypedArrayElementAsTagged(
1944           backing_store, intptr_index, BIGINT64_ELEMENTS, INTPTR_PARAMETERS));
1945     }
1946     BIND(&biguint64_elements);
1947     {
1948       Comment("BIGUINT64_ELEMENTS");
1949       exit_point->Return(LoadFixedTypedArrayElementAsTagged(
1950           backing_store, intptr_index, BIGUINT64_ELEMENTS, INTPTR_PARAMETERS));
1951     }
1952   }
1953 }
1954 
NameDictionaryNegativeLookup(Node * object,SloppyTNode<Name> name,Label * miss)1955 void AccessorAssembler::NameDictionaryNegativeLookup(Node* object,
1956                                                      SloppyTNode<Name> name,
1957                                                      Label* miss) {
1958   CSA_ASSERT(this, IsDictionaryMap(LoadMap(object)));
1959   TNode<NameDictionary> properties = CAST(LoadSlowProperties(object));
1960   // Ensure the property does not exist in a dictionary-mode object.
1961   TVARIABLE(IntPtrT, var_name_index);
1962   Label done(this);
1963   NameDictionaryLookup<NameDictionary>(properties, name, miss, &var_name_index,
1964                                        &done);
1965   BIND(&done);
1966 }
1967 
BranchIfStrictMode(Node * vector,Node * slot,Label * if_strict)1968 void AccessorAssembler::BranchIfStrictMode(Node* vector, Node* slot,
1969                                            Label* if_strict) {
1970   Node* sfi =
1971       LoadObjectField(vector, FeedbackVector::kSharedFunctionInfoOffset);
1972   TNode<FeedbackMetadata> metadata = CAST(LoadObjectField(
1973       sfi, SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset));
1974   Node* slot_int = SmiToInt32(slot);
1975 
1976   // See VectorICComputer::index().
1977   const int kItemsPerWord = FeedbackMetadata::VectorICComputer::kItemsPerWord;
1978   Node* word_index = Int32Div(slot_int, Int32Constant(kItemsPerWord));
1979   Node* word_offset = Int32Mod(slot_int, Int32Constant(kItemsPerWord));
1980 
1981   int32_t first_item = FeedbackMetadata::kHeaderSize - kHeapObjectTag;
1982   Node* offset =
1983       ElementOffsetFromIndex(ChangeInt32ToIntPtr(word_index), UINT32_ELEMENTS,
1984                              INTPTR_PARAMETERS, first_item);
1985 
1986   Node* data = Load(MachineType::Int32(), metadata, offset);
1987 
1988   // See VectorICComputer::decode().
1989   const int kBitsPerItem = FeedbackMetadata::kFeedbackSlotKindBits;
1990   Node* shift = Int32Mul(word_offset, Int32Constant(kBitsPerItem));
1991   const int kMask = FeedbackMetadata::VectorICComputer::kMask;
1992   Node* kind = Word32And(Word32Shr(data, shift), Int32Constant(kMask));
1993 
1994   STATIC_ASSERT(FeedbackSlotKind::kStoreGlobalSloppy <=
1995                 FeedbackSlotKind::kLastSloppyKind);
1996   STATIC_ASSERT(FeedbackSlotKind::kStoreKeyedSloppy <=
1997                 FeedbackSlotKind::kLastSloppyKind);
1998   STATIC_ASSERT(FeedbackSlotKind::kStoreNamedSloppy <=
1999                 FeedbackSlotKind::kLastSloppyKind);
2000   GotoIfNot(Int32LessThanOrEqual(kind, Int32Constant(static_cast<int>(
2001                                            FeedbackSlotKind::kLastSloppyKind))),
2002             if_strict);
2003 }
2004 
InvalidateValidityCellIfPrototype(Node * map,Node * bitfield2)2005 void AccessorAssembler::InvalidateValidityCellIfPrototype(Node* map,
2006                                                           Node* bitfield2) {
2007   Label is_prototype(this), cont(this);
2008   if (bitfield2 == nullptr) {
2009     bitfield2 = LoadMapBitField2(map);
2010   }
2011 
2012   Branch(IsSetWord32(bitfield2, Map::IsPrototypeMapBit::kMask), &is_prototype,
2013          &cont);
2014 
2015   BIND(&is_prototype);
2016   {
2017     Node* maybe_prototype_info =
2018         LoadObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
2019     // If there's no prototype info then there's nothing to invalidate.
2020     GotoIf(TaggedIsSmi(maybe_prototype_info), &cont);
2021 
2022     Node* function = ExternalConstant(
2023         ExternalReference::invalidate_prototype_chains_function());
2024     CallCFunction1(MachineType::AnyTagged(), MachineType::AnyTagged(), function,
2025                    map);
2026     Goto(&cont);
2027   }
2028   BIND(&cont);
2029 }
2030 
GenericElementLoad(Node * receiver,Node * receiver_map,SloppyTNode<Int32T> instance_type,Node * index,Label * slow)2031 void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
2032                                            SloppyTNode<Int32T> instance_type,
2033                                            Node* index, Label* slow) {
2034   Comment("integer index");
2035 
2036   ExitPoint direct_exit(this);
2037 
2038   Label if_custom(this), if_element_hole(this), if_oob(this);
2039   // Receivers requiring non-standard element accesses (interceptors, access
2040   // checks, strings and string wrappers, proxies) are handled in the runtime.
2041   GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &if_custom);
2042   Node* elements = LoadElements(receiver);
2043   Node* elements_kind = LoadMapElementsKind(receiver_map);
2044   Node* is_jsarray_condition = InstanceTypeEqual(instance_type, JS_ARRAY_TYPE);
2045   VARIABLE(var_double_value, MachineRepresentation::kFloat64);
2046   Label rebox_double(this, &var_double_value);
2047 
2048   // Unimplemented elements kinds fall back to a runtime call.
2049   Label* unimplemented_elements_kind = slow;
2050   IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
2051   EmitElementLoad(receiver, elements, elements_kind, index,
2052                   is_jsarray_condition, &if_element_hole, &rebox_double,
2053                   &var_double_value, unimplemented_elements_kind, &if_oob, slow,
2054                   &direct_exit);
2055 
2056   BIND(&rebox_double);
2057   Return(AllocateHeapNumberWithValue(var_double_value.value()));
2058 
2059   BIND(&if_oob);
2060   {
2061     Comment("out of bounds");
2062     // Positive OOB indices are effectively the same as hole loads.
2063     GotoIf(IntPtrGreaterThanOrEqual(index, IntPtrConstant(0)),
2064            &if_element_hole);
2065     // Negative keys can't take the fast OOB path, except for typed arrays.
2066     GotoIfNot(InstanceTypeEqual(instance_type, JS_TYPED_ARRAY_TYPE), slow);
2067     Return(UndefinedConstant());
2068   }
2069 
2070   BIND(&if_element_hole);
2071   {
2072     Comment("found the hole");
2073     Label return_undefined(this);
2074     BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, slow);
2075 
2076     BIND(&return_undefined);
2077     Return(UndefinedConstant());
2078   }
2079 
2080   BIND(&if_custom);
2081   {
2082     Comment("check if string");
2083     GotoIfNot(IsStringInstanceType(instance_type), slow);
2084     Comment("load string character");
2085     Node* length = LoadAndUntagObjectField(receiver, String::kLengthOffset);
2086     GotoIfNot(UintPtrLessThan(index, length), slow);
2087     IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
2088     TailCallBuiltin(Builtins::kStringCharAt, NoContextConstant(), receiver,
2089                     index);
2090   }
2091 }
2092 
GenericPropertyLoad(Node * receiver,Node * receiver_map,SloppyTNode<Int32T> instance_type,const LoadICParameters * p,Label * slow,UseStubCache use_stub_cache)2093 void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
2094                                             SloppyTNode<Int32T> instance_type,
2095                                             const LoadICParameters* p,
2096                                             Label* slow,
2097                                             UseStubCache use_stub_cache) {
2098   ExitPoint direct_exit(this);
2099 
2100   Comment("key is unique name");
2101   Label if_found_on_receiver(this), if_property_dictionary(this),
2102       lookup_prototype_chain(this), special_receiver(this);
2103   VARIABLE(var_details, MachineRepresentation::kWord32);
2104   VARIABLE(var_value, MachineRepresentation::kTagged);
2105 
2106   // Receivers requiring non-standard accesses (interceptors, access
2107   // checks, strings and string wrappers) are handled in the runtime.
2108   GotoIf(IsSpecialReceiverInstanceType(instance_type), &special_receiver);
2109 
2110   // Check if the receiver has fast or slow properties.
2111   Node* bitfield3 = LoadMapBitField3(receiver_map);
2112   GotoIf(IsSetWord32<Map::IsDictionaryMapBit>(bitfield3),
2113          &if_property_dictionary);
2114 
2115   // Try looking up the property on the receiver; if unsuccessful, look
2116   // for a handler in the stub cache.
2117   TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
2118 
2119   Label if_descriptor_found(this), stub_cache(this);
2120   TVARIABLE(IntPtrT, var_name_index);
2121   Label* notfound =
2122       use_stub_cache == kUseStubCache ? &stub_cache : &lookup_prototype_chain;
2123   DescriptorLookup(p->name, descriptors, bitfield3, &if_descriptor_found,
2124                    &var_name_index, notfound);
2125 
2126   BIND(&if_descriptor_found);
2127   {
2128     LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
2129                                var_name_index.value(), &var_details,
2130                                &var_value);
2131     Goto(&if_found_on_receiver);
2132   }
2133 
2134   if (use_stub_cache == kUseStubCache) {
2135     BIND(&stub_cache);
2136     Comment("stub cache probe for fast property load");
2137     TVARIABLE(MaybeObject, var_handler);
2138     Label found_handler(this, &var_handler), stub_cache_miss(this);
2139     TryProbeStubCache(isolate()->load_stub_cache(), receiver, p->name,
2140                       &found_handler, &var_handler, &stub_cache_miss);
2141     BIND(&found_handler);
2142     {
2143       HandleLoadICHandlerCase(p, CAST(var_handler.value()), &stub_cache_miss,
2144                               &direct_exit);
2145     }
2146 
2147     BIND(&stub_cache_miss);
2148     {
2149       // TODO(jkummerow): Check if the property exists on the prototype
2150       // chain. If it doesn't, then there's no point in missing.
2151       Comment("KeyedLoadGeneric_miss");
2152       TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
2153                       p->name, p->slot, p->vector);
2154     }
2155   }
2156 
2157   BIND(&if_property_dictionary);
2158   {
2159     Comment("dictionary property load");
2160     // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
2161     // seeing global objects here (which would need special handling).
2162 
2163     TVARIABLE(IntPtrT, var_name_index);
2164     Label dictionary_found(this, &var_name_index);
2165     TNode<NameDictionary> properties = CAST(LoadSlowProperties(receiver));
2166     NameDictionaryLookup<NameDictionary>(properties, CAST(p->name),
2167                                          &dictionary_found, &var_name_index,
2168                                          &lookup_prototype_chain);
2169     BIND(&dictionary_found);
2170     {
2171       LoadPropertyFromNameDictionary(properties, var_name_index.value(),
2172                                      &var_details, &var_value);
2173       Goto(&if_found_on_receiver);
2174     }
2175   }
2176 
2177   BIND(&if_found_on_receiver);
2178   {
2179     Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
2180                                        p->context, receiver, slow);
2181     IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
2182     Return(value);
2183   }
2184 
2185   BIND(&lookup_prototype_chain);
2186   {
2187     VARIABLE(var_holder_map, MachineRepresentation::kTagged);
2188     VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32);
2189     Label return_undefined(this);
2190     Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type};
2191     Label loop(this, arraysize(merged_variables), merged_variables);
2192 
2193     var_holder_map.Bind(receiver_map);
2194     var_holder_instance_type.Bind(instance_type);
2195     // Private symbols must not be looked up on the prototype chain.
2196     GotoIf(IsPrivateSymbol(p->name), &return_undefined);
2197     Goto(&loop);
2198     BIND(&loop);
2199     {
2200       // Bailout if it can be an integer indexed exotic case.
2201       GotoIf(InstanceTypeEqual(var_holder_instance_type.value(),
2202                                JS_TYPED_ARRAY_TYPE),
2203              slow);
2204       Node* proto = LoadMapPrototype(var_holder_map.value());
2205       GotoIf(WordEqual(proto, NullConstant()), &return_undefined);
2206       Node* proto_map = LoadMap(proto);
2207       Node* proto_instance_type = LoadMapInstanceType(proto_map);
2208       var_holder_map.Bind(proto_map);
2209       var_holder_instance_type.Bind(proto_instance_type);
2210       Label next_proto(this), return_value(this, &var_value), goto_slow(this);
2211       TryGetOwnProperty(p->context, receiver, proto, proto_map,
2212                         proto_instance_type, p->name, &return_value, &var_value,
2213                         &next_proto, &goto_slow);
2214 
2215       // This trampoline and the next are required to appease Turbofan's
2216       // variable merging.
2217       BIND(&next_proto);
2218       Goto(&loop);
2219 
2220       BIND(&goto_slow);
2221       Goto(slow);
2222 
2223       BIND(&return_value);
2224       Return(var_value.value());
2225     }
2226 
2227     BIND(&return_undefined);
2228     Return(UndefinedConstant());
2229   }
2230 
2231   BIND(&special_receiver);
2232   {
2233     // TODO(jkummerow): Consider supporting JSModuleNamespace.
2234     GotoIfNot(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), slow);
2235 
2236     // Private field/symbol lookup is not supported.
2237     GotoIf(IsPrivateSymbol(p->name), slow);
2238 
2239     direct_exit.ReturnCallStub(
2240         Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
2241         p->context, receiver /*holder is the same as receiver*/, p->name,
2242         receiver, SmiConstant(OnNonExistent::kReturnUndefined));
2243   }
2244 }
2245 
2246 //////////////////// Stub cache access helpers.
2247 
2248 enum AccessorAssembler::StubCacheTable : int {
2249   kPrimary = static_cast<int>(StubCache::kPrimary),
2250   kSecondary = static_cast<int>(StubCache::kSecondary)
2251 };
2252 
StubCachePrimaryOffset(Node * name,Node * map)2253 Node* AccessorAssembler::StubCachePrimaryOffset(Node* name, Node* map) {
2254   // See v8::internal::StubCache::PrimaryOffset().
2255   STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift);
2256   // Compute the hash of the name (use entire hash field).
2257   Node* hash_field = LoadNameHashField(name);
2258   CSA_ASSERT(this,
2259              Word32Equal(Word32And(hash_field,
2260                                    Int32Constant(Name::kHashNotComputedMask)),
2261                          Int32Constant(0)));
2262 
2263   // Using only the low bits in 64-bit mode is unlikely to increase the
2264   // risk of collision even if the heap is spread over an area larger than
2265   // 4Gb (and not at all if it isn't).
2266   Node* map32 = TruncateIntPtrToInt32(BitcastTaggedToWord(map));
2267   // Base the offset on a simple combination of name and map.
2268   Node* hash = Int32Add(hash_field, map32);
2269   uint32_t mask = (StubCache::kPrimaryTableSize - 1)
2270                   << StubCache::kCacheIndexShift;
2271   return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
2272 }
2273 
StubCacheSecondaryOffset(Node * name,Node * seed)2274 Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) {
2275   // See v8::internal::StubCache::SecondaryOffset().
2276 
2277   // Use the seed from the primary cache in the secondary cache.
2278   Node* name32 = TruncateIntPtrToInt32(BitcastTaggedToWord(name));
2279   Node* hash = Int32Sub(TruncateIntPtrToInt32(seed), name32);
2280   hash = Int32Add(hash, Int32Constant(StubCache::kSecondaryMagic));
2281   int32_t mask = (StubCache::kSecondaryTableSize - 1)
2282                  << StubCache::kCacheIndexShift;
2283   return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
2284 }
2285 
TryProbeStubCacheTable(StubCache * stub_cache,StubCacheTable table_id,Node * entry_offset,Node * name,Node * map,Label * if_handler,TVariable<MaybeObject> * var_handler,Label * if_miss)2286 void AccessorAssembler::TryProbeStubCacheTable(
2287     StubCache* stub_cache, StubCacheTable table_id, Node* entry_offset,
2288     Node* name, Node* map, Label* if_handler,
2289     TVariable<MaybeObject>* var_handler, Label* if_miss) {
2290   StubCache::Table table = static_cast<StubCache::Table>(table_id);
2291 #ifdef DEBUG
2292   if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
2293     Goto(if_miss);
2294     return;
2295   } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
2296     Goto(if_miss);
2297     return;
2298   }
2299 #endif
2300   // The {table_offset} holds the entry offset times four (due to masking
2301   // and shifting optimizations).
2302   const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift;
2303   entry_offset = IntPtrMul(entry_offset, IntPtrConstant(kMultiplier));
2304 
2305   // Check that the key in the entry matches the name.
2306   Node* key_base = ExternalConstant(
2307       ExternalReference::Create(stub_cache->key_reference(table)));
2308   Node* entry_key = Load(MachineType::Pointer(), key_base, entry_offset);
2309   GotoIf(WordNotEqual(name, entry_key), if_miss);
2310 
2311   // Get the map entry from the cache.
2312   DCHECK_EQ(kPointerSize * 2, stub_cache->map_reference(table).address() -
2313                                   stub_cache->key_reference(table).address());
2314   Node* entry_map =
2315       Load(MachineType::Pointer(), key_base,
2316            IntPtrAdd(entry_offset, IntPtrConstant(kPointerSize * 2)));
2317   GotoIf(WordNotEqual(map, entry_map), if_miss);
2318 
2319   DCHECK_EQ(kPointerSize, stub_cache->value_reference(table).address() -
2320                               stub_cache->key_reference(table).address());
2321   TNode<MaybeObject> handler = ReinterpretCast<MaybeObject>(
2322       Load(MachineType::TaggedPointer(), key_base,
2323            IntPtrAdd(entry_offset, IntPtrConstant(kPointerSize))));
2324 
2325   // We found the handler.
2326   *var_handler = handler;
2327   Goto(if_handler);
2328 }
2329 
TryProbeStubCache(StubCache * stub_cache,Node * receiver,Node * name,Label * if_handler,TVariable<MaybeObject> * var_handler,Label * if_miss)2330 void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
2331                                           Node* name, Label* if_handler,
2332                                           TVariable<MaybeObject>* var_handler,
2333                                           Label* if_miss) {
2334   Label try_secondary(this), miss(this);
2335 
2336   Counters* counters = isolate()->counters();
2337   IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
2338 
2339   // Check that the {receiver} isn't a smi.
2340   GotoIf(TaggedIsSmi(receiver), &miss);
2341 
2342   Node* receiver_map = LoadMap(receiver);
2343 
2344   // Probe the primary table.
2345   Node* primary_offset = StubCachePrimaryOffset(name, receiver_map);
2346   TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name,
2347                          receiver_map, if_handler, var_handler, &try_secondary);
2348 
2349   BIND(&try_secondary);
2350   {
2351     // Probe the secondary table.
2352     Node* secondary_offset = StubCacheSecondaryOffset(name, primary_offset);
2353     TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name,
2354                            receiver_map, if_handler, var_handler, &miss);
2355   }
2356 
2357   BIND(&miss);
2358   {
2359     IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
2360     Goto(if_miss);
2361   }
2362 }
2363 
2364 //////////////////// Entry points into private implementation (one per stub).
2365 
LoadIC_BytecodeHandler(const LoadICParameters * p,ExitPoint * exit_point)2366 void AccessorAssembler::LoadIC_BytecodeHandler(const LoadICParameters* p,
2367                                                ExitPoint* exit_point) {
2368   // Must be kept in sync with LoadIC.
2369 
2370   // This function is hand-tuned to omit frame construction for common cases,
2371   // e.g.: monomorphic field and constant loads through smi handlers.
2372   // Polymorphic ICs with a hit in the first two entries also omit frames.
2373   // TODO(jgruber): Frame omission is fragile and can be affected by minor
2374   // changes in control flow and logic. We currently have no way of ensuring
2375   // that no frame is constructed, so it's easy to break this optimization by
2376   // accident.
2377   Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred);
2378 
2379   // Inlined fast path.
2380   {
2381     Comment("LoadIC_BytecodeHandler_fast");
2382 
2383     Node* recv_map = LoadReceiverMap(p->receiver);
2384     GotoIf(IsDeprecatedMap(recv_map), &miss);
2385 
2386     TVARIABLE(MaybeObject, var_handler);
2387     Label try_polymorphic(this), if_handler(this, &var_handler);
2388 
2389     TNode<MaybeObject> feedback =
2390         TryMonomorphicCase(p->slot, p->vector, recv_map, &if_handler,
2391                            &var_handler, &try_polymorphic);
2392 
2393     BIND(&if_handler);
2394     HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, exit_point);
2395 
2396     BIND(&try_polymorphic);
2397     {
2398       TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss);
2399       GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &stub_call);
2400       HandlePolymorphicCase(recv_map, CAST(strong_feedback), &if_handler,
2401                             &var_handler, &miss, 2);
2402     }
2403   }
2404 
2405   BIND(&stub_call);
2406   {
2407     Comment("LoadIC_BytecodeHandler_noninlined");
2408 
2409     // Call into the stub that implements the non-inlined parts of LoadIC.
2410     Callable ic =
2411         Builtins::CallableFor(isolate(), Builtins::kLoadIC_Noninlined);
2412     Node* code_target = HeapConstant(ic.code());
2413     exit_point->ReturnCallStub(ic.descriptor(), code_target, p->context,
2414                                p->receiver, p->name, p->slot, p->vector);
2415   }
2416 
2417   BIND(&miss);
2418   {
2419     Comment("LoadIC_BytecodeHandler_miss");
2420 
2421     exit_point->ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context,
2422                                   p->receiver, p->name, p->slot, p->vector);
2423   }
2424 }
2425 
LoadIC(const LoadICParameters * p)2426 void AccessorAssembler::LoadIC(const LoadICParameters* p) {
2427   // Must be kept in sync with LoadIC_BytecodeHandler.
2428 
2429   ExitPoint direct_exit(this);
2430 
2431   TVARIABLE(MaybeObject, var_handler);
2432   Label if_handler(this, &var_handler), non_inlined(this, Label::kDeferred),
2433       try_polymorphic(this), miss(this, Label::kDeferred);
2434 
2435   Node* receiver_map = LoadReceiverMap(p->receiver);
2436   GotoIf(IsDeprecatedMap(receiver_map), &miss);
2437 
2438   // Check monomorphic case.
2439   TNode<MaybeObject> feedback =
2440       TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
2441                          &var_handler, &try_polymorphic);
2442   BIND(&if_handler);
2443   HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, &direct_exit);
2444 
2445   BIND(&try_polymorphic);
2446   TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss);
2447   {
2448     // Check polymorphic case.
2449     Comment("LoadIC_try_polymorphic");
2450     GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &non_inlined);
2451     HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
2452                           &var_handler, &miss, 2);
2453   }
2454 
2455   BIND(&non_inlined);
2456   {
2457     LoadIC_Noninlined(p, receiver_map, strong_feedback, &var_handler,
2458                       &if_handler, &miss, &direct_exit);
2459   }
2460 
2461   BIND(&miss);
2462   direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver,
2463                                 p->name, p->slot, p->vector);
2464 }
2465 
LoadIC_Noninlined(const LoadICParameters * p,Node * receiver_map,TNode<HeapObject> feedback,TVariable<MaybeObject> * var_handler,Label * if_handler,Label * miss,ExitPoint * exit_point)2466 void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
2467                                           Node* receiver_map,
2468                                           TNode<HeapObject> feedback,
2469                                           TVariable<MaybeObject>* var_handler,
2470                                           Label* if_handler, Label* miss,
2471                                           ExitPoint* exit_point) {
2472   Label try_uninitialized(this, Label::kDeferred);
2473 
2474   // Neither deprecated map nor monomorphic. These cases are handled in the
2475   // bytecode handler.
2476   CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map)));
2477   CSA_ASSERT(this, WordNotEqual(receiver_map, feedback));
2478   CSA_ASSERT(this, Word32BinaryNot(IsWeakFixedArrayMap(LoadMap(feedback))));
2479   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
2480 
2481   {
2482     // Check megamorphic case.
2483     GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
2484               &try_uninitialized);
2485 
2486     TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name,
2487                       if_handler, var_handler, miss);
2488   }
2489 
2490   BIND(&try_uninitialized);
2491   {
2492     // Check uninitialized case.
2493     GotoIfNot(
2494         WordEqual(feedback, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
2495         miss);
2496     exit_point->ReturnCallStub(
2497         Builtins::CallableFor(isolate(), Builtins::kLoadIC_Uninitialized),
2498         p->context, p->receiver, p->name, p->slot, p->vector);
2499   }
2500 }
2501 
LoadIC_Uninitialized(const LoadICParameters * p)2502 void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
2503   Label miss(this, Label::kDeferred);
2504   Node* receiver = p->receiver;
2505   GotoIf(TaggedIsSmi(receiver), &miss);
2506   Node* receiver_map = LoadMap(receiver);
2507   Node* instance_type = LoadMapInstanceType(receiver_map);
2508 
2509   // Optimistically write the state transition to the vector.
2510   StoreFeedbackVectorSlot(p->vector, p->slot,
2511                           LoadRoot(Heap::kpremonomorphic_symbolRootIndex),
2512                           SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
2513   StoreWeakReferenceInFeedbackVector(p->vector, p->slot, receiver_map,
2514                                      kPointerSize, SMI_PARAMETERS);
2515 
2516   {
2517     // Special case for Function.prototype load, because it's very common
2518     // for ICs that are only executed once (MyFunc.prototype.foo = ...).
2519     Label not_function_prototype(this, Label::kDeferred);
2520     GotoIfNot(InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE),
2521               &not_function_prototype);
2522     GotoIfNot(IsPrototypeString(p->name), &not_function_prototype);
2523 
2524     GotoIfPrototypeRequiresRuntimeLookup(CAST(receiver), CAST(receiver_map),
2525                                          &not_function_prototype);
2526     Return(LoadJSFunctionPrototype(receiver, &miss));
2527     BIND(&not_function_prototype);
2528   }
2529 
2530   GenericPropertyLoad(receiver, receiver_map, instance_type, p, &miss,
2531                       kDontUseStubCache);
2532 
2533   BIND(&miss);
2534   {
2535     // Undo the optimistic state transition.
2536     StoreFeedbackVectorSlot(p->vector, p->slot,
2537                             LoadRoot(Heap::kuninitialized_symbolRootIndex),
2538                             SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
2539 
2540     TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
2541                     p->slot, p->vector);
2542   }
2543 }
2544 
LoadGlobalIC(TNode<FeedbackVector> vector,Node * slot,const LazyNode<Context> & lazy_context,const LazyNode<Name> & lazy_name,TypeofMode typeof_mode,ExitPoint * exit_point,ParameterMode slot_mode)2545 void AccessorAssembler::LoadGlobalIC(TNode<FeedbackVector> vector, Node* slot,
2546                                      const LazyNode<Context>& lazy_context,
2547                                      const LazyNode<Name>& lazy_name,
2548                                      TypeofMode typeof_mode,
2549                                      ExitPoint* exit_point,
2550                                      ParameterMode slot_mode) {
2551   Label try_handler(this, Label::kDeferred), miss(this, Label::kDeferred);
2552   LoadGlobalIC_TryPropertyCellCase(vector, slot, lazy_context, exit_point,
2553                                    &try_handler, &miss, slot_mode);
2554 
2555   BIND(&try_handler);
2556   LoadGlobalIC_TryHandlerCase(vector, slot, lazy_context, lazy_name,
2557                               typeof_mode, exit_point, &miss, slot_mode);
2558 
2559   BIND(&miss);
2560   {
2561     Comment("LoadGlobalIC_MissCase");
2562     TNode<Context> context = lazy_context();
2563     TNode<Name> name = lazy_name();
2564     exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, context, name,
2565                                   ParameterToTagged(slot, slot_mode), vector);
2566   }
2567 }
2568 
LoadGlobalIC_TryPropertyCellCase(TNode<FeedbackVector> vector,Node * slot,const LazyNode<Context> & lazy_context,ExitPoint * exit_point,Label * try_handler,Label * miss,ParameterMode slot_mode)2569 void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
2570     TNode<FeedbackVector> vector, Node* slot,
2571     const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
2572     Label* try_handler, Label* miss, ParameterMode slot_mode) {
2573   Comment("LoadGlobalIC_TryPropertyCellCase");
2574 
2575   Label if_lexical_var(this), if_property_cell(this);
2576   TNode<MaybeObject> maybe_weak_ref =
2577       LoadFeedbackVectorSlot(vector, slot, 0, slot_mode);
2578   Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_property_cell);
2579 
2580   BIND(&if_property_cell);
2581   {
2582     // Load value or try handler case if the weak reference is cleared.
2583     CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_weak_ref));
2584     TNode<PropertyCell> property_cell =
2585         CAST(ToWeakHeapObject(maybe_weak_ref, try_handler));
2586     TNode<Object> value =
2587         LoadObjectField(property_cell, PropertyCell::kValueOffset);
2588     GotoIf(WordEqual(value, TheHoleConstant()), miss);
2589     exit_point->Return(value);
2590   }
2591 
2592   BIND(&if_lexical_var);
2593   {
2594     Comment("Load lexical variable");
2595     TNode<IntPtrT> lexical_handler = SmiUntag(CAST(maybe_weak_ref));
2596     TNode<IntPtrT> context_index =
2597         Signed(DecodeWord<FeedbackNexus::ContextIndexBits>(lexical_handler));
2598     TNode<IntPtrT> slot_index =
2599         Signed(DecodeWord<FeedbackNexus::SlotIndexBits>(lexical_handler));
2600     TNode<Context> context = lazy_context();
2601     TNode<Context> script_context = LoadScriptContext(context, context_index);
2602     TNode<Object> result = LoadContextElement(script_context, slot_index);
2603     exit_point->Return(result);
2604   }
2605 }
2606 
LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector,Node * slot,const LazyNode<Context> & lazy_context,const LazyNode<Name> & lazy_name,TypeofMode typeof_mode,ExitPoint * exit_point,Label * miss,ParameterMode slot_mode)2607 void AccessorAssembler::LoadGlobalIC_TryHandlerCase(
2608     TNode<FeedbackVector> vector, Node* slot,
2609     const LazyNode<Context>& lazy_context, const LazyNode<Name>& lazy_name,
2610     TypeofMode typeof_mode, ExitPoint* exit_point, Label* miss,
2611     ParameterMode slot_mode) {
2612   Comment("LoadGlobalIC_TryHandlerCase");
2613 
2614   Label call_handler(this), non_smi(this);
2615 
2616   TNode<MaybeObject> feedback_element =
2617       LoadFeedbackVectorSlot(vector, slot, kPointerSize, slot_mode);
2618   TNode<Object> handler = CAST(feedback_element);
2619   GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
2620          miss);
2621 
2622   OnNonExistent on_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF
2623                                      ? OnNonExistent::kThrowReferenceError
2624                                      : OnNonExistent::kReturnUndefined;
2625 
2626   TNode<Context> context = lazy_context();
2627   TNode<Context> native_context = LoadNativeContext(context);
2628   TNode<JSGlobalProxy> receiver =
2629       CAST(LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX));
2630   Node* holder = LoadContextElement(native_context, Context::EXTENSION_INDEX);
2631 
2632   LoadICParameters p(context, receiver, lazy_name(),
2633                      ParameterToTagged(slot, slot_mode), vector, holder);
2634 
2635   HandleLoadICHandlerCase(&p, handler, miss, exit_point, ICMode::kGlobalIC,
2636                           on_nonexistent);
2637 }
2638 
KeyedLoadIC(const LoadICParameters * p)2639 void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
2640   ExitPoint direct_exit(this);
2641 
2642   TVARIABLE(MaybeObject, var_handler);
2643   Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred),
2644       try_megamorphic(this, Label::kDeferred),
2645       try_polymorphic_name(this, Label::kDeferred),
2646       miss(this, Label::kDeferred);
2647 
2648   Node* receiver_map = LoadReceiverMap(p->receiver);
2649   GotoIf(IsDeprecatedMap(receiver_map), &miss);
2650 
2651   // Check monomorphic case.
2652   TNode<MaybeObject> feedback =
2653       TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
2654                          &var_handler, &try_polymorphic);
2655   BIND(&if_handler);
2656   {
2657     HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, &direct_exit,
2658                             ICMode::kNonGlobalIC,
2659                             OnNonExistent::kReturnUndefined, kSupportElements);
2660   }
2661 
2662   BIND(&try_polymorphic);
2663   TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss);
2664   {
2665     // Check polymorphic case.
2666     Comment("KeyedLoadIC_try_polymorphic");
2667     GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
2668     HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
2669                           &var_handler, &miss, 2);
2670   }
2671 
2672   BIND(&try_megamorphic);
2673   {
2674     // Check megamorphic case.
2675     Comment("KeyedLoadIC_try_megamorphic");
2676     GotoIfNot(WordEqual(strong_feedback,
2677                         LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
2678               &try_polymorphic_name);
2679     // TODO(jkummerow): Inline this? Or some of it?
2680     TailCallBuiltin(Builtins::kKeyedLoadIC_Megamorphic, p->context, p->receiver,
2681                     p->name, p->slot, p->vector);
2682   }
2683   BIND(&try_polymorphic_name);
2684   {
2685     // We might have a name in feedback, and a weak fixed array in the next
2686     // slot.
2687     Node* name = p->name;
2688     Comment("KeyedLoadIC_try_polymorphic_name");
2689     VARIABLE(var_name, MachineRepresentation::kTagged, name);
2690     VARIABLE(var_index, MachineType::PointerRepresentation());
2691     Label if_polymorphic_name(this, &var_name), if_internalized(this),
2692         if_notinternalized(this, Label::kDeferred);
2693 
2694     // Fast-case: The recorded {feedback} matches the {name}.
2695     GotoIf(WordEqual(strong_feedback, name), &if_polymorphic_name);
2696 
2697     // Try to internalize the {name} if it isn't already.
2698     TryToName(name, &miss, &var_index, &if_internalized, &var_name, &miss,
2699               &if_notinternalized);
2700 
2701     BIND(&if_internalized);
2702     {
2703       // The {var_name} now contains a unique name.
2704       Branch(WordEqual(strong_feedback, var_name.value()), &if_polymorphic_name,
2705              &miss);
2706     }
2707 
2708     BIND(&if_notinternalized);
2709     {
2710       // Try to internalize the {name}.
2711       Node* function = ExternalConstant(
2712           ExternalReference::try_internalize_string_function());
2713       Node* const isolate_ptr =
2714           ExternalConstant(ExternalReference::isolate_address(isolate()));
2715       var_name.Bind(CallCFunction2(
2716           MachineType::AnyTagged(), MachineType::Pointer(),
2717           MachineType::AnyTagged(), function, isolate_ptr, name));
2718       Goto(&if_internalized);
2719     }
2720 
2721     BIND(&if_polymorphic_name);
2722     {
2723       // If the name comparison succeeded, we know we have a weak fixed array
2724       // with at least one map/handler pair.
2725       Node* name = var_name.value();
2726       TailCallBuiltin(Builtins::kKeyedLoadIC_PolymorphicName, p->context,
2727                       p->receiver, name, p->slot, p->vector);
2728     }
2729   }
2730 
2731   BIND(&miss);
2732   {
2733     Comment("KeyedLoadIC_miss");
2734     TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
2735                     p->name, p->slot, p->vector);
2736   }
2737 }
2738 
KeyedLoadICGeneric(const LoadICParameters * p)2739 void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
2740   VARIABLE(var_index, MachineType::PointerRepresentation());
2741   VARIABLE(var_unique, MachineRepresentation::kTagged);
2742   var_unique.Bind(p->name);  // Dummy initialization.
2743   Label if_index(this), if_unique_name(this), if_notunique(this), slow(this);
2744 
2745   Node* receiver = p->receiver;
2746   GotoIf(TaggedIsSmi(receiver), &slow);
2747   Node* receiver_map = LoadMap(receiver);
2748   Node* instance_type = LoadMapInstanceType(receiver_map);
2749 
2750   TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique, &slow,
2751             &if_notunique);
2752 
2753   BIND(&if_index);
2754   {
2755     GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(),
2756                        &slow);
2757   }
2758 
2759   BIND(&if_unique_name);
2760   {
2761     LoadICParameters pp = *p;
2762     pp.name = var_unique.value();
2763     GenericPropertyLoad(receiver, receiver_map, instance_type, &pp, &slow);
2764   }
2765 
2766   BIND(&if_notunique);
2767   {
2768     if (FLAG_internalize_on_the_fly) {
2769       // Ideally we could return undefined directly here if the name is not
2770       // found in the string table, i.e. it was never internalized, but that
2771       // invariant doesn't hold with named property interceptors (at this
2772       // point), so we take the {slow} path instead.
2773       Label if_in_string_table(this);
2774       TryInternalizeString(p->name, &if_index, &var_index, &if_in_string_table,
2775                            &var_unique, &slow, &slow);
2776 
2777       BIND(&if_in_string_table);
2778       {
2779         // TODO(bmeurer): We currently use a version of GenericPropertyLoad
2780         // here, where we don't try to probe the megamorphic stub cache after
2781         // successfully internalizing the incoming string. Past experiments
2782         // with this have shown that it causes too much traffic on the stub
2783         // cache. We may want to re-evaluate that in the future.
2784         LoadICParameters pp = *p;
2785         pp.name = var_unique.value();
2786         GenericPropertyLoad(receiver, receiver_map, instance_type, &pp, &slow,
2787                             kDontUseStubCache);
2788       }
2789     } else {
2790       Goto(&slow);
2791     }
2792   }
2793 
2794   BIND(&slow);
2795   {
2796     Comment("KeyedLoadGeneric_slow");
2797     IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1);
2798     // TODO(jkummerow): Should we use the GetProperty TF stub instead?
2799     TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver,
2800                     p->name);
2801   }
2802 }
2803 
KeyedLoadICPolymorphicName(const LoadICParameters * p)2804 void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p) {
2805   TVARIABLE(MaybeObject, var_handler);
2806   Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
2807 
2808   Node* receiver = p->receiver;
2809   Node* receiver_map = LoadReceiverMap(receiver);
2810   Node* name = p->name;
2811   Node* vector = p->vector;
2812   Node* slot = p->slot;
2813   Node* context = p->context;
2814 
2815   // When we get here, we know that the {name} matches the recorded
2816   // feedback name in the {vector} and can safely be used for the
2817   // LoadIC handler logic below.
2818   CSA_ASSERT(this, IsName(name));
2819   CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map)));
2820   CSA_ASSERT(this, WordEqual(name, CAST(LoadFeedbackVectorSlot(
2821                                        vector, slot, 0, SMI_PARAMETERS))));
2822 
2823   // Check if we have a matching handler for the {receiver_map}.
2824   TNode<MaybeObject> feedback_element =
2825       LoadFeedbackVectorSlot(vector, slot, kPointerSize, SMI_PARAMETERS);
2826   TNode<WeakFixedArray> array = CAST(feedback_element);
2827   HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss,
2828                         1);
2829 
2830   BIND(&if_handler);
2831   {
2832     ExitPoint direct_exit(this);
2833     HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, &direct_exit,
2834                             ICMode::kNonGlobalIC,
2835                             OnNonExistent::kReturnUndefined, kOnlyProperties);
2836   }
2837 
2838   BIND(&miss);
2839   {
2840     Comment("KeyedLoadIC_miss");
2841     TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, name, slot,
2842                     vector);
2843   }
2844 }
2845 
StoreIC(const StoreICParameters * p)2846 void AccessorAssembler::StoreIC(const StoreICParameters* p) {
2847   TVARIABLE(MaybeObject, var_handler,
2848             ReinterpretCast<MaybeObject>(SmiConstant(0)));
2849 
2850   Label if_handler(this, &var_handler),
2851       if_handler_from_stub_cache(this, &var_handler, Label::kDeferred),
2852       try_polymorphic(this, Label::kDeferred),
2853       try_megamorphic(this, Label::kDeferred),
2854       try_uninitialized(this, Label::kDeferred), miss(this, Label::kDeferred);
2855 
2856   Node* receiver_map = LoadReceiverMap(p->receiver);
2857   GotoIf(IsDeprecatedMap(receiver_map), &miss);
2858 
2859   // Check monomorphic case.
2860   TNode<MaybeObject> feedback =
2861       TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
2862                          &var_handler, &try_polymorphic);
2863   BIND(&if_handler);
2864   {
2865     Comment("StoreIC_if_handler");
2866     HandleStoreICHandlerCase(p, var_handler.value(), &miss,
2867                              ICMode::kNonGlobalIC);
2868   }
2869 
2870   BIND(&try_polymorphic);
2871   TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss);
2872   {
2873     // Check polymorphic case.
2874     Comment("StoreIC_try_polymorphic");
2875     GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
2876     HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
2877                           &var_handler, &miss, 2);
2878   }
2879 
2880   BIND(&try_megamorphic);
2881   {
2882     // Check megamorphic case.
2883     GotoIfNot(WordEqual(strong_feedback,
2884                         LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
2885               &try_uninitialized);
2886 
2887     TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name,
2888                       &if_handler, &var_handler, &miss);
2889   }
2890   BIND(&try_uninitialized);
2891   {
2892     // Check uninitialized case.
2893     GotoIfNot(WordEqual(strong_feedback,
2894                         LoadRoot(Heap::kuninitialized_symbolRootIndex)),
2895               &miss);
2896     TailCallBuiltin(Builtins::kStoreIC_Uninitialized, p->context, p->receiver,
2897                     p->name, p->value, p->slot, p->vector);
2898   }
2899   BIND(&miss);
2900   {
2901     TailCallRuntime(Runtime::kStoreIC_Miss, p->context, p->value, p->slot,
2902                     p->vector, p->receiver, p->name);
2903   }
2904 }
2905 
StoreGlobalIC(const StoreICParameters * pp)2906 void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
2907   Label if_lexical_var(this), if_property_cell(this);
2908   TNode<MaybeObject> maybe_weak_ref =
2909       LoadFeedbackVectorSlot(pp->vector, pp->slot, 0, SMI_PARAMETERS);
2910   Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_property_cell);
2911 
2912   BIND(&if_property_cell);
2913   {
2914     Label try_handler(this), miss(this, Label::kDeferred);
2915     CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_weak_ref));
2916     TNode<PropertyCell> property_cell =
2917         CAST(ToWeakHeapObject(maybe_weak_ref, &try_handler));
2918 
2919     ExitPoint direct_exit(this);
2920     StoreGlobalIC_PropertyCellCase(property_cell, pp->value, &direct_exit,
2921                                    &miss);
2922 
2923     BIND(&try_handler);
2924     {
2925       Comment("StoreGlobalIC_try_handler");
2926       TNode<MaybeObject> handler = LoadFeedbackVectorSlot(
2927           pp->vector, pp->slot, kPointerSize, SMI_PARAMETERS);
2928 
2929       GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
2930              &miss);
2931 
2932       StoreICParameters p = *pp;
2933       DCHECK_NULL(p.receiver);
2934       Node* native_context = LoadNativeContext(p.context);
2935       p.receiver =
2936           LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX);
2937 
2938       HandleStoreICHandlerCase(&p, handler, &miss, ICMode::kGlobalIC);
2939     }
2940 
2941     BIND(&miss);
2942     {
2943       TailCallRuntime(Runtime::kStoreGlobalIC_Miss, pp->context, pp->value,
2944                       pp->slot, pp->vector, pp->name);
2945     }
2946   }
2947 
2948   BIND(&if_lexical_var);
2949   {
2950     Comment("Store lexical variable");
2951     TNode<IntPtrT> lexical_handler = SmiUntag(CAST(maybe_weak_ref));
2952     TNode<IntPtrT> context_index =
2953         Signed(DecodeWord<FeedbackNexus::ContextIndexBits>(lexical_handler));
2954     TNode<IntPtrT> slot_index =
2955         Signed(DecodeWord<FeedbackNexus::SlotIndexBits>(lexical_handler));
2956     TNode<Context> script_context =
2957         LoadScriptContext(CAST(pp->context), context_index);
2958     StoreContextElement(script_context, slot_index, pp->value);
2959     Return(pp->value);
2960   }
2961 }
2962 
StoreGlobalIC_PropertyCellCase(Node * property_cell,Node * value,ExitPoint * exit_point,Label * miss)2963 void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
2964                                                        Node* value,
2965                                                        ExitPoint* exit_point,
2966                                                        Label* miss) {
2967   Comment("StoreGlobalIC_TryPropertyCellCase");
2968   CSA_ASSERT(this, IsPropertyCell(property_cell));
2969 
2970   // Load the payload of the global parameter cell. A hole indicates that
2971   // the cell has been invalidated and that the store must be handled by the
2972   // runtime.
2973   Node* cell_contents =
2974       LoadObjectField(property_cell, PropertyCell::kValueOffset);
2975   Node* details = LoadAndUntagToWord32ObjectField(property_cell,
2976                                                   PropertyCell::kDetailsOffset);
2977   GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), miss);
2978   CSA_ASSERT(this,
2979              Word32Equal(DecodeWord32<PropertyDetails::KindField>(details),
2980                          Int32Constant(kData)));
2981 
2982   Node* type = DecodeWord32<PropertyDetails::PropertyCellTypeField>(details);
2983 
2984   Label constant(this), store(this), not_smi(this);
2985 
2986   GotoIf(Word32Equal(type, Int32Constant(
2987                                static_cast<int>(PropertyCellType::kConstant))),
2988          &constant);
2989 
2990   GotoIf(IsTheHole(cell_contents), miss);
2991 
2992   GotoIf(Word32Equal(
2993              type, Int32Constant(static_cast<int>(PropertyCellType::kMutable))),
2994          &store);
2995   CSA_ASSERT(this,
2996              Word32Or(Word32Equal(type, Int32Constant(static_cast<int>(
2997                                             PropertyCellType::kConstantType))),
2998                       Word32Equal(type, Int32Constant(static_cast<int>(
2999                                             PropertyCellType::kUndefined)))));
3000 
3001   GotoIfNot(TaggedIsSmi(cell_contents), &not_smi);
3002   GotoIfNot(TaggedIsSmi(value), miss);
3003   Goto(&store);
3004 
3005   BIND(&not_smi);
3006   {
3007     GotoIf(TaggedIsSmi(value), miss);
3008     Node* expected_map = LoadMap(cell_contents);
3009     Node* map = LoadMap(value);
3010     GotoIfNot(WordEqual(expected_map, map), miss);
3011     Goto(&store);
3012   }
3013 
3014   BIND(&store);
3015   {
3016     StoreObjectField(property_cell, PropertyCell::kValueOffset, value);
3017     exit_point->Return(value);
3018   }
3019 
3020   BIND(&constant);
3021   {
3022     GotoIfNot(WordEqual(cell_contents, value), miss);
3023     exit_point->Return(value);
3024   }
3025 }
3026 
KeyedStoreIC(const StoreICParameters * p)3027 void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
3028   Label miss(this, Label::kDeferred);
3029   {
3030     TVARIABLE(MaybeObject, var_handler);
3031 
3032     Label if_handler(this, &var_handler),
3033         try_polymorphic(this, Label::kDeferred),
3034         try_megamorphic(this, Label::kDeferred),
3035         try_polymorphic_name(this, Label::kDeferred);
3036 
3037     Node* receiver_map = LoadReceiverMap(p->receiver);
3038     GotoIf(IsDeprecatedMap(receiver_map), &miss);
3039 
3040     // Check monomorphic case.
3041     TNode<MaybeObject> feedback =
3042         TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
3043                            &var_handler, &try_polymorphic);
3044     BIND(&if_handler);
3045     {
3046       Comment("KeyedStoreIC_if_handler");
3047       HandleStoreICHandlerCase(p, var_handler.value(), &miss,
3048                                ICMode::kNonGlobalIC, kSupportElements);
3049     }
3050 
3051     BIND(&try_polymorphic);
3052     TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss);
3053     {
3054       // CheckPolymorphic case.
3055       Comment("KeyedStoreIC_try_polymorphic");
3056       GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
3057                 &try_megamorphic);
3058       HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
3059                             &var_handler, &miss, 2);
3060     }
3061 
3062     BIND(&try_megamorphic);
3063     {
3064       // Check megamorphic case.
3065       Comment("KeyedStoreIC_try_megamorphic");
3066       GotoIfNot(WordEqual(strong_feedback,
3067                           LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
3068                 &try_polymorphic_name);
3069       TailCallBuiltin(Builtins::kKeyedStoreIC_Megamorphic, p->context,
3070                       p->receiver, p->name, p->value, p->slot, p->vector);
3071     }
3072 
3073     BIND(&try_polymorphic_name);
3074     {
3075       // We might have a name in feedback, and a fixed array in the next slot.
3076       Comment("KeyedStoreIC_try_polymorphic_name");
3077       GotoIfNot(WordEqual(strong_feedback, p->name), &miss);
3078       // If the name comparison succeeded, we know we have a feedback vector
3079       // with at least one map/handler pair.
3080       TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot(
3081           p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
3082       TNode<WeakFixedArray> array = CAST(feedback_element);
3083       HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler,
3084                             &miss, 1);
3085     }
3086   }
3087   BIND(&miss);
3088   {
3089     Comment("KeyedStoreIC_miss");
3090     TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
3091                     p->vector, p->receiver, p->name);
3092   }
3093 }
3094 
StoreInArrayLiteralIC(const StoreICParameters * p)3095 void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
3096   Label miss(this, Label::kDeferred);
3097   {
3098     TVARIABLE(MaybeObject, var_handler);
3099 
3100     Label if_handler(this, &var_handler),
3101         try_polymorphic(this, Label::kDeferred),
3102         try_megamorphic(this, Label::kDeferred);
3103 
3104     Node* array_map = LoadReceiverMap(p->receiver);
3105     GotoIf(IsDeprecatedMap(array_map), &miss);
3106     TNode<MaybeObject> feedback =
3107         TryMonomorphicCase(p->slot, p->vector, array_map, &if_handler,
3108                            &var_handler, &try_polymorphic);
3109 
3110     BIND(&if_handler);
3111     {
3112       Comment("StoreInArrayLiteralIC_if_handler");
3113       // This is a stripped-down version of HandleStoreICHandlerCase.
3114 
3115       TNode<HeapObject> handler = CAST(var_handler.value());
3116       Label if_transitioning_element_store(this);
3117       GotoIfNot(IsCode(handler), &if_transitioning_element_store);
3118       TailCallStub(StoreWithVectorDescriptor{}, CAST(handler), CAST(p->context),
3119                    p->receiver, p->name, p->value, p->slot, p->vector);
3120 
3121       BIND(&if_transitioning_element_store);
3122       {
3123         TNode<MaybeObject> maybe_transition_map =
3124             LoadHandlerDataField(CAST(handler), 1);
3125         TNode<Map> transition_map =
3126             CAST(ToWeakHeapObject(maybe_transition_map, &miss));
3127         GotoIf(IsDeprecatedMap(transition_map), &miss);
3128         Node* code = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
3129         CSA_ASSERT(this, IsCode(code));
3130         TailCallStub(StoreTransitionDescriptor{}, code, p->context, p->receiver,
3131                      p->name, transition_map, p->value, p->slot, p->vector);
3132       }
3133     }
3134 
3135     BIND(&try_polymorphic);
3136     TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss);
3137     {
3138       Comment("StoreInArrayLiteralIC_try_polymorphic");
3139       GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
3140                 &try_megamorphic);
3141       HandlePolymorphicCase(array_map, CAST(strong_feedback), &if_handler,
3142                             &var_handler, &miss, 2);
3143     }
3144 
3145     BIND(&try_megamorphic);
3146     {
3147       Comment("StoreInArrayLiteralIC_try_megamorphic");
3148       CSA_ASSERT(
3149           this,
3150           Word32Or(WordEqual(strong_feedback,
3151                              LoadRoot(Heap::kuninitialized_symbolRootIndex)),
3152                    WordEqual(strong_feedback,
3153                              LoadRoot(Heap::kmegamorphic_symbolRootIndex))));
3154       GotoIfNot(WordEqual(strong_feedback,
3155                           LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
3156                 &miss);
3157       TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context,
3158                       p->value, p->receiver, p->name);
3159     }
3160   }
3161 
3162   BIND(&miss);
3163   {
3164     Comment("StoreInArrayLiteralIC_miss");
3165     // TODO(neis): Introduce Runtime::kStoreInArrayLiteralIC_Miss.
3166     TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
3167                     p->vector, p->receiver, p->name);
3168   }
3169 }
3170 
3171 //////////////////// Public methods.
3172 
GenerateLoadIC()3173 void AccessorAssembler::GenerateLoadIC() {
3174   typedef LoadWithVectorDescriptor Descriptor;
3175 
3176   Node* receiver = Parameter(Descriptor::kReceiver);
3177   Node* name = Parameter(Descriptor::kName);
3178   Node* slot = Parameter(Descriptor::kSlot);
3179   Node* vector = Parameter(Descriptor::kVector);
3180   Node* context = Parameter(Descriptor::kContext);
3181 
3182   LoadICParameters p(context, receiver, name, slot, vector);
3183   LoadIC(&p);
3184 }
3185 
GenerateLoadIC_Noninlined()3186 void AccessorAssembler::GenerateLoadIC_Noninlined() {
3187   typedef LoadWithVectorDescriptor Descriptor;
3188 
3189   Node* receiver = Parameter(Descriptor::kReceiver);
3190   Node* name = Parameter(Descriptor::kName);
3191   Node* slot = Parameter(Descriptor::kSlot);
3192   Node* vector = Parameter(Descriptor::kVector);
3193   Node* context = Parameter(Descriptor::kContext);
3194 
3195   ExitPoint direct_exit(this);
3196   TVARIABLE(MaybeObject, var_handler);
3197   Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
3198 
3199   Node* receiver_map = LoadReceiverMap(receiver);
3200   TNode<MaybeObject> feedback_element =
3201       LoadFeedbackVectorSlot(vector, slot, 0, SMI_PARAMETERS);
3202   TNode<HeapObject> feedback = CAST(feedback_element);
3203 
3204   LoadICParameters p(context, receiver, name, slot, vector);
3205   LoadIC_Noninlined(&p, receiver_map, feedback, &var_handler, &if_handler,
3206                     &miss, &direct_exit);
3207 
3208   BIND(&if_handler);
3209   HandleLoadICHandlerCase(&p, CAST(var_handler.value()), &miss, &direct_exit);
3210 
3211   BIND(&miss);
3212   direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name,
3213                                 slot, vector);
3214 }
3215 
GenerateLoadIC_Uninitialized()3216 void AccessorAssembler::GenerateLoadIC_Uninitialized() {
3217   typedef LoadWithVectorDescriptor Descriptor;
3218 
3219   Node* receiver = Parameter(Descriptor::kReceiver);
3220   Node* name = Parameter(Descriptor::kName);
3221   Node* slot = Parameter(Descriptor::kSlot);
3222   Node* vector = Parameter(Descriptor::kVector);
3223   Node* context = Parameter(Descriptor::kContext);
3224 
3225   LoadICParameters p(context, receiver, name, slot, vector);
3226   LoadIC_Uninitialized(&p);
3227 }
3228 
GenerateLoadICTrampoline()3229 void AccessorAssembler::GenerateLoadICTrampoline() {
3230   typedef LoadDescriptor Descriptor;
3231 
3232   Node* receiver = Parameter(Descriptor::kReceiver);
3233   Node* name = Parameter(Descriptor::kName);
3234   Node* slot = Parameter(Descriptor::kSlot);
3235   Node* context = Parameter(Descriptor::kContext);
3236   Node* vector = LoadFeedbackVectorForStub();
3237 
3238   TailCallBuiltin(Builtins::kLoadIC, context, receiver, name, slot, vector);
3239 }
3240 
GenerateLoadGlobalIC(TypeofMode typeof_mode)3241 void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
3242   typedef LoadGlobalWithVectorDescriptor Descriptor;
3243 
3244   Node* name = Parameter(Descriptor::kName);
3245   Node* slot = Parameter(Descriptor::kSlot);
3246   Node* vector = Parameter(Descriptor::kVector);
3247   Node* context = Parameter(Descriptor::kContext);
3248 
3249   ExitPoint direct_exit(this);
3250   LoadGlobalIC(CAST(vector), slot,
3251                // lazy_context
3252                [=] { return CAST(context); },
3253                // lazy_name
3254                [=] { return CAST(name); }, typeof_mode, &direct_exit);
3255 }
3256 
GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode)3257 void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) {
3258   typedef LoadGlobalDescriptor Descriptor;
3259 
3260   Node* name = Parameter(Descriptor::kName);
3261   Node* slot = Parameter(Descriptor::kSlot);
3262   Node* context = Parameter(Descriptor::kContext);
3263   Node* vector = LoadFeedbackVectorForStub();
3264 
3265   Callable callable =
3266       CodeFactory::LoadGlobalICInOptimizedCode(isolate(), typeof_mode);
3267   TailCallStub(callable, context, name, slot, vector);
3268 }
3269 
GenerateKeyedLoadIC()3270 void AccessorAssembler::GenerateKeyedLoadIC() {
3271   typedef LoadWithVectorDescriptor Descriptor;
3272 
3273   Node* receiver = Parameter(Descriptor::kReceiver);
3274   Node* name = Parameter(Descriptor::kName);
3275   Node* slot = Parameter(Descriptor::kSlot);
3276   Node* vector = Parameter(Descriptor::kVector);
3277   Node* context = Parameter(Descriptor::kContext);
3278 
3279   LoadICParameters p(context, receiver, name, slot, vector);
3280   KeyedLoadIC(&p);
3281 }
3282 
GenerateKeyedLoadICTrampoline()3283 void AccessorAssembler::GenerateKeyedLoadICTrampoline() {
3284   typedef LoadDescriptor Descriptor;
3285 
3286   Node* receiver = Parameter(Descriptor::kReceiver);
3287   Node* name = Parameter(Descriptor::kName);
3288   Node* slot = Parameter(Descriptor::kSlot);
3289   Node* context = Parameter(Descriptor::kContext);
3290   Node* vector = LoadFeedbackVectorForStub();
3291 
3292   TailCallBuiltin(Builtins::kKeyedLoadIC, context, receiver, name, slot,
3293                   vector);
3294 }
3295 
GenerateKeyedLoadIC_Megamorphic()3296 void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
3297   typedef LoadWithVectorDescriptor Descriptor;
3298 
3299   Node* receiver = Parameter(Descriptor::kReceiver);
3300   Node* name = Parameter(Descriptor::kName);
3301   Node* slot = Parameter(Descriptor::kSlot);
3302   Node* vector = Parameter(Descriptor::kVector);
3303   Node* context = Parameter(Descriptor::kContext);
3304 
3305   LoadICParameters p(context, receiver, name, slot, vector);
3306   KeyedLoadICGeneric(&p);
3307 }
3308 
GenerateKeyedLoadIC_PolymorphicName()3309 void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() {
3310   typedef LoadWithVectorDescriptor Descriptor;
3311 
3312   Node* receiver = Parameter(Descriptor::kReceiver);
3313   Node* name = Parameter(Descriptor::kName);
3314   Node* slot = Parameter(Descriptor::kSlot);
3315   Node* vector = Parameter(Descriptor::kVector);
3316   Node* context = Parameter(Descriptor::kContext);
3317 
3318   LoadICParameters p(context, receiver, name, slot, vector);
3319   KeyedLoadICPolymorphicName(&p);
3320 }
3321 
GenerateStoreGlobalIC()3322 void AccessorAssembler::GenerateStoreGlobalIC() {
3323   typedef StoreGlobalWithVectorDescriptor Descriptor;
3324 
3325   Node* name = Parameter(Descriptor::kName);
3326   Node* value = Parameter(Descriptor::kValue);
3327   Node* slot = Parameter(Descriptor::kSlot);
3328   Node* vector = Parameter(Descriptor::kVector);
3329   Node* context = Parameter(Descriptor::kContext);
3330 
3331   StoreICParameters p(context, nullptr, name, value, slot, vector);
3332   StoreGlobalIC(&p);
3333 }
3334 
GenerateStoreGlobalICTrampoline()3335 void AccessorAssembler::GenerateStoreGlobalICTrampoline() {
3336   typedef StoreGlobalDescriptor Descriptor;
3337 
3338   Node* name = Parameter(Descriptor::kName);
3339   Node* value = Parameter(Descriptor::kValue);
3340   Node* slot = Parameter(Descriptor::kSlot);
3341   Node* context = Parameter(Descriptor::kContext);
3342   Node* vector = LoadFeedbackVectorForStub();
3343 
3344   TailCallBuiltin(Builtins::kStoreGlobalIC, context, name, value, slot, vector);
3345 }
3346 
GenerateStoreIC()3347 void AccessorAssembler::GenerateStoreIC() {
3348   typedef StoreWithVectorDescriptor Descriptor;
3349 
3350   Node* receiver = Parameter(Descriptor::kReceiver);
3351   Node* name = Parameter(Descriptor::kName);
3352   Node* value = Parameter(Descriptor::kValue);
3353   Node* slot = Parameter(Descriptor::kSlot);
3354   Node* vector = Parameter(Descriptor::kVector);
3355   Node* context = Parameter(Descriptor::kContext);
3356 
3357   StoreICParameters p(context, receiver, name, value, slot, vector);
3358   StoreIC(&p);
3359 }
3360 
GenerateStoreICTrampoline()3361 void AccessorAssembler::GenerateStoreICTrampoline() {
3362   typedef StoreDescriptor Descriptor;
3363 
3364   Node* receiver = Parameter(Descriptor::kReceiver);
3365   Node* name = Parameter(Descriptor::kName);
3366   Node* value = Parameter(Descriptor::kValue);
3367   Node* slot = Parameter(Descriptor::kSlot);
3368   Node* context = Parameter(Descriptor::kContext);
3369   Node* vector = LoadFeedbackVectorForStub();
3370 
3371   TailCallBuiltin(Builtins::kStoreIC, context, receiver, name, value, slot,
3372                   vector);
3373 }
3374 
GenerateKeyedStoreIC()3375 void AccessorAssembler::GenerateKeyedStoreIC() {
3376   typedef StoreWithVectorDescriptor Descriptor;
3377 
3378   Node* receiver = Parameter(Descriptor::kReceiver);
3379   Node* name = Parameter(Descriptor::kName);
3380   Node* value = Parameter(Descriptor::kValue);
3381   Node* slot = Parameter(Descriptor::kSlot);
3382   Node* vector = Parameter(Descriptor::kVector);
3383   Node* context = Parameter(Descriptor::kContext);
3384 
3385   StoreICParameters p(context, receiver, name, value, slot, vector);
3386   KeyedStoreIC(&p);
3387 }
3388 
GenerateKeyedStoreICTrampoline()3389 void AccessorAssembler::GenerateKeyedStoreICTrampoline() {
3390   typedef StoreDescriptor Descriptor;
3391 
3392   Node* receiver = Parameter(Descriptor::kReceiver);
3393   Node* name = Parameter(Descriptor::kName);
3394   Node* value = Parameter(Descriptor::kValue);
3395   Node* slot = Parameter(Descriptor::kSlot);
3396   Node* context = Parameter(Descriptor::kContext);
3397   Node* vector = LoadFeedbackVectorForStub();
3398 
3399   TailCallBuiltin(Builtins::kKeyedStoreIC, context, receiver, name, value, slot,
3400                   vector);
3401 }
3402 
GenerateStoreInArrayLiteralIC()3403 void AccessorAssembler::GenerateStoreInArrayLiteralIC() {
3404   typedef StoreWithVectorDescriptor Descriptor;
3405 
3406   Node* array = Parameter(Descriptor::kReceiver);
3407   Node* index = Parameter(Descriptor::kName);
3408   Node* value = Parameter(Descriptor::kValue);
3409   Node* slot = Parameter(Descriptor::kSlot);
3410   Node* vector = Parameter(Descriptor::kVector);
3411   Node* context = Parameter(Descriptor::kContext);
3412 
3413   StoreICParameters p(context, array, index, value, slot, vector);
3414   StoreInArrayLiteralIC(&p);
3415 }
3416 
GenerateCloneObjectIC()3417 void AccessorAssembler::GenerateCloneObjectIC() {
3418   typedef CloneObjectWithVectorDescriptor Descriptor;
3419   Node* source = Parameter(Descriptor::kSource);
3420   Node* flags = Parameter(Descriptor::kFlags);
3421   Node* slot = Parameter(Descriptor::kSlot);
3422   Node* vector = Parameter(Descriptor::kVector);
3423   Node* context = Parameter(Descriptor::kContext);
3424   TVARIABLE(MaybeObject, var_handler);
3425   Label if_handler(this, &var_handler);
3426   Label miss(this, Label::kDeferred), try_polymorphic(this, Label::kDeferred),
3427       try_megamorphic(this, Label::kDeferred);
3428 
3429   CSA_SLOW_ASSERT(this, TaggedIsNotSmi(source));
3430   Node* source_map = LoadMap(UncheckedCast<HeapObject>(source));
3431   GotoIf(IsDeprecatedMap(source_map), &miss);
3432   TNode<MaybeObject> feedback = TryMonomorphicCase(
3433       slot, vector, source_map, &if_handler, &var_handler, &try_polymorphic);
3434 
3435   BIND(&if_handler);
3436   {
3437     Comment("CloneObjectIC_if_handler");
3438 
3439     // Handlers for the CloneObjectIC stub are weak references to the Map of
3440     // a result object.
3441     TNode<Map> result_map = CAST(var_handler.value());
3442     TVARIABLE(Object, var_properties, EmptyFixedArrayConstant());
3443     TVARIABLE(FixedArrayBase, var_elements, EmptyFixedArrayConstant());
3444 
3445     Label allocate_object(this);
3446     GotoIf(IsNullOrUndefined(source), &allocate_object);
3447     CSA_SLOW_ASSERT(this, IsJSObjectMap(result_map));
3448 
3449     // The IC fast case should only be taken if the result map a compatible
3450     // elements kind with the source object.
3451     TNode<FixedArrayBase> source_elements = LoadElements(source);
3452 
3453     auto flags = ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW;
3454     var_elements = CAST(CloneFixedArray(source_elements, flags));
3455 
3456     // Copy the PropertyArray backing store. The source PropertyArray must be
3457     // either an Smi, or a PropertyArray.
3458     // FIXME: Make a CSA macro for this
3459     TNode<Object> source_properties =
3460         LoadObjectField(source, JSObject::kPropertiesOrHashOffset);
3461     {
3462       GotoIf(TaggedIsSmi(source_properties), &allocate_object);
3463       GotoIf(IsEmptyFixedArray(source_properties), &allocate_object);
3464 
3465       // This IC requires that the source object has fast properties
3466       CSA_SLOW_ASSERT(this, IsPropertyArray(CAST(source_properties)));
3467       TNode<IntPtrT> length = LoadPropertyArrayLength(
3468           UncheckedCast<PropertyArray>(source_properties));
3469       GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &allocate_object);
3470 
3471       auto mode = INTPTR_PARAMETERS;
3472       var_properties = CAST(AllocatePropertyArray(length, mode));
3473       CopyPropertyArrayValues(source_properties, var_properties.value(), length,
3474                               SKIP_WRITE_BARRIER, mode);
3475     }
3476 
3477     Goto(&allocate_object);
3478     BIND(&allocate_object);
3479     TNode<JSObject> object = UncheckedCast<JSObject>(AllocateJSObjectFromMap(
3480         result_map, var_properties.value(), var_elements.value()));
3481     ReturnIf(IsNullOrUndefined(source), object);
3482 
3483     // Lastly, clone any in-object properties.
3484     // Determine the inobject property capacity of both objects, and copy the
3485     // smaller number into the resulting object.
3486     Node* source_start = LoadMapInobjectPropertiesStartInWords(source_map);
3487     Node* source_size = LoadMapInstanceSizeInWords(source_map);
3488     Node* result_start = LoadMapInobjectPropertiesStartInWords(result_map);
3489     Node* field_offset_difference =
3490         TimesPointerSize(IntPtrSub(result_start, source_start));
3491     BuildFastLoop(source_start, source_size,
3492                   [=](Node* field_index) {
3493                     Node* field_offset = TimesPointerSize(field_index);
3494                     Node* field = LoadObjectField(source, field_offset);
3495                     Node* result_offset =
3496                         IntPtrAdd(field_offset, field_offset_difference);
3497                     StoreObjectFieldNoWriteBarrier(object, result_offset,
3498                                                    field);
3499                   },
3500                   1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
3501     Return(object);
3502   }
3503 
3504   BIND(&try_polymorphic);
3505   TNode<HeapObject> strong_feedback = ToStrongHeapObject(feedback, &miss);
3506   {
3507     Comment("CloneObjectIC_try_polymorphic");
3508     GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
3509     HandlePolymorphicCase(source_map, CAST(strong_feedback), &if_handler,
3510                           &var_handler, &miss, 2);
3511   }
3512 
3513   BIND(&try_megamorphic);
3514   {
3515     Comment("CloneObjectIC_try_megamorphic");
3516     CSA_ASSERT(
3517         this,
3518         Word32Or(WordEqual(strong_feedback,
3519                            LoadRoot(Heap::kuninitialized_symbolRootIndex)),
3520                  WordEqual(strong_feedback,
3521                            LoadRoot(Heap::kmegamorphic_symbolRootIndex))));
3522     GotoIfNot(WordEqual(strong_feedback,
3523                         LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
3524               &miss);
3525     TailCallRuntime(Runtime::kCloneObjectIC_Slow, context, source, flags);
3526   }
3527 
3528   BIND(&miss);
3529   {
3530     Comment("CloneObjectIC_miss");
3531     Node* map_or_result = CallRuntime(Runtime::kCloneObjectIC_Miss, context,
3532                                       source, flags, slot, vector);
3533     var_handler = UncheckedCast<MaybeObject>(map_or_result);
3534     GotoIf(IsMap(map_or_result), &if_handler);
3535     CSA_ASSERT(this, IsJSObject(map_or_result));
3536     Return(map_or_result);
3537   }
3538 }
3539 
3540 }  // namespace internal
3541 }  // namespace v8
3542