v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
accessor-assembler.cc
Go to the documentation of this file.
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
6
7#include <optional>
8
9#include "src/ast/ast.h"
14#include "src/common/globals.h"
16#include "src/ic/ic.h"
18#include "src/ic/stub-cache.h"
20#include "src/objects/cell.h"
24#include "src/objects/foreign.h"
27#include "src/objects/module.h"
30#include "src/objects/smi.h"
31
32namespace v8 {
33namespace internal {
34
36
38
39#define LOAD_KIND(kind) \
40 Int32Constant(static_cast<intptr_t>(LoadHandler::Kind::kind))
41#define STORE_KIND(kind) \
42 Int32Constant(static_cast<intptr_t>(StoreHandler::Kind::kind))
43
44// Loads dataX field from the DataHandler object.
46 TNode<DataHandler> handler, int data_index) {
47#ifdef DEBUG
48 TNode<Map> handler_map = LoadMap(handler);
49 TNode<Uint16T> instance_type = LoadMapInstanceType(handler_map);
50#endif
51 CSA_DCHECK(this,
52 Word32Or(InstanceTypeEqual(instance_type, LOAD_HANDLER_TYPE),
53 InstanceTypeEqual(instance_type, STORE_HANDLER_TYPE)));
54 // data_index is 1-indexed, so subtract one to make it 0-indexed.
55 data_index -= 1;
56 CHECK_GE(data_index, 0);
57 CHECK_LT(data_index, 3);
58 int offset = DataHandler::OffsetOf(data_index);
59 CSA_DCHECK(this, UintPtrGreaterThanOrEqual(
60 LoadMapInstanceSizeInWords(handler_map),
61 IntPtrConstant(DataHandler::SizeFor(data_index + 1) /
62 kTaggedSize)));
63 return LoadMaybeWeakObjectField(handler, offset);
64}
65
68 TNode<HeapObjectReference> weak_lookup_start_object_map, Label* if_handler,
69 TVariable<MaybeObject>* var_handler, Label* if_miss) {
70 Comment("TryMonomorphicCase");
72
73 // TODO(ishell): add helper class that hides offset computations for a series
74 // of loads.
75 int32_t header_size =
76 FeedbackVector::kRawFeedbackSlotsOffset - kHeapObjectTag;
77 // Adding |header_size| with a separate IntPtrAdd rather than passing it
78 // into ElementOffsetFromIndex() allows it to be folded into a single
79 // [base, index, offset] indirect memory access on x64.
82 vector, IntPtrAdd(offset, IntPtrConstant(header_size))));
83
84 // Try to quickly handle the monomorphic case without knowing for sure
85 // if we have a weak reference in feedback.
86 CSA_DCHECK(this,
87 IsMap(GetHeapObjectAssumeWeak(weak_lookup_start_object_map)));
88 GotoIfNot(TaggedEqual(feedback, weak_lookup_start_object_map), if_miss);
89
92 IntPtrAdd(offset, IntPtrConstant(header_size + kTaggedSize))));
93
94 *var_handler = handler;
95 Goto(if_handler);
96 return feedback;
97}
98
100 TNode<HeapObjectReference> weak_lookup_start_object_map,
101 TNode<WeakFixedArray> feedback, Label* if_handler,
102 TVariable<MaybeObject>* var_handler, Label* if_miss) {
103 Comment("HandlePolymorphicCase");
105
106 // Iterate {feedback} array.
107 const int kEntrySize = 2;
108
109 // Load the {feedback} array length.
110 TNode<Int32T> length =
112 CSA_DCHECK(this, Int32LessThanOrEqual(Int32Constant(kEntrySize), length));
113
114 // This is a hand-crafted loop that iterates backwards and only compares
115 // against zero at the end, since we already know that we will have at least a
116 // single entry in the {feedback} array anyways.
117 TVARIABLE(Int32T, var_index, Int32Sub(length, Int32Constant(kEntrySize)));
118 Label loop(this, &var_index), loop_next(this);
119 Goto(&loop);
120 BIND(&loop);
121 {
122 TNode<IntPtrT> index = ChangePositiveInt32ToIntPtr(var_index.value());
123 TNode<MaybeObject> maybe_cached_map =
124 LoadWeakFixedArrayElement(feedback, index);
125 CSA_DCHECK(this,
126 IsMap(GetHeapObjectAssumeWeak(weak_lookup_start_object_map)));
127 GotoIfNot(TaggedEqual(maybe_cached_map, weak_lookup_start_object_map),
128 &loop_next);
129
130 // Found, now call handler.
131 TNode<MaybeObject> handler =
132 LoadWeakFixedArrayElement(feedback, index, kTaggedSize);
133 *var_handler = handler;
134 Goto(if_handler);
135
136 BIND(&loop_next);
137 var_index = Int32Sub(var_index.value(), Int32Constant(kEntrySize));
138 Branch(Int32GreaterThanOrEqual(var_index.value(), Int32Constant(0)), &loop,
139 if_miss);
140 }
141}
142
144 TNode<Map> lookup_start_object_map,
145 TVariable<MaybeObject>* var_handler,
146 TNode<Object> vector,
147 TNode<TaggedIndex> slot, Label* miss,
148 ExitPoint* exit_point) {
149 // Check if the receiver is a JS_API_OBJECT
150 GotoIfNot(IsJSApiObjectMap(lookup_start_object_map), miss);
151
152 // Check if receiver requires access check
154 LoadMapBitField(lookup_start_object_map)),
155 miss);
156
158 MegaDOMSymbolConstant()));
159
160 // In some cases, we load the
162 if (var_handler->IsBound()) {
163 handler = CAST(var_handler->value());
164 } else {
165 TNode<MaybeObject> maybe_handler =
167 CSA_DCHECK(this, IsStrong(maybe_handler));
168 handler = CAST(maybe_handler);
169 }
170
171 // Check if dom protector cell is still valid
173
174 // Load the getter
175 TNode<MaybeObject> maybe_getter = LoadMegaDomHandlerAccessor(handler);
176 CSA_DCHECK(this, IsWeakOrCleared(maybe_getter));
178 CAST(GetHeapObjectAssumeWeak(maybe_getter, miss));
179
180 // Load the accessor context
181 TNode<MaybeObject> maybe_context = LoadMegaDomHandlerContext(handler);
182 CSA_DCHECK(this, IsWeakOrCleared(maybe_context));
183 TNode<Context> context = CAST(GetHeapObjectAssumeWeak(maybe_context, miss));
184
185 // TODO(gsathya): This builtin throws an exception on interface check fail but
186 // we should miss to the runtime.
187 TNode<Context> caller_context = context;
188 exit_point->Return(CallBuiltin(Builtin::kCallFunctionTemplate_Generic,
189 context, getter, Int32Constant(1),
190 caller_context, lookup_start_object));
191}
192
194 const LoadICParameters* p, TNode<Map> lookup_start_object_map,
195 ExitPoint* exit_point) {
196 if (!p->IsEnumeratedKeyedLoad()) return;
197 Label no_enum_cache(this);
198 // |p->cache_type()| comes from the outer loop's ForIn state.
199 GotoIf(TaggedNotEqual(p->cache_type(), lookup_start_object_map),
200 &no_enum_cache);
201
202 // Use field index in EnumCache.
203 TNode<DescriptorArray> descriptors =
204 LoadMapDescriptors(lookup_start_object_map);
206 descriptors, DescriptorArray::kEnumCacheOffset);
207 TNode<FixedArray> enum_keys =
208 LoadObjectField<FixedArray>(enum_cache, EnumCache::kKeysOffset);
209 // |p->enum_index()| comes from the outer loop's ForIn state.
211 // Check if |p->name()| matches the key in enum cache. |p->name()| is the
212 // "each" variable of a for-in loop, but it can be modified by debugger or
213 // other bytecodes.
214 GotoIf(TaggedNotEqual(key, p->name()), &no_enum_cache);
215 TNode<FixedArray> enum_indices =
216 LoadObjectField<FixedArray>(enum_cache, EnumCache::kIndicesOffset);
217 // Check if we have enum indices available.
218 GotoIf(IsEmptyFixedArray(enum_indices), &no_enum_cache);
219 TNode<Int32T> field_index =
220 SmiToInt32(CAST(LoadFixedArrayElement(enum_indices, p->enum_index())));
221
223 Label if_double(this, Label::kDeferred), done(this, &result);
224 // Check if field is a mutable double field.
225 uint32_t kIsMutableDoubleFieldMask = 1;
226 GotoIf(IsSetWord32(field_index, kIsMutableDoubleFieldMask), &if_double);
227
229 {
230 Label if_outofobject(this);
231 // Check if field is in-object or out-of-object.
232 GotoIf(Int32LessThan(field_index, zero), &if_outofobject);
233
234 // The field is located in the {object} itself.
235 {
238 Int32Constant(JSObject::kHeaderSize))));
239 result =
241 Goto(&done);
242 }
243
244 // The field is located in the properties backing store of {object}.
245 // The {index} is equal to the negated out of property index plus 1.
246 BIND(&if_outofobject);
247 {
251 Word32Shl(Int32Sub(zero, field_index),
254 result = LoadObjectField(properties, offset);
255 Goto(&done);
256 }
257 }
258
259 // The field is a Double field, either unboxed in the object on 64-bit
260 // architectures, or a mutable HeapNumber.
261 BIND(&if_double);
262 {
263 TVARIABLE(Object, field);
264 Label loaded_field(this, &field), if_outofobject(this);
265 field_index = Word32Sar(field_index, Int32Constant(1));
266 // Check if field is in-object or out-of-object.
267 GotoIf(Int32LessThan(field_index, zero), &if_outofobject);
268
269 // The field is located in the {object} itself.
270 {
273 Int32Constant(JSObject::kHeaderSize))));
274 field =
276 Goto(&loaded_field);
277 }
278
279 BIND(&if_outofobject);
280 {
284 Word32Shl(Int32Sub(zero, field_index),
287 field = LoadObjectField(properties, offset);
288 Goto(&loaded_field);
289 }
290
291 BIND(&loaded_field);
292 {
293 // We may have transitioned in-place away from double, so check that
294 // this is a HeapNumber -- otherwise the load is fine and we don't need
295 // to copy anything anyway.
296 Label if_not_double(this);
297 GotoIf(TaggedIsSmi(field.value()), &if_not_double);
298
299 TNode<HeapObject> double_field = CAST(field.value());
300 TNode<Map> field_map = LoadMap(double_field);
301 GotoIfNot(TaggedEqual(field_map, HeapNumberMapConstant()),
302 &if_not_double);
303
304 TNode<Float64T> value = LoadHeapNumberValue(double_field);
306 Goto(&done);
307
308 BIND(&if_not_double);
309 {
310 result = field.value();
311 Goto(&done);
312 }
313 }
314 }
315
316 BIND(&done);
317 { exit_point->Return(result.value()); }
318
319 BIND(&no_enum_cache);
320}
321
323 const LazyLoadICParameters* p, TNode<MaybeObject> handler, Label* miss,
324 ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
325 ElementSupport support_elements, LoadAccessMode access_mode) {
326 Comment("have_handler");
327
328 TVARIABLE(Object, var_holder, p->lookup_start_object());
329 TVARIABLE(MaybeObject, var_smi_handler, handler);
330
331 Label if_smi_handler(this, {&var_holder, &var_smi_handler});
332 Label try_proto_handler(this, Label::kDeferred),
333 call_code_handler(this, Label::kDeferred),
334 call_getter(this, Label::kDeferred);
335
336 Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler);
337
338 BIND(&try_proto_handler);
339 {
340 GotoIf(IsWeakOrCleared(handler), &call_getter);
341 GotoIf(IsCode(CAST(handler)), &call_code_handler);
342 HandleLoadICProtoHandler(p, CAST(handler), &var_holder, &var_smi_handler,
343 &if_smi_handler, miss, exit_point, ic_mode,
344 access_mode);
345 }
346
347 // |handler| is a Smi, encoding what to do. See SmiHandler methods
348 // for the encoding format.
349 BIND(&if_smi_handler);
350 {
352 p, var_holder.value(), CAST(var_smi_handler.value()), handler, miss,
353 exit_point, ic_mode, on_nonexistent, support_elements, access_mode);
354 }
355
356 BIND(&call_getter);
357 {
358 if (access_mode == LoadAccessMode::kHas) {
359 exit_point->Return(TrueConstant());
360 } else {
361 TNode<HeapObject> strong_handler = GetHeapObjectAssumeWeak(handler, miss);
363 CAST(LoadAccessorPairGetter(CAST(strong_handler)));
364
366 p->lookup_start_object() == p->receiver()
367 // LoadIC case: the receiver is definitely not null or undefined.
369 // LoadSuperIC case: the receiver might be anything.
371 exit_point->Return(
372 CallFunction(p->context(), getter, mode, p->receiver()));
373 }
374 }
375
376 BIND(&call_code_handler);
377 {
378 TNode<Code> code_handler = CAST(handler);
379 exit_point->ReturnCallStub(LoadWithVectorDescriptor{}, code_handler,
380 p->context(), p->lookup_start_object(),
381 p->name(), p->slot(), p->vector());
382 }
383}
384
386 const LazyLoadICParameters* p, TNode<JSObject> holder,
387 TNode<Word32T> handler_word, ExitPoint* exit_point) {
388 Comment("native_data_property_load");
389 TNode<IntPtrT> descriptor =
391
392 TNode<AccessorInfo> accessor_info =
393 CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
394
395 exit_point->ReturnCallBuiltin(Builtin::kCallApiGetter, p->context(),
396 p->receiver(), holder, accessor_info);
397}
398
400 const LazyLoadICParameters* p,
401 TNode<FunctionTemplateInfo> function_template_info,
402 TNode<Word32T> handler_word, TNode<DataHandler> handler,
403 TNode<Uint32T> handler_kind, ExitPoint* exit_point) {
404 Comment("api_getter");
405 // Context is stored either in data2 or data3 field depending on whether
406 // the access check is enabled for this handler or not.
409 handler_word),
410 [=, this] { return LoadHandlerDataField(handler, 3); },
411 [=, this] { return LoadHandlerDataField(handler, 2); });
412
413 CSA_DCHECK(this, IsWeakOrCleared(maybe_context));
414 CSA_CHECK(this, IsNotCleared(maybe_context));
415 TNode<HeapObject> context = GetHeapObjectAssumeWeak(maybe_context);
417 TNode<Context> caller_context = p->context();
418 exit_point->Return(CallBuiltin(Builtin::kCallApiCallbackGeneric, context,
419 argc, caller_context, function_template_info,
420 p->receiver()));
421}
422
424 TNode<Word32T> handler_word,
425 TVariable<Float64T>* var_double_value,
426 Label* rebox_double, Label* miss,
427 ExitPoint* exit_point) {
428 Comment("LoadField");
429 TNode<IntPtrT> index =
432
433 TNode<BoolT> is_inobject =
435 TNode<HeapObject> property_storage = Select<HeapObject>(
436 is_inobject, [&]() { return holder; },
437 [&]() { return LoadFastProperties(holder, true); });
438
439 Label is_double(this);
440 TNode<Object> value = LoadObjectField(property_storage, offset);
441 GotoIf(IsSetWord32<LoadHandler::IsDoubleBits>(handler_word), &is_double);
442 exit_point->Return(value);
443
444 BIND(&is_double);
445 // This is not an "old" Smi value from before a Smi->Double transition.
446 // Rather, it's possible that since the last update of this IC, the Double
447 // field transitioned to a Tagged field, and was then assigned a Smi.
448 GotoIf(TaggedIsSmi(value), miss);
449 GotoIfNot(IsHeapNumber(CAST(value)), miss);
450 *var_double_value = LoadHeapNumberValue(CAST(value));
451 Goto(rebox_double);
452}
453
454#if V8_ENABLE_WEBASSEMBLY
455
456void AccessorAssembler::HandleLoadWasmField(
457 TNode<WasmObject> holder, TNode<Int32T> wasm_value_type,
458 TNode<IntPtrT> field_offset, TVariable<Float64T>* var_double_value,
459 Label* rebox_double, ExitPoint* exit_point) {
460 Label type_I8(this), type_I16(this), type_I32(this), type_U32(this),
461 type_I64(this), type_U64(this), type_F32(this), type_F64(this),
462 type_Ref(this), unsupported_type(this, Label::kDeferred),
463 unexpected_type(this, Label::kDeferred);
464 Label* wasm_value_type_labels[] = {
465 &type_I8, &type_I16, &type_I32, &type_U32, &type_I64,
466 &type_F32, &type_F64, &type_Ref, &type_Ref, &unsupported_type};
467 int32_t wasm_value_types[] = {
468 static_cast<int32_t>(WasmValueType::kI8),
469 static_cast<int32_t>(WasmValueType::kI16),
470 static_cast<int32_t>(WasmValueType::kI32),
471 static_cast<int32_t>(WasmValueType::kU32),
472 static_cast<int32_t>(WasmValueType::kI64),
473 static_cast<int32_t>(WasmValueType::kF32),
474 static_cast<int32_t>(WasmValueType::kF64),
475 static_cast<int32_t>(WasmValueType::kRef),
476 static_cast<int32_t>(WasmValueType::kRefNull),
477 // TODO(v8:11804): support the following value types.
478 static_cast<int32_t>(WasmValueType::kS128)};
479 const size_t kWasmValueTypeCount =
480 static_cast<size_t>(WasmValueType::kNumTypes);
481 DCHECK_EQ(kWasmValueTypeCount, arraysize(wasm_value_types));
482 DCHECK_EQ(kWasmValueTypeCount, arraysize(wasm_value_type_labels));
483
484 Switch(wasm_value_type, &unexpected_type, wasm_value_types,
485 wasm_value_type_labels, kWasmValueTypeCount);
486 BIND(&type_I8);
487 {
488 Comment("type_I8");
489 TNode<Int32T> value = LoadObjectField<Int8T>(holder, field_offset);
490 exit_point->Return(SmiFromInt32(value));
491 }
492 BIND(&type_I16);
493 {
494 Comment("type_I16");
495 TNode<Int32T> value = LoadObjectField<Int16T>(holder, field_offset);
496 exit_point->Return(SmiFromInt32(value));
497 }
498 BIND(&type_I32);
499 {
500 Comment("type_I32");
501 TNode<Int32T> value = LoadObjectField<Int32T>(holder, field_offset);
502 exit_point->Return(ChangeInt32ToTagged(value));
503 }
504 BIND(&type_U32);
505 {
506 Comment("type_U32");
507 TNode<Uint32T> value = LoadObjectField<Uint32T>(holder, field_offset);
508 exit_point->Return(ChangeUint32ToTagged(value));
509 }
510 BIND(&type_I64);
511 {
512 Comment("type_I64");
513 TNode<RawPtrT> data_pointer =
515 TNode<BigInt> value = LoadFixedBigInt64ArrayElementAsTagged(
516 data_pointer,
518 exit_point->Return(value);
519 }
520 BIND(&type_F32);
521 {
522 Comment("type_F32");
523 TNode<Float32T> value = LoadObjectField<Float32T>(holder, field_offset);
524 *var_double_value = ChangeFloat32ToFloat64(value);
525 Goto(rebox_double);
526 }
527 BIND(&type_F64);
528 {
529 Comment("type_F64");
530 TNode<Float64T> value = LoadObjectField<Float64T>(holder, field_offset);
531 *var_double_value = value;
532 Goto(rebox_double);
533 }
534 BIND(&type_Ref);
535 {
536 Comment("type_Ref");
537 TNode<Object> value = LoadObjectField(holder, field_offset);
538 exit_point->Return(value);
539 }
540 BIND(&unsupported_type);
541 {
542 Print("Not supported Wasm field type");
543 Unreachable();
544 }
545 BIND(&unexpected_type);
546 { Unreachable(); }
547}
548
549void AccessorAssembler::HandleLoadWasmField(
550 TNode<WasmObject> holder, TNode<Word32T> handler_word,
551 TVariable<Float64T>* var_double_value, Label* rebox_double,
552 ExitPoint* exit_point) {
553 Comment("LoadWasmField");
554 TNode<Int32T> wasm_value_type =
556 TNode<IntPtrT> field_offset = Signed(
558
559 HandleLoadWasmField(holder, wasm_value_type, field_offset, var_double_value,
560 rebox_double, exit_point);
561}
562
563#endif // V8_ENABLE_WEBASSEMBLY
564
566 TNode<Map> map, TNode<IntPtrT> descriptor_entry) {
567 return CAST(LoadDescriptorValueOrFieldType(map, descriptor_entry));
568}
569
575
577 const LazyLoadICParameters* p, TNode<Object> holder, TNode<Smi> smi_handler,
578 TNode<MaybeObject> handler, Label* miss, ExitPoint* exit_point,
579 ICMode ic_mode, OnNonExistent on_nonexistent,
580 ElementSupport support_elements, LoadAccessMode access_mode) {
581 TVARIABLE(Float64T, var_double_value);
582 Label rebox_double(this, &var_double_value);
583
584 TNode<Int32T> handler_word = SmiToInt32(smi_handler);
585 TNode<Uint32T> handler_kind =
587
588 if (support_elements == kSupportElements) {
589 Label if_element(this), if_indexed_string(this), if_property(this),
590 if_hole(this), unimplemented_elements_kind(this),
591 if_oob(this, Label::kDeferred), try_string_to_array_index(this),
592 emit_element_load(this);
593 TVARIABLE(IntPtrT, var_intptr_index);
594 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kElement)), &if_element);
595
596 if (access_mode == LoadAccessMode::kHas) {
597 CSA_DCHECK(this, Word32NotEqual(handler_kind, LOAD_KIND(kIndexedString)));
598 Goto(&if_property);
599 } else {
600 Branch(Word32Equal(handler_kind, LOAD_KIND(kIndexedString)),
601 &if_indexed_string, &if_property);
602 }
603
604 BIND(&if_element);
605 {
606 Comment("element_load");
607 // TODO(ishell): implement
608 CSA_DCHECK(this,
610 TVARIABLE(Int32T, var_instance_type);
611 TNode<IntPtrT> intptr_index = TryToIntptr(
612 p->name(), &try_string_to_array_index, &var_instance_type);
613 var_intptr_index = intptr_index;
614 Goto(&emit_element_load);
615
616 BIND(&try_string_to_array_index);
617 {
618 GotoIfNot(IsStringInstanceType(var_instance_type.value()), miss);
619
621 ExternalReference::string_to_array_index_function());
624 std::make_pair(MachineType::AnyTagged(), p->name())));
626 CSA_DCHECK(this, Int32GreaterThanOrEqual(result, Int32Constant(0)));
627 var_intptr_index = ChangeInt32ToIntPtr(result);
628
629 Goto(&emit_element_load);
630 }
631
632 BIND(&emit_element_load);
633 {
634 TNode<BoolT> is_jsarray_condition =
636 TNode<Uint32T> elements_kind =
638 EmitElementLoad(CAST(holder), elements_kind, var_intptr_index.value(),
639 is_jsarray_condition, &if_hole, &rebox_double,
640 &var_double_value, &unimplemented_elements_kind,
641 &if_oob, miss, exit_point, access_mode);
642 }
643 }
644
645 BIND(&unimplemented_elements_kind);
646 {
647 // Smi handlers should only be installed for supported elements kinds.
648 // Crash if we get here.
649 DebugBreak();
650 Goto(miss);
651 }
652
653 BIND(&if_oob);
654 {
655 Comment("out of bounds elements access");
656 Label return_undefined(this);
657
658 // Check if we're allowed to handle OOB accesses.
659 TNode<BoolT> allow_out_of_bounds =
661 GotoIfNot(allow_out_of_bounds, miss);
662
663 // Negative indices aren't valid array indices (according to
664 // the ECMAScript specification), and are stored as properties
665 // in V8, not elements. So we cannot handle them here, except
666 // in case of typed arrays, where integer indexed properties
667 // aren't looked up in the prototype chain.
668 GotoIf(IsJSTypedArray(CAST(holder)), &return_undefined);
669 if (Is64()) {
670 GotoIfNot(
671 UintPtrLessThanOrEqual(var_intptr_index.value(),
673 miss);
674 } else {
675 GotoIf(IntPtrLessThan(var_intptr_index.value(), IntPtrConstant(0)),
676 miss);
677 }
678
679 // For all other receivers we need to check that the prototype chain
680 // doesn't contain any elements.
681 BranchIfPrototypesHaveNoElements(LoadMap(CAST(holder)), &return_undefined,
682 miss);
683
684 BIND(&return_undefined);
685 exit_point->Return(access_mode == LoadAccessMode::kHas
686 ? TNode<Object>(FalseConstant())
687 : TNode<Object>(UndefinedConstant()));
688 }
689
690 BIND(&if_hole);
691 {
692 Comment("read hole and convert to undefined");
693
695 miss);
697 exit_point->Return(access_mode == LoadAccessMode::kHas
698 ? TNode<Object>(FalseConstant())
699 : TNode<Object>(UndefinedConstant()));
700 }
701
702 if (access_mode != LoadAccessMode::kHas) {
703 BIND(&if_indexed_string);
704 {
705 Label if_oob_string(this, Label::kDeferred);
706
707 Comment("indexed string");
708 TNode<String> string_holder = CAST(holder);
709 TNode<IntPtrT> index = TryToIntptr(p->name(), miss);
710 TNode<UintPtrT> length =
711 Unsigned(LoadStringLengthAsWord(string_holder));
712 GotoIf(UintPtrGreaterThanOrEqual(index, length), &if_oob_string);
713 TNode<Int32T> code = StringCharCodeAt(string_holder, Unsigned(index));
715 Return(result);
716
717 BIND(&if_oob_string);
718 if (Is64()) {
719 // Indices >= 4294967295 are stored as named properties; handle them
720 // in the runtime.
723 miss);
724 } else {
725 GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), miss);
726 }
727 TNode<BoolT> allow_out_of_bounds =
729 GotoIfNot(allow_out_of_bounds, miss);
731 Return(UndefinedConstant());
732 }
733 }
734
735 BIND(&if_property);
736 Comment("property_load");
737 }
738
739 if (access_mode == LoadAccessMode::kHas) {
740 HandleLoadICSmiHandlerHasNamedCase(p, holder, handler_kind, miss,
741 exit_point, ic_mode);
742 } else {
744 p, holder, handler_kind, handler_word, &rebox_double, &var_double_value,
745 handler, miss, exit_point, ic_mode, on_nonexistent, support_elements);
746 }
747}
748
750 const LazyLoadICParameters* p, TNode<Object> holder,
751 TNode<Uint32T> handler_kind, TNode<Word32T> handler_word,
752 Label* rebox_double, TVariable<Float64T>* var_double_value,
753 TNode<MaybeObject> handler, Label* miss, ExitPoint* exit_point,
754 ICMode ic_mode, OnNonExistent on_nonexistent,
755 ElementSupport support_elements) {
756 Label constant(this), field(this), normal(this, Label::kDeferred),
757 slow(this, Label::kDeferred), interceptor(this, Label::kDeferred),
758 nonexistent(this), accessor(this, Label::kDeferred),
759 global(this, Label::kDeferred), module_export(this, Label::kDeferred),
760 proxy(this, Label::kDeferred),
761 native_data_property(this, Label::kDeferred),
762 api_getter(this, Label::kDeferred);
763
764 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kField)), &field);
765
766 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kConstantFromPrototype)),
767 &constant);
768
769 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNonExistent)), &nonexistent);
770
771 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNormal)), &normal);
772
773 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kAccessorFromPrototype)),
774 &accessor);
775
776 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNativeDataProperty)),
777 &native_data_property);
778
779 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kApiGetter)), &api_getter);
780
781 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kGlobal)), &global);
782
783 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kSlow)), &slow);
784
785 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kProxy)), &proxy);
786
787 Branch(Word32Equal(handler_kind, LOAD_KIND(kModuleExport)), &module_export,
788 &interceptor);
789
790 BIND(&field);
791 {
792#if V8_ENABLE_WEBASSEMBLY
793 Label is_wasm_field(this);
795 &is_wasm_field);
796#else
797 CSA_DCHECK(this,
799#endif // V8_ENABLE_WEBASSEMBLY
800
801 HandleLoadField(CAST(holder), handler_word, var_double_value, rebox_double,
802 miss, exit_point);
803
804#if V8_ENABLE_WEBASSEMBLY
805 BIND(&is_wasm_field);
806 HandleLoadWasmField(CAST(holder), handler_word, var_double_value,
807 rebox_double, exit_point);
808#endif // V8_ENABLE_WEBASSEMBLY
809 }
810
811 BIND(&nonexistent);
812 // This is a handler for a load of a non-existent value.
813 if (on_nonexistent == OnNonExistent::kThrowReferenceError) {
814 exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context(),
815 p->name());
816 } else {
818 exit_point->Return(UndefinedConstant());
819 }
820
821 BIND(&constant);
822 {
823 Comment("constant_load");
824 exit_point->Return(holder);
825 }
826
827 BIND(&normal);
828 {
829 Comment("load_normal");
830 TNode<PropertyDictionary> properties =
831 CAST(LoadSlowProperties(CAST(holder)));
832 TVARIABLE(IntPtrT, var_name_index);
833 Label found(this, &var_name_index);
835 &found, &var_name_index, miss);
836 BIND(&found);
837 {
838 TVARIABLE(Uint32T, var_details);
839 TVARIABLE(Object, var_value);
841 properties, var_name_index.value(), &var_details, &var_value);
843 var_value.value(), CAST(holder), var_details.value(), p->context(),
844 p->receiver(), p->name(), miss);
845 exit_point->Return(value);
846 }
847 }
848
849 BIND(&accessor);
850 {
851 Comment("accessor_load");
852 // The "holder" slot (data1) in the from-prototype LoadHandler is instead
853 // directly the getter function.
854 TNode<HeapObject> getter = CAST(holder);
856
857 exit_point->Return(Call(p->context(), getter, p->receiver()));
858 }
859
860 BIND(&native_data_property);
861 HandleLoadCallbackProperty(p, CAST(holder), handler_word, exit_point);
862
863 BIND(&api_getter);
864 {
865 if (p->receiver() != p->lookup_start_object()) {
866 // Force super ICs using API getters into the slow path, so that we get
867 // the correct receiver checks.
868 Goto(&slow);
869 } else {
870 HandleLoadAccessor(p, CAST(holder), handler_word, CAST(handler),
871 handler_kind, exit_point);
872 }
873 }
874
875 BIND(&proxy);
876 {
877 // TODO(mythria): LoadGlobals don't use this path. LoadGlobals need special
878 // handling with proxies which is currently not supported by builtins. So
879 // for such cases, we should install a slow path and never reach here. Fix
880 // it to not generate this for LoadGlobals.
881 CSA_DCHECK(this,
882 WordNotEqual(IntPtrConstant(static_cast<int>(on_nonexistent)),
883 IntPtrConstant(static_cast<int>(
885 TVARIABLE(IntPtrT, var_index);
886 TVARIABLE(Name, var_unique);
887
888 Label if_index(this), if_unique_name(this),
889 to_name_failed(this, Label::kDeferred);
890
891 if (support_elements == kSupportElements) {
893
894 TryToName(p->name(), &if_index, &var_index, &if_unique_name, &var_unique,
895 &to_name_failed);
896
897 BIND(&if_unique_name);
898 exit_point->ReturnCallBuiltin(Builtin::kProxyGetProperty, p->context(),
899 holder, var_unique.value(), p->receiver(),
900 SmiConstant(on_nonexistent));
901
902 BIND(&if_index);
903 // TODO(mslekova): introduce TryToName that doesn't try to compute
904 // the intptr index value
905 Goto(&to_name_failed);
906
907 BIND(&to_name_failed);
908 // TODO(duongn): use GetPropertyWithReceiver builtin once
909 // |lookup_element_in_holder| supports elements.
910 exit_point->ReturnCallRuntime(Runtime::kGetPropertyWithReceiver,
911 p->context(), holder, p->name(),
912 p->receiver(), SmiConstant(on_nonexistent));
913 } else {
914 exit_point->ReturnCallBuiltin(Builtin::kProxyGetProperty, p->context(),
915 holder, p->name(), p->receiver(),
916 SmiConstant(on_nonexistent));
917 }
918 }
919
920 BIND(&global);
921 {
922 CSA_DCHECK(this, IsPropertyCell(CAST(holder)));
923 // Ensure the property cell doesn't contain the hole.
924 TNode<Object> value =
925 LoadObjectField(CAST(holder), PropertyCell::kValueOffset);
927 CAST(holder), PropertyCell::kPropertyDetailsRawOffset));
928 GotoIf(IsPropertyCellHole(value), miss);
929
930 exit_point->Return(CallGetterIfAccessor(value, CAST(holder), details,
931 p->context(), p->receiver(),
932 p->name(), miss));
933 }
934
935 BIND(&interceptor);
936 {
937 Comment("load_interceptor");
938 exit_point->ReturnCallRuntime(Runtime::kLoadPropertyWithInterceptor,
939 p->context(), p->name(), p->receiver(),
940 holder, p->slot(), p->vector());
941 }
942 BIND(&slow);
943 {
944 Comment("load_slow");
945 if (ic_mode == ICMode::kGlobalIC) {
946 exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Slow, p->context(),
947 p->name(), p->slot(), p->vector());
948
949 } else {
950 exit_point->ReturnCallRuntime(Runtime::kGetProperty, p->context(),
951 p->lookup_start_object(), p->name(),
952 p->receiver());
953 }
954 }
955
956 BIND(&module_export);
957 {
958 Comment("module export");
959 TNode<UintPtrT> index =
961 TNode<Module> module =
962 LoadObjectField<Module>(CAST(holder), JSModuleNamespace::kModuleOffset);
963 TNode<ObjectHashTable> exports =
964 LoadObjectField<ObjectHashTable>(module, Module::kExportsOffset);
965 TNode<Cell> cell = CAST(LoadFixedArrayElement(exports, index));
966 // The handler is only installed for exports that exist.
967 TNode<Object> value = LoadCellValue(cell);
968 Label is_the_hole(this, Label::kDeferred);
969 GotoIf(IsTheHole(value), &is_the_hole);
970 exit_point->Return(value);
971
972 BIND(&is_the_hole);
973 {
974 TNode<Smi> message = SmiConstant(MessageTemplate::kNotDefined);
975 exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context(),
976 message, p->name());
977 }
978 }
979
980 BIND(rebox_double);
981 {
982#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
983 Label if_not_undefined(this);
984 GotoIfNot(IsDoubleUndefined(var_double_value->value()), &if_not_undefined);
985 exit_point->Return(UndefinedConstant());
986
987 BIND(&if_not_undefined);
988#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
989 exit_point->Return(AllocateHeapNumberWithValue(var_double_value->value()));
990 }
991}
992
994 const LazyLoadICParameters* p, TNode<Object> holder,
995 TNode<Uint32T> handler_kind, Label* miss, ExitPoint* exit_point,
996 ICMode ic_mode) {
997 Label return_true(this), return_false(this), return_lookup(this),
998 normal(this), global(this), slow(this);
999
1000 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kField)), &return_true);
1001
1002 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kConstantFromPrototype)),
1003 &return_true);
1004
1005 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNonExistent)), &return_false);
1006
1007 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNormal)), &normal);
1008
1009 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kAccessorFromPrototype)),
1010 &return_true);
1011
1012 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kNativeDataProperty)),
1013 &return_true);
1014
1015 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kApiGetter)), &return_true);
1016
1017 GotoIf(Word32Equal(handler_kind, LOAD_KIND(kSlow)), &slow);
1018
1019 Branch(Word32Equal(handler_kind, LOAD_KIND(kGlobal)), &global,
1020 &return_lookup);
1021
1022 BIND(&return_true);
1023 exit_point->Return(TrueConstant());
1024
1025 BIND(&return_false);
1026 exit_point->Return(FalseConstant());
1027
1028 BIND(&return_lookup);
1029 {
1030 CSA_DCHECK(this,
1031 Word32Or(Word32Equal(handler_kind, LOAD_KIND(kInterceptor)),
1032 Word32Or(Word32Equal(handler_kind, LOAD_KIND(kProxy)),
1033 Word32Equal(handler_kind,
1034 LOAD_KIND(kModuleExport)))));
1035 exit_point->ReturnCallBuiltin(Builtin::kHasProperty, p->context(),
1036 p->receiver(), p->name());
1037 }
1038
1039 BIND(&normal);
1040 {
1041 Comment("has_normal");
1042 TNode<PropertyDictionary> properties =
1043 CAST(LoadSlowProperties(CAST(holder)));
1044 TVARIABLE(IntPtrT, var_name_index);
1045 Label found(this);
1047 &found, &var_name_index, miss);
1048
1049 BIND(&found);
1050 exit_point->Return(TrueConstant());
1051 }
1052
1053 BIND(&global);
1054 {
1055 CSA_DCHECK(this, IsPropertyCell(CAST(holder)));
1056 // Ensure the property cell doesn't contain the hole.
1057 TNode<Object> value =
1058 LoadObjectField(CAST(holder), PropertyCell::kValueOffset);
1059 GotoIf(IsPropertyCellHole(value), miss);
1060
1061 exit_point->Return(TrueConstant());
1062 }
1063
1064 BIND(&slow);
1065 {
1066 Comment("load_slow");
1067 if (ic_mode == ICMode::kGlobalIC) {
1068 exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Slow, p->context(),
1069 p->name(), p->slot(), p->vector());
1070 } else {
1071 exit_point->ReturnCallRuntime(Runtime::kHasProperty, p->context(),
1072 p->receiver(), p->name());
1073 }
1074 }
1075}
1076
1077// Performs actions common to both load and store handlers:
1078// 1. Checks prototype validity cell.
1079// 2. If |on_code_handler| is provided, then it checks if the sub handler is
1080// a smi or code and if it's a code then it calls |on_code_handler| to
1081// generate a code that handles Code handlers.
1082// If |on_code_handler| is not provided, then only smi sub handler are
1083// expected.
1084// 3. Does access check on lookup start object if
1085// ICHandler::DoAccessCheckOnLookupStartObjectBits bit is set in the smi
1086// handler.
1087// 4. Does dictionary lookup on receiver if
1088// ICHandler::LookupOnLookupStartObjectBits bit is set in the smi handler. If
1089// |on_found_on_lookup_start_object| is provided then it calls it to
1090// generate a code that handles the "found on receiver case" or just misses
1091// if the |on_found_on_lookup_start_object| is not provided.
1092// 5. Falls through in a case of a smi handler which is returned from this
1093// function (tagged!).
1094// TODO(ishell): Remove templatezation once we move common bits from
1095// Load/StoreHandler to the base class.
1096template <typename ICHandler, typename ICParameters>
1098 const ICParameters* p, TNode<DataHandler> handler,
1099 const OnCodeHandler& on_code_handler,
1100 const OnFoundOnLookupStartObject& on_found_on_lookup_start_object,
1101 Label* miss, ICMode ic_mode) {
1102 //
1103 // Check prototype validity cell.
1104 //
1105 {
1106 TNode<Object> maybe_validity_cell =
1107 LoadObjectField(handler, offsetof(ICHandler, validity_cell_));
1108 CheckPrototypeValidityCell(maybe_validity_cell, miss);
1109 }
1110
1111 //
1112 // Check smi handler bits.
1113 //
1114 {
1115 TNode<Object> smi_or_code_handler =
1116 LoadObjectField(handler, offsetof(ICHandler, smi_handler_));
1117 if (on_code_handler) {
1118 Label if_smi_handler(this);
1119 GotoIf(TaggedIsSmi(smi_or_code_handler), &if_smi_handler);
1120 TNode<Code> code = CAST(smi_or_code_handler);
1121 on_code_handler(code);
1122
1123 BIND(&if_smi_handler);
1124 }
1125 TNode<IntPtrT> handler_flags = SmiUntag(CAST(smi_or_code_handler));
1126
1127 // Lookup on receiver and access checks are not necessary for global ICs
1128 // because in the former case the validity cell check guards modifications
1129 // of the global object and the latter is not applicable to the global
1130 // object.
1131 int mask = ICHandler::LookupOnLookupStartObjectBits::kMask |
1132 ICHandler::DoAccessCheckOnLookupStartObjectBits::kMask;
1133 if (ic_mode == ICMode::kGlobalIC) {
1134 CSA_DCHECK(this, IsClearWord(handler_flags, mask));
1135 } else {
1137
1138 Label done(this), if_do_access_check(this),
1139 if_lookup_on_lookup_start_object(this);
1140 GotoIf(IsClearWord(handler_flags, mask), &done);
1141 // Only one of the bits can be set at a time.
1142 CSA_DCHECK(this,
1143 WordNotEqual(WordAnd(handler_flags, IntPtrConstant(mask)),
1145 Branch(
1147 handler_flags),
1148 &if_do_access_check, &if_lookup_on_lookup_start_object);
1149
1150 BIND(&if_do_access_check);
1151 {
1152 TNode<MaybeObject> data2 = LoadHandlerDataField(handler, 2);
1153 CSA_DCHECK(this, IsWeakOrCleared(data2));
1154 TNode<Context> expected_native_context =
1155 CAST(GetHeapObjectAssumeWeak(data2, miss));
1156 EmitAccessCheck(expected_native_context, p->context(),
1157 p->lookup_start_object(), &done, miss);
1158 }
1159
1160 BIND(&if_lookup_on_lookup_start_object);
1161 {
1162 // Dictionary lookup on lookup start object is not necessary for
1163 // Load/StoreGlobalIC (which is the only case when the
1164 // lookup_start_object can be a JSGlobalObject) because prototype
1165 // validity cell check already guards modifications of the global
1166 // object.
1167 CSA_DCHECK(this,
1168 Word32BinaryNot(HasInstanceType(
1169 CAST(p->lookup_start_object()), JS_GLOBAL_OBJECT_TYPE)));
1170
1171 TNode<PropertyDictionary> properties =
1172 CAST(LoadSlowProperties(CAST(p->lookup_start_object())));
1173 TVARIABLE(IntPtrT, var_name_index);
1174 Label found(this, &var_name_index);
1176 properties, CAST(p->name()), &found, &var_name_index, &done);
1177 BIND(&found);
1178 {
1179 if (on_found_on_lookup_start_object) {
1180 on_found_on_lookup_start_object(properties, var_name_index.value());
1181 } else {
1182 Goto(miss);
1183 }
1184 }
1185 }
1186
1187 BIND(&done);
1188 }
1189 return smi_or_code_handler;
1190 }
1191}
1192
1194 const LazyLoadICParameters* p, TNode<DataHandler> handler,
1195 TVariable<Object>* var_holder, TVariable<MaybeObject>* var_smi_handler,
1196 Label* if_smi_handler, Label* miss, ExitPoint* exit_point, ICMode ic_mode,
1197 LoadAccessMode access_mode) {
1199 p, handler,
1200 // Code sub-handlers are not expected in LoadICs, so no |on_code_handler|.
1201 nullptr,
1202 // on_found_on_lookup_start_object
1203 [=, this](TNode<PropertyDictionary> properties,
1204 TNode<IntPtrT> name_index) {
1205 if (access_mode == LoadAccessMode::kHas) {
1206 exit_point->Return(TrueConstant());
1207 } else {
1208 TVARIABLE(Uint32T, var_details);
1209 TVARIABLE(Object, var_value);
1211 properties, name_index, &var_details, &var_value);
1213 var_value.value(), CAST(var_holder->value()), var_details.value(),
1214 p->context(), p->receiver(), p->name(), miss);
1215 exit_point->Return(value);
1216 }
1217 },
1218 miss, ic_mode));
1219
1220 TNode<MaybeObject> maybe_holder_or_constant =
1221 LoadHandlerDataField(handler, 1);
1222
1223 Label load_from_cached_holder(this), is_smi(this), done(this);
1224
1225 GotoIf(TaggedIsSmi(maybe_holder_or_constant), &is_smi);
1226 Branch(TaggedEqual(maybe_holder_or_constant, NullConstant()), &done,
1227 &load_from_cached_holder);
1228
1229 BIND(&is_smi);
1230 {
1231 // If the "maybe_holder_or_constant" in the handler is a smi, then it's
1232 // guaranteed that it's not a holder object, but a constant value.
1234 SmiToInt32(smi_handler)),
1235 LOAD_KIND(kConstantFromPrototype)));
1236 if (access_mode == LoadAccessMode::kHas) {
1237 exit_point->Return(TrueConstant());
1238 } else {
1239 exit_point->Return(CAST(maybe_holder_or_constant));
1240 }
1241 }
1242
1243 BIND(&load_from_cached_holder);
1244 {
1245 // For regular holders, having passed the receiver map check and
1246 // the validity cell check implies that |holder| is
1247 // alive. However, for global object receivers, |maybe_holder| may
1248 // be cleared.
1249 CSA_DCHECK(this, IsWeakOrCleared(maybe_holder_or_constant));
1250 TNode<HeapObject> holder =
1251 GetHeapObjectAssumeWeak(maybe_holder_or_constant, miss);
1252 *var_holder = holder;
1253 Goto(&done);
1254 }
1255
1256 BIND(&done);
1257 {
1258 *var_smi_handler = smi_handler;
1259 Goto(if_smi_handler);
1260 }
1261}
1262
1264 TNode<Context> context,
1266 Label* can_access, Label* miss) {
1267 CSA_DCHECK(this, IsNativeContext(expected_native_context));
1268
1270 GotoIf(TaggedEqual(expected_native_context, native_context), can_access);
1271 // If the receiver is not a JSGlobalProxy then we miss.
1272 GotoIf(TaggedIsSmi(receiver), miss);
1274 // For JSGlobalProxy receiver try to compare security tokens of current
1275 // and expected native contexts.
1276 TNode<Object> expected_token = LoadContextElement(
1277 expected_native_context, Context::SECURITY_TOKEN_INDEX);
1278 TNode<Object> current_token =
1279 LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
1280 Branch(TaggedEqual(expected_token, current_token), can_access, miss);
1281}
1282
1284 Label* writable, Label* readonly) {
1285 if (readonly) {
1286 // Accessor properties never have the READ_ONLY attribute set.
1288 readonly);
1289 } else {
1290 CSA_DCHECK(this, IsNotSetWord32(details,
1292 }
1294 GotoIf(
1296 writable);
1297 // Fall through if it's an accessor property.
1298}
1299
1301 const StoreICParameters* p, TNode<HeapObject> holder,
1302 TNode<Word32T> handler_word) {
1303 Comment("native_data_property_store");
1304 TNode<IntPtrT> descriptor =
1306 TNode<AccessorInfo> accessor_info =
1307 CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
1308
1309 TailCallRuntime(Runtime::kStoreCallbackProperty, p->context(), p->receiver(),
1310 holder, accessor_info, p->name(), p->value());
1311}
1312
1314 TNode<Context> context, TNode<Word32T> handler_word, TNode<JSObject> holder,
1315 TNode<Object> value) {
1316 CSA_DCHECK(this,
1318 STORE_KIND(kSharedStructField)));
1319 CSA_DCHECK(
1320 this,
1323
1324 TVARIABLE(Object, shared_value, value);
1325 SharedValueBarrier(context, &shared_value);
1326
1327 TNode<BoolT> is_inobject =
1329 TNode<HeapObject> property_storage = Select<HeapObject>(
1330 is_inobject, [&]() { return holder; },
1331 [&]() { return LoadFastProperties(holder, true); });
1332
1333 TNode<UintPtrT> index =
1336
1337 StoreSharedObjectField(property_storage, offset, shared_value.value());
1338
1339 // Return the original value.
1340 Return(value);
1341}
1342
1344 const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
1345 ICMode ic_mode, ElementSupport support_elements) {
1346 Label if_smi_handler(this), if_nonsmi_handler(this);
1347 Label if_proto_handler(this), call_handler(this),
1348 store_transition_or_global_or_accessor(this);
1349
1350 Branch(TaggedIsSmi(handler), &if_smi_handler, &if_nonsmi_handler);
1351
1352 Label if_slow(this);
1353
1354 // |handler| is a Smi, encoding what to do. See SmiHandler methods
1355 // for the encoding format.
1356 BIND(&if_smi_handler);
1357 {
1358 TNode<Object> holder = p->receiver();
1359 TNode<Int32T> handler_word = SmiToInt32(CAST(handler));
1360
1361 Label if_fast_smi(this), if_proxy(this), if_interceptor(this);
1362
1363#define ASSERT_CONSECUTIVE(a, b) \
1364 static_assert(static_cast<intptr_t>(StoreHandler::Kind::a) + 1 == \
1365 static_cast<intptr_t>(StoreHandler::Kind::b));
1366 ASSERT_CONSECUTIVE(kGlobalProxy, kNormal)
1367 ASSERT_CONSECUTIVE(kNormal, kInterceptor)
1368 ASSERT_CONSECUTIVE(kInterceptor, kSlow)
1369 ASSERT_CONSECUTIVE(kSlow, kProxy)
1370 ASSERT_CONSECUTIVE(kProxy, kKindsNumber)
1371#undef ASSERT_CONSECUTIVE
1372
1373 TNode<Uint32T> handler_kind =
1375 GotoIf(Int32LessThan(handler_kind, STORE_KIND(kGlobalProxy)), &if_fast_smi);
1376 GotoIf(Word32Equal(handler_kind, STORE_KIND(kProxy)), &if_proxy);
1377 GotoIf(Word32Equal(handler_kind, STORE_KIND(kInterceptor)),
1378 &if_interceptor);
1379 GotoIf(Word32Equal(handler_kind, STORE_KIND(kSlow)), &if_slow);
1380 CSA_DCHECK(this, Word32Equal(handler_kind, STORE_KIND(kNormal)));
1381 TNode<PropertyDictionary> properties =
1382 CAST(LoadSlowProperties(CAST(holder)));
1383
1384 TVARIABLE(IntPtrT, var_name_index);
1385 Label dictionary_found(this, &var_name_index);
1386 if (p->IsAnyDefineOwn()) {
1388 &if_slow, nullptr, miss);
1389 } else {
1391 &dictionary_found,
1392 &var_name_index, miss);
1393 }
1394
1395 // When dealing with class fields defined with DefineKeyedOwnIC or
1396 // DefineNamedOwnIC, use the slow path to check the existing property.
1397 if (!p->IsAnyDefineOwn()) {
1398 BIND(&dictionary_found);
1399 {
1400 Label if_constant(this), done(this);
1401 TNode<Uint32T> details =
1402 LoadDetailsByKeyIndex(properties, var_name_index.value());
1403 // Check that the property is a writable data property (no accessor).
1404 const int kTypeAndReadOnlyMask =
1407 static_assert(static_cast<int>(PropertyKind::kData) == 0);
1408 GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
1409
1411 GotoIf(IsPropertyDetailsConst(details), miss);
1412 }
1413
1415 properties, var_name_index.value(), p->value());
1416 Return(p->value());
1417 }
1418 }
1419 BIND(&if_fast_smi);
1420 {
1421 Label data(this), shared_struct_field(this), native_data_property(this);
1422 GotoIf(Word32Equal(handler_kind, STORE_KIND(kNativeDataProperty)),
1423 &native_data_property);
1424 Branch(Word32Equal(handler_kind, STORE_KIND(kSharedStructField)),
1425 &shared_struct_field, &data);
1426
1427 BIND(&native_data_property);
1428 HandleStoreICNativeDataProperty(p, CAST(holder), handler_word);
1429
1430 BIND(&shared_struct_field);
1432 CAST(holder), p->value());
1433
1434 BIND(&data);
1435 // Handle non-transitioning field stores.
1436 HandleStoreICSmiHandlerCase(handler_word, CAST(holder), p->value(), miss);
1437 }
1438
1439 BIND(&if_proxy);
1440 {
1442 HandleStoreToProxy(p, CAST(holder), miss, support_elements);
1443 }
1444
1445 BIND(&if_interceptor);
1446 {
1447 Comment("store_interceptor");
1448 TailCallRuntime(Runtime::kStorePropertyWithInterceptor, p->context(),
1449 p->value(), p->receiver(), p->name());
1450 }
1451
1452 BIND(&if_slow);
1453 {
1454 Comment("store_slow");
1455 // The slow case calls into the runtime to complete the store without
1456 // causing an IC miss that would otherwise cause a transition to the
1457 // generic stub.
1458 if (ic_mode == ICMode::kGlobalIC) {
1459 TailCallRuntime(Runtime::kStoreGlobalIC_Slow, p->context(), p->value(),
1460 p->slot(), p->vector(), p->receiver(), p->name());
1461 } else {
1463 if (p->IsDefineNamedOwn()) {
1464 id = Runtime::kDefineNamedOwnIC_Slow;
1465 } else if (p->IsDefineKeyedOwn()) {
1466 id = Runtime::kDefineKeyedOwnIC_Slow;
1467 } else {
1468 id = Runtime::kKeyedStoreIC_Slow;
1469 }
1470 TailCallRuntime(id, p->context(), p->value(), p->receiver(), p->name());
1471 }
1472 }
1473 }
1474
1475 BIND(&if_nonsmi_handler);
1476 {
1477 TNode<HeapObjectReference> ref_handler = CAST(handler);
1478 GotoIf(IsWeakOrCleared(ref_handler),
1479 &store_transition_or_global_or_accessor);
1480 TNode<HeapObject> strong_handler = CAST(handler);
1481 TNode<Map> handler_map = LoadMap(strong_handler);
1482 Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler);
1483
1484 BIND(&if_proto_handler);
1485 {
1486 // Note, although DefineOwnICs don't reqiure checking for prototype
1487 // chain modifications the proto handlers shape is still used for
1488 // StoreHandler::StoreElementTransition in order to store both Code
1489 // handler and transition target map.
1490 HandleStoreICProtoHandler(p, CAST(strong_handler), &if_slow, miss,
1491 ic_mode, support_elements);
1492 }
1493
1494 // |handler| is a heap object. Must be code, call it.
1495 BIND(&call_handler);
1496 {
1497 TNode<Code> code_handler = CAST(strong_handler);
1498 TailCallStub(StoreWithVectorDescriptor{}, code_handler, p->context(),
1499 p->receiver(), p->name(), p->value(), p->slot(),
1500 p->vector());
1501 }
1502 }
1503
1504 BIND(&store_transition_or_global_or_accessor);
1505 {
1506 // Load value or miss if the {handler} weak cell is cleared.
1507 CSA_DCHECK(this, IsWeakOrCleared(handler));
1508 TNode<HeapObject> strong_handler = GetHeapObjectAssumeWeak(handler, miss);
1509
1510 Label store_global(this), store_transition(this), store_accessor(this);
1511 TNode<Map> strong_handler_map = LoadMap(strong_handler);
1512 GotoIf(IsPropertyCellMap(strong_handler_map), &store_global);
1513 Branch(IsAccessorPairMap(strong_handler_map), &store_accessor,
1514 &store_transition);
1515
1516 BIND(&store_global);
1517 {
1518 if (p->IsDefineNamedOwn()) {
1519 // The global proxy has its attributes set in the global object,
1520 // which can't be handled by StoreGlobalIC_PropertyCellCase when
1521 // defining public fields. Handle it in runtime.
1522 GotoIf(IsJSGlobalProxy(CAST(p->receiver())), &if_slow);
1523 } else if (p->IsDefineKeyedOwn()) {
1524 Label proceed_defining(this);
1525 // StoreGlobalIC_PropertyCellCase doesn't support definition
1526 // of private fields, so handle them in runtime.
1527 GotoIfNot(IsSymbol(CAST(p->name())), &proceed_defining);
1528 Branch(IsPrivateName(CAST(p->name())), &if_slow, &proceed_defining);
1529 BIND(&proceed_defining);
1530 }
1531
1532 TNode<PropertyCell> property_cell = CAST(strong_handler);
1533 ExitPoint direct_exit(this);
1534 StoreGlobalIC_PropertyCellCase(property_cell, p->value(), &direct_exit,
1535 miss);
1536 }
1537 BIND(&store_accessor);
1538 {
1539 TNode<AccessorPair> pair = CAST(strong_handler);
1541 // As long as this code path is not used for StoreSuperIC the receiver
1542 // is known to be neither undefined nor null.
1544 Return(
1545 CallFunction(p->context(), setter, mode, p->receiver(), p->value()));
1546 }
1547 BIND(&store_transition);
1548 {
1549 TNode<Map> map = CAST(strong_handler);
1551 p->IsAnyDefineOwn()
1554 Return(p->value());
1555 }
1556 }
1557}
1558
1560 const StoreICParameters* p, TNode<Map> transition_map, Label* miss,
1563 if (flags & kCheckPrototypeValidity) {
1564 TNode<Object> maybe_validity_cell =
1565 LoadObjectField(transition_map, Map::kPrototypeValidityCellOffset);
1566 CheckPrototypeValidityCell(maybe_validity_cell, miss);
1567 }
1568
1569 TNode<Uint32T> bitfield3 = LoadMapBitField3(transition_map);
1572
1573 // Load last descriptor details.
1574 TNode<UintPtrT> nof =
1576 CSA_DCHECK(this, WordNotEqual(nof, IntPtrConstant(0)));
1577 TNode<DescriptorArray> descriptors = LoadMapDescriptors(transition_map);
1578
1582 if (flags & kValidateTransitionHandler) {
1583 TNode<Name> key = LoadKeyByKeyIndex(descriptors, last_key_index);
1584 GotoIf(TaggedNotEqual(key, p->name()), miss);
1585 } else {
1586 CSA_DCHECK(this, TaggedEqual(LoadKeyByKeyIndex(descriptors, last_key_index),
1587 p->name()));
1588 }
1589 TNode<Uint32T> details = LoadDetailsByKeyIndex(descriptors, last_key_index);
1590 if (flags & kValidateTransitionHandler) {
1591 // Follow transitions only in the following cases:
1592 // 1) name is a non-private symbol and attributes equal to NONE,
1593 // 2) name is a private symbol and attributes equal to DONT_ENUM.
1594 Label attributes_ok(this);
1595 const int kKindAndAttributesDontDeleteReadOnlyMask =
1599 static_assert(static_cast<int>(PropertyKind::kData) == 0);
1600 // Both DontDelete and ReadOnly attributes must not be set and it has to be
1601 // a kData property.
1602 GotoIf(IsSetWord32(details, kKindAndAttributesDontDeleteReadOnlyMask),
1603 miss);
1604
1605 // DontEnum attribute is allowed only for private symbols and vice versa.
1608 IsPrivateSymbol(CAST(p->name()))),
1609 &attributes_ok, miss);
1610
1611 BIND(&attributes_ok);
1612 }
1613
1614 OverwriteExistingFastDataProperty(CAST(p->receiver()), transition_map,
1615 descriptors, last_key_index, details,
1616 p->value(), miss, true);
1617}
1618
1621 Comment("UpdateMayHaveInterestingProperty");
1622 Label done(this);
1623
1625 // TODO(pthier): Add flags to swiss dictionaries.
1626 Goto(&done);
1627 } else {
1628 GotoIfNot(IsInterestingProperty(name), &done);
1629 TNode<Smi> flags = GetNameDictionaryFlags(dict);
1630 flags = SmiOr(
1631 flags,
1634 SetNameDictionaryFlags(dict, flags);
1635 Goto(&done);
1636 }
1637 BIND(&done);
1638}
1639
1641 TNode<IntPtrT> name_index,
1642 TNode<Word32T> representation,
1643 TNode<Object> value, Label* bailout) {
1644 Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this);
1646 &r_smi);
1648 &r_double);
1649 GotoIf(
1651 &r_heapobject);
1653 bailout);
1654 CSA_DCHECK(this, Word32Equal(representation,
1656 Goto(&all_fine);
1657
1658 BIND(&r_smi);
1659 { Branch(TaggedIsSmi(value), &all_fine, bailout); }
1660
1661 BIND(&r_double);
1662 {
1663 GotoIf(TaggedIsSmi(value), &all_fine);
1664 Branch(IsHeapNumber(CAST(value)), &all_fine, bailout);
1665 }
1666
1667 BIND(&r_heapobject);
1668 {
1669 GotoIf(TaggedIsSmi(value), bailout);
1670 TNode<MaybeObject> field_type =
1671 LoadFieldTypeByKeyIndex(descriptors, name_index);
1672 const Address kAnyType = FieldType::Any().ptr();
1673 // FieldType::Any can hold any value.
1674 GotoIf(
1675 TaggedEqual(field_type, BitcastWordToTagged(IntPtrConstant(kAnyType))),
1676 &all_fine);
1677 // FieldType::Class(...) performs a map check.
1678 // If the type is None we want this check to fail too, thus we compare the
1679 // maybe weak field type as is against a weak map ptr.
1680#ifdef DEBUG
1681 {
1682 // Check the field type is None or a weak map.
1683 Label check_done(this);
1684 GotoIf(TaggedEqual(field_type, BitcastWordToTagged(IntPtrConstant(
1685 FieldType::None().ptr()))),
1686 &check_done);
1687 CSA_DCHECK(this, IsMap(GetHeapObjectAssumeWeak(field_type)));
1688 Goto(&check_done);
1689 BIND(&check_done);
1690 }
1691#endif // DEBUG
1692 Branch(TaggedEqual(MakeWeak(LoadMap(CAST(value))), field_type), &all_fine,
1693 bailout);
1694 }
1695
1696 BIND(&all_fine);
1697}
1698
1704
1706 TNode<HeapObject> object, TNode<Map> object_map,
1707 TNode<DescriptorArray> descriptors, TNode<IntPtrT> descriptor_name_index,
1708 TNode<Uint32T> details, TNode<Object> value, Label* slow,
1709 bool do_transitioning_store) {
1710 Label done(this), if_field(this), if_descriptor(this);
1711
1712 CSA_DCHECK(this,
1714 Int32Constant(static_cast<int>(PropertyKind::kData))));
1715
1718 Int32Constant(static_cast<int32_t>(PropertyLocation::kField))),
1719 &if_field, &if_descriptor);
1720
1721 BIND(&if_field);
1722 {
1723 TNode<Uint32T> representation =
1725
1726 CheckFieldType(descriptors, descriptor_name_index, representation, value,
1727 slow);
1728
1729 TNode<UintPtrT> field_index =
1731 field_index = Unsigned(
1732 IntPtrAdd(field_index,
1734 TNode<IntPtrT> instance_size_in_words =
1735 LoadMapInstanceSizeInWords(object_map);
1736
1737 Label inobject(this), backing_store(this);
1738 Branch(UintPtrLessThan(field_index, instance_size_in_words), &inobject,
1739 &backing_store);
1740
1741 BIND(&inobject);
1742 {
1743 TNode<IntPtrT> field_offset = Signed(TimesTaggedSize(field_index));
1744 Label tagged_rep(this), double_rep(this);
1745 Branch(
1747 &double_rep, &tagged_rep);
1748 BIND(&double_rep);
1749 {
1750 TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value));
1751 if (do_transitioning_store) {
1752 TNode<HeapNumber> heap_number =
1753 AllocateHeapNumberWithValue(double_value);
1754 StoreMap(object, object_map);
1755 StoreObjectField(object, field_offset, heap_number);
1756 } else {
1757 GotoIf(IsPropertyDetailsConst(details), slow);
1758 TNode<HeapNumber> heap_number =
1759 CAST(LoadObjectField(object, field_offset));
1760 StoreHeapNumberValue(heap_number, double_value);
1761 }
1762 Goto(&done);
1763 }
1764
1765 BIND(&tagged_rep);
1766 {
1767 if (do_transitioning_store) {
1768 StoreMap(object, object_map);
1769 } else {
1770 GotoIf(IsPropertyDetailsConst(details), slow);
1771 }
1772 StoreObjectField(object, field_offset, value);
1773 Goto(&done);
1774 }
1775 }
1776
1777 BIND(&backing_store);
1778 {
1779 TNode<IntPtrT> backing_store_index =
1780 Signed(IntPtrSub(field_index, instance_size_in_words));
1781
1782 if (do_transitioning_store) {
1783 // Allocate mutable heap number before extending properties backing
1784 // store to ensure that heap verifier will not see the heap in
1785 // inconsistent state.
1786 TVARIABLE(Object, var_value, value);
1787 {
1788 Label cont(this);
1789 GotoIf(Word32NotEqual(representation,
1791 &cont);
1792 {
1793 TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value));
1794 TNode<HeapNumber> heap_number =
1795 AllocateHeapNumberWithValue(double_value);
1796 var_value = heap_number;
1797 Goto(&cont);
1798 }
1799 BIND(&cont);
1800 }
1801
1802 TNode<PropertyArray> properties =
1803 ExtendPropertiesBackingStore(object, backing_store_index);
1804 StorePropertyArrayElement(properties, backing_store_index,
1805 var_value.value());
1806 StoreMap(object, object_map);
1807 Goto(&done);
1808
1809 } else {
1810 Label tagged_rep(this), double_rep(this);
1811 TNode<PropertyArray> properties =
1812 CAST(LoadFastProperties(CAST(object), true));
1813 Branch(
1815 &double_rep, &tagged_rep);
1816 BIND(&double_rep);
1817 {
1818 GotoIf(IsPropertyDetailsConst(details), slow);
1819 TNode<HeapNumber> heap_number =
1820 CAST(LoadPropertyArrayElement(properties, backing_store_index));
1821 TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value));
1822 StoreHeapNumberValue(heap_number, double_value);
1823 Goto(&done);
1824 }
1825 BIND(&tagged_rep);
1826 {
1827 GotoIf(IsPropertyDetailsConst(details), slow);
1828 StorePropertyArrayElement(properties, backing_store_index, value);
1829 Goto(&done);
1830 }
1831 }
1832 }
1833 }
1834
1835 BIND(&if_descriptor);
1836 {
1837 // Check that constant matches value.
1838 TNode<Object> constant =
1839 LoadValueByKeyIndex(descriptors, descriptor_name_index);
1840 GotoIf(TaggedNotEqual(value, constant), slow);
1841
1842 if (do_transitioning_store) {
1843 StoreMap(object, object_map);
1844 }
1845 Goto(&done);
1846 }
1847 BIND(&done);
1848}
1849
1851 TNode<Context> context, TNode<HeapObject> shared_struct,
1852 TNode<Map> shared_struct_map, TNode<DescriptorArray> descriptors,
1853 TNode<IntPtrT> descriptor_name_index, TNode<Uint32T> details,
1854 TNode<Object> maybe_local_value) {
1855 CSA_DCHECK(this, IsJSSharedStruct(shared_struct));
1856
1857 Label done(this);
1858
1859 TNode<UintPtrT> field_index =
1861 field_index = Unsigned(IntPtrAdd(
1862 field_index,
1863 Unsigned(LoadMapInobjectPropertiesStartInWords(shared_struct_map))));
1864
1865 TNode<IntPtrT> instance_size_in_words =
1866 LoadMapInstanceSizeInWords(shared_struct_map);
1867
1868 TVARIABLE(Object, shared_value, maybe_local_value);
1869 SharedValueBarrier(context, &shared_value);
1870
1871 Label inobject(this), backing_store(this);
1872 Branch(UintPtrLessThan(field_index, instance_size_in_words), &inobject,
1873 &backing_store);
1874
1875 BIND(&inobject);
1876 {
1877 TNode<IntPtrT> field_offset = Signed(TimesTaggedSize(field_index));
1878 StoreSharedObjectField(shared_struct, field_offset, shared_value.value());
1879 Goto(&done);
1880 }
1881
1882 BIND(&backing_store);
1883 {
1884 TNode<IntPtrT> backing_store_index =
1885 Signed(IntPtrSub(field_index, instance_size_in_words));
1886
1887 CSA_DCHECK(
1888 this,
1891 TNode<PropertyArray> properties =
1892 CAST(LoadFastProperties(CAST(shared_struct), true));
1893 StoreJSSharedStructPropertyArrayElement(properties, backing_store_index,
1894 shared_value.value());
1895 Goto(&done);
1896 }
1897
1898 BIND(&done);
1899}
1900
1902 TNode<Object> maybe_validity_cell, Label* miss) {
1903 Label done(this);
1904 GotoIf(
1905 TaggedEqual(maybe_validity_cell, SmiConstant(Map::kPrototypeChainValid)),
1906 &done);
1907 CSA_DCHECK(this, TaggedIsNotSmi(maybe_validity_cell));
1908
1909 TNode<Object> cell_value =
1910 LoadObjectField(CAST(maybe_validity_cell), Cell::kValueOffset);
1912 miss);
1913
1914 BIND(&done);
1915}
1916
1918 const StoreICParameters* p, TNode<StoreHandler> handler, Label* slow,
1919 Label* miss, ICMode ic_mode, ElementSupport support_elements) {
1920 Comment("HandleStoreICProtoHandler");
1921
1922 OnCodeHandler on_code_handler;
1923 if (support_elements == kSupportElements) {
1924 // Code sub-handlers are expected only in KeyedStoreICs.
1925 on_code_handler = [=, this](TNode<Code> code_handler) {
1926 // This is either element store or transitioning element store.
1927 Label if_element_store(this), if_transitioning_element_store(this);
1928 Branch(IsStoreHandler0Map(LoadMap(handler)), &if_element_store,
1929 &if_transitioning_element_store);
1930 BIND(&if_element_store);
1931 {
1932 TailCallStub(StoreWithVectorDescriptor{}, code_handler, p->context(),
1933 p->receiver(), p->name(), p->value(), p->slot(),
1934 p->vector());
1935 }
1936
1937 BIND(&if_transitioning_element_store);
1938 {
1939 TNode<MaybeObject> maybe_transition_map =
1940 LoadHandlerDataField(handler, 1);
1941 TNode<Map> transition_map =
1942 CAST(GetHeapObjectAssumeWeak(maybe_transition_map, miss));
1943
1944 GotoIf(IsDeprecatedMap(transition_map), miss);
1945
1946 TailCallStub(StoreTransitionDescriptor{}, code_handler, p->context(),
1947 p->receiver(), p->name(), transition_map, p->value(),
1948 p->slot(), p->vector());
1949 }
1950 };
1951 }
1952
1954 p, handler, on_code_handler,
1955 // on_found_on_lookup_start_object
1956 [=, this](TNode<PropertyDictionary> properties,
1957 TNode<IntPtrT> name_index) {
1958 TNode<Uint32T> details = LoadDetailsByKeyIndex(properties, name_index);
1959 // Check that the property is a writable data property (no accessor).
1960 const int kTypeAndReadOnlyMask =
1963 static_assert(static_cast<int>(PropertyKind::kData) == 0);
1964 GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
1965
1966 StoreValueByKeyIndex<PropertyDictionary>(properties, name_index,
1967 p->value());
1968 Return(p->value());
1969 },
1970 miss, ic_mode);
1971
1972 {
1973 Label if_add_normal(this), if_store_global_proxy(this), if_api_setter(this),
1974 if_accessor(this), if_native_data_property(this);
1975
1976 CSA_DCHECK(this, TaggedIsSmi(smi_handler));
1977 TNode<Int32T> handler_word = SmiToInt32(CAST(smi_handler));
1978
1979 TNode<Uint32T> handler_kind =
1981 GotoIf(Word32Equal(handler_kind, STORE_KIND(kNormal)), &if_add_normal);
1982
1983 GotoIf(Word32Equal(handler_kind, STORE_KIND(kSlow)), slow);
1984
1985 TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
1986 CSA_DCHECK(this, IsWeakOrCleared(maybe_holder));
1987 TNode<HeapObject> holder = GetHeapObjectAssumeWeak(maybe_holder, miss);
1988
1989 GotoIf(Word32Equal(handler_kind, STORE_KIND(kGlobalProxy)),
1990 &if_store_global_proxy);
1991
1992 GotoIf(Word32Equal(handler_kind, STORE_KIND(kAccessorFromPrototype)),
1993 &if_accessor);
1994
1995 GotoIf(Word32Equal(handler_kind, STORE_KIND(kNativeDataProperty)),
1996 &if_native_data_property);
1997
1998 GotoIf(Word32Equal(handler_kind, STORE_KIND(kApiSetter)), &if_api_setter);
1999
2000 CSA_DCHECK(this, Word32Equal(handler_kind, STORE_KIND(kProxy)));
2001 HandleStoreToProxy(p, CAST(holder), miss, support_elements);
2002
2003 BIND(&if_add_normal);
2004 {
2005 // This is a case of "transitioning store" to a dictionary mode object
2006 // when the property does not exist. The "existing property" case is
2007 // covered above by LookupOnLookupStartObject bit handling of the smi
2008 // handler.
2009 Label slow_runtime_call(this);
2010 TNode<Map> receiver_map = LoadMap(CAST(p->receiver()));
2012
2013 TNode<PropertyDictionary> properties =
2015 TNode<Name> name = CAST(p->name());
2016 AddToDictionary<PropertyDictionary>(properties, name, p->value(),
2017 &slow_runtime_call);
2018 UpdateMayHaveInterestingProperty(properties, name);
2019 Return(p->value());
2020
2021 BIND(&slow_runtime_call);
2022 TailCallRuntime(Runtime::kAddDictionaryProperty, p->context(),
2023 p->receiver(), p->name(), p->value());
2024 }
2025
2026 BIND(&if_accessor);
2027 {
2028 Comment("accessor_store");
2029 // The "holder" slot (data1) in the from-prototype StoreHandler is
2030 // instead directly the setter function.
2031 TNode<JSFunction> setter = CAST(holder);
2032
2033 // As long as this code path is not used for StoreSuperIC the receiver
2034 // is known to be neither undefined nor null.
2036 Return(
2037 CallFunction(p->context(), setter, mode, p->receiver(), p->value()));
2038 }
2039
2040 BIND(&if_native_data_property);
2041 HandleStoreICNativeDataProperty(p, holder, handler_word);
2042
2043 BIND(&if_api_setter);
2044 {
2045 Comment("api_setter");
2046 CSA_DCHECK(this, TaggedIsNotSmi(handler));
2047 TNode<FunctionTemplateInfo> function_template_info = CAST(holder);
2048
2049 // Context is stored either in data2 or data3 field depending on whether
2050 // the access check is enabled for this handler or not.
2053 handler_word),
2054 [=, this] { return LoadHandlerDataField(handler, 3); },
2055 [=, this] { return LoadHandlerDataField(handler, 2); });
2056
2057 CSA_DCHECK(this, IsWeakOrCleared(maybe_context));
2058 TNode<Object> context = Select<Object>(
2059 IsCleared(maybe_context), [=, this] { return SmiConstant(0); },
2060 [=, this] { return GetHeapObjectAssumeWeak(maybe_context); });
2061
2062 TNode<Int32T> argc = Int32Constant(1);
2063 TNode<Context> caller_context = p->context();
2064 Return(CallBuiltin(Builtin::kCallApiCallbackGeneric, context, argc,
2065 caller_context, function_template_info, p->receiver(),
2066 p->value()));
2067 }
2068
2069 BIND(&if_store_global_proxy);
2070 {
2071 ExitPoint direct_exit(this);
2072 // StoreGlobalIC_PropertyCellCase doesn't properly handle private names
2073 // but they are not expected here anyway.
2075 StoreGlobalIC_PropertyCellCase(CAST(holder), p->value(), &direct_exit,
2076 miss);
2077 }
2078 }
2079}
2080
2082 TNode<JSProxy> proxy, Label* miss,
2083 ElementSupport support_elements) {
2084 TVARIABLE(IntPtrT, var_index);
2085 TVARIABLE(Name, var_unique);
2086
2087 Label if_index(this), if_unique_name(this),
2088 to_name_failed(this, Label::kDeferred);
2089
2090 if (support_elements == kSupportElements) {
2091 TryToName(p->name(), &if_index, &var_index, &if_unique_name, &var_unique,
2092 &to_name_failed);
2093
2094 BIND(&if_unique_name);
2095 CallBuiltin(Builtin::kProxySetProperty, p->context(), proxy,
2096 var_unique.value(), p->value(), p->receiver());
2097 Return(p->value());
2098
2099 // The index case is handled earlier by the runtime.
2100 BIND(&if_index);
2101 // TODO(mslekova): introduce TryToName that doesn't try to compute
2102 // the intptr index value
2103 Goto(&to_name_failed);
2104
2105 BIND(&to_name_failed);
2106 TailCallRuntime(Runtime::kSetPropertyWithReceiver, p->context(), proxy,
2107 p->name(), p->value(), p->receiver());
2108 } else {
2109 TNode<Object> name = CallBuiltin(Builtin::kToName, p->context(), p->name());
2110 TailCallBuiltin(Builtin::kProxySetProperty, p->context(), proxy, name,
2111 p->value(), p->receiver());
2112 }
2113}
2114
2116 TNode<JSObject> holder,
2117 TNode<Object> value,
2118 Label* miss) {
2119 Comment("field store");
2120#ifdef DEBUG
2121 TNode<Uint32T> handler_kind =
2123 CSA_DCHECK(this,
2124 Word32Or(Word32Equal(handler_kind, STORE_KIND(kField)),
2125 Word32Equal(handler_kind, STORE_KIND(kConstField))));
2126#endif
2127
2128 TNode<Uint32T> field_representation =
2130
2131 Label if_smi_field(this), if_double_field(this), if_heap_object_field(this),
2132 if_tagged_field(this);
2133
2134 int32_t case_values[] = {Representation::kTagged, Representation::kHeapObject,
2136 Label* case_labels[] = {&if_tagged_field, &if_heap_object_field,
2137 &if_smi_field};
2138
2139 Switch(field_representation, &if_double_field, case_values, case_labels, 3);
2140
2141 BIND(&if_tagged_field);
2142 {
2143 Comment("store tagged field");
2144 HandleStoreFieldAndReturn(handler_word, holder, value, std::nullopt,
2145 Representation::Tagged(), miss);
2146 }
2147
2148 BIND(&if_heap_object_field);
2149 {
2150 Comment("heap object field checks");
2151 CheckHeapObjectTypeMatchesDescriptor(handler_word, holder, value, miss);
2152
2153 Comment("store heap object field");
2154 HandleStoreFieldAndReturn(handler_word, holder, value, std::nullopt,
2156 }
2157
2158 BIND(&if_smi_field);
2159 {
2160 Comment("smi field checks");
2161 GotoIfNot(TaggedIsSmi(value), miss);
2162
2163 Comment("store smi field");
2164 HandleStoreFieldAndReturn(handler_word, holder, value, std::nullopt,
2165 Representation::Smi(), miss);
2166 }
2167
2168 BIND(&if_double_field);
2169 {
2170 CSA_DCHECK(this, Word32Equal(field_representation,
2172 Comment("double field checks");
2173 TNode<Float64T> double_value = TryTaggedToFloat64(value,
2174#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
2175 nullptr,
2176#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
2177 miss);
2178 CheckDescriptorConsidersNumbersMutable(handler_word, holder, miss);
2179
2180 Comment("store double field");
2181 HandleStoreFieldAndReturn(handler_word, holder, value, double_value,
2182 Representation::Double(), miss);
2183 }
2184}
2185
2187 TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value,
2188 Label* bailout) {
2189 GotoIf(TaggedIsSmi(value), bailout);
2190
2191 Label done(this);
2192 // Skip field type check in favor of constant value check when storing
2193 // to constant field.
2195 STORE_KIND(kConstField)),
2196 &done);
2197 TNode<IntPtrT> descriptor =
2199 TNode<MaybeObject> field_type =
2200 LoadDescriptorValueOrFieldType(LoadMap(holder), descriptor);
2201
2202 const Address kAnyType = FieldType::Any().ptr();
2203 GotoIf(TaggedEqual(field_type, BitcastWordToTagged(IntPtrConstant(kAnyType))),
2204 &done);
2205 // Check that value type matches the field type.
2206 {
2207 // If the type is None we want this check to fail too, thus we compare the
2208 // maybe weak field type as is against a weak map ptr.
2209#ifdef DEBUG
2210 {
2211 // Check the field type is None or a weak map.
2212 Label check_done(this);
2213 GotoIf(TaggedEqual(field_type, BitcastWordToTagged(IntPtrConstant(
2214 FieldType::None().ptr()))),
2215 &check_done);
2216 CSA_DCHECK(this, IsMap(GetHeapObjectAssumeWeak(field_type)));
2217 Goto(&check_done);
2218 BIND(&check_done);
2219 }
2220#endif // DEBUG
2221 Branch(TaggedEqual(MakeWeak(LoadMap(CAST(value))), field_type), &done,
2222 bailout);
2223 }
2224 BIND(&done);
2225}
2226
2228 TNode<Word32T> handler_word, TNode<JSObject> holder, Label* bailout) {
2229 // We have to check that the representation is Double. Checking the value
2230 // (either in the field or being assigned) is not enough, as we could have
2231 // transitioned to Tagged but still be holding a HeapNumber, which would no
2232 // longer be allowed to be mutable.
2233
2234 // TODO(leszeks): We could skip the representation check in favor of a
2235 // constant value check in HandleStoreFieldAndReturn here, but then
2236 // HandleStoreFieldAndReturn would need an IsHeapNumber check in case both the
2237 // representation changed and the value is no longer a HeapNumber.
2238 TNode<IntPtrT> descriptor_entry =
2240 TNode<DescriptorArray> descriptors = LoadMapDescriptors(LoadMap(holder));
2241 TNode<Uint32T> details =
2242 LoadDetailsByDescriptorEntry(descriptors, descriptor_entry);
2243
2245 details, Representation::kDouble),
2246 bailout);
2247}
2248
2250 TNode<Float64T> right,
2251 Label* miss) {
2252 // TODO(verwaest): Use a single compare on 64bit archs.
2253 const TNode<Uint32T> lhs_hi = Float64ExtractHighWord32(left);
2254 const TNode<Uint32T> rhs_hi = Float64ExtractHighWord32(right);
2255 GotoIfNot(Word32Equal(lhs_hi, rhs_hi), miss);
2256 const TNode<Uint32T> lhs_lo = Float64ExtractLowWord32(left);
2257 const TNode<Uint32T> rhs_lo = Float64ExtractLowWord32(right);
2258 GotoIfNot(Word32Equal(lhs_lo, rhs_lo), miss);
2259}
2260
2262 TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value,
2263 std::optional<TNode<Float64T>> double_value, Representation representation,
2264 Label* miss) {
2265 bool store_value_as_double = representation.IsDouble();
2266
2267 TNode<BoolT> is_inobject =
2269 TNode<HeapObject> property_storage = Select<HeapObject>(
2270 is_inobject, [&]() { return holder; },
2271 [&]() { return LoadFastProperties(holder, true); });
2272
2273 TNode<UintPtrT> index =
2276
2277 // For Double fields, we want to mutate the current double-value
2278 // field rather than changing it to point at a new HeapNumber.
2279 if (store_value_as_double) {
2280 TVARIABLE(HeapObject, actual_property_storage, property_storage);
2281 TVARIABLE(IntPtrT, actual_offset, offset);
2282
2283 Label property_and_offset_ready(this);
2284
2285 // Store the double value directly into the mutable HeapNumber.
2286 TNode<Object> field = LoadObjectField(property_storage, offset);
2287 CSA_DCHECK(this, IsHeapNumber(CAST(field)));
2288 actual_property_storage = CAST(field);
2289 actual_offset = IntPtrConstant(offsetof(HeapNumber, value_));
2290 Goto(&property_and_offset_ready);
2291
2292 BIND(&property_and_offset_ready);
2293 property_storage = actual_property_storage.value();
2294 offset = actual_offset.value();
2295 }
2296
2297 // Do constant value check if necessary.
2298 Label do_store(this);
2300 STORE_KIND(kConstField)),
2301 &do_store);
2302 {
2303 if (store_value_as_double) {
2304 TNode<Float64T> current_value =
2305 LoadObjectField<Float64T>(property_storage, offset);
2306 GotoIfNotSameNumberBitPattern(current_value, *double_value, miss);
2307 Return(value);
2308 } else {
2309 TNode<Object> current_value = LoadObjectField(property_storage, offset);
2310 GotoIfNot(TaggedEqual(current_value, value), miss);
2311 Return(value);
2312 }
2313 }
2314
2315 BIND(&do_store);
2316 // Do the store.
2317 if (store_value_as_double) {
2318 StoreObjectFieldNoWriteBarrier(property_storage, offset, *double_value);
2319 } else if (representation.IsSmi()) {
2320 TNode<Smi> value_smi = CAST(value);
2321 StoreObjectFieldNoWriteBarrier(property_storage, offset, value_smi);
2322 } else {
2323 StoreObjectField(property_storage, offset, value);
2324 }
2325
2326 Return(value);
2327}
2328
2330 TNode<HeapObject> object, TNode<IntPtrT> index) {
2331 Comment("[ Extend storage");
2332
2333 TVARIABLE(HeapObject, var_properties);
2334 TVARIABLE(Int32T, var_encoded_hash);
2335 TVARIABLE(IntPtrT, var_length);
2336
2337 TNode<Object> properties =
2338 LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
2339
2340 Label if_smi_hash(this), if_property_array(this), extend_store(this);
2341 Branch(TaggedIsSmi(properties), &if_smi_hash, &if_property_array);
2342
2343 BIND(&if_smi_hash);
2344 {
2345 TNode<Int32T> hash = SmiToInt32(CAST(properties));
2346 TNode<Int32T> encoded_hash =
2348 var_encoded_hash = encoded_hash;
2349 var_length = IntPtrConstant(0);
2350 var_properties = EmptyFixedArrayConstant();
2351 Goto(&extend_store);
2352 }
2353
2354 BIND(&if_property_array);
2355 {
2356 var_properties = CAST(properties);
2357 TNode<Int32T> length_and_hash_int32 = LoadAndUntagToWord32ObjectField(
2358 var_properties.value(), PropertyArray::kLengthAndHashOffset);
2359 var_encoded_hash = Word32And(
2360 length_and_hash_int32, Int32Constant(PropertyArray::HashField::kMask));
2361 var_length = ChangeInt32ToIntPtr(
2362 Word32And(length_and_hash_int32,
2364 Goto(&extend_store);
2365 }
2366
2367 BIND(&extend_store);
2368 {
2369 TVARIABLE(HeapObject, var_new_properties, var_properties.value());
2370 Label done(this);
2371 // Previous property deletion could have left behind unused backing store
2372 // capacity even for a map that think it doesn't have any unused fields.
2373 // Perform a bounds check to see if we actually have to grow the array.
2374 GotoIf(UintPtrLessThan(index, ParameterToIntPtr(var_length.value())),
2375 &done);
2376
2378 TNode<IntPtrT> new_capacity = IntPtrAdd(var_length.value(), delta);
2379
2380 // Grow properties array.
2383 // The size of a new properties backing store is guaranteed to be small
2384 // enough that the new backing store will be allocated in new space.
2385 CSA_DCHECK(this, IntPtrLessThan(new_capacity,
2388
2389 TNode<PropertyArray> new_properties = AllocatePropertyArray(new_capacity);
2390 var_new_properties = new_properties;
2391
2392 FillPropertyArrayWithUndefined(new_properties, var_length.value(),
2393 new_capacity);
2394
2395 // |new_properties| is guaranteed to be in new space, so we can skip
2396 // the write barrier.
2397 CopyPropertyArrayValues(var_properties.value(), new_properties,
2398 var_length.value(), SKIP_WRITE_BARRIER,
2400
2401 TNode<Int32T> new_capacity_int32 = TruncateIntPtrToInt32(new_capacity);
2402 TNode<Int32T> new_length_and_hash_int32 =
2403 Word32Or(var_encoded_hash.value(), new_capacity_int32);
2404 StoreObjectField(new_properties, PropertyArray::kLengthAndHashOffset,
2405 SmiFromInt32(new_length_and_hash_int32));
2406 StoreObjectField(object, JSObject::kPropertiesOrHashOffset, new_properties);
2407 Comment("] Extend storage");
2408 Goto(&done);
2409 BIND(&done);
2410 return CAST(var_new_properties.value());
2411 }
2412}
2413
2415 TNode<JSObject> object, TNode<FixedArrayBase> elements,
2416 TNode<IntPtrT> intptr_index, TNode<BoolT> is_jsarray_condition,
2417 Label* miss) {
2418 TVARIABLE(IntPtrT, var_length);
2419 Comment("Fast elements bounds check");
2420 Label if_array(this), length_loaded(this, &var_length);
2421 GotoIf(is_jsarray_condition, &if_array);
2422 {
2423 var_length = LoadAndUntagFixedArrayBaseLength(elements);
2424 Goto(&length_loaded);
2425 }
2426 BIND(&if_array);
2427 {
2428 var_length = PositiveSmiUntag(LoadFastJSArrayLength(CAST(object)));
2429 Goto(&length_loaded);
2430 }
2431 BIND(&length_loaded);
2432 GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss);
2433}
2434
2436 TNode<HeapObject> object, TNode<Word32T> elements_kind,
2437 TNode<IntPtrT> intptr_index, TNode<BoolT> is_jsarray_condition,
2438 Label* if_hole, Label* rebox_double, TVariable<Float64T>* var_double_value,
2439 Label* unimplemented_elements_kind, Label* out_of_bounds, Label* miss,
2440 ExitPoint* exit_point, LoadAccessMode access_mode) {
2441 Label if_rab_gsab_typed_array(this), if_typed_array(this), if_fast(this),
2442 if_fast_packed(this), if_fast_holey(this), if_fast_double(this),
2443 if_fast_holey_double(this), if_nonfast(this), if_dictionary(this);
2444 Branch(Int32GreaterThan(elements_kind,
2446 &if_nonfast, &if_fast);
2447
2448 BIND(&if_fast);
2449 {
2450 TNode<FixedArrayBase> elements = LoadJSObjectElements(CAST(object));
2451 EmitFastElementsBoundsCheck(CAST(object), elements, intptr_index,
2452 is_jsarray_condition, out_of_bounds);
2453 int32_t kinds[] = {
2454 // Handled by if_fast_packed.
2457 // Handled by if_fast_holey.
2460 // Handled by if_fast_double.
2462 // Handled by if_fast_holey_double.
2464 Label* labels[] = {// FAST_{SMI,}_ELEMENTS
2465 &if_fast_packed, &if_fast_packed, &if_fast_packed,
2466 &if_fast_packed, &if_fast_packed, &if_fast_packed,
2467 // FAST_HOLEY_{SMI,}_ELEMENTS
2468 &if_fast_holey, &if_fast_holey, &if_fast_holey,
2469 &if_fast_holey, &if_fast_holey,
2470 // PACKED_DOUBLE_ELEMENTS
2471 &if_fast_double,
2472 // HOLEY_DOUBLE_ELEMENTS
2473 &if_fast_holey_double};
2474 Switch(elements_kind, unimplemented_elements_kind, kinds, labels,
2475 arraysize(kinds));
2476
2477 BIND(&if_fast_packed);
2478 {
2479 Comment("fast packed elements");
2480 exit_point->Return(
2481 access_mode == LoadAccessMode::kHas
2482 ? TrueConstant()
2483 : UnsafeLoadFixedArrayElement(CAST(elements), intptr_index));
2484 }
2485
2486 BIND(&if_fast_holey);
2487 {
2488 Comment("fast holey elements");
2489 TNode<Object> element =
2490 UnsafeLoadFixedArrayElement(CAST(elements), intptr_index);
2491 GotoIf(TaggedEqual(element, TheHoleConstant()), if_hole);
2492 exit_point->Return(access_mode == LoadAccessMode::kHas ? TrueConstant()
2493 : element);
2494 }
2495
2496 BIND(&if_fast_double);
2497 {
2498 Comment("packed double elements");
2499 if (access_mode == LoadAccessMode::kHas) {
2500 exit_point->Return(TrueConstant());
2501 } else {
2502 *var_double_value =
2503 LoadFixedDoubleArrayElement(CAST(elements), intptr_index);
2504 Goto(rebox_double);
2505 }
2506 }
2507
2508 BIND(&if_fast_holey_double);
2509 {
2510 Comment("holey double elements");
2511 if (access_mode == LoadAccessMode::kHas) {
2512 LoadFixedDoubleArrayElement(CAST(elements), intptr_index, if_hole,
2514 exit_point->Return(TrueConstant());
2515 } else {
2516#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
2517 Label if_undefined(this);
2518 TNode<Float64T> value = LoadFixedDoubleArrayElementWithUndefinedCheck(
2519 CAST(elements), intptr_index, &if_undefined, if_hole);
2520 *var_double_value = value;
2521 Goto(rebox_double);
2522
2523 BIND(&if_undefined);
2524 exit_point->Return(UndefinedConstant());
2525#else
2526 *var_double_value =
2527 LoadFixedDoubleArrayElement(CAST(elements), intptr_index, if_hole);
2528 Goto(rebox_double);
2529#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
2530 }
2531 }
2532 }
2533
2534 BIND(&if_nonfast);
2535 {
2536 Label uint8_elements(this), int8_elements(this), uint16_elements(this),
2537 int16_elements(this), uint32_elements(this), int32_elements(this),
2538 float32_elements(this), float64_elements(this), bigint64_elements(this),
2539 biguint64_elements(this), float16_elements(this);
2540 static_assert(LAST_ELEMENTS_KIND ==
2542 GotoIf(Int32GreaterThanOrEqual(
2543 elements_kind,
2545 &if_rab_gsab_typed_array);
2546 GotoIf(Int32GreaterThanOrEqual(
2547 elements_kind,
2549 &if_typed_array);
2551 &if_dictionary);
2552 Goto(unimplemented_elements_kind);
2553
2554 BIND(&if_dictionary);
2555 {
2556 Comment("dictionary elements");
2557 if (Is64()) {
2559 intptr_index),
2560 out_of_bounds);
2561 } else {
2562 GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds);
2563 }
2564
2565 TNode<FixedArrayBase> elements = LoadJSObjectElements(CAST(object));
2567 CAST(elements), intptr_index, miss, if_hole);
2568 exit_point->Return(access_mode == LoadAccessMode::kHas ? TrueConstant()
2569 : value);
2570 }
2571 {
2572 TVARIABLE(RawPtrT, data_ptr);
2573 BIND(&if_rab_gsab_typed_array);
2574 {
2575 Comment("rab gsab typed elements");
2576 Label variable_length(this), normal(this), length_check_ok(this);
2577
2578 TNode<JSTypedArray> array = CAST(object);
2580
2581 // Bounds check (incl. detachedness check).
2582 TNode<UintPtrT> length =
2583 LoadVariableLengthJSTypedArrayLength(array, buffer, miss);
2584 Branch(UintPtrLessThan(intptr_index, length), &length_check_ok,
2585 out_of_bounds);
2586 BIND(&length_check_ok);
2587 {
2588 if (access_mode == LoadAccessMode::kHas) {
2589 exit_point->Return(TrueConstant());
2590 } else {
2591 data_ptr = LoadJSTypedArrayDataPtr(array);
2592 Label* elements_kind_labels[] = {
2593 &uint8_elements, &uint8_elements, &int8_elements,
2594 &uint16_elements, &int16_elements, &uint32_elements,
2595 &int32_elements, &float32_elements, &float64_elements,
2596 &bigint64_elements, &biguint64_elements, &float16_elements,
2597 };
2598 int32_t elements_kinds[] = {
2599 RAB_GSAB_UINT8_ELEMENTS, RAB_GSAB_UINT8_CLAMPED_ELEMENTS,
2600 RAB_GSAB_INT8_ELEMENTS, RAB_GSAB_UINT16_ELEMENTS,
2601 RAB_GSAB_INT16_ELEMENTS, RAB_GSAB_UINT32_ELEMENTS,
2602 RAB_GSAB_INT32_ELEMENTS, RAB_GSAB_FLOAT32_ELEMENTS,
2603 RAB_GSAB_FLOAT64_ELEMENTS, RAB_GSAB_BIGINT64_ELEMENTS,
2604 RAB_GSAB_BIGUINT64_ELEMENTS, RAB_GSAB_FLOAT16_ELEMENTS};
2605 const size_t kTypedElementsKindCount =
2608 DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
2609 DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
2610 Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
2611 kTypedElementsKindCount);
2612 }
2613 }
2614 }
2615 BIND(&if_typed_array);
2616 {
2617 Comment("typed elements");
2618 // Check if buffer has been detached.
2620 GotoIf(IsDetachedBuffer(buffer), miss);
2621
2622 // Bounds check.
2624 GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds);
2625 if (access_mode == LoadAccessMode::kHas) {
2626 exit_point->Return(TrueConstant());
2627 } else {
2628 data_ptr = LoadJSTypedArrayDataPtr(CAST(object));
2629
2630 Label* elements_kind_labels[] = {
2631 &uint8_elements, &uint8_elements, &int8_elements,
2632 &uint16_elements, &int16_elements, &uint32_elements,
2633 &int32_elements, &float32_elements, &float64_elements,
2634 &bigint64_elements, &biguint64_elements, &float16_elements};
2635 int32_t elements_kinds[] = {
2636 UINT8_ELEMENTS, UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
2637 UINT16_ELEMENTS, INT16_ELEMENTS, UINT32_ELEMENTS,
2638 INT32_ELEMENTS, FLOAT32_ELEMENTS, FLOAT64_ELEMENTS,
2639 BIGINT64_ELEMENTS, BIGUINT64_ELEMENTS, FLOAT16_ELEMENTS};
2640 const size_t kTypedElementsKindCount =
2643 DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
2644 DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
2645 Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
2646 kTypedElementsKindCount);
2647 }
2648 }
2649 if (access_mode != LoadAccessMode::kHas) {
2650 BIND(&uint8_elements);
2651 {
2652 Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
2653 TNode<Int32T> element = Load<Uint8T>(data_ptr.value(), intptr_index);
2654 exit_point->Return(SmiFromInt32(element));
2655 }
2656 BIND(&int8_elements);
2657 {
2658 Comment("INT8_ELEMENTS");
2659 TNode<Int32T> element = Load<Int8T>(data_ptr.value(), intptr_index);
2660 exit_point->Return(SmiFromInt32(element));
2661 }
2662 BIND(&uint16_elements);
2663 {
2664 Comment("UINT16_ELEMENTS");
2665 TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
2666 TNode<Int32T> element = Load<Uint16T>(data_ptr.value(), index);
2667 exit_point->Return(SmiFromInt32(element));
2668 }
2669 BIND(&int16_elements);
2670 {
2671 Comment("INT16_ELEMENTS");
2672 TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
2673 TNode<Int32T> element = Load<Int16T>(data_ptr.value(), index);
2674 exit_point->Return(SmiFromInt32(element));
2675 }
2676 BIND(&uint32_elements);
2677 {
2678 Comment("UINT32_ELEMENTS");
2679 TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
2680 TNode<Uint32T> element = Load<Uint32T>(data_ptr.value(), index);
2681 exit_point->Return(ChangeUint32ToTagged(element));
2682 }
2683 BIND(&int32_elements);
2684 {
2685 Comment("INT32_ELEMENTS");
2686 TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
2687 TNode<Int32T> element = Load<Int32T>(data_ptr.value(), index);
2688 exit_point->Return(ChangeInt32ToTagged(element));
2689 }
2690 BIND(&float16_elements);
2691 {
2692 Comment("FLOAT16_ELEMENTS");
2693 TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
2694 TNode<Float16RawBitsT> raw_element =
2695 Load<Float16RawBitsT>(data_ptr.value(), index);
2696 *var_double_value = ChangeFloat16ToFloat64(raw_element);
2697 Goto(rebox_double);
2698 }
2699 BIND(&float32_elements);
2700 {
2701 Comment("FLOAT32_ELEMENTS");
2702 TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
2703 TNode<Float32T> element = Load<Float32T>(data_ptr.value(), index);
2704 *var_double_value = ChangeFloat32ToFloat64(element);
2705 Goto(rebox_double);
2706 }
2707 BIND(&float64_elements);
2708 {
2709 Comment("FLOAT64_ELEMENTS");
2710 TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(3));
2711 TNode<Float64T> element = Load<Float64T>(data_ptr.value(), index);
2712 *var_double_value = element;
2713 Goto(rebox_double);
2714 }
2715 BIND(&bigint64_elements);
2716 {
2717 Comment("BIGINT64_ELEMENTS");
2719 data_ptr.value(), Unsigned(intptr_index), BIGINT64_ELEMENTS));
2720 }
2721 BIND(&biguint64_elements);
2722 {
2723 Comment("BIGUINT64_ELEMENTS");
2725 data_ptr.value(), Unsigned(intptr_index), BIGUINT64_ELEMENTS));
2726 }
2727 }
2728 }
2729 }
2730}
2731
2733 TNode<Map> map, std::optional<TNode<Uint32T>> maybe_bitfield3) {
2734 Label is_prototype(this), cont(this);
2735 TNode<Uint32T> bitfield3;
2736 if (maybe_bitfield3) {
2737 bitfield3 = maybe_bitfield3.value();
2738 } else {
2739 bitfield3 = LoadMapBitField3(map);
2740 }
2741
2742 Branch(IsSetWord32(bitfield3, Map::Bits3::IsPrototypeMapBit::kMask),
2743 &is_prototype, &cont);
2744
2745 BIND(&is_prototype);
2746 {
2747 TNode<Object> maybe_prototype_info =
2748 LoadObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
2749 // If there's no prototype info then there's nothing to invalidate.
2750 GotoIf(TaggedIsSmi(maybe_prototype_info), &cont);
2751
2753 ExternalReference::invalidate_prototype_chains_function());
2755 std::make_pair(MachineType::AnyTagged(), map));
2756 Goto(&cont);
2757 }
2758 BIND(&cont);
2759}
2760
2762 TNode<JSAnyNotSmi> lookup_start_object, TNode<Map> lookup_start_object_map,
2763 TNode<Int32T> lookup_start_object_instance_type, TNode<IntPtrT> index,
2764 Label* slow) {
2765 Comment("integer index");
2766
2767 ExitPoint direct_exit(this);
2768
2769 Label if_custom(this), if_element_hole(this), if_oob(this);
2770 Label return_undefined(this);
2771 // Receivers requiring non-standard element accesses (interceptors, access
2772 // checks, strings and string wrappers, proxies) are handled in the runtime.
2773 GotoIf(
2774 IsCustomElementsReceiverInstanceType(lookup_start_object_instance_type),
2775 &if_custom);
2776 TNode<Int32T> elements_kind = LoadMapElementsKind(lookup_start_object_map);
2777 TNode<BoolT> is_jsarray_condition =
2778 IsJSArrayInstanceType(lookup_start_object_instance_type);
2779 TVARIABLE(Float64T, var_double_value);
2780 Label rebox_double(this, &var_double_value);
2781
2782 // Unimplemented elements kinds fall back to a runtime call.
2783 Label* unimplemented_elements_kind = slow;
2784 EmitElementLoad(lookup_start_object, elements_kind, index,
2785 is_jsarray_condition, &if_element_hole, &rebox_double,
2786 &var_double_value, unimplemented_elements_kind, &if_oob, slow,
2787 &direct_exit);
2788
2789 BIND(&rebox_double);
2790#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
2791 GotoIf(IsDoubleUndefined(var_double_value.value()), &return_undefined);
2792#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
2793 Return(AllocateHeapNumberWithValue(var_double_value.value()));
2794
2795 BIND(&if_oob);
2796 {
2797 Comment("out of bounds");
2798 // On TypedArrays, all OOB loads (positive and negative) return undefined
2799 // without ever checking the prototype chain.
2800 GotoIf(IsJSTypedArrayInstanceType(lookup_start_object_instance_type),
2801 &return_undefined);
2802 // Positive OOB indices within elements index range are effectively the same
2803 // as hole loads. Larger keys and negative keys are named loads.
2804 if (Is64()) {
2807 &if_element_hole, slow);
2808 } else {
2809 Branch(IntPtrLessThan(index, IntPtrConstant(0)), slow, &if_element_hole);
2810 }
2811 }
2812
2813 BIND(&if_element_hole);
2814 {
2815 Comment("found the hole");
2816 BranchIfPrototypesHaveNoElements(lookup_start_object_map, &return_undefined,
2817 slow);
2818 }
2819
2820 BIND(&if_custom);
2821 {
2822 Comment("check if string");
2823 GotoIfNot(IsStringInstanceType(lookup_start_object_instance_type), slow);
2824 Comment("load string character");
2825 TNode<IntPtrT> length = LoadStringLengthAsWord(CAST(lookup_start_object));
2826 GotoIfNot(UintPtrLessThan(index, length), slow);
2827 TailCallBuiltin(Builtin::kStringCharAt, NoContextConstant(),
2828 lookup_start_object, index);
2829 }
2830
2831 BIND(&return_undefined);
2832 Return(UndefinedConstant());
2833}
2834
2836 TNode<JSAnyNotSmi> lookup_start_object, TNode<Map> lookup_start_object_map,
2837 TNode<Int32T> lookup_start_object_instance_type, const LoadICParameters* p,
2838 Label* slow, UseStubCache use_stub_cache) {
2839 DCHECK_EQ(lookup_start_object, p->lookup_start_object());
2840 ExitPoint direct_exit(this);
2841
2842 Comment("key is unique name");
2843 Label if_found_on_lookup_start_object(this), if_property_dictionary(this),
2844 lookup_prototype_chain(this), special_receiver(this);
2845 TVARIABLE(Uint32T, var_details);
2846 TVARIABLE(Object, var_value);
2847
2848 TNode<Name> name = CAST(p->name());
2849
2850 // Receivers requiring non-standard accesses (interceptors, access
2851 // checks, strings and string wrappers) are handled in the runtime.
2852 GotoIf(IsSpecialReceiverInstanceType(lookup_start_object_instance_type),
2853 &special_receiver);
2854
2855 // Check if the lookup_start_object has fast or slow properties.
2856 TNode<Uint32T> bitfield3 = LoadMapBitField3(lookup_start_object_map);
2858 &if_property_dictionary);
2859
2860 {
2861 // Try looking up the property on the lookup_start_object; if unsuccessful,
2862 // look for a handler in the stub cache.
2863 TNode<DescriptorArray> descriptors =
2864 LoadMapDescriptors(lookup_start_object_map);
2865
2866 Label if_descriptor_found(this), try_stub_cache(this);
2867 TVARIABLE(IntPtrT, var_name_index);
2868 Label* notfound = use_stub_cache == kUseStubCache ? &try_stub_cache
2869 : &lookup_prototype_chain;
2870 DescriptorLookup(name, descriptors, bitfield3, &if_descriptor_found,
2871 &var_name_index, notfound);
2872
2873 BIND(&if_descriptor_found);
2874 {
2875 LoadPropertyFromFastObject(lookup_start_object, lookup_start_object_map,
2876 descriptors, var_name_index.value(),
2877 &var_details, &var_value);
2878 Goto(&if_found_on_lookup_start_object);
2879 }
2880
2881 if (use_stub_cache == kUseStubCache) {
2882 DCHECK_EQ(lookup_start_object, p->receiver_and_lookup_start_object());
2883 Label stub_cache(this);
2884 BIND(&try_stub_cache);
2885 // When there is no feedback vector don't use stub cache.
2886 GotoIfNot(IsUndefined(p->vector()), &stub_cache);
2887 // Fall back to the slow path for private symbols.
2888 Branch(IsPrivateSymbol(name), slow, &lookup_prototype_chain);
2889
2890 BIND(&stub_cache);
2891 Comment("stub cache probe for fast property load");
2892 TVARIABLE(MaybeObject, var_handler);
2893 Label found_handler(this, &var_handler), stub_cache_miss(this);
2894 TryProbeStubCache(isolate()->load_stub_cache(), lookup_start_object,
2895 lookup_start_object_map, name, &found_handler,
2896 &var_handler, &stub_cache_miss);
2897 BIND(&found_handler);
2898 {
2899 LazyLoadICParameters lazy_p(p);
2900 HandleLoadICHandlerCase(&lazy_p, var_handler.value(), &stub_cache_miss,
2901 &direct_exit);
2902 }
2903
2904 BIND(&stub_cache_miss);
2905 {
2906 // TODO(jkummerow): Check if the property exists on the prototype
2907 // chain. If it doesn't, then there's no point in missing.
2908 Comment("KeyedLoadGeneric_miss");
2909 TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context(),
2910 p->receiver_and_lookup_start_object(), name, p->slot(),
2911 p->vector());
2912 }
2913 }
2914 }
2915
2916 BIND(&if_property_dictionary);
2917 {
2918 Comment("dictionary property load");
2919 // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
2920 // seeing global objects here (which would need special handling).
2921
2922 TVARIABLE(IntPtrT, var_name_index);
2923 Label dictionary_found(this, &var_name_index);
2924 TNode<PropertyDictionary> properties =
2925 CAST(LoadSlowProperties(CAST(lookup_start_object)));
2927 &dictionary_found, &var_name_index,
2928 &lookup_prototype_chain);
2929 BIND(&dictionary_found);
2930 {
2932 properties, var_name_index.value(), &var_details, &var_value);
2933 Goto(&if_found_on_lookup_start_object);
2934 }
2935 }
2936
2937 BIND(&if_found_on_lookup_start_object);
2938 {
2940 var_value.value(), CAST(lookup_start_object), var_details.value(),
2941 p->context(), p->receiver(), p->name(), slow);
2942 Return(value);
2943 }
2944
2945 BIND(&lookup_prototype_chain);
2946 {
2947 TVARIABLE(Map, var_holder_map);
2948 TVARIABLE(Int32T, var_holder_instance_type);
2949 Label return_undefined(this), is_private_symbol(this);
2950 Label loop(this, {&var_holder_map, &var_holder_instance_type});
2951
2952 var_holder_map = lookup_start_object_map;
2953 var_holder_instance_type = lookup_start_object_instance_type;
2954 GotoIf(IsPrivateSymbol(name), &is_private_symbol);
2955
2956 Goto(&loop);
2957 BIND(&loop);
2958 {
2959 // Bailout if it can be an integer indexed exotic case.
2960 GotoIf(InstanceTypeEqual(var_holder_instance_type.value(),
2961 JS_TYPED_ARRAY_TYPE),
2962 slow);
2963 TNode<HeapObject> proto = LoadMapPrototype(var_holder_map.value());
2964 GotoIf(TaggedEqual(proto, NullConstant()), &return_undefined);
2965 TNode<Map> proto_map = LoadMap(proto);
2966 TNode<Uint16T> proto_instance_type = LoadMapInstanceType(proto_map);
2967 var_holder_map = proto_map;
2968 var_holder_instance_type = proto_instance_type;
2969 Label next_proto(this), return_value(this, &var_value), goto_slow(this);
2970 TryGetOwnProperty(p->context(), p->receiver(), CAST(proto), proto_map,
2971 proto_instance_type, name, &return_value, &var_value,
2972 &next_proto, &goto_slow);
2973
2974 // This trampoline and the next are required to appease Turbofan's
2975 // variable merging.
2976 BIND(&next_proto);
2977 Goto(&loop);
2978
2979 BIND(&goto_slow);
2980 Goto(slow);
2981
2982 BIND(&return_value);
2983 Return(var_value.value());
2984 }
2985
2986 BIND(&is_private_symbol);
2987 {
2988 CSA_DCHECK(this, IsPrivateSymbol(name));
2989
2990 // For private names that don't exist on the receiver, we bail
2991 // to the runtime to throw. For private symbols, we just return
2992 // undefined.
2993 Branch(IsPrivateName(CAST(name)), slow, &return_undefined);
2994 }
2995
2996 BIND(&return_undefined);
2997 Return(UndefinedConstant());
2998 }
2999
3000 BIND(&special_receiver);
3001 {
3002 // TODO(ishell): Consider supporting WasmObjects.
3003 // TODO(jkummerow): Consider supporting JSModuleNamespace.
3004 GotoIfNot(
3005 InstanceTypeEqual(lookup_start_object_instance_type, JS_PROXY_TYPE),
3006 slow);
3007
3008 // Private field/symbol lookup is not supported.
3009 GotoIf(IsPrivateSymbol(name), slow);
3010
3011 direct_exit.ReturnCallBuiltin(Builtin::kProxyGetProperty, p->context(),
3012 lookup_start_object, name, p->receiver(),
3014 }
3015}
3016
3018
3023
3025 TNode<Map> map) {
3026 // Compute the hash of the name (use entire hash field).
3027 TNode<Uint32T> raw_hash_field = LoadNameRawHash(name);
3028 CSA_DCHECK(this,
3029 Word32Equal(Word32And(raw_hash_field,
3031 Int32Constant(0)));
3032
3033 // Using only the low bits in 64-bit mode is unlikely to increase the
3034 // risk of collision even if the heap is spread over an area larger than
3035 // 4Gb (and not at all if it isn't).
3036 TNode<IntPtrT> map_word = BitcastTaggedToWord(map);
3037
3039 WordXor(map_word, WordShr(map_word, StubCache::kPrimaryTableBits))));
3040 // Base the offset on a simple combination of name and map.
3041 TNode<Word32T> hash = Int32Add(raw_hash_field, map32);
3042 uint32_t mask = (StubCache::kPrimaryTableSize - 1)
3046 return Signed(result);
3047}
3048
3050 TNode<Map> map) {
3051 // See v8::internal::StubCache::SecondaryOffset().
3052
3053 // Use the seed from the primary cache in the secondary cache.
3056 // Base the offset on a simple combination of name and map.
3057 TNode<Word32T> hash_a = Int32Add(map32, name32);
3059 TNode<Word32T> hash = Int32Add(hash_a, hash_b);
3060 int32_t mask = (StubCache::kSecondaryTableSize - 1)
3064 return Signed(result);
3065}
3066
3068 StubCache* stub_cache, StubCacheTable table_id, TNode<IntPtrT> entry_offset,
3069 TNode<Object> name, TNode<Map> map, Label* if_handler,
3070 TVariable<MaybeObject>* var_handler, Label* if_miss) {
3071 StubCache::Table table = static_cast<StubCache::Table>(table_id);
3072 // The {table_offset} holds the entry offset times four (due to masking
3073 // and shifting optimizations).
3074 const int kMultiplier =
3076 entry_offset = IntPtrMul(entry_offset, IntPtrConstant(kMultiplier));
3077
3079 ExternalReference::Create(stub_cache->key_reference(table)));
3080
3081 // Check that the key in the entry matches the name.
3082 DCHECK_EQ(0, offsetof(StubCache::Entry, key));
3083 TNode<HeapObject> cached_key =
3084 CAST(Load(MachineType::TaggedPointer(), key_base, entry_offset));
3085 GotoIf(TaggedNotEqual(name, cached_key), if_miss);
3086
3087 // Check that the map in the entry matches.
3088 TNode<Object> cached_map = Load<Object>(
3089 key_base,
3090 IntPtrAdd(entry_offset, IntPtrConstant(offsetof(StubCache::Entry, map))));
3091 GotoIf(TaggedNotEqual(map, cached_map), if_miss);
3092
3094 Load(MachineType::AnyTagged(), key_base,
3095 IntPtrAdd(entry_offset,
3096 IntPtrConstant(offsetof(StubCache::Entry, value)))));
3097
3098 // We found the handler.
3099 *var_handler = handler;
3100 Goto(if_handler);
3101}
3102
3104 TNode<JSAny> lookup_start_object,
3105 TNode<Map> lookup_start_object_map,
3106 TNode<Name> name, Label* if_handler,
3107 TVariable<MaybeObject>* var_handler,
3108 Label* if_miss) {
3109 Label try_secondary(this), miss(this);
3110
3111 Counters* counters = isolate()->counters();
3112 IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
3113
3114 // Probe the primary table.
3115 TNode<IntPtrT> primary_offset =
3116 StubCachePrimaryOffset(name, lookup_start_object_map);
3117 TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name,
3118 lookup_start_object_map, if_handler, var_handler,
3119 &try_secondary);
3120
3121 BIND(&try_secondary);
3122 {
3123 // Probe the secondary table.
3124 TNode<IntPtrT> secondary_offset =
3125 StubCacheSecondaryOffset(name, lookup_start_object_map);
3126 TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name,
3127 lookup_start_object_map, if_handler, var_handler,
3128 &miss);
3129 }
3130
3131 BIND(&miss);
3132 {
3133 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
3134 Goto(if_miss);
3135 }
3136}
3137
3139
3141 ExitPoint* exit_point) {
3142 // Must be kept in sync with LoadIC.
3143
3144 // This function is hand-tuned to omit frame construction for common cases,
3145 // e.g.: monomorphic field and constant loads through smi handlers.
3146 // Polymorphic ICs with a hit in the first two entries also omit frames.
3147 // TODO(jgruber): Frame omission is fragile and can be affected by minor
3148 // changes in control flow and logic. We currently have no way of ensuring
3149 // that no frame is constructed, so it's easy to break this optimization by
3150 // accident.
3151 Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred),
3152 no_feedback(this, Label::kDeferred);
3153
3154 GotoIf(IsUndefined(p->vector()), &no_feedback);
3155
3156 TNode<Map> lookup_start_object_map =
3158
3159 // Inlined fast path.
3160 {
3161 Comment("LoadIC_BytecodeHandler_fast");
3162
3163 TVARIABLE(MaybeObject, var_handler);
3164 Label try_polymorphic(this), if_handler(this, &var_handler);
3165
3166 TNode<HeapObjectReference> weak_lookup_start_object_map =
3167 MakeWeak(lookup_start_object_map);
3169 p->slot(), CAST(p->vector()), weak_lookup_start_object_map, &if_handler,
3170 &var_handler, &try_polymorphic);
3171
3172 BIND(&if_handler);
3173 HandleLoadICHandlerCase(p, var_handler.value(), &miss, exit_point);
3174
3175 BIND(&try_polymorphic);
3176 {
3177 TNode<HeapObject> strong_feedback =
3178 GetHeapObjectIfStrong(feedback, &miss);
3179 GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &stub_call);
3180 HandlePolymorphicCase(weak_lookup_start_object_map, CAST(strong_feedback),
3181 &if_handler, &var_handler, &miss);
3182 }
3183 }
3184
3185 BIND(&stub_call);
3186 {
3187 Comment("LoadIC_BytecodeHandler_noninlined");
3188
3189 // Call into the stub that implements the non-inlined parts of LoadIC.
3190 exit_point->ReturnCallBuiltin(Builtin::kLoadIC_Noninlined, p->context(),
3192 p->name(), p->slot(), p->vector());
3193 }
3194
3195 BIND(&no_feedback);
3196 {
3197 Comment("LoadIC_BytecodeHandler_nofeedback");
3198 // Call into the stub that implements the non-inlined parts of LoadIC.
3199 exit_point->ReturnCallBuiltin(Builtin::kLoadIC_NoFeedback, p->context(),
3200 p->receiver(), p->name(),
3202 }
3203
3204 BIND(&miss);
3205 {
3206 Comment("LoadIC_BytecodeHandler_miss");
3207
3208 exit_point->ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context(),
3209 p->receiver(), p->name(), p->slot(),
3210 p->vector());
3211 }
3212}
3213
3215 // Must be kept in sync with LoadIC_BytecodeHandler.
3216
3217 ExitPoint direct_exit(this);
3218
3219 TVARIABLE(MaybeObject, var_handler);
3220 Label if_handler(this, &var_handler), non_inlined(this, Label::kDeferred),
3221 try_polymorphic(this), miss(this, Label::kDeferred),
3222 no_feedback(this, Label::kDeferred);
3223
3224 TNode<Map> lookup_start_object_map =
3226
3227 GotoIf(IsUndefined(p->vector()), &no_feedback);
3228
3229 // Check monomorphic case.
3230 TNode<HeapObjectReference> weak_lookup_start_object_map =
3231 MakeWeak(lookup_start_object_map);
3233 p->slot(), CAST(p->vector()), weak_lookup_start_object_map, &if_handler,
3234 &var_handler, &try_polymorphic);
3235 BIND(&if_handler);
3236 {
3237 LazyLoadICParameters lazy_p(p);
3238 HandleLoadICHandlerCase(&lazy_p, var_handler.value(), &miss, &direct_exit);
3239 }
3240
3241 BIND(&try_polymorphic);
3242 TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3243 {
3244 // Check polymorphic case.
3245 Comment("LoadIC_try_polymorphic");
3246 GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &non_inlined);
3247 HandlePolymorphicCase(weak_lookup_start_object_map, CAST(strong_feedback),
3248 &if_handler, &var_handler, &miss);
3249 }
3250
3251 BIND(&non_inlined);
3252 {
3253 LoadIC_Noninlined(p, lookup_start_object_map, strong_feedback, &var_handler,
3254 &if_handler, &miss, &direct_exit);
3255 }
3256
3257 BIND(&no_feedback);
3258 {
3259 Comment("LoadIC_nofeedback");
3260 // Call into the stub that implements the non-inlined parts of LoadIC.
3261 direct_exit.ReturnCallBuiltin(Builtin::kLoadIC_NoFeedback, p->context(),
3262 p->receiver(), p->name(),
3264 }
3265
3266 BIND(&miss);
3267 direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context(),
3269 p->name(), p->slot(), p->vector());
3270}
3271
3273 ExitPoint direct_exit(this);
3274
3275 TVARIABLE(MaybeObject, var_handler);
3276 Label if_handler(this, &var_handler), no_feedback(this),
3277 non_inlined(this, Label::kDeferred), try_polymorphic(this),
3278 miss(this, Label::kDeferred);
3279
3280 GotoIf(IsUndefined(p->vector()), &no_feedback);
3281
3282 // The lookup start object cannot be a SMI, since it's the home object's
3283 // prototype, and it's not possible to set SMIs as prototypes.
3284 TNode<Map> lookup_start_object_map = LoadMap(CAST(p->lookup_start_object()));
3285 GotoIf(IsDeprecatedMap(lookup_start_object_map), &miss);
3286
3287 TNode<HeapObjectReference> weak_lookup_start_object_map =
3288 MakeWeak(lookup_start_object_map);
3290 p->slot(), CAST(p->vector()), weak_lookup_start_object_map, &if_handler,
3291 &var_handler, &try_polymorphic);
3292
3293 BIND(&if_handler);
3294 {
3295 LazyLoadICParameters lazy_p(p);
3296 HandleLoadICHandlerCase(&lazy_p, var_handler.value(), &miss, &direct_exit);
3297 }
3298
3299 BIND(&no_feedback);
3301
3302 BIND(&try_polymorphic);
3303 TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3304 {
3305 Comment("LoadSuperIC_try_polymorphic");
3306 GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &non_inlined);
3307 HandlePolymorphicCase(weak_lookup_start_object_map, CAST(strong_feedback),
3308 &if_handler, &var_handler, &miss);
3309 }
3310
3311 BIND(&non_inlined);
3312 {
3313 // LoadIC_Noninlined can be used here, since it handles the
3314 // lookup_start_object != receiver case gracefully.
3315 LoadIC_Noninlined(p, lookup_start_object_map, strong_feedback, &var_handler,
3316 &if_handler, &miss, &direct_exit);
3317 }
3318
3319 BIND(&miss);
3320 direct_exit.ReturnCallRuntime(Runtime::kLoadWithReceiverIC_Miss, p->context(),
3321 p->receiver(), p->lookup_start_object(),
3322 p->name(), p->slot(), p->vector());
3323}
3324
3326 TNode<Map> lookup_start_object_map,
3327 TNode<HeapObject> feedback,
3328 TVariable<MaybeObject>* var_handler,
3329 Label* if_handler, Label* miss,
3330 ExitPoint* exit_point) {
3331 // Not monomorphic -- this cases is handled in the bytecode handler.
3332 CSA_DCHECK(this, TaggedNotEqual(lookup_start_object_map, feedback));
3333 CSA_DCHECK(this, Word32BinaryNot(IsWeakFixedArrayMap(LoadMap(feedback))));
3335
3336 {
3337 Label try_megamorphic(this), try_megadom(this);
3338 GotoIf(TaggedEqual(feedback, MegamorphicSymbolConstant()),
3339 &try_megamorphic);
3340 GotoIf(TaggedEqual(feedback, MegaDOMSymbolConstant()), &try_megadom);
3341 Goto(miss);
3342
3343 BIND(&try_megamorphic);
3344 {
3345 TryProbeStubCache(isolate()->load_stub_cache(), p->lookup_start_object(),
3346 lookup_start_object_map, CAST(p->name()), if_handler,
3347 var_handler, miss);
3348 }
3349
3350 BIND(&try_megadom);
3351 {
3352 TryMegaDOMCase(p->lookup_start_object(), lookup_start_object_map,
3353 var_handler, p->vector(), p->slot(), miss, exit_point);
3354 }
3355 }
3356}
3357
3359 TNode<Smi> ic_kind) {
3360 Label miss(this, Label::kDeferred);
3361 TNode<Object> lookup_start_object = p->receiver_and_lookup_start_object();
3362 GotoIf(TaggedIsSmi(lookup_start_object), &miss);
3363 TNode<Map> lookup_start_object_map = LoadMap(CAST(lookup_start_object));
3364 GotoIf(IsDeprecatedMap(lookup_start_object_map), &miss);
3365
3366 TNode<Uint16T> instance_type = LoadMapInstanceType(lookup_start_object_map);
3367
3368 {
3369 // Special case for Function.prototype load, because it's very common
3370 // for ICs that are only executed once (MyFunc.prototype.foo = ...).
3371 Label not_function_prototype(this, Label::kDeferred);
3372 GotoIfNot(IsJSFunctionInstanceType(instance_type), &not_function_prototype);
3373 GotoIfNot(IsPrototypeString(p->name()), &not_function_prototype);
3374
3375 GotoIfPrototypeRequiresRuntimeLookup(CAST(lookup_start_object),
3376 lookup_start_object_map,
3377 &not_function_prototype);
3378 Return(LoadJSFunctionPrototype(CAST(lookup_start_object), &miss));
3379 BIND(&not_function_prototype);
3380 }
3381
3382 GenericPropertyLoad(CAST(lookup_start_object), lookup_start_object_map,
3383 instance_type, p, &miss, kDontUseStubCache);
3384
3385 BIND(&miss);
3386 {
3387 TailCallRuntime(Runtime::kLoadNoFeedbackIC_Miss, p->context(),
3388 p->receiver(), p->name(), ic_kind);
3389 }
3390}
3391
3393 Label miss(this, Label::kDeferred);
3394 TNode<Object> lookup_start_object = p->lookup_start_object();
3395
3396 // The lookup start object cannot be a SMI, since it's the home object's
3397 // prototype, and it's not possible to set SMIs as prototypes.
3398 TNode<Map> lookup_start_object_map = LoadMap(CAST(lookup_start_object));
3399 GotoIf(IsDeprecatedMap(lookup_start_object_map), &miss);
3400
3401 TNode<Uint16T> instance_type = LoadMapInstanceType(lookup_start_object_map);
3402
3403 GenericPropertyLoad(CAST(lookup_start_object), lookup_start_object_map,
3404 instance_type, p, &miss, kDontUseStubCache);
3405
3406 BIND(&miss);
3407 {
3408 TailCallRuntime(Runtime::kLoadWithReceiverNoFeedbackIC_Miss, p->context(),
3409 p->receiver(), p->lookup_start_object(), p->name());
3410 }
3411}
3412
3414 const LazyNode<TaggedIndex>& lazy_slot,
3415 const LazyNode<Context>& lazy_context,
3416 const LazyNode<Name>& lazy_name,
3417 TypeofMode typeof_mode,
3418 ExitPoint* exit_point) {
3419 Label try_handler(this, Label::kDeferred), miss(this, Label::kDeferred),
3420 no_feedback(this, Label::kDeferred);
3421
3422 GotoIf(IsUndefined(maybe_feedback_vector), &no_feedback);
3423 {
3424 TNode<TaggedIndex> slot = lazy_slot();
3425
3426 {
3427 TNode<FeedbackVector> vector = CAST(maybe_feedback_vector);
3428 LoadGlobalIC_TryPropertyCellCase(vector, slot, lazy_context, exit_point,
3429 &try_handler, &miss);
3430
3431 BIND(&try_handler);
3432 LoadGlobalIC_TryHandlerCase(vector, slot, lazy_context, lazy_name,
3433 typeof_mode, exit_point, &miss);
3434 }
3435
3436 BIND(&miss);
3437 {
3438 Comment("LoadGlobalIC_MissCase");
3439 TNode<Context> context = lazy_context();
3440 TNode<Name> name = lazy_name();
3441 exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, context, name,
3442 slot, maybe_feedback_vector,
3443 SmiConstant(typeof_mode));
3444 }
3445 }
3446
3447 BIND(&no_feedback);
3448 {
3449 int ic_kind =
3450 static_cast<int>((typeof_mode == TypeofMode::kInside)
3453 exit_point->ReturnCallBuiltin(Builtin::kLoadGlobalIC_NoFeedback,
3454 lazy_context(), lazy_name(),
3455 SmiConstant(ic_kind));
3456 }
3457}
3458
3461 const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
3462 Label* try_handler, Label* miss) {
3463 Comment("LoadGlobalIC_TryPropertyCellCase");
3464
3465 Label if_lexical_var(this), if_property_cell(this);
3466 TNode<MaybeObject> maybe_weak_ref = LoadFeedbackVectorSlot(vector, slot);
3467 Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_property_cell);
3468
3469 BIND(&if_property_cell);
3470 {
3471 // This branch also handles the "handler mode": the weak reference is
3472 // cleared, the feedback extra is the handler. In that case we jump to
3473 // try_handler. (See FeedbackNexus::ConfigureHandlerMode.)
3474 CSA_DCHECK(this, IsWeakOrCleared(maybe_weak_ref));
3475 TNode<PropertyCell> property_cell =
3476 CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, try_handler));
3477 TNode<Object> value =
3478 LoadObjectField(property_cell, PropertyCell::kValueOffset);
3479 GotoIf(TaggedEqual(value, PropertyCellHoleConstant()), miss);
3480 exit_point->Return(value);
3481 }
3482
3483 BIND(&if_lexical_var);
3484 {
3485 // This branch handles the "lexical variable mode": the feedback is a SMI
3486 // encoding the variable location. (See
3487 // FeedbackNexus::ConfigureLexicalVarMode.)
3488 Comment("Load lexical variable");
3489 TNode<IntPtrT> lexical_handler = SmiUntag(CAST(maybe_weak_ref));
3490 TNode<IntPtrT> context_index =
3492 TNode<IntPtrT> slot_index =
3494 TNode<Context> context = lazy_context();
3495 TNode<Context> script_context = LoadScriptContext(context, context_index);
3496 TNode<Object> result = LoadScriptContextElement(script_context, slot_index);
3497 exit_point->Return(result);
3498 }
3499}
3500
3503 const LazyNode<Context>& lazy_context, const LazyNode<Name>& lazy_name,
3504 TypeofMode typeof_mode, ExitPoint* exit_point, Label* miss) {
3505 Comment("LoadGlobalIC_TryHandlerCase");
3506
3507 Label call_handler(this), non_smi(this);
3508
3509 TNode<MaybeObject> feedback_element =
3510 LoadFeedbackVectorSlot(vector, slot, kTaggedSize);
3511 TNode<Object> handler = CAST(feedback_element);
3512 GotoIf(TaggedEqual(handler, UninitializedSymbolConstant()), miss);
3513
3514 OnNonExistent on_nonexistent = typeof_mode == TypeofMode::kNotInside
3517
3518 TNode<Context> context = lazy_context();
3521 CAST(LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX));
3522 TNode<JSAny> global =
3523 CAST(LoadContextElement(native_context, Context::EXTENSION_INDEX));
3524
3525 LazyLoadICParameters p([=] { return context; }, receiver, lazy_name,
3526 [=] { return slot; }, vector, global);
3527
3528 HandleLoadICHandlerCase(&p, handler, miss, exit_point, ICMode::kGlobalIC,
3529 on_nonexistent);
3530}
3531
3534 Label* not_found) {
3535 TNode<ScriptContextTable> script_context_table = CAST(
3536 LoadContextElement(native_context, Context::SCRIPT_CONTEXT_TABLE_INDEX));
3537 TVARIABLE(IntPtrT, context_index, IntPtrConstant(-1));
3538 Label loop(this, &context_index);
3540 script_context_table, offsetof(ScriptContextTable, length_))));
3541 Goto(&loop);
3542
3543 BIND(&loop);
3544 {
3545 context_index = IntPtrAdd(context_index.value(), IntPtrConstant(1));
3546 GotoIf(IntPtrGreaterThanOrEqual(context_index.value(), num_script_contexts),
3547 not_found);
3548
3549 TNode<Context> script_context =
3550 LoadArrayElement(script_context_table, context_index.value());
3551 TNode<ScopeInfo> scope_info =
3552 CAST(LoadContextElement(script_context, Context::SCOPE_INFO_INDEX));
3553
3554 TNode<IntPtrT> context_local_index =
3555 IndexOfLocalName(scope_info, name, &loop);
3556
3557 TNode<IntPtrT> var_index =
3559 context_local_index);
3560 TNode<Object> result = LoadScriptContextElement(script_context, var_index);
3561 GotoIf(IsTheHole(result), found_hole);
3562 Return(result);
3563 }
3564}
3565
3567 TNode<Object> name,
3568 TNode<Smi> smi_typeof_mode) {
3570 Label regular_load(this), throw_reference_error(this, Label::kDeferred);
3571
3572 GotoIfNot(IsString(CAST(name)), &regular_load);
3573 ScriptContextTableLookup(CAST(name), native_context, &throw_reference_error,
3574 &regular_load);
3575
3576 BIND(&throw_reference_error);
3577 Return(CallRuntime(Runtime::kThrowReferenceError, context, name));
3578
3579 BIND(&regular_load);
3580 TNode<JSGlobalObject> global_object =
3581 CAST(LoadContextElement(native_context, Context::EXTENSION_INDEX));
3582 TailCallBuiltin(Builtin::kLoadIC_NoFeedback, context, global_object, name,
3583 smi_typeof_mode);
3584}
3585
3587 LoadAccessMode access_mode) {
3588 ExitPoint direct_exit(this);
3589
3590 TVARIABLE(MaybeObject, var_handler);
3591 Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred),
3592 try_megamorphic(this, Label::kDeferred),
3593 try_uninitialized(this, Label::kDeferred),
3594 try_polymorphic_name(this, Label::kDeferred),
3595 miss(this, Label::kDeferred), generic(this, Label::kDeferred);
3596
3597 TNode<Map> lookup_start_object_map =
3599 GotoIf(IsDeprecatedMap(lookup_start_object_map), &miss);
3600
3601 TryEnumeratedKeyedLoad(p, lookup_start_object_map, &direct_exit);
3602
3603 GotoIf(IsUndefined(p->vector()), &generic);
3604
3605 // Check monomorphic case.
3606 TNode<HeapObjectReference> weak_lookup_start_object_map =
3607 MakeWeak(lookup_start_object_map);
3609 p->slot(), CAST(p->vector()), weak_lookup_start_object_map, &if_handler,
3610 &var_handler, &try_polymorphic);
3611 BIND(&if_handler);
3612 {
3613 LazyLoadICParameters lazy_p(p);
3615 &lazy_p, var_handler.value(), &miss, &direct_exit, ICMode::kNonGlobalIC,
3617 }
3618
3619 BIND(&try_polymorphic);
3620 TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3621 {
3622 // Check polymorphic case.
3623 Comment("KeyedLoadIC_try_polymorphic");
3624 GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
3625 HandlePolymorphicCase(weak_lookup_start_object_map, CAST(strong_feedback),
3626 &if_handler, &var_handler, &miss);
3627 }
3628
3629 BIND(&try_megamorphic);
3630 {
3631 // Check megamorphic case.
3632 Comment("KeyedLoadIC_try_megamorphic");
3633 Branch(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()), &generic,
3634 &try_uninitialized);
3635 }
3636
3637 BIND(&generic);
3638 {
3639 // TODO(jkummerow): Inline this? Or some of it?
3641 access_mode == LoadAccessMode::kLoad ? Builtin::kKeyedLoadIC_Megamorphic
3642 : Builtin::kKeyedHasIC_Megamorphic,
3643 p->context(), p->receiver(), p->name(), p->slot(), p->vector());
3644 }
3645
3646 BIND(&try_uninitialized);
3647 {
3648 // Check uninitialized case.
3649 Comment("KeyedLoadIC_try_uninitialized");
3650 Branch(TaggedEqual(strong_feedback, UninitializedSymbolConstant()), &miss,
3651 &try_polymorphic_name);
3652 }
3653
3654 BIND(&try_polymorphic_name);
3655 {
3656 // We might have a name in feedback, and a weak fixed array in the next
3657 // slot.
3658 Comment("KeyedLoadIC_try_polymorphic_name");
3659 TVARIABLE(Name, var_name);
3660 Label if_polymorphic_name(this), feedback_matches(this),
3661 if_internalized(this), if_notinternalized(this, Label::kDeferred);
3662
3663 // Fast-case: The recorded {feedback} matches the {name}.
3664 GotoIf(TaggedEqual(strong_feedback, p->name()), &feedback_matches);
3665
3666 {
3667 // Try to internalize the {name} if it isn't already.
3668 TVARIABLE(IntPtrT, var_index);
3669 TryToName(p->name(), &miss, &var_index, &if_internalized, &var_name,
3670 &miss, &if_notinternalized);
3671 }
3672
3673 BIND(&if_internalized);
3674 {
3675 // The {var_name} now contains a unique name.
3676 Branch(TaggedEqual(strong_feedback, var_name.value()),
3677 &if_polymorphic_name, &miss);
3678 }
3679
3680 BIND(&if_notinternalized);
3681 {
3682 TVARIABLE(IntPtrT, var_index);
3683 TryInternalizeString(CAST(p->name()), &miss, &var_index, &if_internalized,
3684 &var_name, &miss, &miss);
3685 }
3686
3687 BIND(&feedback_matches);
3688 {
3689 var_name = CAST(p->name());
3690 Goto(&if_polymorphic_name);
3691 }
3692
3693 BIND(&if_polymorphic_name);
3694 {
3695 // If the name comparison succeeded, we know we have a weak fixed array
3696 // with at least one map/handler pair.
3698 ? Builtin::kKeyedLoadIC_PolymorphicName
3699 : Builtin::kKeyedHasIC_PolymorphicName,
3700 p->context(), p->receiver(), var_name.value(), p->slot(),
3701 p->vector());
3702 }
3703 }
3704
3705 BIND(&miss);
3706 {
3707 Comment("KeyedLoadIC_miss");
3709 access_mode == LoadAccessMode::kLoad ? Runtime::kKeyedLoadIC_Miss
3710 : Runtime::kKeyedHasIC_Miss,
3711 p->context(), p->receiver(), p->name(), p->slot(), p->vector());
3712 }
3713}
3714
3716 TVARIABLE(Object, var_name, p->name());
3717
3718 Label if_runtime(this, Label::kDeferred);
3719 TNode<Object> lookup_start_object = p->lookup_start_object();
3720 GotoIf(TaggedIsSmi(lookup_start_object), &if_runtime);
3721 GotoIf(IsNullOrUndefined(lookup_start_object), &if_runtime);
3722
3723 {
3724 TVARIABLE(IntPtrT, var_index);
3725 TVARIABLE(Name, var_unique);
3726 Label if_index(this), if_unique_name(this, &var_name), if_notunique(this),
3727 if_other(this, Label::kDeferred);
3728
3729 TryToName(var_name.value(), &if_index, &var_index, &if_unique_name,
3730 &var_unique, &if_other, &if_notunique);
3731
3732 BIND(&if_unique_name);
3733 {
3734 LoadICParameters pp(p, var_unique.value());
3735 TNode<Map> lookup_start_object_map = LoadMap(CAST(lookup_start_object));
3736 GenericPropertyLoad(CAST(lookup_start_object), lookup_start_object_map,
3737 LoadMapInstanceType(lookup_start_object_map), &pp,
3738 &if_runtime);
3739 }
3740
3741 BIND(&if_other);
3742 {
3743 var_name = CallBuiltin(Builtin::kToName, p->context(), var_name.value());
3744 TryToName(var_name.value(), &if_index, &var_index, &if_unique_name,
3745 &var_unique, &if_runtime, &if_notunique);
3746 }
3747
3748 BIND(&if_notunique);
3749 {
3750 if (v8_flags.internalize_on_the_fly) {
3751 // Ideally we could return undefined directly here if the name is not
3752 // found in the string table, i.e. it was never internalized, but that
3753 // invariant doesn't hold with named property interceptors (at this
3754 // point), so we take the {if_runtime} path instead.
3755 Label if_in_string_table(this);
3756 TryInternalizeString(CAST(var_name.value()), &if_index, &var_index,
3757 &if_in_string_table, &var_unique, &if_runtime,
3758 &if_runtime);
3759
3760 BIND(&if_in_string_table);
3761 {
3762 // TODO(bmeurer): We currently use a version of GenericPropertyLoad
3763 // here, where we don't try to probe the megamorphic stub cache
3764 // after successfully internalizing the incoming string. Past
3765 // experiments with this have shown that it causes too much traffic
3766 // on the stub cache. We may want to re-evaluate that in the future.
3767 LoadICParameters pp(p, var_unique.value());
3768 TNode<Map> lookup_start_object_map =
3769 LoadMap(CAST(lookup_start_object));
3770 GenericPropertyLoad(CAST(lookup_start_object),
3771 lookup_start_object_map,
3772 LoadMapInstanceType(lookup_start_object_map), &pp,
3773 &if_runtime, kDontUseStubCache);
3774 }
3775 } else {
3776 Goto(&if_runtime);
3777 }
3778 }
3779
3780 BIND(&if_index);
3781 {
3782 TNode<Map> lookup_start_object_map = LoadMap(CAST(lookup_start_object));
3783 GenericElementLoad(CAST(lookup_start_object), lookup_start_object_map,
3784 LoadMapInstanceType(lookup_start_object_map),
3785 var_index.value(), &if_runtime);
3786 }
3787 }
3788
3789 BIND(&if_runtime);
3790 {
3791 Comment("KeyedLoadGeneric_slow");
3792 // TODO(jkummerow): Should we use the GetProperty TF stub instead?
3793 TailCallRuntime(Runtime::kGetProperty, p->context(),
3794 p->receiver_and_lookup_start_object(), var_name.value());
3795 }
3796}
3797
3799 LoadAccessMode access_mode) {
3800 TVARIABLE(MaybeObject, var_handler);
3801 Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
3802
3803 TNode<JSAny> lookup_start_object = p->lookup_start_object();
3804 TNode<Map> lookup_start_object_map = LoadReceiverMap(lookup_start_object);
3805 TNode<Name> name = CAST(p->name());
3806 TNode<FeedbackVector> vector = CAST(p->vector());
3807 TNode<TaggedIndex> slot = p->slot();
3808 TNode<Context> context = p->context();
3809
3810 // When we get here, we know that the {name} matches the recorded
3811 // feedback name in the {vector} and can safely be used for the
3812 // LoadIC handler logic below.
3813 CSA_DCHECK(this, Word32BinaryNot(IsDeprecatedMap(lookup_start_object_map)));
3814 CSA_DCHECK(this, TaggedEqual(name, LoadFeedbackVectorSlot(vector, slot)),
3815 name, vector);
3816
3817 // Check if we have a matching handler for the {lookup_start_object_map}.
3818 TNode<MaybeObject> feedback_element =
3819 LoadFeedbackVectorSlot(vector, slot, kTaggedSize);
3820 TNode<WeakFixedArray> array = CAST(feedback_element);
3821 HandlePolymorphicCase(MakeWeak(lookup_start_object_map), array, &if_handler,
3822 &var_handler, &miss);
3823
3824 BIND(&if_handler);
3825 {
3826 ExitPoint direct_exit(this);
3827 LazyLoadICParameters lazy_p(p);
3829 &lazy_p, var_handler.value(), &miss, &direct_exit, ICMode::kNonGlobalIC,
3831 }
3832
3833 BIND(&miss);
3834 {
3835 Comment("KeyedLoadIC_miss");
3837 access_mode == LoadAccessMode::kLoad ? Runtime::kKeyedLoadIC_Miss
3838 : Runtime::kKeyedHasIC_Miss,
3839 context, p->receiver_and_lookup_start_object(), name, slot, vector);
3840 }
3841}
3842
3844 TVARIABLE(MaybeObject, var_handler,
3846
3847 Label if_handler(this, &var_handler),
3848 if_handler_from_stub_cache(this, &var_handler, Label::kDeferred),
3849 try_polymorphic(this, Label::kDeferred),
3850 try_megamorphic(this, Label::kDeferred), miss(this, Label::kDeferred),
3851 no_feedback(this, Label::kDeferred);
3852
3853 TNode<Map> receiver_map = LoadReceiverMap(p->receiver());
3854 GotoIf(IsDeprecatedMap(receiver_map), &miss);
3855
3856 GotoIf(IsUndefined(p->vector()), &no_feedback);
3857
3858 // Check monomorphic case.
3859 TNode<HeapObjectReference> weak_receiver_map = MakeWeak(receiver_map);
3861 TryMonomorphicCase(p->slot(), CAST(p->vector()), weak_receiver_map,
3862 &if_handler, &var_handler, &try_polymorphic);
3863 BIND(&if_handler);
3864 {
3865 Comment("StoreIC_if_handler");
3866 HandleStoreICHandlerCase(p, var_handler.value(), &miss,
3868 }
3869
3870 BIND(&try_polymorphic);
3871 TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3872 {
3873 // Check polymorphic case.
3874 Comment("StoreIC_try_polymorphic");
3875 GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
3876 HandlePolymorphicCase(weak_receiver_map, CAST(strong_feedback), &if_handler,
3877 &var_handler, &miss);
3878 }
3879
3880 BIND(&try_megamorphic);
3881 {
3882 // Check megamorphic case.
3883 GotoIfNot(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()), &miss);
3884
3885 TryProbeStubCache(p->stub_cache(isolate()), p->receiver(), receiver_map,
3886 CAST(p->name()), &if_handler, &var_handler, &miss);
3887 }
3888
3889 BIND(&no_feedback);
3890 {
3891 // TODO(v8:12548): refactor SetNamedIC as a subclass of StoreIC, which can
3892 // be called here and below when !p->IsDefineNamedOwn().
3893 auto builtin = p->IsDefineNamedOwn() ? Builtin::kDefineNamedOwnIC_NoFeedback
3894 : Builtin::kStoreIC_NoFeedback;
3895 TailCallBuiltin(builtin, p->context(), p->receiver(), p->name(),
3896 p->value());
3897 }
3898
3899 BIND(&miss);
3900 {
3901 auto runtime = p->IsDefineNamedOwn() ? Runtime::kDefineNamedOwnIC_Miss
3902 : Runtime::kStoreIC_Miss;
3903 TailCallRuntime(runtime, p->context(), p->value(), p->slot(), p->vector(),
3904 p->receiver(), p->name());
3905 }
3906}
3907
3909 Label no_feedback(this, Label::kDeferred), if_lexical_var(this),
3910 if_heapobject(this);
3911 GotoIf(IsUndefined(pp->vector()), &no_feedback);
3912
3913 TNode<MaybeObject> maybe_weak_ref =
3914 LoadFeedbackVectorSlot(CAST(pp->vector()), pp->slot());
3915 Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_heapobject);
3916
3917 BIND(&if_heapobject);
3918 {
3919 Label try_handler(this), miss(this, Label::kDeferred);
3920
3921 // This branch also handles the "handler mode": the weak reference is
3922 // cleared, the feedback extra is the handler. In that case we jump to
3923 // try_handler. (See FeedbackNexus::ConfigureHandlerMode.)
3924 CSA_DCHECK(this, IsWeakOrCleared(maybe_weak_ref));
3925 TNode<PropertyCell> property_cell =
3926 CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, &try_handler));
3927
3928 ExitPoint direct_exit(this);
3929 StoreGlobalIC_PropertyCellCase(property_cell, pp->value(), &direct_exit,
3930 &miss);
3931
3932 BIND(&try_handler);
3933 {
3934 Comment("StoreGlobalIC_try_handler");
3935 TNode<MaybeObject> handler =
3937
3938 GotoIf(TaggedEqual(handler, UninitializedSymbolConstant()), &miss);
3939
3940 DCHECK(pp->receiver_is_null());
3941 DCHECK(pp->flags_is_null());
3944 pp->context(),
3945 CAST(LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX)),
3946 pp->name(), pp->value(), std::nullopt, pp->slot(), pp->vector(),
3948
3949 HandleStoreICHandlerCase(&p, handler, &miss, ICMode::kGlobalIC);
3950 }
3951
3952 BIND(&miss);
3953 {
3954 TailCallRuntime(Runtime::kStoreGlobalIC_Miss, pp->context(), pp->value(),
3955 pp->slot(), pp->vector(), pp->name());
3956 }
3957 }
3958
3959 BIND(&if_lexical_var);
3960 {
3961 // This branch handles the "lexical variable mode": the feedback is a SMI
3962 // encoding the variable location. (See
3963 // FeedbackNexus::ConfigureLexicalVarMode.)
3964 Comment("Store lexical variable");
3965 TNode<IntPtrT> lexical_handler = SmiUntag(CAST(maybe_weak_ref));
3966 TNode<IntPtrT> context_index =
3968 TNode<IntPtrT> slot_index =
3970 TNode<Context> script_context =
3971 LoadScriptContext(pp->context(), context_index);
3972 StoreContextElementAndUpdateSideData(script_context, slot_index,
3973 pp->value());
3974 Return(pp->value());
3975 }
3976
3977 BIND(&no_feedback);
3978 {
3979 TailCallRuntime(Runtime::kStoreGlobalICNoFeedback_Miss, pp->context(),
3980 pp->value(), pp->name());
3981 }
3982}
3983
3985 TNode<PropertyCell> property_cell, TNode<Object> value,
3986 ExitPoint* exit_point, Label* miss) {
3987 Comment("StoreGlobalIC_TryPropertyCellCase");
3988
3989 // Load the payload of the global parameter cell. A hole indicates that
3990 // the cell has been invalidated and that the store must be handled by the
3991 // runtime.
3992 TNode<Object> cell_contents =
3993 LoadObjectField(property_cell, PropertyCell::kValueOffset);
3995 property_cell, PropertyCell::kPropertyDetailsRawOffset);
3997 CSA_DCHECK(this,
3999 Int32Constant(static_cast<int>(PropertyKind::kData))));
4000
4001 TNode<Uint32T> type =
4003
4004 Label constant(this), store(this), not_smi(this);
4005
4007 static_cast<int>(PropertyCellType::kConstant))),
4008 &constant);
4009 CSA_DCHECK(this, IsNotAnyHole(cell_contents));
4010
4012 type, Int32Constant(static_cast<int>(PropertyCellType::kMutable))),
4013 &store);
4014 CSA_DCHECK(this,
4015 Word32Or(Word32Equal(type, Int32Constant(static_cast<int>(
4017 Word32Equal(type, Int32Constant(static_cast<int>(
4019
4020 GotoIfNot(TaggedIsSmi(cell_contents), &not_smi);
4021 GotoIfNot(TaggedIsSmi(value), miss);
4022 Goto(&store);
4023
4024 BIND(&not_smi);
4025 {
4026 GotoIf(TaggedIsSmi(value), miss);
4027 TNode<Map> expected_map = LoadMap(CAST(cell_contents));
4028 TNode<Map> map = LoadMap(CAST(value));
4029 GotoIfNot(TaggedEqual(expected_map, map), miss);
4030 Goto(&store);
4031 }
4032
4033 BIND(&store);
4034 {
4035 StoreObjectField(property_cell, PropertyCell::kValueOffset, value);
4036 exit_point->Return(value);
4037 }
4038
4039 BIND(&constant);
4040 {
4041 // Since |value| is never the hole, the equality check below also handles an
4042 // invalidated property cell correctly.
4043 CSA_DCHECK(this, IsNotAnyHole(value));
4044 GotoIfNot(TaggedEqual(cell_contents, value), miss);
4045 exit_point->Return(value);
4046 }
4047}
4048
4050 Label miss(this, Label::kDeferred);
4051 {
4052 TVARIABLE(MaybeObject, var_handler);
4053
4054 Label if_handler(this, &var_handler),
4055 try_polymorphic(this, Label::kDeferred),
4056 try_megamorphic(this, Label::kDeferred),
4057 no_feedback(this, Label::kDeferred),
4058 try_polymorphic_name(this, Label::kDeferred);
4059
4060 TNode<Map> receiver_map = LoadReceiverMap(p->receiver());
4061 GotoIf(IsDeprecatedMap(receiver_map), &miss);
4062
4063 GotoIf(IsUndefined(p->vector()), &no_feedback);
4064
4065 // Check monomorphic case.
4066 TNode<HeapObjectReference> weak_receiver_map = MakeWeak(receiver_map);
4068 TryMonomorphicCase(p->slot(), CAST(p->vector()), weak_receiver_map,
4069 &if_handler, &var_handler, &try_polymorphic);
4070 BIND(&if_handler);
4071 {
4072 Comment("KeyedStoreIC_if_handler");
4073 HandleStoreICHandlerCase(p, var_handler.value(), &miss,
4075 }
4076
4077 BIND(&try_polymorphic);
4078 TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
4079 {
4080 // CheckPolymorphic case.
4081 Comment("KeyedStoreIC_try_polymorphic");
4082 GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
4083 &try_megamorphic);
4084 HandlePolymorphicCase(weak_receiver_map, CAST(strong_feedback),
4085 &if_handler, &var_handler, &miss);
4086 }
4087
4088 BIND(&try_megamorphic);
4089 {
4090 // Check megamorphic case.
4091 Comment("KeyedStoreIC_try_megamorphic");
4092 Branch(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()),
4093 &no_feedback, &try_polymorphic_name);
4094 }
4095
4096 BIND(&no_feedback);
4097 {
4098 TailCallBuiltin(Builtin::kKeyedStoreIC_Megamorphic, p->context(),
4099 p->receiver(), p->name(), p->value(), p->slot(),
4100 p->vector());
4101 }
4102
4103 BIND(&try_polymorphic_name);
4104 {
4105 // We might have a name in feedback, and a fixed array in the next slot.
4106 Comment("KeyedStoreIC_try_polymorphic_name");
4107 GotoIfNot(TaggedEqual(strong_feedback, p->name()), &miss);
4108 // If the name comparison succeeded, we know we have a feedback vector
4109 // with at least one map/handler pair.
4110 TNode<MaybeObject> feedback_element =
4112 TNode<WeakFixedArray> array = CAST(feedback_element);
4113 HandlePolymorphicCase(weak_receiver_map, array, &if_handler, &var_handler,
4114 &miss);
4115 }
4116 }
4117 BIND(&miss);
4118 {
4119 Comment("KeyedStoreIC_miss");
4120 TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context(), p->value(),
4121 p->slot(), p->vector(), p->receiver(), p->name());
4122 }
4123}
4124
4126 Label miss(this, Label::kDeferred);
4127 {
4128 {
4129 // TODO(v8:13451): Port SetFunctionName to an ic so that we can remove
4130 // the runtime call here. Potentially we may also remove the
4131 // StoreICParameters flags and have builtins:kDefineKeyedOwnIC reusing
4132 // StoreWithVectorDescriptor again.
4133 Label did_set_function_name_if_needed(this);
4134 TNode<Int32T> needs_set_function_name = Word32And(
4135 SmiToInt32(p->flags()),
4138 GotoIfNot(needs_set_function_name, &did_set_function_name_if_needed);
4139
4140 Comment("DefineKeyedOwnIC_set_function_name");
4141 CallRuntime(Runtime::kSetFunctionName, p->context(), p->value(),
4142 p->name());
4143
4144 Goto(&did_set_function_name_if_needed);
4145 BIND(&did_set_function_name_if_needed);
4146 }
4147 TVARIABLE(MaybeObject, var_handler);
4148
4149 Label if_handler(this, &var_handler),
4150 try_polymorphic(this, Label::kDeferred),
4151 try_megamorphic(this, Label::kDeferred),
4152 no_feedback(this, Label::kDeferred),
4153 try_polymorphic_name(this, Label::kDeferred);
4154
4155 TNode<Map> receiver_map = LoadReceiverMap(p->receiver());
4156 GotoIf(IsDeprecatedMap(receiver_map), &miss);
4157
4158 GotoIf(IsUndefined(p->vector()), &no_feedback);
4159
4160 // Check monomorphic case.
4161 TNode<HeapObjectReference> weak_receiver_map = MakeWeak(receiver_map);
4163 TryMonomorphicCase(p->slot(), CAST(p->vector()), weak_receiver_map,
4164 &if_handler, &var_handler, &try_polymorphic);
4165 BIND(&if_handler);
4166 {
4167 Comment("DefineKeyedOwnIC_if_handler");
4168 HandleStoreICHandlerCase(p, var_handler.value(), &miss,
4170 }
4171
4172 BIND(&try_polymorphic);
4173 TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
4174 {
4175 // CheckPolymorphic case.
4176 Comment("DefineKeyedOwnIC_try_polymorphic");
4177 GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
4178 &try_megamorphic);
4179 HandlePolymorphicCase(weak_receiver_map, CAST(strong_feedback),
4180 &if_handler, &var_handler, &miss);
4181 }
4182
4183 BIND(&try_megamorphic);
4184 {
4185 // Check megamorphic case.
4186 Comment("DefineKeyedOwnIC_try_megamorphic");
4187 Branch(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()),
4188 &no_feedback, &try_polymorphic_name);
4189 }
4190
4191 BIND(&no_feedback);
4192 {
4193 TailCallBuiltin(Builtin::kDefineKeyedOwnIC_Megamorphic, p->context(),
4194 p->receiver(), p->name(), p->value());
4195 }
4196
4197 BIND(&try_polymorphic_name);
4198 {
4199 // We might have a name in feedback, and a fixed array in the next slot.
4200 Comment("DefineKeyedOwnIC_try_polymorphic_name");
4201 GotoIfNot(TaggedEqual(strong_feedback, p->name()), &miss);
4202 // If the name comparison succeeded, we know we have a feedback vector
4203 // with at least one map/handler pair.
4204 TNode<MaybeObject> feedback_element =
4206 TNode<WeakFixedArray> array = CAST(feedback_element);
4207 HandlePolymorphicCase(weak_receiver_map, array, &if_handler, &var_handler,
4208 &miss);
4209 }
4210 }
4211 BIND(&miss);
4212 {
4213 Comment("DefineKeyedOwnIC_miss");
4214 TailCallRuntime(Runtime::kDefineKeyedOwnIC_Miss, p->context(), p->value(),
4215 p->slot(), p->vector(), p->receiver(), p->name());
4216 }
4217}
4218
4220 Label miss(this, Label::kDeferred), no_feedback(this, Label::kDeferred);
4221 {
4222 TVARIABLE(MaybeObject, var_handler);
4223
4224 Label if_handler(this, &var_handler),
4225 try_polymorphic(this, Label::kDeferred),
4226 try_megamorphic(this, Label::kDeferred);
4227
4228 TNode<Map> array_map = LoadReceiverMap(p->receiver());
4229 GotoIf(IsDeprecatedMap(array_map), &miss);
4230
4231 GotoIf(IsUndefined(p->vector()), &no_feedback);
4232
4233 TNode<HeapObjectReference> weak_array_map = MakeWeak(array_map);
4235 TryMonomorphicCase(p->slot(), CAST(p->vector()), weak_array_map,
4236 &if_handler, &var_handler, &try_polymorphic);
4237
4238 BIND(&if_handler);
4239 {
4240 Comment("StoreInArrayLiteralIC_if_handler");
4241 // This is a stripped-down version of HandleStoreICHandlerCase.
4242 Label if_transitioning_element_store(this), if_smi_handler(this);
4243
4244 // Check used to identify the Slow case.
4245 // Currently only the Slow case uses a Smi handler.
4246 GotoIf(TaggedIsSmi(var_handler.value()), &if_smi_handler);
4247
4248 TNode<HeapObject> handler = CAST(var_handler.value());
4249 GotoIfNot(IsCode(handler), &if_transitioning_element_store);
4250
4251 {
4252 // Call the handler.
4253 TNode<Code> code_handler = CAST(handler);
4254 TailCallStub(StoreWithVectorDescriptor{}, code_handler, p->context(),
4255 p->receiver(), p->name(), p->value(), p->slot(),
4256 p->vector());
4257 }
4258
4259 BIND(&if_transitioning_element_store);
4260 {
4261 TNode<MaybeObject> maybe_transition_map =
4262 LoadHandlerDataField(CAST(handler), 1);
4263 TNode<Map> transition_map =
4264 CAST(GetHeapObjectAssumeWeak(maybe_transition_map, &miss));
4265 GotoIf(IsDeprecatedMap(transition_map), &miss);
4266 TNode<Code> code = CAST(
4267 LoadObjectField(handler, offsetof(StoreHandler, smi_handler_)));
4269 p->receiver(), p->name(), transition_map, p->value(),
4270 p->slot(), p->vector());
4271 }
4272
4273 BIND(&if_smi_handler);
4274 {
4275#ifdef DEBUG
4276 // A check to ensure that no other Smi handler uses this path.
4277 TNode<Int32T> handler_word = SmiToInt32(CAST(var_handler.value()));
4278 TNode<Uint32T> handler_kind =
4280 CSA_DCHECK(this, Word32Equal(handler_kind, STORE_KIND(kSlow)));
4281#endif
4282
4283 Comment("StoreInArrayLiteralIC_Slow");
4284 TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context(),
4285 p->value(), p->receiver(), p->name());
4286 }
4287 }
4288
4289 BIND(&try_polymorphic);
4290 TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
4291 {
4292 Comment("StoreInArrayLiteralIC_try_polymorphic");
4293 GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
4294 &try_megamorphic);
4295 HandlePolymorphicCase(weak_array_map, CAST(strong_feedback), &if_handler,
4296 &var_handler, &miss);
4297 }
4298
4299 BIND(&try_megamorphic);
4300 {
4301 Comment("StoreInArrayLiteralIC_try_megamorphic");
4302 CSA_DCHECK(
4303 this,
4304 Word32Or(TaggedEqual(strong_feedback, UninitializedSymbolConstant()),
4305 TaggedEqual(strong_feedback, MegamorphicSymbolConstant())));
4306 GotoIfNot(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()),
4307 &miss);
4308 TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context(),
4309 p->value(), p->receiver(), p->name());
4310 }
4311 }
4312
4313 BIND(&no_feedback);
4314 {
4315 Comment("StoreInArrayLiteralIC_NoFeedback");
4316 TailCallBuiltin(Builtin::kCreateDataProperty, p->context(), p->receiver(),
4317 p->name(), p->value());
4318 }
4319
4320 BIND(&miss);
4321 {
4322 Comment("StoreInArrayLiteralIC_miss");
4323 TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Miss, p->context(),
4324 p->value(), p->slot(), p->vector(), p->receiver(),
4325 p->name());
4326 }
4327}
4328
4330
4333
4334 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4335 auto name = Parameter<Object>(Descriptor::kName);
4336 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4337 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4338 auto context = Parameter<Context>(Descriptor::kContext);
4339
4340 LoadICParameters p(context, receiver, name, slot, vector);
4341 LoadIC(&p);
4342}
4343
4346
4347 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4348 auto name = Parameter<Object>(Descriptor::kName);
4349 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4350 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4351 auto context = Parameter<Context>(Descriptor::kContext);
4352
4353 ExitPoint direct_exit(this);
4354 TVARIABLE(MaybeObject, var_handler);
4355 Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
4356
4358 MegamorphicSymbolConstant()));
4359
4360 TryProbeStubCache(isolate()->load_stub_cache(), receiver, CAST(name),
4361 &if_handler, &var_handler, &miss);
4362
4363 BIND(&if_handler);
4365 // lazy_context
4366 [=] { return context; }, receiver,
4367 // lazy_name
4368 [=] { return name; },
4369 // lazy_slot
4370 [=] { return slot; }, vector);
4371 HandleLoadICHandlerCase(&p, var_handler.value(), &miss, &direct_exit);
4372
4373 BIND(&miss);
4374 direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name,
4375 slot, vector);
4376}
4377
4380
4381 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4382 auto name = Parameter<Object>(Descriptor::kName);
4383 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4384 auto vector = Parameter<FeedbackVector>(Descriptor::kVector);
4385 auto context = Parameter<Context>(Descriptor::kContext);
4386
4387 ExitPoint direct_exit(this);
4388 TVARIABLE(MaybeObject, var_handler);
4389 Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
4390
4391 TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot(vector, slot);
4392 TNode<HeapObject> feedback = CAST(feedback_element);
4393
4394 LoadICParameters p(context, receiver, name, slot, vector);
4395 TNode<Map> lookup_start_object_map = LoadReceiverMap(p.lookup_start_object());
4396 LoadIC_Noninlined(&p, lookup_start_object_map, feedback, &var_handler,
4397 &if_handler, &miss, &direct_exit);
4398
4399 BIND(&if_handler);
4400 {
4401 LazyLoadICParameters lazy_p(&p);
4402 HandleLoadICHandlerCase(&lazy_p, var_handler.value(), &miss, &direct_exit);
4403 }
4404
4405 BIND(&miss);
4406 direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name,
4407 slot, vector);
4408}
4409
4412
4413 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4414 auto name = Parameter<Object>(Descriptor::kName);
4415 auto context = Parameter<Context>(Descriptor::kContext);
4416 auto ic_kind = Parameter<Smi>(Descriptor::kICKind);
4417
4418 LoadICParameters p(context, receiver, name,
4420 UndefinedConstant());
4421 LoadIC_NoFeedback(&p, ic_kind);
4422}
4423
4425 using Descriptor = LoadDescriptor;
4426
4427 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4428 auto name = Parameter<Object>(Descriptor::kName);
4429 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4430 auto context = Parameter<Context>(Descriptor::kContext);
4432
4433 TailCallBuiltin(Builtin::kLoadIC, context, receiver, name, slot, vector);
4434}
4435
4438
4439 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4440 auto name = Parameter<Object>(Descriptor::kName);
4441 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4444
4445 TailCallBuiltin(Builtin::kLoadIC, context, receiver, name, slot, vector);
4446}
4447
4449 using Descriptor = LoadDescriptor;
4450
4451 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4452 auto name = Parameter<Object>(Descriptor::kName);
4453 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4454 auto context = Parameter<Context>(Descriptor::kContext);
4456
4457 TailCallBuiltin(Builtin::kLoadIC_Megamorphic, context, receiver, name, slot,
4458 vector);
4459}
4460
4463
4464 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4465 auto lookup_start_object = Parameter<JSAny>(Descriptor::kLookupStartObject);
4466 auto name = Parameter<Object>(Descriptor::kName);
4467 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4468 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4469 auto context = Parameter<Context>(Descriptor::kContext);
4470
4471 LoadICParameters p(context, receiver, name, slot, vector,
4472 lookup_start_object);
4473 LoadSuperIC(&p);
4474}
4475
4478
4479 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4480 auto lookup_start_object = Parameter<Object>(Descriptor::kLookupStartObject);
4481 auto name = Parameter<Object>(Descriptor::kName);
4482 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4485
4486 TailCallBuiltin(Builtin::kLoadSuperIC, context, receiver, lookup_start_object,
4487 name, slot, vector);
4488}
4489
4492
4493 auto name = Parameter<Object>(Descriptor::kName);
4494 auto context = Parameter<Context>(Descriptor::kContext);
4495 auto ic_kind = Parameter<Smi>(Descriptor::kICKind);
4496
4497 LoadGlobalIC_NoFeedback(context, name, ic_kind);
4498}
4499
4502
4503 auto name = Parameter<Name>(Descriptor::kName);
4504 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4505 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4506 auto context = Parameter<Context>(Descriptor::kContext);
4507
4508 ExitPoint direct_exit(this);
4510 vector,
4511 // lazy_slot
4512 [=] { return slot; },
4513 // lazy_context
4514 [=] { return context; },
4515 // lazy_name
4516 [=] { return name; }, typeof_mode, &direct_exit);
4517}
4518
4521
4522 auto name = Parameter<Object>(Descriptor::kName);
4523 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4524 auto context = Parameter<Context>(Descriptor::kContext);
4526
4528 name, slot, vector);
4529}
4530
4533
4534 auto name = Parameter<Object>(Descriptor::kName);
4535 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4538
4540 name, slot, vector);
4541}
4542
4544 TNode<TaggedIndex> depth,
4545 LazyNode<TaggedIndex> lazy_slot,
4546 TNode<Context> context,
4547 TypeofMode typeof_mode,
4548 ContextKind context_kind) {
4549 Label slowpath(this, Label::kDeferred);
4550
4551 // Check for context extensions to allow the fast path.
4554 &slowpath);
4555
4556 // Fast path does a normal load context.
4557 {
4558 auto slot = lazy_slot();
4559 Return(
4560 context_kind == ContextKind::kScriptContext
4561 ? LoadScriptContextElement(slot_context, TaggedIndexToIntPtr(slot))
4562 : LoadContextElement(slot_context, TaggedIndexToIntPtr(slot)));
4563 }
4564
4565 // Slow path when we have to call out to the runtime.
4566 BIND(&slowpath);
4567 {
4568 auto name = lazy_name();
4569 Runtime::FunctionId function_id = typeof_mode == TypeofMode::kInside
4570 ? Runtime::kLoadLookupSlotInsideTypeof
4571 : Runtime::kLoadLookupSlot;
4572 TailCallRuntime(function_id, context, name);
4573 }
4574}
4575
4577 TypeofMode typeof_mode, ContextKind context_kind) {
4579 LookupContext([&] { return Parameter<Object>(Descriptor::kName); },
4580 Parameter<TaggedIndex>(Descriptor::kDepth),
4581 [&] { return Parameter<TaggedIndex>(Descriptor::kSlot); },
4582 Parameter<Context>(Descriptor::kContext), typeof_mode,
4583 context_kind);
4584}
4585
4587 TypeofMode typeof_mode, ContextKind context_kind) {
4589 LookupContext([&] { return Parameter<Object>(Descriptor::kName); },
4590 Parameter<TaggedIndex>(Descriptor::kDepth),
4591 [&] { return Parameter<TaggedIndex>(Descriptor::kSlot); },
4592 LoadContextFromBaseline(), typeof_mode, context_kind);
4593}
4594
4596 LazyNode<Object> lazy_name, TNode<TaggedIndex> depth,
4597 LazyNode<TaggedIndex> lazy_slot, TNode<Context> context,
4598 LazyNode<FeedbackVector> lazy_feedback_vector, TypeofMode typeof_mode) {
4599 Label slowpath(this, Label::kDeferred);
4600
4601 // Check for context extensions to allow the fast path
4604 &slowpath);
4605
4606 // Fast path does a normal load global
4607 {
4609 lazy_name(), lazy_slot(), lazy_feedback_vector());
4610 }
4611
4612 // Slow path when we have to call out to the runtime
4613 BIND(&slowpath);
4614 Runtime::FunctionId function_id = typeof_mode == TypeofMode::kInside
4615 ? Runtime::kLoadLookupSlotInsideTypeof
4616 : Runtime::kLoadLookupSlot;
4617 TailCallRuntime(function_id, context, lazy_name());
4618}
4619
4622 LookupGlobalIC([&] { return Parameter<Object>(Descriptor::kName); },
4623 Parameter<TaggedIndex>(Descriptor::kDepth),
4624 [&] { return Parameter<TaggedIndex>(Descriptor::kSlot); },
4625 Parameter<Context>(Descriptor::kContext),
4626 [&] { return Parameter<FeedbackVector>(Descriptor::kVector); },
4627 typeof_mode);
4628}
4629
4631 TypeofMode typeof_mode) {
4633 LookupGlobalIC([&] { return Parameter<Object>(Descriptor::kName); },
4634 Parameter<TaggedIndex>(Descriptor::kDepth),
4635 [&] { return Parameter<TaggedIndex>(Descriptor::kSlot); },
4636 Parameter<Context>(Descriptor::kContext),
4637 [&] { return LoadFeedbackVectorForStub(); }, typeof_mode);
4638}
4639
4642 LookupGlobalIC([&] { return Parameter<Object>(Descriptor::kName); },
4643 Parameter<TaggedIndex>(Descriptor::kDepth),
4644 [&] { return Parameter<TaggedIndex>(Descriptor::kSlot); },
4646 [&] { return LoadFeedbackVectorFromBaseline(); }, typeof_mode);
4647}
4648
4651
4652 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4653 auto name = Parameter<Object>(Descriptor::kName);
4654 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4655 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4656 auto context = Parameter<Context>(Descriptor::kContext);
4657
4658 LoadICParameters p(context, receiver, name, slot, vector);
4660}
4661
4664
4665 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4666 auto name = Parameter<Object>(Descriptor::kName);
4667 auto enum_index = Parameter<Smi>(Descriptor::kEnumIndex);
4668 auto cache_type = Parameter<Object>(Descriptor::kCacheType);
4669 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4670 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4671 auto context = Parameter<Context>(Descriptor::kContext);
4672 auto lookup_start_object = std::nullopt;
4673
4674 LoadICParameters p(context, receiver, name, slot, vector, lookup_start_object,
4675 enum_index, cache_type);
4677}
4678
4681
4682 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4683 auto name = Parameter<Object>(Descriptor::kName);
4684 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4685 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4686 auto context = Parameter<Context>(Descriptor::kContext);
4687
4688 LoadICParameters p(context, receiver, name, slot, vector);
4690}
4691
4694
4695 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4696 auto name = Parameter<Object>(Descriptor::kName);
4697 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4698 auto context = Parameter<Context>(Descriptor::kContext);
4700
4701 TailCallBuiltin(Builtin::kKeyedLoadIC, context, receiver, name, slot, vector);
4702}
4703
4706
4707 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4708 auto name = Parameter<Object>(Descriptor::kName);
4709 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4712
4713 TailCallBuiltin(Builtin::kKeyedLoadIC, context, receiver, name, slot, vector);
4714}
4715
4718
4719 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4720 auto name = Parameter<Object>(Descriptor::kName);
4721 auto enum_index = Parameter<Smi>(Descriptor::kEnumIndex);
4722 auto cache_type = Parameter<Object>(Descriptor::kCacheType);
4723 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4726
4727 TailCallBuiltin(Builtin::kEnumeratedKeyedLoadIC, context, receiver, name,
4728 enum_index, cache_type, slot, vector);
4729}
4730
4733
4734 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4735 auto name = Parameter<Object>(Descriptor::kName);
4736 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4737 auto context = Parameter<Context>(Descriptor::kContext);
4739
4740 TailCallBuiltin(Builtin::kKeyedLoadIC_Megamorphic, context, receiver, name,
4741 slot, vector);
4742}
4743
4746
4747 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4748 auto name = Parameter<Object>(Descriptor::kName);
4749 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4750 auto vector = Parameter<FeedbackVector>(Descriptor::kVector);
4751 auto context = Parameter<Context>(Descriptor::kContext);
4752
4753 LoadICParameters p(context, receiver, name, slot, vector);
4755}
4756
4759
4760 auto name = Parameter<Object>(Descriptor::kName);
4761 auto value = Parameter<Object>(Descriptor::kValue);
4762 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4763 auto flags = std::nullopt;
4764 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4765 auto context = Parameter<Context>(Descriptor::kContext);
4766
4767 StoreICParameters p(context, std::nullopt, name, value, flags, slot, vector,
4769 StoreGlobalIC(&p);
4770}
4771
4774
4775 auto name = Parameter<Object>(Descriptor::kName);
4776 auto value = Parameter<Object>(Descriptor::kValue);
4777 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4778 auto context = Parameter<Context>(Descriptor::kContext);
4780
4781 TailCallBuiltin(Builtin::kStoreGlobalIC, context, name, value, slot, vector);
4782}
4783
4786
4787 auto name = Parameter<Object>(Descriptor::kName);
4788 auto value = Parameter<Object>(Descriptor::kValue);
4789 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4792
4793 TailCallBuiltin(Builtin::kStoreGlobalIC, context, name, value, slot, vector);
4794}
4795
4798
4799 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4800 auto name = Parameter<Object>(Descriptor::kName);
4801 auto value = Parameter<Object>(Descriptor::kValue);
4802 auto flags = std::nullopt;
4803 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4804 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4805 auto context = Parameter<Context>(Descriptor::kContext);
4806
4807 StoreICParameters p(context, receiver, name, value, flags, slot, vector,
4809 StoreIC(&p);
4810}
4811
4814
4815 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4816 auto name = Parameter<Object>(Descriptor::kName);
4817 auto value = Parameter<Object>(Descriptor::kValue);
4818 auto flags = std::nullopt;
4819 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4820 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4821 auto context = Parameter<Context>(Descriptor::kContext);
4822
4823 ExitPoint direct_exit(this);
4824 TVARIABLE(MaybeObject, var_handler);
4825 Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
4826
4828 MegamorphicSymbolConstant()));
4829
4830 TryProbeStubCache(isolate()->store_stub_cache(), receiver, CAST(name),
4831 &if_handler, &var_handler, &miss);
4832
4833 BIND(&if_handler);
4834 {
4835 StoreICParameters p(context, receiver, name, value, flags, slot, vector,
4837 HandleStoreICHandlerCase(&p, var_handler.value(), &miss,
4839 }
4840
4841 BIND(&miss);
4842 {
4843 direct_exit.ReturnCallRuntime(Runtime::kStoreIC_Miss, context, value, slot,
4844 vector, receiver, name);
4845 }
4846}
4847
4850
4851 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4852 auto name = Parameter<Object>(Descriptor::kName);
4853 auto value = Parameter<Object>(Descriptor::kValue);
4854 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4855 auto context = Parameter<Context>(Descriptor::kContext);
4857
4858 TailCallBuiltin(Builtin::kStoreIC, context, receiver, name, value, slot,
4859 vector);
4860}
4861
4864
4865 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4866 auto name = Parameter<Object>(Descriptor::kName);
4867 auto value = Parameter<Object>(Descriptor::kValue);
4868 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4869 auto context = Parameter<Context>(Descriptor::kContext);
4871
4872 TailCallBuiltin(Builtin::kStoreIC_Megamorphic, context, receiver, name, value,
4873 slot, vector);
4874}
4875
4878
4879 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4880 auto name = Parameter<Object>(Descriptor::kName);
4881 auto value = Parameter<Object>(Descriptor::kValue);
4882 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4885
4886 TailCallBuiltin(Builtin::kStoreIC, context, receiver, name, value, slot,
4887 vector);
4888}
4889
4892
4893 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4894 auto name = Parameter<Object>(Descriptor::kName);
4895 auto value = Parameter<Object>(Descriptor::kValue);
4896 auto flags = std::nullopt;
4897 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4898 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4899 auto context = Parameter<Context>(Descriptor::kContext);
4900
4901 StoreICParameters p(context, receiver, name, value, flags, slot, vector,
4903 // StoreIC is a generic helper than handle both set and define own
4904 // named stores.
4905 StoreIC(&p);
4906}
4907
4910
4911 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4912 auto name = Parameter<Object>(Descriptor::kName);
4913 auto value = Parameter<Object>(Descriptor::kValue);
4914 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4915 auto context = Parameter<Context>(Descriptor::kContext);
4917
4918 TailCallBuiltin(Builtin::kDefineNamedOwnIC, context, receiver, name, value,
4919 slot, vector);
4920}
4921
4924
4925 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4926 auto name = Parameter<Object>(Descriptor::kName);
4927 auto value = Parameter<Object>(Descriptor::kValue);
4928 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4931
4932 TailCallBuiltin(Builtin::kDefineNamedOwnIC, context, receiver, name, value,
4933 slot, vector);
4934}
4935
4938
4939 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4940 auto name = Parameter<Object>(Descriptor::kName);
4941 auto value = Parameter<Object>(Descriptor::kValue);
4942 auto flags = std::nullopt;
4943 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4944 auto vector = Parameter<HeapObject>(Descriptor::kVector);
4945 auto context = Parameter<Context>(Descriptor::kContext);
4946
4947 StoreICParameters p(context, receiver, name, value, flags, slot, vector,
4949 KeyedStoreIC(&p);
4950}
4951
4954
4955 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4956 auto name = Parameter<Object>(Descriptor::kName);
4957 auto value = Parameter<Object>(Descriptor::kValue);
4958 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4959 auto context = Parameter<Context>(Descriptor::kContext);
4961
4962 TailCallBuiltin(Builtin::kKeyedStoreIC, context, receiver, name, value, slot,
4963 vector);
4964}
4965
4968
4969 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4970 auto name = Parameter<Object>(Descriptor::kName);
4971 auto value = Parameter<Object>(Descriptor::kValue);
4972 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4973 auto context = Parameter<Context>(Descriptor::kContext);
4975
4976 TailCallBuiltin(Builtin::kKeyedStoreIC_Megamorphic, context, receiver, name,
4977 value, slot, vector);
4978}
4979
4982
4983 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4984 auto name = Parameter<Object>(Descriptor::kName);
4985 auto value = Parameter<Object>(Descriptor::kValue);
4986 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
4989
4990 TailCallBuiltin(Builtin::kKeyedStoreIC, context, receiver, name, value, slot,
4991 vector);
4992}
4993
4996
4997 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
4998 auto name = Parameter<Object>(Descriptor::kName);
4999 auto value = Parameter<Object>(Descriptor::kValue);
5000 auto flags = Parameter<Smi>(Descriptor::kFlags);
5001 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
5002 auto vector = Parameter<HeapObject>(Descriptor::kVector);
5003 auto context = Parameter<Context>(Descriptor::kContext);
5004
5005 StoreICParameters p(context, receiver, name, value, flags, slot, vector,
5007 DefineKeyedOwnIC(&p);
5008}
5009
5012
5013 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
5014 auto name = Parameter<Object>(Descriptor::kName);
5015 auto value = Parameter<Object>(Descriptor::kValue);
5016 auto flags = Parameter<Smi>(Descriptor::kFlags);
5017 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
5018 auto context = Parameter<Context>(Descriptor::kContext);
5020
5021 TailCallBuiltin(Builtin::kDefineKeyedOwnIC, context, receiver, name, value,
5022 flags, slot, vector);
5023}
5024
5027
5028 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
5029 auto name = Parameter<Object>(Descriptor::kName);
5030 auto value = Parameter<Object>(Descriptor::kValue);
5031 auto flags = Parameter<Smi>(Descriptor::kFlags);
5032 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
5035
5036 TailCallBuiltin(Builtin::kDefineKeyedOwnIC, context, receiver, name, value,
5037 flags, slot, vector);
5038}
5039
5042
5043 auto array = Parameter<JSAny>(Descriptor::kReceiver);
5044 auto index = Parameter<Object>(Descriptor::kName);
5045 auto value = Parameter<Object>(Descriptor::kValue);
5046 auto flags = std::nullopt;
5047 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
5048 auto vector = Parameter<HeapObject>(Descriptor::kVector);
5049 auto context = Parameter<Context>(Descriptor::kContext);
5050
5051 StoreICParameters p(context, array, index, value, flags, slot, vector,
5054}
5055
5058
5059 auto array = Parameter<JSAny>(Descriptor::kReceiver);
5060 auto index = Parameter<Object>(Descriptor::kName);
5061 auto value = Parameter<Object>(Descriptor::kValue);
5062 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
5063
5066
5067 TailCallBuiltin(Builtin::kStoreInArrayLiteralIC, context, array, index, value,
5068 slot, vector);
5069}
5070
5073 auto source = Parameter<Object>(Descriptor::kSource);
5074 auto flags = Parameter<Smi>(Descriptor::kFlags);
5075 auto context = Parameter<Context>(Descriptor::kContext);
5076
5077 // The CloneObjectIC_Slow implementation uses the same call interface as
5078 // CloneObjectIC, so that it can be tail called from it. However, the feedback
5079 // slot and vector are not used.
5080
5081 // First try a fast case where we copy the properties with a CSA loop.
5082 Label try_fast_case(this), call_runtime(this, Label::kDeferred);
5083
5084 // For SMIs and non JSObjects we use 0 in object properties.
5085 TVARIABLE(IntPtrT, number_of_properties, IntPtrConstant(0));
5086 GotoIf(TaggedIsSmi(source), &try_fast_case);
5087 {
5088 TNode<Map> source_map = LoadMap(CAST(source));
5089 // We still want to stay in the semi-fast case for oddballs, strings,
5090 // proxies and such. Therefore we continue here, but using 0 in object
5091 // properties.
5092 GotoIfNot(IsJSObjectMap(source_map), &try_fast_case);
5093
5094 // At this point we don't know yet if ForEachEnumerableOwnProperty can
5095 // handle the source object. In case it is a dictionary mode object or has
5096 // non simple properties the latter will bail to `runtime_copy`. For code
5097 // compactness we don't check it here, assuming that the number of in-object
5098 // properties is set to 0 (or a reasonable value).
5099 number_of_properties = MapUsedInObjectProperties(source_map);
5100 GotoIf(IntPtrGreaterThanOrEqual(number_of_properties.value(),
5102 &call_runtime);
5103 }
5104 Goto(&try_fast_case);
5105
5106 BIND(&try_fast_case);
5108 TNode<Map> initial_map = LoadCachedMap(
5109 native_context, number_of_properties.value(), &call_runtime);
5111
5112 // Handle the case where the object literal overrides the prototype.
5113 {
5114 Label did_set_proto_if_needed(this);
5115 TNode<BoolT> is_null_proto = SmiNotEqual(
5118 GotoIfNot(is_null_proto, &did_set_proto_if_needed);
5119
5120 CallRuntime(Runtime::kInternalSetPrototype, context, result,
5121 NullConstant());
5122
5123 Goto(&did_set_proto_if_needed);
5124 BIND(&did_set_proto_if_needed);
5125 }
5126
5127 // Early return for when we know there are no properties.
5128 ReturnIf(TaggedIsSmi(source), result);
5130
5131 Label runtime_copy(this, Label::kDeferred);
5132
5133 TNode<Map> source_map = LoadMap(CAST(source));
5134 GotoIfNot(IsJSObjectMap(source_map), &runtime_copy);
5135 // Takes care of objects with elements.
5136 GotoIfNot(IsEmptyFixedArray(LoadElements(CAST(source))), &runtime_copy);
5137
5138 // TODO(olivf, chrome:1204540) This can still be several times slower than the
5139 // Babel translation. TF uses FastGetOwnValuesOrEntries -- should we do sth
5140 // similar here?
5142 context, source_map, CAST(source), kPropertyAdditionOrder,
5143 [=, this](TNode<Name> key, LazyNode<Object> value) {
5144 CreateDataProperty(context, result, key, value());
5145 },
5146 &runtime_copy);
5147 Return(result);
5148
5149 // This is the fall-back case for the above fastcase, where we allocated an
5150 // object, but failed to copy the properties in CSA.
5151 BIND(&runtime_copy);
5152 CallRuntime(Runtime::kCopyDataProperties, context, result, source);
5153 Return(result);
5154
5155 // Final fallback is to call into the runtime version.
5156 BIND(&call_runtime);
5157 Return(CallRuntime(Runtime::kCloneObjectIC_Slow, context, source, flags));
5158}
5159
5162
5163 auto source = Parameter<Object>(Descriptor::kSource);
5164 auto flags = Parameter<Smi>(Descriptor::kFlags);
5165 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
5166
5169
5170 TailCallBuiltin(Builtin::kCloneObjectIC, context, source, flags, slot,
5171 vector);
5172}
5173
5176 auto source = Parameter<JSAny>(Descriptor::kSource);
5177 auto flags = Parameter<Smi>(Descriptor::kFlags);
5178 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
5179 auto maybe_vector = Parameter<HeapObject>(Descriptor::kVector);
5180 auto context = Parameter<Context>(Descriptor::kContext);
5181 TVARIABLE(Map, result_map);
5182 Label if_result_map(this, &result_map), if_empty_object(this),
5183 miss(this, Label::kDeferred), try_polymorphic(this, Label::kDeferred),
5184 try_megamorphic(this, Label::kDeferred), slow(this, Label::kDeferred);
5185
5186 TNode<Map> source_map = LoadReceiverMap(source);
5187 GotoIf(IsDeprecatedMap(source_map), &miss);
5188
5189 GotoIf(IsUndefined(maybe_vector), &miss);
5190
5192 TNode<HeapObjectReference> weak_source_map = MakeWeak(source_map);
5193
5194 // Decide if monomorphic or polymorphic, then dispatch based on the handler.
5195 {
5196 TVARIABLE(MaybeObject, var_handler);
5197 Label if_handler(this, &var_handler);
5198 feedback = TryMonomorphicCase(slot, CAST(maybe_vector), weak_source_map,
5199 &if_handler, &var_handler, &try_polymorphic);
5200
5201 BIND(&try_polymorphic);
5202 TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
5203 {
5204 Comment("CloneObjectIC_try_polymorphic");
5205 GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
5206 &try_megamorphic);
5207 HandlePolymorphicCase(weak_source_map, CAST(strong_feedback), &if_handler,
5208 &var_handler, &miss);
5209 }
5210
5211 BIND(&try_megamorphic);
5212 {
5213 Comment("CloneObjectIC_try_megamorphic");
5214 CSA_DCHECK(
5215 this,
5216 Word32Or(TaggedEqual(strong_feedback, UninitializedSymbolConstant()),
5217 TaggedEqual(strong_feedback, MegamorphicSymbolConstant())));
5218 GotoIfNot(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()),
5219 &miss);
5220 Goto(&slow);
5221 }
5222
5223 BIND(&if_handler);
5224 Comment("CloneObjectIC_if_handler");
5225
5226 // When the result of cloning the object is an empty object literal we store
5227 // a Smi into the feedback.
5228 GotoIf(TaggedIsSmi(var_handler.value()), &if_empty_object);
5229
5230 // Handlers for the CloneObjectIC stub are weak references to the Map of
5231 // a result object.
5232 result_map = CAST(GetHeapObjectAssumeWeak(var_handler.value(), &miss));
5233 GotoIf(IsDeprecatedMap(result_map.value()), &miss);
5234 Goto(&if_result_map);
5235 }
5236
5237 // Cloning with a concrete result_map.
5238 {
5239 BIND(&if_result_map);
5240 Comment("CloneObjectIC_if_result_map");
5241
5243 CAST(source), source_map, result_map.value(),
5244 [&](TNode<Map> map, TNode<HeapObject> properties,
5245 TNode<FixedArray> elements) {
5246 return UncheckedCast<JSObject>(AllocateJSObjectFromMap(
5247 map, properties, elements, AllocationFlag::kNone,
5248 SlackTrackingMode::kDontInitializeInObjectProperties));
5249 },
5250 true /* target_is_new */);
5251
5252 Return(object);
5253 }
5254
5255 // Case for when the result is the empty object literal. Can't be shared with
5256 // the above since we must initialize the in-object properties.
5257 {
5258 BIND(&if_empty_object);
5259 Comment("CloneObjectIC_if_empty_object");
5262 TNode<JSObject> object =
5264 Return(object);
5265 }
5266
5267 BIND(&slow);
5268 {
5269 TailCallBuiltin(Builtin::kCloneObjectIC_Slow, context, source, flags, slot,
5270 maybe_vector);
5271 }
5272
5273 BIND(&miss);
5274 {
5275 Comment("CloneObjectIC_miss");
5276 TNode<HeapObject> map_or_result =
5277 CAST(CallRuntime(Runtime::kCloneObjectIC_Miss, context, source, flags,
5278 slot, maybe_vector));
5279 Label restart(this);
5280 GotoIf(IsMap(map_or_result), &restart);
5281 CSA_DCHECK(this, IsJSObject(map_or_result));
5282 Return(map_or_result);
5283
5284 BIND(&restart);
5285 result_map = CAST(map_or_result);
5286 Goto(&if_result_map);
5287 }
5288}
5289
5292
5293 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
5294 auto name = Parameter<Object>(Descriptor::kName);
5295 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
5296 auto vector = Parameter<HeapObject>(Descriptor::kVector);
5297 auto context = Parameter<Context>(Descriptor::kContext);
5298
5299 LoadICParameters p(context, receiver, name, slot, vector);
5301}
5302
5305
5306 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
5307 auto name = Parameter<Object>(Descriptor::kName);
5308 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
5311
5312 TailCallBuiltin(Builtin::kKeyedHasIC, context, receiver, name, slot, vector);
5313}
5314
5317
5318 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
5319 auto name = Parameter<Object>(Descriptor::kName);
5320 auto context = Parameter<Context>(Descriptor::kContext);
5321 // TODO(magardn): implement HasProperty handling in KeyedLoadICGeneric
5322 Return(HasProperty(context, receiver, name,
5324}
5325
5328
5329 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
5330 auto name = Parameter<Object>(Descriptor::kName);
5331 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
5332 auto vector = Parameter<HeapObject>(Descriptor::kVector);
5333 auto context = Parameter<Context>(Descriptor::kContext);
5334
5335 LoadICParameters p(context, receiver, name, slot, vector);
5337}
5338
5340 TNode<Map> receiver_map, Label* definitely_no_elements,
5341 Label* possibly_elements) {
5342 TVARIABLE(Map, var_map, receiver_map);
5343 Label loop_body(this, &var_map);
5344 TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
5345 TNode<NumberDictionary> empty_slow_element_dictionary =
5346 EmptySlowElementDictionaryConstant();
5347 Goto(&loop_body);
5348
5349 BIND(&loop_body);
5350 {
5351 TNode<Map> map = var_map.value();
5352 TNode<HeapObject> prototype = LoadMapPrototype(map);
5353 GotoIf(IsNull(prototype), definitely_no_elements);
5354 TNode<Map> prototype_map = LoadMap(prototype);
5355 TNode<Uint16T> prototype_instance_type = LoadMapInstanceType(prototype_map);
5356
5357 // Pessimistically assume elements if a Proxy, Special API Object,
5358 // or JSPrimitiveWrapper wrapper is found on the prototype chain. After this
5359 // instance type check, it's not necessary to check for interceptors or
5360 // access checks.
5361 Label if_custom(this, Label::kDeferred), if_notcustom(this);
5362 Branch(IsCustomElementsReceiverInstanceType(prototype_instance_type),
5363 &if_custom, &if_notcustom);
5364
5365 BIND(&if_custom);
5366 {
5367 // For string JSPrimitiveWrapper wrappers we still support the checks as
5368 // long as they wrap the empty string.
5369 GotoIfNot(
5370 InstanceTypeEqual(prototype_instance_type, JS_PRIMITIVE_WRAPPER_TYPE),
5371 possibly_elements);
5372 TNode<Object> prototype_value =
5374 Branch(IsEmptyString(prototype_value), &if_notcustom, possibly_elements);
5375 }
5376
5377 BIND(&if_notcustom);
5378 {
5379 TNode<FixedArrayBase> prototype_elements = LoadElements(CAST(prototype));
5380 var_map = prototype_map;
5381 GotoIf(TaggedEqual(prototype_elements, empty_fixed_array), &loop_body);
5382 Branch(TaggedEqual(prototype_elements, empty_slow_element_dictionary),
5383 &loop_body, possibly_elements);
5384 }
5385 }
5386}
5387
5388#undef LOAD_KIND
5389#undef STORE_KIND
5390
5392
5393} // namespace internal
5394} // namespace v8
#define STORE_KIND(kind)
#define LOAD_KIND(kind)
#define BIND(label)
#define TVARIABLE(...)
#define CSA_DCHECK(csa,...)
#define CSA_CHECK(csa, x)
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
Builtins::Kind kind
Definition builtins.cc:40
PropertyT * getter
static constexpr U encode(T value)
Definition bit-field.h:55
static constexpr U kMask
Definition bit-field.h:41
static constexpr int kShift
Definition bit-field.h:39
void HandleLoadICSmiHandlerHasNamedCase(const LazyLoadICParameters *p, TNode< Object > holder, TNode< Uint32T > handler_kind, Label *miss, ExitPoint *exit_point, ICMode ic_mode)
TNode< Object > 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)
void GenerateLoadGlobalICBaseline(TypeofMode typeof_mode)
void UpdateMayHaveInterestingProperty(TNode< PropertyDictionary > dict, TNode< Name > name)
void StoreIC(const StoreICParameters *p)
void CheckPrototypeValidityCell(TNode< Object > maybe_validity_cell, Label *miss)
void InvalidateValidityCellIfPrototype(TNode< Map > map, std::optional< TNode< Uint32T > > bitfield3=std::nullopt)
void HandleStoreICSmiHandlerCase(TNode< Word32T > handler_word, TNode< JSObject > holder, TNode< Object > value, Label *miss)
void HandleStoreICSmiHandlerJSSharedStructFieldCase(TNode< Context > context, TNode< Word32T > handler_word, TNode< JSObject > holder, TNode< Object > value)
void LookupGlobalIC(LazyNode< Object > lazy_name, TNode< TaggedIndex > depth, LazyNode< TaggedIndex > lazy_slot, TNode< Context > context, LazyNode< FeedbackVector > lazy_feedback_vector, TypeofMode typeof_mode)
void JumpIfDataProperty(TNode< Uint32T > details, Label *writable, Label *readonly)
void EmitAccessCheck(TNode< Context > expected_native_context, TNode< Context > context, TNode< Object > receiver, Label *can_access, Label *miss)
void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode)
void EmitElementLoad(TNode< HeapObject > object, TNode< Word32T > elements_kind, TNode< IntPtrT > key, 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=LoadAccessMode::kLoad)
void HandleStoreFieldAndReturn(TNode< Word32T > handler_word, TNode< JSObject > holder, TNode< Object > value, std::optional< TNode< Float64T > > double_value, Representation representation, Label *miss)
void HandleStoreToProxy(const StoreICParameters *p, TNode< JSProxy > proxy, Label *miss, ElementSupport support_elements)
void HandleLoadCallbackProperty(const LazyLoadICParameters *p, TNode< JSObject > holder, TNode< Word32T > handler_word, ExitPoint *exit_point)
void CheckDescriptorConsidersNumbersMutable(TNode< Word32T > handler_word, TNode< JSObject > holder, Label *bailout)
void HandleStoreICTransitionMapHandlerCase(const StoreICParameters *p, TNode< Map > transition_map, Label *miss, StoreTransitionMapFlags flags)
void HandlePolymorphicCase(TNode< HeapObjectReference > weak_lookup_start_object_map, TNode< WeakFixedArray > feedback, Label *if_handler, TVariable< MaybeObject > *var_handler, Label *if_miss)
void HandleLoadICHandlerCase(const LazyLoadICParameters *p, TNode< MaybeObject > handler, Label *miss, ExitPoint *exit_point, ICMode ic_mode=ICMode::kNonGlobalIC, OnNonExistent on_nonexistent=OnNonExistent::kReturnUndefined, ElementSupport support_elements=kOnlyProperties, LoadAccessMode access_mode=LoadAccessMode::kLoad)
void EmitFastElementsBoundsCheck(TNode< JSObject > object, TNode< FixedArrayBase > elements, TNode< IntPtrT > intptr_index, TNode< BoolT > is_jsarray_condition, Label *miss)
void 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)
TNode< BoolT > IsPropertyDetailsConst(TNode< Uint32T > details)
void HandleStoreICProtoHandler(const StoreICParameters *p, TNode< StoreHandler > handler, Label *slow, Label *miss, ICMode ic_mode, ElementSupport support_elements)
void KeyedLoadIC(const LoadICParameters *p, LoadAccessMode access_mode)
void LoadGlobalIC_TryPropertyCellCase(TNode< FeedbackVector > vector, TNode< TaggedIndex > slot, const LazyNode< Context > &lazy_context, ExitPoint *exit_point, Label *try_handler, Label *miss)
void KeyedLoadICGeneric(const LoadICParameters *p)
void 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)
void ScriptContextTableLookup(TNode< Name > name, TNode< NativeContext > native_context, Label *found_hole, Label *not_found)
TNode< PropertyArray > ExtendPropertiesBackingStore(TNode< HeapObject > object, TNode< IntPtrT > index)
void LoadSuperIC_NoFeedback(const LoadICParameters *p)
void HandleStoreICHandlerCase(const StoreICParameters *p, TNode< MaybeObject > handler, Label *miss, ICMode ic_mode, ElementSupport support_elements=kOnlyProperties)
TNode< Object > LoadDescriptorValue(TNode< Map > map, TNode< IntPtrT > descriptor_entry)
void TryEnumeratedKeyedLoad(const LoadICParameters *p, TNode< Map > lookup_start_object_map, ExitPoint *exit_point)
TNode< MaybeObject > LoadDescriptorValueOrFieldType(TNode< Map > map, TNode< IntPtrT > descriptor_entry)
void TryProbeStubCache(StubCache *stub_cache, TNode< JSAny > lookup_start_object, TNode< Map > lookup_start_object_map, TNode< Name > name, Label *if_handler, TVariable< MaybeObject > *var_handler, Label *if_miss)
void 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)
void HandleLoadICSmiHandlerLoadNamedCase(const LazyLoadICParameters *p, TNode< Object > holder, TNode< Uint32T > handler_kind, TNode< Word32T > handler_word, Label *rebox_double, TVariable< Float64T > *var_double_value, TNode< MaybeObject > handler, Label *miss, ExitPoint *exit_point, ICMode ic_mode, OnNonExistent on_nonexistent, ElementSupport support_elements)
TNode< IntPtrT > StubCacheSecondaryOffset(TNode< Name > name, TNode< Map > map)
void GenericElementLoad(TNode< JSAnyNotSmi > lookup_start_object, TNode< Map > lookup_start_object_map, TNode< Int32T > lookup_start_object_instance_type, TNode< IntPtrT > index, Label *slow)
std::function< void(TNode< Code > code_handler)> OnCodeHandler
TNode< MaybeObject > LoadHandlerDataField(TNode< DataHandler > handler, int data_index)
void HandleLoadAccessor(const LazyLoadICParameters *p, TNode< FunctionTemplateInfo > function_template_info, TNode< Word32T > handler_word, TNode< DataHandler > handler, TNode< Uint32T > handler_kind, ExitPoint *exit_point)
void StoreGlobalIC_PropertyCellCase(TNode< PropertyCell > property_cell, TNode< Object > value, ExitPoint *exit_point, Label *miss)
void StoreInArrayLiteralIC(const StoreICParameters *p)
void GotoIfNotSameNumberBitPattern(TNode< Float64T > left, TNode< Float64T > right, Label *miss)
void GenerateLookupContextTrampoline(TypeofMode typeof_mode, ContextKind context_kind)
void 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 > value)
void GenericPropertyLoad(TNode< JSAnyNotSmi > 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=kUseStubCache)
void GenerateLookupContextBaseline(TypeofMode typeof_mode, ContextKind context_kind)
void HandleLoadICSmiHandlerCase(const LazyLoadICParameters *p, TNode< Object > holder, TNode< Smi > smi_handler, TNode< MaybeObject > handler, Label *miss, ExitPoint *exit_point, ICMode ic_mode, OnNonExistent on_nonexistent, ElementSupport support_elements, LoadAccessMode access_mode)
void LookupContext(LazyNode< Object > lazy_name, TNode< TaggedIndex > depth, LazyNode< TaggedIndex > lazy_slot, TNode< Context > context, TypeofMode typeof_mode, ContextKind context_kind)
void 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)
void KeyedStoreIC(const StoreICParameters *p)
TNode< IntPtrT > StubCachePrimaryOffset(TNode< Name > name, TNode< Map > map)
void CheckHeapObjectTypeMatchesDescriptor(TNode< Word32T > handler_word, TNode< JSObject > holder, TNode< Object > value, Label *bailout)
void KeyedLoadICPolymorphicName(const LoadICParameters *p, LoadAccessMode access_mode)
void GenerateLookupGlobalIC(TypeofMode typeof_mode)
void GenerateLookupGlobalICBaseline(TypeofMode typeof_mode)
void HandleLoadICProtoHandler(const LazyLoadICParameters *p, TNode< DataHandler > handler, TVariable< Object > *var_holder, TVariable< MaybeObject > *var_smi_handler, Label *if_smi_handler, Label *miss, ExitPoint *exit_point, ICMode ic_mode, LoadAccessMode access_mode)
void GenerateLookupGlobalICTrampoline(TypeofMode typeof_mode)
void CheckFieldType(TNode< DescriptorArray > descriptors, TNode< IntPtrT > name_index, TNode< Word32T > representation, TNode< Object > value, Label *bailout)
void LoadGlobalIC_NoFeedback(TNode< Context > context, TNode< Object > name, TNode< Smi > smi_typeof_mode)
void HandleLoadField(TNode< JSObject > holder, TNode< Word32T > handler_word, TVariable< Float64T > *var_double_value, Label *rebox_double, Label *miss, ExitPoint *exit_point)
void LoadIC_BytecodeHandler(const LazyLoadICParameters *p, ExitPoint *exit_point)
std::function< void( TNode< PropertyDictionary > properties, TNode< IntPtrT > name_index)> OnFoundOnLookupStartObject
void LoadSuperIC(const LoadICParameters *p)
void HandleStoreICNativeDataProperty(const StoreICParameters *p, TNode< HeapObject > holder, TNode< Word32T > handler_word)
void LoadIC(const LoadICParameters *p)
void 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)
void BranchIfPrototypesHaveNoElements(TNode< Map > receiver_map, Label *definitely_no_elements, Label *possibly_elements)
TNode< HeapObjectReference > TryMonomorphicCase(TNode< TaggedIndex > slot, TNode< FeedbackVector > vector, TNode< HeapObjectReference > weak_lookup_start_object_map, Label *if_handler, TVariable< MaybeObject > *var_handler, Label *if_miss)
void LoadIC_NoFeedback(const LoadICParameters *p, TNode< Smi > smi_typeof_mode)
void StoreGlobalIC(const StoreICParameters *p)
void DefineKeyedOwnIC(const StoreICParameters *p)
void GenerateLoadGlobalIC(TypeofMode typeof_mode)
void 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)
static constexpr Builtin LoadGlobalICInOptimizedCode(TypeofMode typeof_mode)
TNode< BoolT > IsJSArrayInstanceType(TNode< Int32T > instance_type)
TNode< BoolT > IsJSObject(TNode< HeapObject > object)
void LoadPropertyFromDictionary(TNode< Dictionary > dictionary, TNode< IntPtrT > name_index, TVariable< Uint32T > *var_details, TVariable< Object > *var_value)
TNode< MaybeObject > LoadFieldTypeByDescriptorEntry(TNode< DescriptorArray > descriptors, TNode< IntPtrT > descriptor)
TNode< WordT > TimesTaggedSize(TNode< WordT > value)
TNode< IntPtrT > LoadAndUntagFixedArrayBaseLength(TNode< FixedArrayBase > array)
TNode< Smi > SmiFromInt32(TNode< Int32T > value)
TNode< MaybeObject > LoadMaybeWeakObjectField(TNode< HeapObject > object, int offset)
void StoreJSSharedStructPropertyArrayElement(TNode< PropertyArray > array, TNode< IntPtrT > index, TNode< Object > value)
TNode< Object > LoadPropertyArrayElement(TNode< PropertyArray > object, TNode< IntPtrT > index)
TNode< BoolT > IsNullOrUndefined(TNode< Object > object)
TNode< BoolT > IsJSGlobalProxy(TNode< HeapObject > object)
TNode< Number > ChangeInt32ToTagged(TNode< Int32T > value)
TNode< Context > LoadScriptContext(TNode< Context > context, TNode< IntPtrT > context_index)
TNode< BoolT > IsJSSharedStruct(TNode< HeapObject > object)
TNode< IntPtrT > TryToIntptr(TNode< Object > key, Label *if_not_intptr, TVariable< Int32T > *var_instance_type=nullptr)
TNode< BoolT > IsJSObjectMap(TNode< Map > map)
void NameDictionaryLookup(TNode< Dictionary > dictionary, TNode< Name > unique_name, Label *if_found, TVariable< IntPtrT > *var_name_index, Label *if_not_found, LookupMode mode=kFindExisting)
TNode< Float64T > TryTaggedToFloat64(TNode< Object > value, Label *if_valueisnotnumber)
TNode< BoolT > IsEqualInWord32(TNode< Word32T > word32, typename BitField::FieldType value)
TNode< Numeric > LoadFixedTypedArrayElementAsTagged(TNode< RawPtrT > data_pointer, TNode< UintPtrT > index, ElementsKind elements_kind)
void FillPropertyArrayWithUndefined(TNode< PropertyArray > array, TNode< IntPtrT > from_index, TNode< IntPtrT > to_index)
TNode< BoolT > IsStrong(TNode< MaybeObject > value)
TNode< Int32T > TruncateIntPtrToInt32(TNode< IntPtrT > value)
void CopyPropertyArrayValues(TNode< HeapObject > from_array, TNode< PropertyArray > to_array, TNode< IntPtrT > length, WriteBarrierMode barrier_mode, DestroySource destroy_source)
TNode< Uint32T > LoadDetailsByKeyIndex(TNode< ContainerType > container, TNode< IntPtrT > key_index)
TNode< IntPtrT > LoadMapInobjectPropertiesStartInWords(TNode< Map > map)
TNode< JSAny > BasicLoadNumberDictionaryElement(TNode< NumberDictionary > dictionary, TNode< IntPtrT > intptr_index, Label *not_data, Label *if_hole)
TNode< IntPtrT > ParameterToIntPtr(TNode< Smi > value)
TNode< JSArrayBuffer > LoadJSArrayBufferViewBuffer(TNode< JSArrayBufferView > array_buffer_view)
TNode< BoolT > IsPrivateName(TNode< Symbol > symbol)
TNode< BoolT > InstanceTypeEqual(TNode< Int32T > instance_type, int type)
TNode< DescriptorArray > LoadMapDescriptors(TNode< Map > map)
TNode< HeapObject > LoadSlowProperties(TNode< JSReceiver > object)
TNode< Object > UnsafeLoadFixedArrayElement(TNode< FixedArray > object, TNode< IntPtrT > index, int additional_offset=0)
void StorePropertyArrayElement(TNode< PropertyArray > array, TNode< IntPtrT > index, TNode< Object > value)
TNode< Smi > GetNameDictionaryFlags(TNode< Dictionary > dictionary)
TNode< IntPtrT > MapUsedInObjectProperties(TNode< Map > map)
TNode< FeedbackVector > LoadFeedbackVectorForStub()
TNode< UintPtrT > DecodeWord(TNode< WordT > word)
TNode< String > StringFromSingleCharCode(TNode< Int32T > code)
void SetNameDictionaryFlags(TNode< Dictionary >, TNode< Smi > flags)
TNode< BoolT > IsInterestingProperty(TNode< Name > name)
TNode< BoolT > TaggedEqual(TNode< AnyTaggedT > a, TNode< AnyTaggedT > b)
TNode< FixedArrayBase > LoadElements(TNode< JSObject > object)
TNode< T > LoadObjectField(TNode< HeapObject > object, int offset)
TNode< UintPtrT > LoadVariableLengthJSTypedArrayLength(TNode< JSTypedArray > array, TNode< JSArrayBuffer > buffer, Label *detached_or_out_of_bounds)
TNode< BoolT > IsNotSetWord32(TNode< Word32T > word32)
TNode< BoolT > TaggedNotEqual(TNode< AnyTaggedT > a, TNode< AnyTaggedT > b)
TNode< Uint32T > LoadMapBitField3(TNode< Map > map)
TNode< BoolT > TaggedIsNotSmi(TNode< MaybeObject > a)
void TryToName(TNode< Object > key, Label *if_keyisindex, TVariable< IntPtrT > *var_index, Label *if_keyisunique, TVariable< Name > *var_unique, Label *if_bailout, Label *if_notinternalized=nullptr)
void GotoIfPrototypeRequiresRuntimeLookup(TNode< JSFunction > function, TNode< Map > map, Label *runtime)
TNode< Context > GotoIfHasContextExtensionUpToDepth(TNode< Context > context, TNode< Uint32T > depth, Label *target)
TNode< IntPtrT > ChangePositiveInt32ToIntPtr(TNode< Int32T > input)
TNode< Number > ChangeUint32ToTagged(TNode< Uint32T > value)
TNode< Uint32T > LoadDetailsByDescriptorEntry(TNode< DescriptorArray > descriptors, TNode< IntPtrT > descriptor)
TNode< BoolT > IsWeakOrCleared(TNode< MaybeObject > value)
void StoreValueByKeyIndex(TNode< ContainerType > container, TNode< IntPtrT > key_index, TNode< Object > value, WriteBarrierMode write_barrier=UPDATE_WRITE_BARRIER)
void TryGetOwnProperty(TNode< Context > context, TNode< JSAny > receiver, TNode< JSReceiver > object, TNode< Map > map, TNode< Int32T > instance_type, TNode< Name > unique_name, Label *if_found_value, TVariable< Object > *var_value, Label *if_not_found, Label *if_bailout, ExpectedReceiverMode expected_receiver_mode=kExpectingAnyReceiver)
void TryInternalizeString(TNode< String > string, Label *if_index, TVariable< IntPtrT > *var_index, Label *if_internalized, TVariable< Name > *var_internalized, Label *if_not_internalized, Label *if_bailout)
TNode< Uint16T > StringCharCodeAt(TNode< String > string, TNode< UintPtrT > index)
TNode< JSPrototype > LoadMapPrototype(TNode< Map > map)
TNode< BoolT > IsSetWord32(TNode< Word32T > word32)
TNode< BoolT > IsJSApiObjectMap(TNode< Map > map)
TNode< HeapObject > LoadFastProperties(TNode< JSReceiver > object, bool skip_empty_check=false)
TNode< IntPtrT > SmiUntag(TNode< Smi > value)
TNode< BoolT > IsDeprecatedMap(TNode< Map > map)
TNode< BoolT > IsNotCleared(TNode< MaybeObject > value)
TNode< RawPtrT > LoadJSTypedArrayDataPtr(TNode< JSTypedArray > typed_array)
TNode< BoolT > IsSetWord(TNode< WordT > word)
TNode< BoolT > IsCode(TNode< HeapObject > object)
void StoreMap(TNode< HeapObject > object, TNode< Map > map)
TNode< Uint32T > DecodeWord32(TNode< Word32T > word32)
TNode< Object > LoadValueByKeyIndex(TNode< ContainerType > container, TNode< IntPtrT > key_index)
TNode< Uint32T > LoadNameRawHash(TNode< Name > name)
TNode< Map > LoadCachedMap(TNode< NativeContext > native_context, TNode< IntPtrT > number_of_properties, Label *runtime)
TNode< BoolT > IsCustomElementsReceiverInstanceType(TNode< Int32T > instance_type)
void DescriptorLookup(TNode< Name > unique_name, TNode< DescriptorArray > descriptors, TNode< Uint32T > bitfield3, Label *if_found, TVariable< IntPtrT > *var_name_index, Label *if_not_found)
TNode< BoolT > IsCleared(TNode< MaybeObject > value)
TNode< Object > LoadAccessorPairGetter(TNode< AccessorPair > accessor_pair)
TNode< Int32T > LoadAndUntagToWord32ObjectField(TNode< HeapObject > object, int offset)
std::function< TNode< T >()> LazyNode
TNode< BoolT > IsClearWord32(TNode< Word32T > word32)
TNode< Map > LoadReceiverMap(TNode< Object > receiver)
void StoreObjectFieldNoWriteBarrier(TNode< HeapObject > object, TNode< IntPtrT > offset, TNode< T > value)
TNode< Object > LoadFixedArrayElement(TNode< FixedArray > object, TNode< TIndex > index, int additional_offset=0, CheckBounds check_bounds=CheckBounds::kAlways)
void IncrementCounter(StatsCounter *counter, int delta)
TNode< JSAny > Call(TNode< Context > context, TNode< TCallable > callable, ConvertReceiverMode mode, TNode< JSAny > receiver, TArgs... args)
TNode< Uint16T > LoadMapInstanceType(TNode< Map > map)
TNode< BoolT > HasInstanceType(TNode< HeapObject > object, InstanceType type)
TNode< IntPtrT > ElementOffsetFromIndex(TNode< TIndex > index, ElementsKind kind, int base_size=0)
TNode< BigInt > LoadFixedBigInt64ArrayElementAsTagged(TNode< RawPtrT > data_pointer, TNode< IntPtrT > offset)
TNode< Name > LoadKeyByKeyIndex(TNode< DescriptorArray > container, TNode< IntPtrT > key_index)
TNode< IntPtrT > LoadStringLengthAsWord(TNode< String > string)
void SharedValueBarrier(TNode< Context > context, TVariable< Object > *var_shared_value)
TNode< HeapNumber > AllocateHeapNumberWithValue(TNode< Float64T > value)
TNode< BoolT > IsNotAnyHole(TNode< Object > object)
void StoreSharedObjectField(TNode< HeapObject > object, TNode< IntPtrT > offset, TNode< Object > value)
TNode< Object > CreateDataProperty(TNode< Context > context, TNode< JSObject > receiver, TNode< Object > key, TNode< Object > value)
TNode< NativeContext > LoadNativeContext(TNode< Context > context)
TNode< MaybeObject > LoadWeakFixedArrayElement(TNode< WeakFixedArray > object, TNode< IntPtrT > index, int additional_offset=0)
TNode< T > Select(TNode< BoolT > condition, const NodeGenerator< T > &true_body, const NodeGenerator< T > &false_body, BranchHint branch_hint=BranchHint::kNone)
TNode< BoolT > TaggedIsSmi(TNode< MaybeObject > a)
TNode< Smi > LoadFastJSArrayLength(TNode< JSArray > array)
TNode< BoolT > IsSpecialReceiverInstanceType(TNode< Int32T > instance_type)
TNode< PropertyArray > AllocatePropertyArray(TNode< IntPtrT > capacity)
TNode< Int32T > LoadMapBitField(TNode< Map > map)
TNode< Float64T > LoadHeapNumberValue(TNode< HeapObject > object)
TNode< BoolT > IsMap(TNode< HeapObject > object)
TNode< HeapObject > LoadJSFunctionPrototype(TNode< JSFunction > function, Label *if_bailout)
TNode< HeapObjectReference > MakeWeak(TNode< HeapObject > value)
TNode< Float64T > LoadFixedDoubleArrayElement(TNode< FixedDoubleArray > object, TNode< IntPtrT > index, Label *if_hole=nullptr, MachineType machine_type=MachineType::Float64())
TNode< Object > LoadJSPrimitiveWrapperValue(TNode< JSPrimitiveWrapper > object)
TNode< Map > LoadMap(TNode< HeapObject > object)
TNode< Object > FastCloneJSObject(TNode< HeapObject > source, TNode< Map > source_map, TNode< Map > target_map, const Function &materialize_target, bool target_is_new)
TNode< BoolT > IsString(TNode< HeapObject > object)
TNode< Int32T > SmiToInt32(TNode< Smi > value)
TNode< Int32T > LoadMapElementsKind(TNode< Map > map)
TNode< IntPtrT > TaggedIndexToIntPtr(TNode< TaggedIndex > value)
TNode< Float64T > ChangeNumberToFloat64(TNode< Number > value)
TNode< JSObject > AllocateJSObjectFromMap(TNode< Map > map, std::optional< TNode< HeapObject > > properties=std::nullopt, std::optional< TNode< FixedArray > > elements=std::nullopt, AllocationFlags flags=AllocationFlag::kNone, SlackTrackingMode slack_tracking_mode=kNoSlackTracking)
TNode< Object > LoadCellValue(TNode< Cell > cell)
TNode< BoolT > IsClearWord(TNode< WordT > word)
TNode< Uint32T > LoadAndUntagWeakFixedArrayLengthAsUint32(TNode< WeakFixedArray > array)
TNode< Float64T > ChangeFloat16ToFloat64(TNode< Float16RawBitsT > value)
TNode< MaybeObject > LoadFieldTypeByKeyIndex(TNode< DescriptorArray > container, TNode< IntPtrT > key_index)
Uint32LessThanOrEqual IntPtrGreaterThanOrEqual
TNode< BoolT > IsStringInstanceType(TNode< Int32T > instance_type)
TNode< Object > LoadAccessorPairSetter(TNode< AccessorPair > accessor_pair)
TNode< IntPtrT > PositiveSmiUntag(TNode< Smi > value)
TNode< BoolT > IsCallable(TNode< HeapObject > object)
TNode< BoolT > IsJSTypedArray(TNode< HeapObject > object)
TNode< HeapObject > GetHeapObjectIfStrong(TNode< MaybeObject > value, Label *if_not_strong)
void ForEachEnumerableOwnProperty(TNode< Context > context, TNode< Map > map, TNode< JSObject > object, PropertiesEnumerationMode mode, const ForEachKeyValueFunction &body, Label *bailout)
TNode< JSAny > CallFunction(TNode< Context > context, TNode< JSFunction > callable, ConvertReceiverMode mode, TNode< JSAny > receiver, TArgs... args)
TNode< BoolT > IsJSFunctionInstanceType(TNode< Int32T > instance_type)
void StoreObjectField(TNode< HeapObject > object, int offset, TNode< Smi > value)
TNode< Int32T > TruncateWordToInt32(TNode< WordT > value)
TNode< UintPtrT > DecodeWordFromWord32(TNode< Word32T > word32)
TNode< FeedbackVector > LoadFeedbackVectorFromBaseline()
TNode< UintPtrT > LoadJSTypedArrayLength(TNode< JSTypedArray > typed_array)
TNode< IntPtrT > LoadMapInstanceSizeInWords(TNode< Map > map)
TNode< MaybeObject > LoadFeedbackVectorSlot(TNode< FeedbackVector > feedback_vector, TNode< TIndex > slot, int additional_offset=0)
TNode< BoolT > IsPropertyCell(TNode< HeapObject > object)
TNode< Map > LoadObjectFunctionInitialMap(TNode< NativeContext > native_context)
TNode< Boolean > HasProperty(TNode< Context > context, TNode< JSAny > object, TNode< Object > key, HasPropertyLookupMode mode)
TNode< TValue > LoadArrayElement(TNode< Array > array, int array_header_size, TNode< TIndex > index, int additional_offset=0)
void LoadPropertyFromFastObject(TNode< HeapObject > object, TNode< Map > map, TNode< DescriptorArray > descriptors, TNode< IntPtrT > name_index, TVariable< Uint32T > *var_details, TVariable< Object > *var_value)
TNode< BoolT > IsJSTypedArrayInstanceType(TNode< Int32T > instance_type)
TNode< HeapObject > GetHeapObjectAssumeWeak(TNode< MaybeObject > value)
void StoreHeapNumberValue(TNode< HeapNumber > object, TNode< Float64T > value)
TNode< Object > CallGetterIfAccessor(TNode< Object > value, TNode< Union< JSReceiver, PropertyCell > > holder, TNode< Uint32T > details, TNode< Context > context, TNode< JSAny > receiver, TNode< Object > name, Label *if_bailout, GetOwnPropertyMode mode=kCallJSGetterDontUseCachedName, ExpectedReceiverMode expected_receiver_mode=kExpectingJSReceiver)
void AddToDictionary(TNode< Dictionary > dictionary, TNode< Name > key, TNode< Object > value, Label *bailout, std::optional< TNode< IntPtrT > > insertion_index=std::nullopt)
static constexpr int SizeFor(int count)
static constexpr int OffsetOf(int index)
static constexpr int ToKeyIndex(int descriptor_number)
void ReturnCallStub(const CallInterfaceDescriptor &descriptor, TNode< Code > target, TNode< Context > context, TArgs... args)
void Return(const TNode< Object > result)
void ReturnCallBuiltin(Builtin builtin, TNode< Context > context, TArgs... args)
void ReturnCallRuntime(Runtime::FunctionId function, TNode< Context > context, TArgs... args)
static ExternalReference Create(const SCTableReference &table_ref)
static FeedbackSlot Invalid()
Definition utils.h:648
static V8_EXPORT_PRIVATE Tagged< FieldType > Any()
Definition field-type.cc:22
static V8_EXPORT_PRIVATE Tagged< FieldType > None()
Definition field-type.cc:17
static int GetMaxLengthForNewSpaceAllocation(ElementsKind kind)
Counters * counters()
Definition isolate.h:1180
static const int kFieldsAdded
Definition js-objects.h:954
static const int kMapCacheSize
Definition js-objects.h:949
static constexpr uint32_t kMaxElementIndex
Definition js-objects.h:924
static constexpr MachineType Int32()
static constexpr MachineType AnyTagged()
static constexpr MachineType None()
static constexpr MachineType TaggedPointer()
static constexpr int kPrototypeChainValid
Definition map.h:517
static constexpr int kHashNotComputedMask
Definition name.h:131
static const int kAttributesDontEnumMask
static const int kAttributesReadOnlyMask
static const int kAttributesDontDeleteMask
static constexpr Representation Double()
constexpr bool IsSmi() const
static constexpr Representation HeapObject()
static constexpr Representation Smi()
static constexpr Representation Tagged()
constexpr bool IsDouble() const
static constexpr Tagged< Smi > zero()
Definition smi.h:99
static const int kCacheIndexShift
Definition stub-cache.h:86
static const int kPrimaryTableBits
Definition stub-cache.h:88
static const int kSecondaryTableBits
Definition stub-cache.h:90
SCTableReference key_reference(StubCache::Table table)
Definition stub-cache.h:54
static const int kSecondaryTableSize
Definition stub-cache.h:91
static const int kPrimaryTableSize
Definition stub-cache.h:89
TNode< BoolT > Word32NotEqual(TNode< Word32T > left, TNode< Word32T > right)
TNode< IntPtrT > IntPtrMul(TNode< IntPtrT > left, TNode< IntPtrT > right)
TNode< IntPtrT > IntPtrAdd(TNode< IntPtrT > left, TNode< IntPtrT > right)
TNode< Int32T > Signed(TNode< Word32T > x)
void Comment(MessageWithSourceLocation message, Args &&... args)
TNode< IntPtrT > IntPtrConstant(intptr_t value)
TNode< UintPtrT > ChangeUint32ToWord(TNode< Word32T > value)
void ReturnIf(TNode< BoolT > condition, TNode< Object > value)
TNode< T > UncheckedCast(Node *value)
TNode< IntPtrT > WordShl(TNode< IntPtrT > left, TNode< IntegralT > right)
void GotoIfNot(TNode< IntegralT > condition, Label *false_label, GotoHint goto_hint=GotoHint::kNone)
void Return(TNode< Object > value)
TNode< Uint32T > Unsigned(TNode< Word32T > x)
TNode< Int32T > Word32And(TNode< Int32T > left, TNode< Int32T > right)
TNode< T > ReinterpretCast(Node *value)
TNode< Int32T > Int32Add(TNode< Int32T > left, TNode< Int32T > right)
TNode< IntPtrT > BitcastTaggedToWord(TNode< Smi > node)
void TailCallRuntime(Runtime::FunctionId function, TNode< Object > context, TArgs... args)
TNode< Smi > SmiConstant(Tagged< Smi > value)
void GotoIf(TNode< IntegralT > condition, Label *true_label, GotoHint goto_hint=GotoHint::kNone)
Node * Load(MachineType type, Node *base)
TNode< IntPtrT > ChangeInt32ToIntPtr(TNode< Word32T > value)
TNode< Int32T > Int32Sub(TNode< Int32T > left, TNode< Int32T > right)
TNode< Int32T > Word32Or(TNode< Int32T > left, TNode< Int32T > right)
TNode< Int32T > Word32Shl(TNode< Int32T > left, TNode< Int32T > right)
TNode< IntPtrT > WordAnd(TNode< IntPtrT > left, TNode< IntPtrT > right)
void Switch(Node *index, Label *default_label, const int32_t *case_values, Label **case_labels, size_t case_count)
TNode< IntPtrT > IntPtrSub(TNode< IntPtrT > left, TNode< IntPtrT > right)
void TailCallBuiltin(Builtin id, TNode< Object > context, TArgs... args)
TNode< BoolT > BoolConstant(bool value)
TNode< Uint32T > Word32Shr(TNode< Uint32T > left, TNode< Uint32T > right)
TNode< ExternalReference > ExternalConstant(ExternalReference address)
TNode< TaggedIndex > TaggedIndexConstant(intptr_t value)
TNode< Int32T > Int32Constant(int32_t value)
TNode< BoolT > WordNotEqual(TNode< WordT > left, TNode< WordT > right)
Node * CallCFunction(Node *function, std::optional< MachineType > return_type, CArgs... cargs)
TNode< Int32T > Word32Sar(TNode< Int32T > left, TNode< Int32T > right)
TNode< BoolT > Word32Equal(TNode< Word32T > left, TNode< Word32T > right)
TNode< T > CallRuntime(Runtime::FunctionId function, TNode< Object > context, TArgs... args)
void TailCallStub(const CallInterfaceDescriptor &descriptor, TNode< Code > target, TNode< Object > context, TArgs... args)
TNode< UintPtrT > WordShr(TNode< UintPtrT > left, TNode< IntegralT > right)
TNode< T > CallBuiltin(Builtin id, TNode< Object > context, TArgs... args)
void Branch(TNode< IntegralT > condition, Label *true_label, Label *false_label, BranchHint branch_hint=BranchHint::kNone)
TNode< T > Parameter(int value, const SourceLocation &loc=SourceLocation::Current())
#define CAST(x)
Register const value_
Handle< Code > code
#define V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
Definition globals.h:242
#define V8_DICT_PROPERTY_CONST_TRACKING_BOOL
Definition globals.h:249
int32_t offset
TNode< Context > context
TNode< Object > receiver
ZoneVector< RpoNumber > & result
MovableLabel handler
uint32_t const mask
#define ASSERT_CONSECUTIVE(rep1, rep2)
const int length_
Definition mul-fft.cc:473
@ kPropertyAdditionOrder
Definition globals.h:2861
constexpr int kTaggedSize
Definition globals.h:542
@ SKIP_WRITE_BARRIER
Definition objects.h:52
compiler::TypedCodeAssemblerVariable< T > TVariable
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats store(v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE)) DEFINE_GENERIC_IMPLICATION(trace_gc_object_stats
@ HOLEY_NONEXTENSIBLE_ELEMENTS
@ FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND
@ LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND
@ PACKED_NONEXTENSIBLE_ELEMENTS
@ LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND
@ FIRST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND
@ LAST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
constexpr int kTaggedSizeLog2
Definition globals.h:543
DONT_OVERRIDE DISABLE_ALLOCATION_SITES HOLEY_ELEMENTS
DONT_OVERRIDE DISABLE_ALLOCATION_SITES DISABLE_ALLOCATION_SITES HOLEY_DOUBLE_ELEMENTS
static const int kMaxNumberOfDescriptors
const int kHeapObjectTag
Definition v8-internal.h:72
V8_EXPORT_PRIVATE FlagValues v8_flags
return value
Definition map-inl.h:893
bool IsPrivateSymbol(Tagged< Object > obj)
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset IsNull(value)||IsJSProxy(value)||IsWasmObject(value)||(IsJSObject(value) &&(HeapLayout
Definition map-inl.h:70
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
#define CHECK_GE(lhs, rhs)
#define CHECK_LT(lhs, rhs)
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define arraysize(array)
Definition macros.h:67
#define OFFSET_OF_DATA_START(Type)