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), ¬_function_prototype);
3232 GotoIfNot(IsPrototypeString(p->name()), ¬_function_prototype);
3233
3234 GotoIfPrototypeRequiresRuntimeLookup(CAST(lookup_start_object),
3235 lookup_start_object_map,
3236 ¬_function_prototype);
3237 Return(LoadJSFunctionPrototype(CAST(lookup_start_object), &miss));
3238 BIND(¬_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)), ®ular_load);
3427 ScriptContextTableLookup(CAST(name), native_context, &throw_reference_error,
3428 ®ular_load);
3429
3430 BIND(&throw_reference_error);
3431 Return(CallRuntime(Runtime::kThrowReferenceError, context, name));
3432
3433 BIND(®ular_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), ¬_smi);
3865 GotoIfNot(TaggedIsSmi(value), miss);
3866 Goto(&store);
3867
3868 BIND(¬_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