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