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