• 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 #ifndef V8_IC_ACCESSOR_ASSEMBLER_H_
6 #define V8_IC_ACCESSOR_ASSEMBLER_H_
7 
8 #include "src/code-stub-assembler.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 namespace compiler {
14 class CodeAssemblerState;
15 }
16 
17 class ExitPoint;
18 
19 class AccessorAssembler : public CodeStubAssembler {
20  public:
21   using Node = compiler::Node;
22   template <class T>
23   using TNode = compiler::TNode<T>;
24   template <class T>
25   using SloppyTNode = compiler::SloppyTNode<T>;
26 
AccessorAssembler(compiler::CodeAssemblerState * state)27   explicit AccessorAssembler(compiler::CodeAssemblerState* state)
28       : CodeStubAssembler(state) {}
29 
30   void GenerateLoadIC();
31   void GenerateLoadIC_Noninlined();
32   void GenerateLoadIC_Uninitialized();
33   void GenerateLoadICTrampoline();
34   void GenerateKeyedLoadIC();
35   void GenerateKeyedLoadICTrampoline();
36   void GenerateKeyedLoadIC_Megamorphic();
37   void GenerateKeyedLoadIC_PolymorphicName();
38   void GenerateStoreIC();
39   void GenerateStoreICTrampoline();
40   void GenerateStoreGlobalIC();
41   void GenerateStoreGlobalICTrampoline();
42   void GenerateCloneObjectIC();
43 
44   void GenerateLoadGlobalIC(TypeofMode typeof_mode);
45   void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
46 
47   void GenerateKeyedStoreIC();
48   void GenerateKeyedStoreICTrampoline();
49 
50   void GenerateStoreInArrayLiteralIC();
51 
52   void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
53                          Label* if_handler, TVariable<MaybeObject>* var_handler,
54                          Label* if_miss);
55 
StubCachePrimaryOffsetForTesting(Node * name,Node * map)56   Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) {
57     return StubCachePrimaryOffset(name, map);
58   }
StubCacheSecondaryOffsetForTesting(Node * name,Node * map)59   Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) {
60     return StubCacheSecondaryOffset(name, map);
61   }
62 
63   struct LoadICParameters {
64     LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot,
65                      Node* vector, Node* holder = nullptr)
contextLoadICParameters66         : context(context),
67           receiver(receiver),
68           name(name),
69           slot(slot),
70           vector(vector),
71           holder(holder ? holder : receiver) {}
72 
73     Node* context;
74     Node* receiver;
75     Node* name;
76     Node* slot;
77     Node* vector;
78     Node* holder;
79   };
80 
81   void LoadGlobalIC(TNode<FeedbackVector> vector, Node* slot,
82                     const LazyNode<Context>& lazy_context,
83                     const LazyNode<Name>& lazy_name, TypeofMode typeof_mode,
84                     ExitPoint* exit_point,
85                     ParameterMode slot_mode = SMI_PARAMETERS);
86 
87   // Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame
88   // construction on common paths.
89   void LoadIC_BytecodeHandler(const LoadICParameters* p, ExitPoint* exit_point);
90 
91   // Loads dataX field from the DataHandler object.
92   TNode<MaybeObject> LoadHandlerDataField(SloppyTNode<DataHandler> handler,
93                                           int data_index);
94 
95  protected:
96   struct StoreICParameters : public LoadICParameters {
StoreICParametersStoreICParameters97     StoreICParameters(Node* context, Node* receiver, Node* name,
98                       SloppyTNode<Object> value, Node* slot, Node* vector)
99         : LoadICParameters(context, receiver, name, slot, vector),
100           value(value) {}
101     SloppyTNode<Object> value;
102   };
103 
104   enum class ICMode { kNonGlobalIC, kGlobalIC };
105   enum ElementSupport { kOnlyProperties, kSupportElements };
106   void HandleStoreICHandlerCase(
107       const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
108       ICMode ic_mode, ElementSupport support_elements = kOnlyProperties);
109   void HandleStoreICTransitionMapHandlerCase(const StoreICParameters* p,
110                                              TNode<Map> transition_map,
111                                              Label* miss,
112                                              bool validate_transition_handler);
113 
114   void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
115 
116   void BranchIfStrictMode(Node* vector, Node* slot, Label* if_strict);
117 
118   void InvalidateValidityCellIfPrototype(Node* map, Node* bitfield2 = nullptr);
119 
120   void OverwriteExistingFastDataProperty(Node* object, Node* object_map,
121                                          Node* descriptors,
122                                          Node* descriptor_name_index,
123                                          Node* details, Node* value,
124                                          Label* slow,
125                                          bool do_transitioning_store);
126 
127   void CheckFieldType(TNode<DescriptorArray> descriptors, Node* name_index,
128                       Node* representation, Node* value, Label* bailout);
129 
130  private:
131   // Stub generation entry points.
132 
133   // LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains
134   // logic not inlined into Ignition bytecode handlers.
135   void LoadIC(const LoadICParameters* p);
136   void LoadIC_Noninlined(const LoadICParameters* p, Node* receiver_map,
137                          TNode<HeapObject> feedback,
138                          TVariable<MaybeObject>* var_handler, Label* if_handler,
139                          Label* miss, ExitPoint* exit_point);
140 
141   TNode<Object> LoadDescriptorValue(TNode<Map> map, Node* descriptor);
142   TNode<MaybeObject> LoadDescriptorValueOrFieldType(
143       TNode<Map> map, SloppyTNode<IntPtrT> descriptor);
144 
145   void LoadIC_Uninitialized(const LoadICParameters* p);
146 
147   void KeyedLoadIC(const LoadICParameters* p);
148   void KeyedLoadICGeneric(const LoadICParameters* p);
149   void KeyedLoadICPolymorphicName(const LoadICParameters* p);
150   void StoreIC(const StoreICParameters* p);
151   void StoreGlobalIC(const StoreICParameters* p);
152   void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value,
153                                       ExitPoint* exit_point, Label* miss);
154   void KeyedStoreIC(const StoreICParameters* p);
155   void StoreInArrayLiteralIC(const StoreICParameters* p);
156 
157   // IC dispatcher behavior.
158 
159   // Checks monomorphic case. Returns {feedback} entry of the vector.
160   TNode<MaybeObject> TryMonomorphicCase(Node* slot, Node* vector,
161                                         Node* receiver_map, Label* if_handler,
162                                         TVariable<MaybeObject>* var_handler,
163                                         Label* if_miss);
164   void HandlePolymorphicCase(Node* receiver_map, TNode<WeakFixedArray> feedback,
165                              Label* if_handler,
166                              TVariable<MaybeObject>* var_handler,
167                              Label* if_miss, int min_feedback_capacity);
168 
169   // LoadIC implementation.
170   void HandleLoadICHandlerCase(
171       const LoadICParameters* p, TNode<Object> handler, Label* miss,
172       ExitPoint* exit_point, ICMode ic_mode = ICMode::kNonGlobalIC,
173       OnNonExistent on_nonexistent = OnNonExistent::kReturnUndefined,
174       ElementSupport support_elements = kOnlyProperties);
175 
176   void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
177                                   SloppyTNode<Smi> smi_handler,
178                                   SloppyTNode<Object> handler, Label* miss,
179                                   ExitPoint* exit_point,
180                                   OnNonExistent on_nonexistent,
181                                   ElementSupport support_elements);
182 
183   void HandleLoadICProtoHandler(const LoadICParameters* p, Node* handler,
184                                 Variable* var_holder, Variable* var_smi_handler,
185                                 Label* if_smi_handler, Label* miss,
186                                 ExitPoint* exit_point, ICMode ic_mode);
187 
188   void HandleLoadCallbackProperty(const LoadICParameters* p,
189                                   TNode<JSObject> holder,
190                                   TNode<WordT> handler_word,
191                                   ExitPoint* exit_point);
192 
193   void HandleLoadAccessor(const LoadICParameters* p,
194                           TNode<CallHandlerInfo> call_handler_info,
195                           TNode<WordT> handler_word, TNode<DataHandler> handler,
196                           TNode<IntPtrT> handler_kind, ExitPoint* exit_point);
197 
198   void HandleLoadField(Node* holder, Node* handler_word,
199                        Variable* var_double_value, Label* rebox_double,
200                        ExitPoint* exit_point);
201 
202   void EmitAccessCheck(Node* expected_native_context, Node* context,
203                        Node* receiver, Label* can_access, Label* miss);
204 
205   // LoadGlobalIC implementation.
206 
207   void LoadGlobalIC_TryPropertyCellCase(
208       TNode<FeedbackVector> vector, Node* slot,
209       const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
210       Label* try_handler, Label* miss,
211       ParameterMode slot_mode = SMI_PARAMETERS);
212 
213   void LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector, Node* slot,
214                                    const LazyNode<Context>& lazy_context,
215                                    const LazyNode<Name>& lazy_name,
216                                    TypeofMode typeof_mode,
217                                    ExitPoint* exit_point, Label* miss,
218                                    ParameterMode slot_mode);
219 
220   // StoreIC implementation.
221 
222   void HandleStoreICProtoHandler(const StoreICParameters* p,
223                                  TNode<StoreHandler> handler, Label* miss,
224                                  ICMode ic_mode,
225                                  ElementSupport support_elements);
226   void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
227                                    Node* value, Label* miss);
228   void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
229                                  Representation representation, Node* value,
230                                  Label* miss);
231 
232   void CheckPrototypeValidityCell(Node* maybe_validity_cell, Label* miss);
233   void HandleStoreICNativeDataProperty(const StoreICParameters* p, Node* holder,
234                                        Node* handler_word);
235 
236   void HandleStoreToProxy(const StoreICParameters* p, Node* proxy, Label* miss,
237                           ElementSupport support_elements);
238 
239   void HandleStoreAccessor(const StoreICParameters* p, Node* holder,
240                            Node* handler_word);
241 
242   // KeyedLoadIC_Generic implementation.
243 
244   void GenericElementLoad(Node* receiver, Node* receiver_map,
245                           SloppyTNode<Int32T> instance_type, Node* index,
246                           Label* slow);
247 
248   enum UseStubCache { kUseStubCache, kDontUseStubCache };
249   void GenericPropertyLoad(Node* receiver, Node* receiver_map,
250                            SloppyTNode<Int32T> instance_type,
251                            const LoadICParameters* p, Label* slow,
252                            UseStubCache use_stub_cache = kUseStubCache);
253 
254   // Low-level helpers.
255 
256   typedef std::function<void(Node* code_handler)> OnCodeHandler;
257   typedef std::function<void(Node* properties, Node* name_index)>
258       OnFoundOnReceiver;
259 
260   template <typename ICHandler, typename ICParameters>
261   Node* HandleProtoHandler(const ICParameters* p, Node* handler,
262                            const OnCodeHandler& on_code_handler,
263                            const OnFoundOnReceiver& on_found_on_receiver,
264                            Label* miss, ICMode ic_mode);
265 
266   Node* GetLanguageMode(Node* vector, Node* slot);
267 
268   Node* PrepareValueForStore(Node* handler_word, Node* holder,
269                              Representation representation, Node* value,
270                              Label* bailout);
271 
272   // Extends properties backing store by JSObject::kFieldsAdded elements,
273   // returns updated properties backing store.
274   Node* ExtendPropertiesBackingStore(Node* object, Node* index);
275 
276   void StoreNamedField(Node* handler_word, Node* object, bool is_inobject,
277                        Representation representation, Node* value,
278                        Label* bailout);
279 
280   void EmitFastElementsBoundsCheck(Node* object, Node* elements,
281                                    Node* intptr_index,
282                                    Node* is_jsarray_condition, Label* miss);
283   void EmitElementLoad(Node* object, Node* elements, Node* elements_kind,
284                        SloppyTNode<IntPtrT> key, Node* is_jsarray_condition,
285                        Label* if_hole, Label* rebox_double,
286                        Variable* var_double_value,
287                        Label* unimplemented_elements_kind, Label* out_of_bounds,
288                        Label* miss, ExitPoint* exit_point);
289   void NameDictionaryNegativeLookup(Node* object, SloppyTNode<Name> name,
290                                     Label* miss);
291 
292   // Stub cache access helpers.
293 
294   // This enum is used here as a replacement for StubCache::Table to avoid
295   // including stub cache header.
296   enum StubCacheTable : int;
297 
298   Node* StubCachePrimaryOffset(Node* name, Node* map);
299   Node* StubCacheSecondaryOffset(Node* name, Node* seed);
300 
301   void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
302                               Node* entry_offset, Node* name, Node* map,
303                               Label* if_handler,
304                               TVariable<MaybeObject>* var_handler,
305                               Label* if_miss);
306 };
307 
308 // Abstraction over direct and indirect exit points. Direct exits correspond to
309 // tailcalls and Return, while indirect exits store the result in a variable
310 // and then jump to an exit label.
311 class ExitPoint {
312  private:
313   typedef compiler::Node Node;
314   typedef compiler::CodeAssemblerLabel CodeAssemblerLabel;
315   typedef compiler::CodeAssemblerVariable CodeAssemblerVariable;
316 
317  public:
318   typedef std::function<void(Node* result)> IndirectReturnHandler;
319 
ExitPoint(CodeStubAssembler * assembler)320   explicit ExitPoint(CodeStubAssembler* assembler)
321       : ExitPoint(assembler, nullptr) {}
322 
ExitPoint(CodeStubAssembler * assembler,const IndirectReturnHandler & indirect_return_handler)323   ExitPoint(CodeStubAssembler* assembler,
324             const IndirectReturnHandler& indirect_return_handler)
325       : asm_(assembler), indirect_return_handler_(indirect_return_handler) {}
326 
ExitPoint(CodeStubAssembler * assembler,CodeAssemblerLabel * out,CodeAssemblerVariable * var_result)327   ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out,
328             CodeAssemblerVariable* var_result)
329       : ExitPoint(assembler, [=](Node* result) {
330           var_result->Bind(result);
331           assembler->Goto(out);
332         }) {
333     DCHECK_EQ(out != nullptr, var_result != nullptr);
334   }
335 
336   template <class... TArgs>
ReturnCallRuntime(Runtime::FunctionId function,Node * context,TArgs...args)337   void ReturnCallRuntime(Runtime::FunctionId function, Node* context,
338                          TArgs... args) {
339     if (IsDirect()) {
340       asm_->TailCallRuntime(function, context, args...);
341     } else {
342       indirect_return_handler_(asm_->CallRuntime(function, context, args...));
343     }
344   }
345 
346   template <class... TArgs>
ReturnCallStub(Callable const & callable,Node * context,TArgs...args)347   void ReturnCallStub(Callable const& callable, Node* context, TArgs... args) {
348     if (IsDirect()) {
349       asm_->TailCallStub(callable, context, args...);
350     } else {
351       indirect_return_handler_(asm_->CallStub(callable, context, args...));
352     }
353   }
354 
355   template <class... TArgs>
ReturnCallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,TArgs...args)356   void ReturnCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
357                       Node* context, TArgs... args) {
358     if (IsDirect()) {
359       asm_->TailCallStub(descriptor, target, context, args...);
360     } else {
361       indirect_return_handler_(
362           asm_->CallStub(descriptor, target, context, args...));
363     }
364   }
365 
Return(Node * const result)366   void Return(Node* const result) {
367     if (IsDirect()) {
368       asm_->Return(result);
369     } else {
370       indirect_return_handler_(result);
371     }
372   }
373 
IsDirect()374   bool IsDirect() const { return !indirect_return_handler_; }
375 
376  private:
377   CodeStubAssembler* const asm_;
378   IndirectReturnHandler indirect_return_handler_;
379 };
380 
381 }  // namespace internal
382 }  // namespace v8
383 
384 #endif  // V8_IC_ACCESSOR_ASSEMBLER_H_
385