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