• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/code-factory.h"
8 #include "src/code-stubs.h"
9 #include "src/counters.h"
10 #include "src/ic/handler-configuration.h"
11 #include "src/ic/stub-cache.h"
12 #include "src/objects-inl.h"
13 
14 namespace v8 {
15 namespace internal {
16 
17 using compiler::CodeAssemblerState;
18 using compiler::Node;
19 
20 //////////////////// Private helpers.
21 
TryMonomorphicCase(Node * slot,Node * vector,Node * receiver_map,Label * if_handler,Variable * var_handler,Label * if_miss)22 Node* AccessorAssembler::TryMonomorphicCase(Node* slot, Node* vector,
23                                             Node* receiver_map,
24                                             Label* if_handler,
25                                             Variable* var_handler,
26                                             Label* if_miss) {
27   Comment("TryMonomorphicCase");
28   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
29 
30   // TODO(ishell): add helper class that hides offset computations for a series
31   // of loads.
32   int32_t header_size = FixedArray::kHeaderSize - kHeapObjectTag;
33   // Adding |header_size| with a separate IntPtrAdd rather than passing it
34   // into ElementOffsetFromIndex() allows it to be folded into a single
35   // [base, index, offset] indirect memory access on x64.
36   Node* offset =
37       ElementOffsetFromIndex(slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS);
38   Node* feedback = Load(MachineType::AnyTagged(), vector,
39                         IntPtrAdd(offset, IntPtrConstant(header_size)));
40 
41   // Try to quickly handle the monomorphic case without knowing for sure
42   // if we have a weak cell in feedback. We do know it's safe to look
43   // at WeakCell::kValueOffset.
44   GotoIf(WordNotEqual(receiver_map, LoadWeakCellValueUnchecked(feedback)),
45          if_miss);
46 
47   Node* handler =
48       Load(MachineType::AnyTagged(), vector,
49            IntPtrAdd(offset, IntPtrConstant(header_size + kPointerSize)));
50 
51   var_handler->Bind(handler);
52   Goto(if_handler);
53   return feedback;
54 }
55 
HandlePolymorphicCase(Node * receiver_map,Node * feedback,Label * if_handler,Variable * var_handler,Label * if_miss,int unroll_count)56 void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
57                                               Node* feedback, Label* if_handler,
58                                               Variable* var_handler,
59                                               Label* if_miss,
60                                               int unroll_count) {
61   Comment("HandlePolymorphicCase");
62   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
63 
64   // Iterate {feedback} array.
65   const int kEntrySize = 2;
66 
67   for (int i = 0; i < unroll_count; i++) {
68     Label next_entry(this);
69     Node* cached_map =
70         LoadWeakCellValue(LoadFixedArrayElement(feedback, i * kEntrySize));
71     GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
72 
73     // Found, now call handler.
74     Node* handler = LoadFixedArrayElement(feedback, i * kEntrySize + 1);
75     var_handler->Bind(handler);
76     Goto(if_handler);
77 
78     Bind(&next_entry);
79   }
80 
81   // Loop from {unroll_count}*kEntrySize to {length}.
82   Node* init = IntPtrConstant(unroll_count * kEntrySize);
83   Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
84   BuildFastLoop(
85       init, length,
86       [this, receiver_map, feedback, if_handler, var_handler](Node* index) {
87         Node* cached_map =
88             LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
89 
90         Label next_entry(this);
91         GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
92 
93         // Found, now call handler.
94         Node* handler = LoadFixedArrayElement(feedback, index, kPointerSize);
95         var_handler->Bind(handler);
96         Goto(if_handler);
97 
98         Bind(&next_entry);
99       },
100       kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
101   // The loop falls through if no handler was found.
102   Goto(if_miss);
103 }
104 
HandleKeyedStorePolymorphicCase(Node * receiver_map,Node * feedback,Label * if_handler,Variable * var_handler,Label * if_transition_handler,Variable * var_transition_map_cell,Label * if_miss)105 void AccessorAssembler::HandleKeyedStorePolymorphicCase(
106     Node* receiver_map, Node* feedback, Label* if_handler,
107     Variable* var_handler, Label* if_transition_handler,
108     Variable* var_transition_map_cell, Label* if_miss) {
109   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
110   DCHECK_EQ(MachineRepresentation::kTagged, var_transition_map_cell->rep());
111 
112   const int kEntrySize = 3;
113 
114   Node* init = IntPtrConstant(0);
115   Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
116   BuildFastLoop(init, length,
117                 [this, receiver_map, feedback, if_handler, var_handler,
118                  if_transition_handler, var_transition_map_cell](Node* index) {
119                   Node* cached_map =
120                       LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
121                   Label next_entry(this);
122                   GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
123 
124                   Node* maybe_transition_map_cell =
125                       LoadFixedArrayElement(feedback, index, kPointerSize);
126 
127                   var_handler->Bind(
128                       LoadFixedArrayElement(feedback, index, 2 * kPointerSize));
129                   GotoIf(WordEqual(maybe_transition_map_cell,
130                                    LoadRoot(Heap::kUndefinedValueRootIndex)),
131                          if_handler);
132                   var_transition_map_cell->Bind(maybe_transition_map_cell);
133                   Goto(if_transition_handler);
134 
135                   Bind(&next_entry);
136                 },
137                 kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
138   // The loop falls through if no handler was found.
139   Goto(if_miss);
140 }
141 
HandleLoadICHandlerCase(const LoadICParameters * p,Node * handler,Label * miss,ElementSupport support_elements)142 void AccessorAssembler::HandleLoadICHandlerCase(
143     const LoadICParameters* p, Node* handler, Label* miss,
144     ElementSupport support_elements) {
145   Comment("have_handler");
146   ExitPoint direct_exit(this);
147 
148   Variable var_holder(this, MachineRepresentation::kTagged);
149   var_holder.Bind(p->receiver);
150   Variable var_smi_handler(this, MachineRepresentation::kTagged);
151   var_smi_handler.Bind(handler);
152 
153   Variable* vars[] = {&var_holder, &var_smi_handler};
154   Label if_smi_handler(this, 2, vars);
155   Label try_proto_handler(this), call_handler(this);
156 
157   Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler);
158 
159   // |handler| is a Smi, encoding what to do. See SmiHandler methods
160   // for the encoding format.
161   Bind(&if_smi_handler);
162   {
163     HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
164                                miss, &direct_exit, support_elements);
165   }
166 
167   Bind(&try_proto_handler);
168   {
169     GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
170     HandleLoadICProtoHandlerCase(p, handler, &var_holder, &var_smi_handler,
171                                  &if_smi_handler, miss, &direct_exit, false);
172   }
173 
174   Bind(&call_handler);
175   {
176     typedef LoadWithVectorDescriptor Descriptor;
177     TailCallStub(Descriptor(isolate()), handler, p->context, p->receiver,
178                  p->name, p->slot, p->vector);
179   }
180 }
181 
HandleLoadICSmiHandlerCase(const LoadICParameters * p,Node * holder,Node * smi_handler,Label * miss,ExitPoint * exit_point,ElementSupport support_elements)182 void AccessorAssembler::HandleLoadICSmiHandlerCase(
183     const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss,
184     ExitPoint* exit_point, ElementSupport support_elements) {
185   Variable var_double_value(this, MachineRepresentation::kFloat64);
186   Label rebox_double(this, &var_double_value);
187 
188   Node* handler_word = SmiUntag(smi_handler);
189   Node* handler_kind = DecodeWord<LoadHandler::KindBits>(handler_word);
190   if (support_elements == kSupportElements) {
191     Label property(this);
192     GotoIfNot(
193         WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)),
194         &property);
195 
196     Comment("element_load");
197     Node* intptr_index = TryToIntptr(p->name, miss);
198     Node* elements = LoadElements(holder);
199     Node* is_jsarray_condition =
200         IsSetWord<LoadHandler::IsJsArrayBits>(handler_word);
201     Node* elements_kind =
202         DecodeWord32FromWord<LoadHandler::ElementsKindBits>(handler_word);
203     Label if_hole(this), unimplemented_elements_kind(this);
204     Label* out_of_bounds = miss;
205     EmitElementLoad(holder, elements, elements_kind, intptr_index,
206                     is_jsarray_condition, &if_hole, &rebox_double,
207                     &var_double_value, &unimplemented_elements_kind,
208                     out_of_bounds, miss, exit_point);
209 
210     Bind(&unimplemented_elements_kind);
211     {
212       // Smi handlers should only be installed for supported elements kinds.
213       // Crash if we get here.
214       DebugBreak();
215       Goto(miss);
216     }
217 
218     Bind(&if_hole);
219     {
220       Comment("convert hole");
221       GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
222       Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex);
223       DCHECK(isolate()->heap()->array_protector()->IsPropertyCell());
224       GotoIfNot(
225           WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
226                     SmiConstant(Smi::FromInt(Isolate::kProtectorValid))),
227           miss);
228       exit_point->Return(UndefinedConstant());
229     }
230 
231     Bind(&property);
232     Comment("property_load");
233   }
234 
235   Label constant(this), field(this);
236   Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForFields)),
237          &field, &constant);
238 
239   Bind(&field);
240   {
241     Comment("field_load");
242     Node* offset = DecodeWord<LoadHandler::FieldOffsetBits>(handler_word);
243 
244     Label inobject(this), out_of_object(this);
245     Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject,
246            &out_of_object);
247 
248     Bind(&inobject);
249     {
250       Label is_double(this);
251       GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
252       exit_point->Return(LoadObjectField(holder, offset));
253 
254       Bind(&is_double);
255       if (FLAG_unbox_double_fields) {
256         var_double_value.Bind(
257             LoadObjectField(holder, offset, MachineType::Float64()));
258       } else {
259         Node* mutable_heap_number = LoadObjectField(holder, offset);
260         var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
261       }
262       Goto(&rebox_double);
263     }
264 
265     Bind(&out_of_object);
266     {
267       Label is_double(this);
268       Node* properties = LoadProperties(holder);
269       Node* value = LoadObjectField(properties, offset);
270       GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
271       exit_point->Return(value);
272 
273       Bind(&is_double);
274       var_double_value.Bind(LoadHeapNumberValue(value));
275       Goto(&rebox_double);
276     }
277 
278     Bind(&rebox_double);
279     exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value()));
280   }
281 
282   Bind(&constant);
283   {
284     Comment("constant_load");
285     Node* descriptors = LoadMapDescriptors(LoadMap(holder));
286     Node* descriptor =
287         DecodeWord<LoadHandler::DescriptorValueIndexBits>(handler_word);
288     CSA_ASSERT(this,
289                UintPtrLessThan(descriptor,
290                                LoadAndUntagFixedArrayBaseLength(descriptors)));
291     Node* value = LoadFixedArrayElement(descriptors, descriptor);
292 
293     Label if_accessor_info(this);
294     GotoIf(IsSetWord<LoadHandler::IsAccessorInfoBits>(handler_word),
295            &if_accessor_info);
296     exit_point->Return(value);
297 
298     Bind(&if_accessor_info);
299     Callable callable = CodeFactory::ApiGetter(isolate());
300     exit_point->ReturnCallStub(callable, p->context, p->receiver, holder,
301                                value);
302   }
303 }
304 
HandleLoadICProtoHandlerCase(const LoadICParameters * p,Node * handler,Variable * var_holder,Variable * var_smi_handler,Label * if_smi_handler,Label * miss,ExitPoint * exit_point,bool throw_reference_error_if_nonexistent)305 void AccessorAssembler::HandleLoadICProtoHandlerCase(
306     const LoadICParameters* p, Node* handler, Variable* var_holder,
307     Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
308     ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) {
309   DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
310   DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
311 
312   // IC dispatchers rely on these assumptions to be held.
313   STATIC_ASSERT(FixedArray::kLengthOffset == LoadHandler::kHolderCellOffset);
314   DCHECK_EQ(FixedArray::OffsetOfElementAt(LoadHandler::kSmiHandlerIndex),
315             LoadHandler::kSmiHandlerOffset);
316   DCHECK_EQ(FixedArray::OffsetOfElementAt(LoadHandler::kValidityCellIndex),
317             LoadHandler::kValidityCellOffset);
318 
319   // Both FixedArray and Tuple3 handlers have validity cell at the same offset.
320   Label validity_cell_check_done(this);
321   Node* validity_cell =
322       LoadObjectField(handler, LoadHandler::kValidityCellOffset);
323   GotoIf(WordEqual(validity_cell, IntPtrConstant(0)),
324          &validity_cell_check_done);
325   Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
326   GotoIf(WordNotEqual(cell_value,
327                       SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
328          miss);
329   Goto(&validity_cell_check_done);
330 
331   Bind(&validity_cell_check_done);
332   Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
333   CSA_ASSERT(this, TaggedIsSmi(smi_handler));
334   Node* handler_flags = SmiUntag(smi_handler);
335 
336   Label check_prototypes(this);
337   GotoIfNot(
338       IsSetWord<LoadHandler::DoNegativeLookupOnReceiverBits>(handler_flags),
339       &check_prototypes);
340   {
341     CSA_ASSERT(this, Word32BinaryNot(
342                          HasInstanceType(p->receiver, JS_GLOBAL_OBJECT_TYPE)));
343     // We have a dictionary receiver, do a negative lookup check.
344     NameDictionaryNegativeLookup(p->receiver, p->name, miss);
345     Goto(&check_prototypes);
346   }
347 
348   Bind(&check_prototypes);
349   Node* maybe_holder_cell =
350       LoadObjectField(handler, LoadHandler::kHolderCellOffset);
351   Label array_handler(this), tuple_handler(this);
352   Branch(TaggedIsSmi(maybe_holder_cell), &array_handler, &tuple_handler);
353 
354   Bind(&tuple_handler);
355   {
356     Label load_existent(this);
357     GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent);
358     // This is a handler for a load of a non-existent value.
359     if (throw_reference_error_if_nonexistent) {
360       exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context,
361                                     p->name);
362     } else {
363       exit_point->Return(UndefinedConstant());
364     }
365 
366     Bind(&load_existent);
367     Node* holder = LoadWeakCellValue(maybe_holder_cell);
368     // The |holder| is guaranteed to be alive at this point since we passed
369     // both the receiver map check and the validity cell check.
370     CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0)));
371 
372     var_holder->Bind(holder);
373     var_smi_handler->Bind(smi_handler);
374     Goto(if_smi_handler);
375   }
376 
377   Bind(&array_handler);
378   {
379     exit_point->ReturnCallStub(
380         CodeFactory::LoadICProtoArray(isolate(),
381                                       throw_reference_error_if_nonexistent),
382         p->context, p->receiver, p->name, p->slot, p->vector, handler);
383   }
384 }
385 
EmitLoadICProtoArrayCheck(const LoadICParameters * p,Node * handler,Node * handler_length,Node * handler_flags,Label * miss,bool throw_reference_error_if_nonexistent)386 Node* AccessorAssembler::EmitLoadICProtoArrayCheck(
387     const LoadICParameters* p, Node* handler, Node* handler_length,
388     Node* handler_flags, Label* miss,
389     bool throw_reference_error_if_nonexistent) {
390   Variable start_index(this, MachineType::PointerRepresentation());
391   start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex));
392 
393   Label can_access(this);
394   GotoIfNot(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
395             &can_access);
396   {
397     // Skip this entry of a handler.
398     start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1));
399 
400     int offset =
401         FixedArray::OffsetOfElementAt(LoadHandler::kFirstPrototypeIndex);
402     Node* expected_native_context =
403         LoadWeakCellValue(LoadObjectField(handler, offset), miss);
404     CSA_ASSERT(this, IsNativeContext(expected_native_context));
405 
406     Node* native_context = LoadNativeContext(p->context);
407     GotoIf(WordEqual(expected_native_context, native_context), &can_access);
408     // If the receiver is not a JSGlobalProxy then we miss.
409     GotoIfNot(IsJSGlobalProxy(p->receiver), miss);
410     // For JSGlobalProxy receiver try to compare security tokens of current
411     // and expected native contexts.
412     Node* expected_token = LoadContextElement(expected_native_context,
413                                               Context::SECURITY_TOKEN_INDEX);
414     Node* current_token =
415         LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
416     Branch(WordEqual(expected_token, current_token), &can_access, miss);
417   }
418   Bind(&can_access);
419 
420   BuildFastLoop(start_index.value(), handler_length,
421                 [this, p, handler, miss](Node* current) {
422                   Node* prototype_cell =
423                       LoadFixedArrayElement(handler, current);
424                   CheckPrototype(prototype_cell, p->name, miss);
425                 },
426                 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
427 
428   Node* maybe_holder_cell =
429       LoadFixedArrayElement(handler, LoadHandler::kHolderCellIndex);
430   Label load_existent(this);
431   GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent);
432   // This is a handler for a load of a non-existent value.
433   if (throw_reference_error_if_nonexistent) {
434     TailCallRuntime(Runtime::kThrowReferenceError, p->context, p->name);
435   } else {
436     Return(UndefinedConstant());
437   }
438 
439   Bind(&load_existent);
440   Node* holder = LoadWeakCellValue(maybe_holder_cell);
441   // The |holder| is guaranteed to be alive at this point since we passed
442   // the receiver map check, the validity cell check and the prototype chain
443   // check.
444   CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0)));
445   return holder;
446 }
447 
HandleLoadGlobalICHandlerCase(const LoadICParameters * pp,Node * handler,Label * miss,ExitPoint * exit_point,bool throw_reference_error_if_nonexistent)448 void AccessorAssembler::HandleLoadGlobalICHandlerCase(
449     const LoadICParameters* pp, Node* handler, Label* miss,
450     ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) {
451   LoadICParameters p = *pp;
452   DCHECK_NULL(p.receiver);
453   Node* native_context = LoadNativeContext(p.context);
454   p.receiver = LoadContextElement(native_context, Context::EXTENSION_INDEX);
455 
456   Variable var_holder(this, MachineRepresentation::kTagged);
457   Variable var_smi_handler(this, MachineRepresentation::kTagged);
458   Label if_smi_handler(this);
459   HandleLoadICProtoHandlerCase(&p, handler, &var_holder, &var_smi_handler,
460                                &if_smi_handler, miss, exit_point,
461                                throw_reference_error_if_nonexistent);
462   Bind(&if_smi_handler);
463   HandleLoadICSmiHandlerCase(&p, var_holder.value(), var_smi_handler.value(),
464                              miss, exit_point, kOnlyProperties);
465 }
466 
HandleStoreICHandlerCase(const StoreICParameters * p,Node * handler,Label * miss,ElementSupport support_elements)467 void AccessorAssembler::HandleStoreICHandlerCase(
468     const StoreICParameters* p, Node* handler, Label* miss,
469     ElementSupport support_elements) {
470   Label if_smi_handler(this), if_nonsmi_handler(this);
471   Label if_proto_handler(this), if_element_handler(this), call_handler(this);
472 
473   Branch(TaggedIsSmi(handler), &if_smi_handler, &if_nonsmi_handler);
474 
475   // |handler| is a Smi, encoding what to do. See SmiHandler methods
476   // for the encoding format.
477   Bind(&if_smi_handler);
478   {
479     Node* holder = p->receiver;
480     Node* handler_word = SmiUntag(handler);
481 
482     // Handle non-transitioning field stores.
483     HandleStoreICSmiHandlerCase(handler_word, holder, p->value, nullptr, miss);
484   }
485 
486   Bind(&if_nonsmi_handler);
487   {
488     Node* handler_map = LoadMap(handler);
489     if (support_elements == kSupportElements) {
490       GotoIf(IsTuple2Map(handler_map), &if_element_handler);
491     }
492     Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler);
493   }
494 
495   if (support_elements == kSupportElements) {
496     Bind(&if_element_handler);
497     { HandleStoreICElementHandlerCase(p, handler, miss); }
498   }
499 
500   Bind(&if_proto_handler);
501   {
502     HandleStoreICProtoHandler(p, handler, miss);
503   }
504 
505   // |handler| is a heap object. Must be code, call it.
506   Bind(&call_handler);
507   {
508     StoreWithVectorDescriptor descriptor(isolate());
509     TailCallStub(descriptor, handler, p->context, p->receiver, p->name,
510                  p->value, p->slot, p->vector);
511   }
512 }
513 
HandleStoreICElementHandlerCase(const StoreICParameters * p,Node * handler,Label * miss)514 void AccessorAssembler::HandleStoreICElementHandlerCase(
515     const StoreICParameters* p, Node* handler, Label* miss) {
516   Comment("HandleStoreICElementHandlerCase");
517   Node* validity_cell = LoadObjectField(handler, Tuple2::kValue1Offset);
518   Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
519   GotoIf(WordNotEqual(cell_value,
520                       SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
521          miss);
522 
523   Node* code_handler = LoadObjectField(handler, Tuple2::kValue2Offset);
524   CSA_ASSERT(this, IsCodeMap(LoadMap(code_handler)));
525 
526   StoreWithVectorDescriptor descriptor(isolate());
527   TailCallStub(descriptor, code_handler, p->context, p->receiver, p->name,
528                p->value, p->slot, p->vector);
529 }
530 
HandleStoreICProtoHandler(const StoreICParameters * p,Node * handler,Label * miss)531 void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
532                                                   Node* handler, Label* miss) {
533   // IC dispatchers rely on these assumptions to be held.
534   STATIC_ASSERT(FixedArray::kLengthOffset ==
535                 StoreHandler::kTransitionCellOffset);
536   DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kSmiHandlerIndex),
537             StoreHandler::kSmiHandlerOffset);
538   DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kValidityCellIndex),
539             StoreHandler::kValidityCellOffset);
540 
541   // Both FixedArray and Tuple3 handlers have validity cell at the same offset.
542   Label validity_cell_check_done(this);
543   Node* validity_cell =
544       LoadObjectField(handler, StoreHandler::kValidityCellOffset);
545   GotoIf(WordEqual(validity_cell, IntPtrConstant(0)),
546          &validity_cell_check_done);
547   Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
548   GotoIf(WordNotEqual(cell_value,
549                       SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
550          miss);
551   Goto(&validity_cell_check_done);
552 
553   Bind(&validity_cell_check_done);
554   Node* smi_handler = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
555   CSA_ASSERT(this, TaggedIsSmi(smi_handler));
556 
557   Node* maybe_transition_cell =
558       LoadObjectField(handler, StoreHandler::kTransitionCellOffset);
559   Label array_handler(this), tuple_handler(this);
560   Branch(TaggedIsSmi(maybe_transition_cell), &array_handler, &tuple_handler);
561 
562   Variable var_transition(this, MachineRepresentation::kTagged);
563   Label if_transition(this), if_transition_to_constant(this);
564   Bind(&tuple_handler);
565   {
566     Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
567     var_transition.Bind(transition);
568     Goto(&if_transition);
569   }
570 
571   Bind(&array_handler);
572   {
573     Node* length = SmiUntag(maybe_transition_cell);
574     BuildFastLoop(IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length,
575                   [this, p, handler, miss](Node* current) {
576                     Node* prototype_cell =
577                         LoadFixedArrayElement(handler, current);
578                     CheckPrototype(prototype_cell, p->name, miss);
579                   },
580                   1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
581 
582     Node* maybe_transition_cell =
583         LoadFixedArrayElement(handler, StoreHandler::kTransitionCellIndex);
584     Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
585     var_transition.Bind(transition);
586     Goto(&if_transition);
587   }
588 
589   Bind(&if_transition);
590   {
591     Node* holder = p->receiver;
592     Node* transition = var_transition.value();
593     Node* handler_word = SmiUntag(smi_handler);
594 
595     GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(transition)), miss);
596 
597     Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
598     GotoIf(WordEqual(handler_kind,
599                      IntPtrConstant(StoreHandler::kTransitionToConstant)),
600            &if_transition_to_constant);
601 
602     // Handle transitioning field stores.
603     HandleStoreICSmiHandlerCase(handler_word, holder, p->value, transition,
604                                 miss);
605 
606     Bind(&if_transition_to_constant);
607     {
608       // Check that constant matches value.
609       Node* value_index_in_descriptor =
610           DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
611       Node* descriptors = LoadMapDescriptors(transition);
612       Node* constant =
613           LoadFixedArrayElement(descriptors, value_index_in_descriptor);
614       GotoIf(WordNotEqual(p->value, constant), miss);
615 
616       StoreMap(p->receiver, transition);
617       Return(p->value);
618     }
619   }
620 }
621 
HandleStoreICSmiHandlerCase(Node * handler_word,Node * holder,Node * value,Node * transition,Label * miss)622 void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
623                                                     Node* holder, Node* value,
624                                                     Node* transition,
625                                                     Label* miss) {
626   Comment(transition ? "transitioning field store" : "field store");
627 
628 #ifdef DEBUG
629   Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
630   if (transition) {
631     CSA_ASSERT(
632         this,
633         Word32Or(
634             WordEqual(handler_kind,
635                       IntPtrConstant(StoreHandler::kTransitionToField)),
636             WordEqual(handler_kind,
637                       IntPtrConstant(StoreHandler::kTransitionToConstant))));
638   } else {
639     if (FLAG_track_constant_fields) {
640       CSA_ASSERT(
641           this,
642           Word32Or(WordEqual(handler_kind,
643                              IntPtrConstant(StoreHandler::kStoreField)),
644                    WordEqual(handler_kind,
645                              IntPtrConstant(StoreHandler::kStoreConstField))));
646     } else {
647       CSA_ASSERT(this, WordEqual(handler_kind,
648                                  IntPtrConstant(StoreHandler::kStoreField)));
649     }
650   }
651 #endif
652 
653   Node* field_representation =
654       DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word);
655 
656   Label if_smi_field(this), if_double_field(this), if_heap_object_field(this),
657       if_tagged_field(this);
658 
659   GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)),
660          &if_tagged_field);
661   GotoIf(WordEqual(field_representation,
662                    IntPtrConstant(StoreHandler::kHeapObject)),
663          &if_heap_object_field);
664   GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)),
665          &if_double_field);
666   CSA_ASSERT(this, WordEqual(field_representation,
667                              IntPtrConstant(StoreHandler::kSmi)));
668   Goto(&if_smi_field);
669 
670   Bind(&if_tagged_field);
671   {
672     Comment("store tagged field");
673     HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(),
674                               value, transition, miss);
675   }
676 
677   Bind(&if_double_field);
678   {
679     Comment("store double field");
680     HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(),
681                               value, transition, miss);
682   }
683 
684   Bind(&if_heap_object_field);
685   {
686     Comment("store heap object field");
687     HandleStoreFieldAndReturn(handler_word, holder,
688                               Representation::HeapObject(), value, transition,
689                               miss);
690   }
691 
692   Bind(&if_smi_field);
693   {
694     Comment("store smi field");
695     HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(),
696                               value, transition, miss);
697   }
698 }
699 
HandleStoreFieldAndReturn(Node * handler_word,Node * holder,Representation representation,Node * value,Node * transition,Label * miss)700 void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
701                                                   Node* holder,
702                                                   Representation representation,
703                                                   Node* value, Node* transition,
704                                                   Label* miss) {
705   bool transition_to_field = transition != nullptr;
706   Node* prepared_value = PrepareValueForStore(
707       handler_word, holder, representation, transition, value, miss);
708 
709   Label if_inobject(this), if_out_of_object(this);
710   Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject,
711          &if_out_of_object);
712 
713   Bind(&if_inobject);
714   {
715     StoreNamedField(handler_word, holder, true, representation, prepared_value,
716                     transition_to_field, miss);
717     if (transition_to_field) {
718       StoreMap(holder, transition);
719     }
720     Return(value);
721   }
722 
723   Bind(&if_out_of_object);
724   {
725     if (transition_to_field) {
726       Label storage_extended(this);
727       GotoIfNot(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word),
728                 &storage_extended);
729       Comment("[ Extend storage");
730       ExtendPropertiesBackingStore(holder);
731       Comment("] Extend storage");
732       Goto(&storage_extended);
733 
734       Bind(&storage_extended);
735     }
736 
737     StoreNamedField(handler_word, holder, false, representation, prepared_value,
738                     transition_to_field, miss);
739     if (transition_to_field) {
740       StoreMap(holder, transition);
741     }
742     Return(value);
743   }
744 }
745 
PrepareValueForStore(Node * handler_word,Node * holder,Representation representation,Node * transition,Node * value,Label * bailout)746 Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
747                                               Representation representation,
748                                               Node* transition, Node* value,
749                                               Label* bailout) {
750   if (representation.IsDouble()) {
751     value = TryTaggedToFloat64(value, bailout);
752 
753   } else if (representation.IsHeapObject()) {
754     GotoIf(TaggedIsSmi(value), bailout);
755 
756     Label done(this);
757     if (FLAG_track_constant_fields && !transition) {
758       // Skip field type check in favor of constant value check when storing
759       // to constant field.
760       GotoIf(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
761                        IntPtrConstant(StoreHandler::kStoreConstField)),
762              &done);
763     }
764     Node* value_index_in_descriptor =
765         DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
766     Node* descriptors =
767         LoadMapDescriptors(transition ? transition : LoadMap(holder));
768     Node* maybe_field_type =
769         LoadFixedArrayElement(descriptors, value_index_in_descriptor);
770 
771     GotoIf(TaggedIsSmi(maybe_field_type), &done);
772     // Check that value type matches the field type.
773     {
774       Node* field_type = LoadWeakCellValue(maybe_field_type, bailout);
775       Branch(WordEqual(LoadMap(value), field_type), &done, bailout);
776     }
777     Bind(&done);
778 
779   } else if (representation.IsSmi()) {
780     GotoIfNot(TaggedIsSmi(value), bailout);
781 
782   } else {
783     DCHECK(representation.IsTagged());
784   }
785   return value;
786 }
787 
ExtendPropertiesBackingStore(Node * object)788 void AccessorAssembler::ExtendPropertiesBackingStore(Node* object) {
789   Node* properties = LoadProperties(object);
790   Node* length = LoadFixedArrayBaseLength(properties);
791 
792   ParameterMode mode = OptimalParameterMode();
793   length = TaggedToParameter(length, mode);
794 
795   Node* delta = IntPtrOrSmiConstant(JSObject::kFieldsAdded, mode);
796   Node* new_capacity = IntPtrOrSmiAdd(length, delta, mode);
797 
798   // Grow properties array.
799   ElementsKind kind = FAST_ELEMENTS;
800   DCHECK(kMaxNumberOfDescriptors + JSObject::kFieldsAdded <
801          FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind));
802   // The size of a new properties backing store is guaranteed to be small
803   // enough that the new backing store will be allocated in new space.
804   CSA_ASSERT(this,
805              UintPtrOrSmiLessThan(
806                  new_capacity,
807                  IntPtrOrSmiConstant(
808                      kMaxNumberOfDescriptors + JSObject::kFieldsAdded, mode),
809                  mode));
810 
811   Node* new_properties = AllocateFixedArray(kind, new_capacity, mode);
812 
813   FillFixedArrayWithValue(kind, new_properties, length, new_capacity,
814                           Heap::kUndefinedValueRootIndex, mode);
815 
816   // |new_properties| is guaranteed to be in new space, so we can skip
817   // the write barrier.
818   CopyFixedArrayElements(kind, properties, new_properties, length,
819                          SKIP_WRITE_BARRIER, mode);
820 
821   StoreObjectField(object, JSObject::kPropertiesOffset, new_properties);
822 }
823 
StoreNamedField(Node * handler_word,Node * object,bool is_inobject,Representation representation,Node * value,bool transition_to_field,Label * bailout)824 void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
825                                         bool is_inobject,
826                                         Representation representation,
827                                         Node* value, bool transition_to_field,
828                                         Label* bailout) {
829   bool store_value_as_double = representation.IsDouble();
830   Node* property_storage = object;
831   if (!is_inobject) {
832     property_storage = LoadProperties(object);
833   }
834 
835   Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word);
836   if (representation.IsDouble()) {
837     if (!FLAG_unbox_double_fields || !is_inobject) {
838       if (transition_to_field) {
839         Node* heap_number = AllocateHeapNumberWithValue(value, MUTABLE);
840         // Store the new mutable heap number into the object.
841         value = heap_number;
842         store_value_as_double = false;
843       } else {
844         // Load the heap number.
845         property_storage = LoadObjectField(property_storage, offset);
846         // Store the double value into it.
847         offset = IntPtrConstant(HeapNumber::kValueOffset);
848       }
849     }
850   }
851 
852   // Do constant value check if necessary.
853   if (FLAG_track_constant_fields && !transition_to_field) {
854     Label done(this);
855     GotoIfNot(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
856                         IntPtrConstant(StoreHandler::kStoreConstField)),
857               &done);
858     {
859       if (store_value_as_double) {
860         Node* current_value =
861             LoadObjectField(property_storage, offset, MachineType::Float64());
862         GotoIfNot(Float64Equal(current_value, value), bailout);
863       } else {
864         Node* current_value = LoadObjectField(property_storage, offset);
865         GotoIfNot(WordEqual(current_value, value), bailout);
866       }
867       Goto(&done);
868     }
869     Bind(&done);
870   }
871 
872   // Do the store.
873   if (store_value_as_double) {
874     StoreObjectFieldNoWriteBarrier(property_storage, offset, value,
875                                    MachineRepresentation::kFloat64);
876   } else if (representation.IsSmi()) {
877     StoreObjectFieldNoWriteBarrier(property_storage, offset, value);
878   } else {
879     StoreObjectField(property_storage, offset, value);
880   }
881 }
882 
EmitFastElementsBoundsCheck(Node * object,Node * elements,Node * intptr_index,Node * is_jsarray_condition,Label * miss)883 void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
884                                                     Node* elements,
885                                                     Node* intptr_index,
886                                                     Node* is_jsarray_condition,
887                                                     Label* miss) {
888   Variable var_length(this, MachineType::PointerRepresentation());
889   Comment("Fast elements bounds check");
890   Label if_array(this), length_loaded(this, &var_length);
891   GotoIf(is_jsarray_condition, &if_array);
892   {
893     var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements)));
894     Goto(&length_loaded);
895   }
896   Bind(&if_array);
897   {
898     var_length.Bind(SmiUntag(LoadJSArrayLength(object)));
899     Goto(&length_loaded);
900   }
901   Bind(&length_loaded);
902   GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss);
903 }
904 
EmitElementLoad(Node * object,Node * elements,Node * elements_kind,Node * intptr_index,Node * is_jsarray_condition,Label * if_hole,Label * rebox_double,Variable * var_double_value,Label * unimplemented_elements_kind,Label * out_of_bounds,Label * miss,ExitPoint * exit_point)905 void AccessorAssembler::EmitElementLoad(
906     Node* object, Node* elements, Node* elements_kind, Node* intptr_index,
907     Node* is_jsarray_condition, Label* if_hole, Label* rebox_double,
908     Variable* var_double_value, Label* unimplemented_elements_kind,
909     Label* out_of_bounds, Label* miss, ExitPoint* exit_point) {
910   Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this),
911       if_fast_double(this), if_fast_holey_double(this), if_nonfast(this),
912       if_dictionary(this);
913   GotoIf(
914       Int32GreaterThan(elements_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
915       &if_nonfast);
916 
917   EmitFastElementsBoundsCheck(object, elements, intptr_index,
918                               is_jsarray_condition, out_of_bounds);
919   int32_t kinds[] = {// Handled by if_fast_packed.
920                      FAST_SMI_ELEMENTS, FAST_ELEMENTS,
921                      // Handled by if_fast_holey.
922                      FAST_HOLEY_SMI_ELEMENTS, FAST_HOLEY_ELEMENTS,
923                      // Handled by if_fast_double.
924                      FAST_DOUBLE_ELEMENTS,
925                      // Handled by if_fast_holey_double.
926                      FAST_HOLEY_DOUBLE_ELEMENTS};
927   Label* labels[] = {// FAST_{SMI,}_ELEMENTS
928                      &if_fast_packed, &if_fast_packed,
929                      // FAST_HOLEY_{SMI,}_ELEMENTS
930                      &if_fast_holey, &if_fast_holey,
931                      // FAST_DOUBLE_ELEMENTS
932                      &if_fast_double,
933                      // FAST_HOLEY_DOUBLE_ELEMENTS
934                      &if_fast_holey_double};
935   Switch(elements_kind, unimplemented_elements_kind, kinds, labels,
936          arraysize(kinds));
937 
938   Bind(&if_fast_packed);
939   {
940     Comment("fast packed elements");
941     exit_point->Return(LoadFixedArrayElement(elements, intptr_index));
942   }
943 
944   Bind(&if_fast_holey);
945   {
946     Comment("fast holey elements");
947     Node* element = LoadFixedArrayElement(elements, intptr_index);
948     GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
949     exit_point->Return(element);
950   }
951 
952   Bind(&if_fast_double);
953   {
954     Comment("packed double elements");
955     var_double_value->Bind(LoadFixedDoubleArrayElement(elements, intptr_index,
956                                                        MachineType::Float64()));
957     Goto(rebox_double);
958   }
959 
960   Bind(&if_fast_holey_double);
961   {
962     Comment("holey double elements");
963     Node* value = LoadFixedDoubleArrayElement(elements, intptr_index,
964                                               MachineType::Float64(), 0,
965                                               INTPTR_PARAMETERS, if_hole);
966     var_double_value->Bind(value);
967     Goto(rebox_double);
968   }
969 
970   Bind(&if_nonfast);
971   {
972     STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
973     GotoIf(Int32GreaterThanOrEqual(
974                elements_kind,
975                Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)),
976            &if_typed_array);
977     GotoIf(Word32Equal(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)),
978            &if_dictionary);
979     Goto(unimplemented_elements_kind);
980   }
981 
982   Bind(&if_dictionary);
983   {
984     Comment("dictionary elements");
985     GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds);
986     Variable var_entry(this, MachineType::PointerRepresentation());
987     Label if_found(this);
988     NumberDictionaryLookup<SeededNumberDictionary>(
989         elements, intptr_index, &if_found, &var_entry, if_hole);
990     Bind(&if_found);
991     // Check that the value is a data property.
992     Node* index = EntryToIndex<SeededNumberDictionary>(var_entry.value());
993     Node* details =
994         LoadDetailsByKeyIndex<SeededNumberDictionary>(elements, index);
995     Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
996     // TODO(jkummerow): Support accessors without missing?
997     GotoIfNot(Word32Equal(kind, Int32Constant(kData)), miss);
998     // Finally, load the value.
999     exit_point->Return(
1000         LoadValueByKeyIndex<SeededNumberDictionary>(elements, index));
1001   }
1002 
1003   Bind(&if_typed_array);
1004   {
1005     Comment("typed elements");
1006     // Check if buffer has been neutered.
1007     Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset);
1008     GotoIf(IsDetachedBuffer(buffer), miss);
1009 
1010     // Bounds check.
1011     Node* length =
1012         SmiUntag(LoadObjectField(object, JSTypedArray::kLengthOffset));
1013     GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds);
1014 
1015     // Backing store = external_pointer + base_pointer.
1016     Node* external_pointer =
1017         LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
1018                         MachineType::Pointer());
1019     Node* base_pointer =
1020         LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
1021     Node* backing_store =
1022         IntPtrAdd(external_pointer, BitcastTaggedToWord(base_pointer));
1023 
1024     Label uint8_elements(this), int8_elements(this), uint16_elements(this),
1025         int16_elements(this), uint32_elements(this), int32_elements(this),
1026         float32_elements(this), float64_elements(this);
1027     Label* elements_kind_labels[] = {
1028         &uint8_elements,  &uint8_elements,   &int8_elements,
1029         &uint16_elements, &int16_elements,   &uint32_elements,
1030         &int32_elements,  &float32_elements, &float64_elements};
1031     int32_t elements_kinds[] = {
1032         UINT8_ELEMENTS,  UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
1033         UINT16_ELEMENTS, INT16_ELEMENTS,         UINT32_ELEMENTS,
1034         INT32_ELEMENTS,  FLOAT32_ELEMENTS,       FLOAT64_ELEMENTS};
1035     const size_t kTypedElementsKindCount =
1036         LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
1037         FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1;
1038     DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
1039     DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
1040     Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
1041            kTypedElementsKindCount);
1042     Bind(&uint8_elements);
1043     {
1044       Comment("UINT8_ELEMENTS");  // Handles UINT8_CLAMPED_ELEMENTS too.
1045       Node* element = Load(MachineType::Uint8(), backing_store, intptr_index);
1046       exit_point->Return(SmiFromWord32(element));
1047     }
1048     Bind(&int8_elements);
1049     {
1050       Comment("INT8_ELEMENTS");
1051       Node* element = Load(MachineType::Int8(), backing_store, intptr_index);
1052       exit_point->Return(SmiFromWord32(element));
1053     }
1054     Bind(&uint16_elements);
1055     {
1056       Comment("UINT16_ELEMENTS");
1057       Node* index = WordShl(intptr_index, IntPtrConstant(1));
1058       Node* element = Load(MachineType::Uint16(), backing_store, index);
1059       exit_point->Return(SmiFromWord32(element));
1060     }
1061     Bind(&int16_elements);
1062     {
1063       Comment("INT16_ELEMENTS");
1064       Node* index = WordShl(intptr_index, IntPtrConstant(1));
1065       Node* element = Load(MachineType::Int16(), backing_store, index);
1066       exit_point->Return(SmiFromWord32(element));
1067     }
1068     Bind(&uint32_elements);
1069     {
1070       Comment("UINT32_ELEMENTS");
1071       Node* index = WordShl(intptr_index, IntPtrConstant(2));
1072       Node* element = Load(MachineType::Uint32(), backing_store, index);
1073       exit_point->Return(ChangeUint32ToTagged(element));
1074     }
1075     Bind(&int32_elements);
1076     {
1077       Comment("INT32_ELEMENTS");
1078       Node* index = WordShl(intptr_index, IntPtrConstant(2));
1079       Node* element = Load(MachineType::Int32(), backing_store, index);
1080       exit_point->Return(ChangeInt32ToTagged(element));
1081     }
1082     Bind(&float32_elements);
1083     {
1084       Comment("FLOAT32_ELEMENTS");
1085       Node* index = WordShl(intptr_index, IntPtrConstant(2));
1086       Node* element = Load(MachineType::Float32(), backing_store, index);
1087       var_double_value->Bind(ChangeFloat32ToFloat64(element));
1088       Goto(rebox_double);
1089     }
1090     Bind(&float64_elements);
1091     {
1092       Comment("FLOAT64_ELEMENTS");
1093       Node* index = WordShl(intptr_index, IntPtrConstant(3));
1094       Node* element = Load(MachineType::Float64(), backing_store, index);
1095       var_double_value->Bind(element);
1096       Goto(rebox_double);
1097     }
1098   }
1099 }
1100 
CheckPrototype(Node * prototype_cell,Node * name,Label * miss)1101 void AccessorAssembler::CheckPrototype(Node* prototype_cell, Node* name,
1102                                        Label* miss) {
1103   Node* maybe_prototype = LoadWeakCellValue(prototype_cell, miss);
1104 
1105   Label done(this);
1106   Label if_property_cell(this), if_dictionary_object(this);
1107 
1108   // |maybe_prototype| is either a PropertyCell or a slow-mode prototype.
1109   Branch(WordEqual(LoadMap(maybe_prototype),
1110                    LoadRoot(Heap::kGlobalPropertyCellMapRootIndex)),
1111          &if_property_cell, &if_dictionary_object);
1112 
1113   Bind(&if_dictionary_object);
1114   {
1115     CSA_ASSERT(this, IsDictionaryMap(LoadMap(maybe_prototype)));
1116     NameDictionaryNegativeLookup(maybe_prototype, name, miss);
1117     Goto(&done);
1118   }
1119 
1120   Bind(&if_property_cell);
1121   {
1122     // Ensure the property cell still contains the hole.
1123     Node* value = LoadObjectField(maybe_prototype, PropertyCell::kValueOffset);
1124     GotoIf(WordNotEqual(value, LoadRoot(Heap::kTheHoleValueRootIndex)), miss);
1125     Goto(&done);
1126   }
1127 
1128   Bind(&done);
1129 }
1130 
NameDictionaryNegativeLookup(Node * object,Node * name,Label * miss)1131 void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name,
1132                                                      Label* miss) {
1133   CSA_ASSERT(this, IsDictionaryMap(LoadMap(object)));
1134   Node* properties = LoadProperties(object);
1135   // Ensure the property does not exist in a dictionary-mode object.
1136   Variable var_name_index(this, MachineType::PointerRepresentation());
1137   Label done(this);
1138   NameDictionaryLookup<NameDictionary>(properties, name, miss, &var_name_index,
1139                                        &done);
1140   Bind(&done);
1141 }
1142 
GenericElementLoad(Node * receiver,Node * receiver_map,Node * instance_type,Node * index,Label * slow)1143 void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
1144                                            Node* instance_type, Node* index,
1145                                            Label* slow) {
1146   Comment("integer index");
1147 
1148   ExitPoint direct_exit(this);
1149 
1150   Label if_element_hole(this), if_oob(this);
1151   // Receivers requiring non-standard element accesses (interceptors, access
1152   // checks, strings and string wrappers, proxies) are handled in the runtime.
1153   GotoIf(Int32LessThanOrEqual(instance_type,
1154                               Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
1155          slow);
1156   Node* elements = LoadElements(receiver);
1157   Node* elements_kind = LoadMapElementsKind(receiver_map);
1158   Node* is_jsarray_condition =
1159       Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE));
1160   Variable var_double_value(this, MachineRepresentation::kFloat64);
1161   Label rebox_double(this, &var_double_value);
1162 
1163   // Unimplemented elements kinds fall back to a runtime call.
1164   Label* unimplemented_elements_kind = slow;
1165   IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
1166   EmitElementLoad(receiver, elements, elements_kind, index,
1167                   is_jsarray_condition, &if_element_hole, &rebox_double,
1168                   &var_double_value, unimplemented_elements_kind, &if_oob, slow,
1169                   &direct_exit);
1170 
1171   Bind(&rebox_double);
1172   Return(AllocateHeapNumberWithValue(var_double_value.value()));
1173 
1174   Bind(&if_oob);
1175   {
1176     Comment("out of bounds");
1177     // Negative keys can't take the fast OOB path.
1178     GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), slow);
1179     // Positive OOB indices are effectively the same as hole loads.
1180     Goto(&if_element_hole);
1181   }
1182 
1183   Bind(&if_element_hole);
1184   {
1185     Comment("found the hole");
1186     Label return_undefined(this);
1187     BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, slow);
1188 
1189     Bind(&return_undefined);
1190     Return(UndefinedConstant());
1191   }
1192 }
1193 
GenericPropertyLoad(Node * receiver,Node * receiver_map,Node * instance_type,Node * key,const LoadICParameters * p,Label * slow)1194 void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
1195                                             Node* instance_type, Node* key,
1196                                             const LoadICParameters* p,
1197                                             Label* slow) {
1198   Comment("key is unique name");
1199   Label if_found_on_receiver(this), if_property_dictionary(this),
1200       lookup_prototype_chain(this);
1201   Variable var_details(this, MachineRepresentation::kWord32);
1202   Variable var_value(this, MachineRepresentation::kTagged);
1203 
1204   // Receivers requiring non-standard accesses (interceptors, access
1205   // checks, strings and string wrappers, proxies) are handled in the runtime.
1206   GotoIf(Int32LessThanOrEqual(instance_type,
1207                               Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
1208          slow);
1209 
1210   // Check if the receiver has fast or slow properties.
1211   Node* properties = LoadProperties(receiver);
1212   Node* properties_map = LoadMap(properties);
1213   GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
1214          &if_property_dictionary);
1215 
1216   // Try looking up the property on the receiver; if unsuccessful, look
1217   // for a handler in the stub cache.
1218   Node* bitfield3 = LoadMapBitField3(receiver_map);
1219   Node* descriptors = LoadMapDescriptors(receiver_map);
1220 
1221   Label if_descriptor_found(this), stub_cache(this);
1222   Variable var_name_index(this, MachineType::PointerRepresentation());
1223   DescriptorLookup(key, descriptors, bitfield3, &if_descriptor_found,
1224                    &var_name_index, &stub_cache);
1225 
1226   Bind(&if_descriptor_found);
1227   {
1228     LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
1229                                var_name_index.value(), &var_details,
1230                                &var_value);
1231     Goto(&if_found_on_receiver);
1232   }
1233 
1234   Bind(&stub_cache);
1235   {
1236     Comment("stub cache probe for fast property load");
1237     Variable var_handler(this, MachineRepresentation::kTagged);
1238     Label found_handler(this, &var_handler), stub_cache_miss(this);
1239     TryProbeStubCache(isolate()->load_stub_cache(), receiver, key,
1240                       &found_handler, &var_handler, &stub_cache_miss);
1241     Bind(&found_handler);
1242     { HandleLoadICHandlerCase(p, var_handler.value(), slow); }
1243 
1244     Bind(&stub_cache_miss);
1245     {
1246       // TODO(jkummerow): Check if the property exists on the prototype
1247       // chain. If it doesn't, then there's no point in missing.
1248       Comment("KeyedLoadGeneric_miss");
1249       TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
1250                       p->name, p->slot, p->vector);
1251     }
1252   }
1253 
1254   Bind(&if_property_dictionary);
1255   {
1256     Comment("dictionary property load");
1257     // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
1258     // seeing global objects here (which would need special handling).
1259 
1260     Variable var_name_index(this, MachineType::PointerRepresentation());
1261     Label dictionary_found(this, &var_name_index);
1262     NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found,
1263                                          &var_name_index,
1264                                          &lookup_prototype_chain);
1265     Bind(&dictionary_found);
1266     {
1267       LoadPropertyFromNameDictionary(properties, var_name_index.value(),
1268                                      &var_details, &var_value);
1269       Goto(&if_found_on_receiver);
1270     }
1271   }
1272 
1273   Bind(&if_found_on_receiver);
1274   {
1275     Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
1276                                        p->context, receiver, slow);
1277     IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
1278     Return(value);
1279   }
1280 
1281   Bind(&lookup_prototype_chain);
1282   {
1283     Variable var_holder_map(this, MachineRepresentation::kTagged);
1284     Variable var_holder_instance_type(this, MachineRepresentation::kWord32);
1285     Label return_undefined(this);
1286     Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type};
1287     Label loop(this, arraysize(merged_variables), merged_variables);
1288 
1289     var_holder_map.Bind(receiver_map);
1290     var_holder_instance_type.Bind(instance_type);
1291     // Private symbols must not be looked up on the prototype chain.
1292     GotoIf(IsPrivateSymbol(key), &return_undefined);
1293     Goto(&loop);
1294     Bind(&loop);
1295     {
1296       // Bailout if it can be an integer indexed exotic case.
1297       GotoIf(Word32Equal(var_holder_instance_type.value(),
1298                          Int32Constant(JS_TYPED_ARRAY_TYPE)),
1299              slow);
1300       Node* proto = LoadMapPrototype(var_holder_map.value());
1301       GotoIf(WordEqual(proto, NullConstant()), &return_undefined);
1302       Node* proto_map = LoadMap(proto);
1303       Node* proto_instance_type = LoadMapInstanceType(proto_map);
1304       var_holder_map.Bind(proto_map);
1305       var_holder_instance_type.Bind(proto_instance_type);
1306       Label next_proto(this), return_value(this, &var_value), goto_slow(this);
1307       TryGetOwnProperty(p->context, receiver, proto, proto_map,
1308                         proto_instance_type, key, &return_value, &var_value,
1309                         &next_proto, &goto_slow);
1310 
1311       // This trampoline and the next are required to appease Turbofan's
1312       // variable merging.
1313       Bind(&next_proto);
1314       Goto(&loop);
1315 
1316       Bind(&goto_slow);
1317       Goto(slow);
1318 
1319       Bind(&return_value);
1320       Return(var_value.value());
1321     }
1322 
1323     Bind(&return_undefined);
1324     Return(UndefinedConstant());
1325   }
1326 }
1327 
1328 //////////////////// Stub cache access helpers.
1329 
1330 enum AccessorAssembler::StubCacheTable : int {
1331   kPrimary = static_cast<int>(StubCache::kPrimary),
1332   kSecondary = static_cast<int>(StubCache::kSecondary)
1333 };
1334 
StubCachePrimaryOffset(Node * name,Node * map)1335 Node* AccessorAssembler::StubCachePrimaryOffset(Node* name, Node* map) {
1336   // See v8::internal::StubCache::PrimaryOffset().
1337   STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift);
1338   // Compute the hash of the name (use entire hash field).
1339   Node* hash_field = LoadNameHashField(name);
1340   CSA_ASSERT(this,
1341              Word32Equal(Word32And(hash_field,
1342                                    Int32Constant(Name::kHashNotComputedMask)),
1343                          Int32Constant(0)));
1344 
1345   // Using only the low bits in 64-bit mode is unlikely to increase the
1346   // risk of collision even if the heap is spread over an area larger than
1347   // 4Gb (and not at all if it isn't).
1348   Node* map32 = TruncateWordToWord32(BitcastTaggedToWord(map));
1349   Node* hash = Int32Add(hash_field, map32);
1350   // Base the offset on a simple combination of name and map.
1351   hash = Word32Xor(hash, Int32Constant(StubCache::kPrimaryMagic));
1352   uint32_t mask = (StubCache::kPrimaryTableSize - 1)
1353                   << StubCache::kCacheIndexShift;
1354   return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
1355 }
1356 
StubCacheSecondaryOffset(Node * name,Node * seed)1357 Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) {
1358   // See v8::internal::StubCache::SecondaryOffset().
1359 
1360   // Use the seed from the primary cache in the secondary cache.
1361   Node* name32 = TruncateWordToWord32(BitcastTaggedToWord(name));
1362   Node* hash = Int32Sub(TruncateWordToWord32(seed), name32);
1363   hash = Int32Add(hash, Int32Constant(StubCache::kSecondaryMagic));
1364   int32_t mask = (StubCache::kSecondaryTableSize - 1)
1365                  << StubCache::kCacheIndexShift;
1366   return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
1367 }
1368 
TryProbeStubCacheTable(StubCache * stub_cache,StubCacheTable table_id,Node * entry_offset,Node * name,Node * map,Label * if_handler,Variable * var_handler,Label * if_miss)1369 void AccessorAssembler::TryProbeStubCacheTable(StubCache* stub_cache,
1370                                                StubCacheTable table_id,
1371                                                Node* entry_offset, Node* name,
1372                                                Node* map, Label* if_handler,
1373                                                Variable* var_handler,
1374                                                Label* if_miss) {
1375   StubCache::Table table = static_cast<StubCache::Table>(table_id);
1376 #ifdef DEBUG
1377   if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
1378     Goto(if_miss);
1379     return;
1380   } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
1381     Goto(if_miss);
1382     return;
1383   }
1384 #endif
1385   // The {table_offset} holds the entry offset times four (due to masking
1386   // and shifting optimizations).
1387   const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift;
1388   entry_offset = IntPtrMul(entry_offset, IntPtrConstant(kMultiplier));
1389 
1390   // Check that the key in the entry matches the name.
1391   Node* key_base =
1392       ExternalConstant(ExternalReference(stub_cache->key_reference(table)));
1393   Node* entry_key = Load(MachineType::Pointer(), key_base, entry_offset);
1394   GotoIf(WordNotEqual(name, entry_key), if_miss);
1395 
1396   // Get the map entry from the cache.
1397   DCHECK_EQ(kPointerSize * 2, stub_cache->map_reference(table).address() -
1398                                   stub_cache->key_reference(table).address());
1399   Node* entry_map =
1400       Load(MachineType::Pointer(), key_base,
1401            IntPtrAdd(entry_offset, IntPtrConstant(kPointerSize * 2)));
1402   GotoIf(WordNotEqual(map, entry_map), if_miss);
1403 
1404   DCHECK_EQ(kPointerSize, stub_cache->value_reference(table).address() -
1405                               stub_cache->key_reference(table).address());
1406   Node* handler = Load(MachineType::TaggedPointer(), key_base,
1407                        IntPtrAdd(entry_offset, IntPtrConstant(kPointerSize)));
1408 
1409   // We found the handler.
1410   var_handler->Bind(handler);
1411   Goto(if_handler);
1412 }
1413 
TryProbeStubCache(StubCache * stub_cache,Node * receiver,Node * name,Label * if_handler,Variable * var_handler,Label * if_miss)1414 void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
1415                                           Node* name, Label* if_handler,
1416                                           Variable* var_handler,
1417                                           Label* if_miss) {
1418   Label try_secondary(this), miss(this);
1419 
1420   Counters* counters = isolate()->counters();
1421   IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
1422 
1423   // Check that the {receiver} isn't a smi.
1424   GotoIf(TaggedIsSmi(receiver), &miss);
1425 
1426   Node* receiver_map = LoadMap(receiver);
1427 
1428   // Probe the primary table.
1429   Node* primary_offset = StubCachePrimaryOffset(name, receiver_map);
1430   TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name,
1431                          receiver_map, if_handler, var_handler, &try_secondary);
1432 
1433   Bind(&try_secondary);
1434   {
1435     // Probe the secondary table.
1436     Node* secondary_offset = StubCacheSecondaryOffset(name, primary_offset);
1437     TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name,
1438                            receiver_map, if_handler, var_handler, &miss);
1439   }
1440 
1441   Bind(&miss);
1442   {
1443     IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
1444     Goto(if_miss);
1445   }
1446 }
1447 
1448 //////////////////// Entry points into private implementation (one per stub).
1449 
LoadIC(const LoadICParameters * p)1450 void AccessorAssembler::LoadIC(const LoadICParameters* p) {
1451   Variable var_handler(this, MachineRepresentation::kTagged);
1452   // TODO(ishell): defer blocks when it works.
1453   Label if_handler(this, &var_handler), try_polymorphic(this),
1454       try_megamorphic(this /*, Label::kDeferred*/),
1455       miss(this /*, Label::kDeferred*/);
1456 
1457   Node* receiver_map = LoadReceiverMap(p->receiver);
1458   GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
1459 
1460   // Check monomorphic case.
1461   Node* feedback =
1462       TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
1463                          &var_handler, &try_polymorphic);
1464   Bind(&if_handler);
1465   { HandleLoadICHandlerCase(p, var_handler.value(), &miss); }
1466 
1467   Bind(&try_polymorphic);
1468   {
1469     // Check polymorphic case.
1470     Comment("LoadIC_try_polymorphic");
1471     GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
1472               &try_megamorphic);
1473     HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
1474                           &miss, 2);
1475   }
1476 
1477   Bind(&try_megamorphic);
1478   {
1479     // Check megamorphic case.
1480     GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
1481               &miss);
1482 
1483     TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name,
1484                       &if_handler, &var_handler, &miss);
1485   }
1486   Bind(&miss);
1487   {
1488     TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
1489                     p->slot, p->vector);
1490   }
1491 }
1492 
LoadICProtoArray(const LoadICParameters * p,Node * handler,bool throw_reference_error_if_nonexistent)1493 void AccessorAssembler::LoadICProtoArray(
1494     const LoadICParameters* p, Node* handler,
1495     bool throw_reference_error_if_nonexistent) {
1496   Label miss(this);
1497   CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
1498   CSA_ASSERT(this, IsFixedArrayMap(LoadMap(handler)));
1499 
1500   ExitPoint direct_exit(this);
1501 
1502   Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
1503   Node* handler_flags = SmiUntag(smi_handler);
1504 
1505   Node* handler_length = LoadAndUntagFixedArrayBaseLength(handler);
1506 
1507   Node* holder =
1508       EmitLoadICProtoArrayCheck(p, handler, handler_length, handler_flags,
1509                                 &miss, throw_reference_error_if_nonexistent);
1510 
1511   HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, &direct_exit,
1512                              kOnlyProperties);
1513 
1514   Bind(&miss);
1515   {
1516     TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
1517                     p->slot, p->vector);
1518   }
1519 }
1520 
LoadGlobalIC_TryPropertyCellCase(Node * vector,Node * slot,ExitPoint * exit_point,Label * try_handler,Label * miss,ParameterMode slot_mode)1521 void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
1522     Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler,
1523     Label* miss, ParameterMode slot_mode) {
1524   Comment("LoadGlobalIC_TryPropertyCellCase");
1525 
1526   Node* weak_cell = LoadFixedArrayElement(vector, slot, 0, slot_mode);
1527   CSA_ASSERT(this, HasInstanceType(weak_cell, WEAK_CELL_TYPE));
1528 
1529   // Load value or try handler case if the {weak_cell} is cleared.
1530   Node* property_cell = LoadWeakCellValue(weak_cell, try_handler);
1531   CSA_ASSERT(this, HasInstanceType(property_cell, PROPERTY_CELL_TYPE));
1532 
1533   Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
1534   GotoIf(WordEqual(value, TheHoleConstant()), miss);
1535   exit_point->Return(value);
1536 }
1537 
LoadGlobalIC_TryHandlerCase(const LoadICParameters * p,TypeofMode typeof_mode,ExitPoint * exit_point,Label * miss)1538 void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* p,
1539                                                     TypeofMode typeof_mode,
1540                                                     ExitPoint* exit_point,
1541                                                     Label* miss) {
1542   Comment("LoadGlobalIC_TryHandlerCase");
1543 
1544   Label call_handler(this);
1545 
1546   Node* handler =
1547       LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
1548   CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
1549   GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
1550          miss);
1551   GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
1552 
1553   bool throw_reference_error_if_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF;
1554   HandleLoadGlobalICHandlerCase(p, handler, miss, exit_point,
1555                                 throw_reference_error_if_nonexistent);
1556 
1557   Bind(&call_handler);
1558   {
1559     LoadWithVectorDescriptor descriptor(isolate());
1560     Node* native_context = LoadNativeContext(p->context);
1561     Node* receiver =
1562         LoadContextElement(native_context, Context::EXTENSION_INDEX);
1563     exit_point->ReturnCallStub(descriptor, handler, p->context, receiver,
1564                                p->name, p->slot, p->vector);
1565   }
1566 }
1567 
LoadGlobalIC_MissCase(const LoadICParameters * p,ExitPoint * exit_point)1568 void AccessorAssembler::LoadGlobalIC_MissCase(const LoadICParameters* p,
1569                                               ExitPoint* exit_point) {
1570   Comment("LoadGlobalIC_MissCase");
1571 
1572   exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context,
1573                                 p->name, p->slot, p->vector);
1574 }
1575 
LoadGlobalIC(const LoadICParameters * p,TypeofMode typeof_mode)1576 void AccessorAssembler::LoadGlobalIC(const LoadICParameters* p,
1577                                      TypeofMode typeof_mode) {
1578   ExitPoint direct_exit(this);
1579 
1580   Label try_handler(this), miss(this);
1581   LoadGlobalIC_TryPropertyCellCase(p->vector, p->slot, &direct_exit,
1582                                    &try_handler, &miss);
1583 
1584   Bind(&try_handler);
1585   LoadGlobalIC_TryHandlerCase(p, typeof_mode, &direct_exit, &miss);
1586 
1587   Bind(&miss);
1588   LoadGlobalIC_MissCase(p, &direct_exit);
1589 }
1590 
KeyedLoadIC(const LoadICParameters * p)1591 void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
1592   Variable var_handler(this, MachineRepresentation::kTagged);
1593   // TODO(ishell): defer blocks when it works.
1594   Label if_handler(this, &var_handler), try_polymorphic(this),
1595       try_megamorphic(this /*, Label::kDeferred*/),
1596       try_polymorphic_name(this /*, Label::kDeferred*/),
1597       miss(this /*, Label::kDeferred*/);
1598 
1599   Node* receiver_map = LoadReceiverMap(p->receiver);
1600   GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
1601 
1602   // Check monomorphic case.
1603   Node* feedback =
1604       TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
1605                          &var_handler, &try_polymorphic);
1606   Bind(&if_handler);
1607   { HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements); }
1608 
1609   Bind(&try_polymorphic);
1610   {
1611     // Check polymorphic case.
1612     Comment("KeyedLoadIC_try_polymorphic");
1613     GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
1614               &try_megamorphic);
1615     HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
1616                           &miss, 2);
1617   }
1618 
1619   Bind(&try_megamorphic);
1620   {
1621     // Check megamorphic case.
1622     Comment("KeyedLoadIC_try_megamorphic");
1623     GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
1624               &try_polymorphic_name);
1625     // TODO(jkummerow): Inline this? Or some of it?
1626     TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context,
1627                  p->receiver, p->name, p->slot, p->vector);
1628   }
1629   Bind(&try_polymorphic_name);
1630   {
1631     // We might have a name in feedback, and a fixed array in the next slot.
1632     Comment("KeyedLoadIC_try_polymorphic_name");
1633     GotoIfNot(WordEqual(feedback, p->name), &miss);
1634     // If the name comparison succeeded, we know we have a fixed array with
1635     // at least one map/handler pair.
1636     Node* offset = ElementOffsetFromIndex(
1637         p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
1638         FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
1639     Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
1640     HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss,
1641                           1);
1642   }
1643   Bind(&miss);
1644   {
1645     Comment("KeyedLoadIC_miss");
1646     TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
1647                     p->name, p->slot, p->vector);
1648   }
1649 }
1650 
KeyedLoadICGeneric(const LoadICParameters * p)1651 void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
1652   Variable var_index(this, MachineType::PointerRepresentation());
1653   Variable var_unique(this, MachineRepresentation::kTagged);
1654   var_unique.Bind(p->name);  // Dummy initialization.
1655   Label if_index(this), if_unique_name(this), slow(this);
1656 
1657   Node* receiver = p->receiver;
1658   GotoIf(TaggedIsSmi(receiver), &slow);
1659   Node* receiver_map = LoadMap(receiver);
1660   Node* instance_type = LoadMapInstanceType(receiver_map);
1661 
1662   TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
1663             &slow);
1664 
1665   Bind(&if_index);
1666   {
1667     GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(),
1668                        &slow);
1669   }
1670 
1671   Bind(&if_unique_name);
1672   {
1673     GenericPropertyLoad(receiver, receiver_map, instance_type,
1674                         var_unique.value(), p, &slow);
1675   }
1676 
1677   Bind(&slow);
1678   {
1679     Comment("KeyedLoadGeneric_slow");
1680     IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1);
1681     // TODO(jkummerow): Should we use the GetProperty TF stub instead?
1682     TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver,
1683                     p->name);
1684   }
1685 }
1686 
StoreIC(const StoreICParameters * p)1687 void AccessorAssembler::StoreIC(const StoreICParameters* p) {
1688   Variable var_handler(this, MachineRepresentation::kTagged);
1689   // TODO(ishell): defer blocks when it works.
1690   Label if_handler(this, &var_handler), try_polymorphic(this),
1691       try_megamorphic(this /*, Label::kDeferred*/),
1692       miss(this /*, Label::kDeferred*/);
1693 
1694   Node* receiver_map = LoadReceiverMap(p->receiver);
1695   GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
1696 
1697   // Check monomorphic case.
1698   Node* feedback =
1699       TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
1700                          &var_handler, &try_polymorphic);
1701   Bind(&if_handler);
1702   {
1703     Comment("StoreIC_if_handler");
1704     HandleStoreICHandlerCase(p, var_handler.value(), &miss);
1705   }
1706 
1707   Bind(&try_polymorphic);
1708   {
1709     // Check polymorphic case.
1710     Comment("StoreIC_try_polymorphic");
1711     GotoIfNot(
1712         WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
1713         &try_megamorphic);
1714     HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
1715                           &miss, 2);
1716   }
1717 
1718   Bind(&try_megamorphic);
1719   {
1720     // Check megamorphic case.
1721     GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
1722               &miss);
1723 
1724     TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name,
1725                       &if_handler, &var_handler, &miss);
1726   }
1727   Bind(&miss);
1728   {
1729     TailCallRuntime(Runtime::kStoreIC_Miss, p->context, p->value, p->slot,
1730                     p->vector, p->receiver, p->name);
1731   }
1732 }
1733 
KeyedStoreIC(const StoreICParameters * p,LanguageMode language_mode)1734 void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p,
1735                                      LanguageMode language_mode) {
1736   // TODO(ishell): defer blocks when it works.
1737   Label miss(this /*, Label::kDeferred*/);
1738   {
1739     Variable var_handler(this, MachineRepresentation::kTagged);
1740 
1741     // TODO(ishell): defer blocks when it works.
1742     Label if_handler(this, &var_handler), try_polymorphic(this),
1743         try_megamorphic(this /*, Label::kDeferred*/),
1744         try_polymorphic_name(this /*, Label::kDeferred*/);
1745 
1746     Node* receiver_map = LoadReceiverMap(p->receiver);
1747     GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
1748 
1749     // Check monomorphic case.
1750     Node* feedback =
1751         TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
1752                            &var_handler, &try_polymorphic);
1753     Bind(&if_handler);
1754     {
1755       Comment("KeyedStoreIC_if_handler");
1756       HandleStoreICHandlerCase(p, var_handler.value(), &miss, kSupportElements);
1757     }
1758 
1759     Bind(&try_polymorphic);
1760     {
1761       // CheckPolymorphic case.
1762       Comment("KeyedStoreIC_try_polymorphic");
1763       GotoIfNot(
1764           WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
1765           &try_megamorphic);
1766       Label if_transition_handler(this);
1767       Variable var_transition_map_cell(this, MachineRepresentation::kTagged);
1768       HandleKeyedStorePolymorphicCase(receiver_map, feedback, &if_handler,
1769                                       &var_handler, &if_transition_handler,
1770                                       &var_transition_map_cell, &miss);
1771       Bind(&if_transition_handler);
1772       Comment("KeyedStoreIC_polymorphic_transition");
1773       {
1774         Node* handler = var_handler.value();
1775 
1776         Label call_handler(this);
1777         Variable var_code_handler(this, MachineRepresentation::kTagged);
1778         var_code_handler.Bind(handler);
1779         GotoIfNot(IsTuple2Map(LoadMap(handler)), &call_handler);
1780         {
1781           CSA_ASSERT(this, IsTuple2Map(LoadMap(handler)));
1782 
1783           // Check validity cell.
1784           Node* validity_cell = LoadObjectField(handler, Tuple2::kValue1Offset);
1785           Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
1786           GotoIf(
1787               WordNotEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)),
1788               &miss);
1789 
1790           var_code_handler.Bind(
1791               LoadObjectField(handler, Tuple2::kValue2Offset));
1792           Goto(&call_handler);
1793         }
1794 
1795         Bind(&call_handler);
1796         {
1797           Node* code_handler = var_code_handler.value();
1798           CSA_ASSERT(this, IsCodeMap(LoadMap(code_handler)));
1799 
1800           Node* transition_map =
1801               LoadWeakCellValue(var_transition_map_cell.value(), &miss);
1802           StoreTransitionDescriptor descriptor(isolate());
1803           TailCallStub(descriptor, code_handler, p->context, p->receiver,
1804                        p->name, transition_map, p->value, p->slot, p->vector);
1805         }
1806       }
1807     }
1808 
1809     Bind(&try_megamorphic);
1810     {
1811       // Check megamorphic case.
1812       Comment("KeyedStoreIC_try_megamorphic");
1813       GotoIfNot(
1814           WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
1815           &try_polymorphic_name);
1816       TailCallStub(
1817           CodeFactory::KeyedStoreIC_Megamorphic(isolate(), language_mode),
1818           p->context, p->receiver, p->name, p->value, p->slot, p->vector);
1819     }
1820 
1821     Bind(&try_polymorphic_name);
1822     {
1823       // We might have a name in feedback, and a fixed array in the next slot.
1824       Comment("KeyedStoreIC_try_polymorphic_name");
1825       GotoIfNot(WordEqual(feedback, p->name), &miss);
1826       // If the name comparison succeeded, we know we have a FixedArray with
1827       // at least one map/handler pair.
1828       Node* offset = ElementOffsetFromIndex(
1829           p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
1830           FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
1831       Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
1832       HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler,
1833                             &miss, 1);
1834     }
1835   }
1836   Bind(&miss);
1837   {
1838     Comment("KeyedStoreIC_miss");
1839     TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
1840                     p->vector, p->receiver, p->name);
1841   }
1842 }
1843 
1844 //////////////////// Public methods.
1845 
GenerateLoadIC()1846 void AccessorAssembler::GenerateLoadIC() {
1847   typedef LoadWithVectorDescriptor Descriptor;
1848 
1849   Node* receiver = Parameter(Descriptor::kReceiver);
1850   Node* name = Parameter(Descriptor::kName);
1851   Node* slot = Parameter(Descriptor::kSlot);
1852   Node* vector = Parameter(Descriptor::kVector);
1853   Node* context = Parameter(Descriptor::kContext);
1854 
1855   LoadICParameters p(context, receiver, name, slot, vector);
1856   LoadIC(&p);
1857 }
1858 
GenerateLoadICTrampoline()1859 void AccessorAssembler::GenerateLoadICTrampoline() {
1860   typedef LoadDescriptor Descriptor;
1861 
1862   Node* receiver = Parameter(Descriptor::kReceiver);
1863   Node* name = Parameter(Descriptor::kName);
1864   Node* slot = Parameter(Descriptor::kSlot);
1865   Node* context = Parameter(Descriptor::kContext);
1866   Node* vector = LoadFeedbackVectorForStub();
1867 
1868   LoadICParameters p(context, receiver, name, slot, vector);
1869   LoadIC(&p);
1870 }
1871 
GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent)1872 void AccessorAssembler::GenerateLoadICProtoArray(
1873     bool throw_reference_error_if_nonexistent) {
1874   typedef LoadICProtoArrayDescriptor Descriptor;
1875 
1876   Node* receiver = Parameter(Descriptor::kReceiver);
1877   Node* name = Parameter(Descriptor::kName);
1878   Node* slot = Parameter(Descriptor::kSlot);
1879   Node* vector = Parameter(Descriptor::kVector);
1880   Node* handler = Parameter(Descriptor::kHandler);
1881   Node* context = Parameter(Descriptor::kContext);
1882 
1883   LoadICParameters p(context, receiver, name, slot, vector);
1884   LoadICProtoArray(&p, handler, throw_reference_error_if_nonexistent);
1885 }
1886 
GenerateLoadField()1887 void AccessorAssembler::GenerateLoadField() {
1888   typedef LoadFieldDescriptor Descriptor;
1889 
1890   Node* receiver = Parameter(Descriptor::kReceiver);
1891   Node* name = nullptr;
1892   Node* slot = nullptr;
1893   Node* vector = nullptr;
1894   Node* context = Parameter(Descriptor::kContext);
1895   LoadICParameters p(context, receiver, name, slot, vector);
1896 
1897   ExitPoint direct_exit(this);
1898 
1899   HandleLoadICSmiHandlerCase(&p, receiver, Parameter(Descriptor::kSmiHandler),
1900                              nullptr, &direct_exit, kOnlyProperties);
1901 }
1902 
GenerateLoadGlobalIC(TypeofMode typeof_mode)1903 void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
1904   typedef LoadGlobalWithVectorDescriptor Descriptor;
1905 
1906   Node* name = Parameter(Descriptor::kName);
1907   Node* slot = Parameter(Descriptor::kSlot);
1908   Node* vector = Parameter(Descriptor::kVector);
1909   Node* context = Parameter(Descriptor::kContext);
1910 
1911   LoadICParameters p(context, nullptr, name, slot, vector);
1912   LoadGlobalIC(&p, typeof_mode);
1913 }
1914 
GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode)1915 void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) {
1916   typedef LoadGlobalDescriptor Descriptor;
1917 
1918   Node* name = Parameter(Descriptor::kName);
1919   Node* slot = Parameter(Descriptor::kSlot);
1920   Node* context = Parameter(Descriptor::kContext);
1921   Node* vector = LoadFeedbackVectorForStub();
1922 
1923   LoadICParameters p(context, nullptr, name, slot, vector);
1924   LoadGlobalIC(&p, typeof_mode);
1925 }
1926 
GenerateKeyedLoadIC()1927 void AccessorAssembler::GenerateKeyedLoadIC() {
1928   typedef LoadWithVectorDescriptor Descriptor;
1929 
1930   Node* receiver = Parameter(Descriptor::kReceiver);
1931   Node* name = Parameter(Descriptor::kName);
1932   Node* slot = Parameter(Descriptor::kSlot);
1933   Node* vector = Parameter(Descriptor::kVector);
1934   Node* context = Parameter(Descriptor::kContext);
1935 
1936   LoadICParameters p(context, receiver, name, slot, vector);
1937   KeyedLoadIC(&p);
1938 }
1939 
GenerateKeyedLoadICTrampoline()1940 void AccessorAssembler::GenerateKeyedLoadICTrampoline() {
1941   typedef LoadDescriptor Descriptor;
1942 
1943   Node* receiver = Parameter(Descriptor::kReceiver);
1944   Node* name = Parameter(Descriptor::kName);
1945   Node* slot = Parameter(Descriptor::kSlot);
1946   Node* context = Parameter(Descriptor::kContext);
1947   Node* vector = LoadFeedbackVectorForStub();
1948 
1949   LoadICParameters p(context, receiver, name, slot, vector);
1950   KeyedLoadIC(&p);
1951 }
1952 
GenerateKeyedLoadIC_Megamorphic()1953 void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
1954   typedef LoadWithVectorDescriptor Descriptor;
1955 
1956   Node* receiver = Parameter(Descriptor::kReceiver);
1957   Node* name = Parameter(Descriptor::kName);
1958   Node* slot = Parameter(Descriptor::kSlot);
1959   Node* vector = Parameter(Descriptor::kVector);
1960   Node* context = Parameter(Descriptor::kContext);
1961 
1962   LoadICParameters p(context, receiver, name, slot, vector);
1963   KeyedLoadICGeneric(&p);
1964 }
1965 
GenerateStoreIC()1966 void AccessorAssembler::GenerateStoreIC() {
1967   typedef StoreWithVectorDescriptor Descriptor;
1968 
1969   Node* receiver = Parameter(Descriptor::kReceiver);
1970   Node* name = Parameter(Descriptor::kName);
1971   Node* value = Parameter(Descriptor::kValue);
1972   Node* slot = Parameter(Descriptor::kSlot);
1973   Node* vector = Parameter(Descriptor::kVector);
1974   Node* context = Parameter(Descriptor::kContext);
1975 
1976   StoreICParameters p(context, receiver, name, value, slot, vector);
1977   StoreIC(&p);
1978 }
1979 
GenerateStoreICTrampoline()1980 void AccessorAssembler::GenerateStoreICTrampoline() {
1981   typedef StoreDescriptor Descriptor;
1982 
1983   Node* receiver = Parameter(Descriptor::kReceiver);
1984   Node* name = Parameter(Descriptor::kName);
1985   Node* value = Parameter(Descriptor::kValue);
1986   Node* slot = Parameter(Descriptor::kSlot);
1987   Node* context = Parameter(Descriptor::kContext);
1988   Node* vector = LoadFeedbackVectorForStub();
1989 
1990   StoreICParameters p(context, receiver, name, value, slot, vector);
1991   StoreIC(&p);
1992 }
1993 
GenerateKeyedStoreIC(LanguageMode language_mode)1994 void AccessorAssembler::GenerateKeyedStoreIC(LanguageMode language_mode) {
1995   typedef StoreWithVectorDescriptor Descriptor;
1996 
1997   Node* receiver = Parameter(Descriptor::kReceiver);
1998   Node* name = Parameter(Descriptor::kName);
1999   Node* value = Parameter(Descriptor::kValue);
2000   Node* slot = Parameter(Descriptor::kSlot);
2001   Node* vector = Parameter(Descriptor::kVector);
2002   Node* context = Parameter(Descriptor::kContext);
2003 
2004   StoreICParameters p(context, receiver, name, value, slot, vector);
2005   KeyedStoreIC(&p, language_mode);
2006 }
2007 
GenerateKeyedStoreICTrampoline(LanguageMode language_mode)2008 void AccessorAssembler::GenerateKeyedStoreICTrampoline(
2009     LanguageMode language_mode) {
2010   typedef StoreDescriptor Descriptor;
2011 
2012   Node* receiver = Parameter(Descriptor::kReceiver);
2013   Node* name = Parameter(Descriptor::kName);
2014   Node* value = Parameter(Descriptor::kValue);
2015   Node* slot = Parameter(Descriptor::kSlot);
2016   Node* context = Parameter(Descriptor::kContext);
2017   Node* vector = LoadFeedbackVectorForStub();
2018 
2019   StoreICParameters p(context, receiver, name, value, slot, vector);
2020   KeyedStoreIC(&p, language_mode);
2021 }
2022 
2023 }  // namespace internal
2024 }  // namespace v8
2025