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