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