Home | History | Annotate | Download | only in ic
      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_SRC_IC_ACCESSOR_ASSEMBLER_H_
      6 #define V8_SRC_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   typedef compiler::Node Node;
     22 
     23   explicit AccessorAssembler(compiler::CodeAssemblerState* state)
     24       : CodeStubAssembler(state) {}
     25 
     26   void GenerateLoadIC();
     27   void GenerateLoadField();
     28   void GenerateLoadICTrampoline();
     29   void GenerateKeyedLoadIC();
     30   void GenerateKeyedLoadICTrampoline();
     31   void GenerateKeyedLoadIC_Megamorphic();
     32   void GenerateStoreIC();
     33   void GenerateStoreICTrampoline();
     34 
     35   void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent);
     36 
     37   void GenerateLoadGlobalIC(TypeofMode typeof_mode);
     38   void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
     39 
     40   void GenerateKeyedStoreIC(LanguageMode language_mode);
     41   void GenerateKeyedStoreICTrampoline(LanguageMode language_mode);
     42 
     43   void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
     44                          Label* if_handler, Variable* var_handler,
     45                          Label* if_miss);
     46 
     47   Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) {
     48     return StubCachePrimaryOffset(name, map);
     49   }
     50   Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) {
     51     return StubCacheSecondaryOffset(name, map);
     52   }
     53 
     54   struct LoadICParameters {
     55     LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot,
     56                      Node* vector)
     57         : context(context),
     58           receiver(receiver),
     59           name(name),
     60           slot(slot),
     61           vector(vector) {}
     62 
     63     Node* context;
     64     Node* receiver;
     65     Node* name;
     66     Node* slot;
     67     Node* vector;
     68   };
     69 
     70   void LoadGlobalIC_TryPropertyCellCase(
     71       Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler,
     72       Label* miss, ParameterMode slot_mode = SMI_PARAMETERS);
     73   void LoadGlobalIC_TryHandlerCase(const LoadICParameters* p,
     74                                    TypeofMode typeof_mode,
     75                                    ExitPoint* exit_point, Label* miss);
     76   void LoadGlobalIC_MissCase(const LoadICParameters* p, ExitPoint* exit_point);
     77 
     78  protected:
     79   struct StoreICParameters : public LoadICParameters {
     80     StoreICParameters(Node* context, Node* receiver, Node* name, Node* value,
     81                       Node* slot, Node* vector)
     82         : LoadICParameters(context, receiver, name, slot, vector),
     83           value(value) {}
     84     Node* value;
     85   };
     86 
     87   enum ElementSupport { kOnlyProperties, kSupportElements };
     88   void HandleStoreICHandlerCase(
     89       const StoreICParameters* p, Node* handler, Label* miss,
     90       ElementSupport support_elements = kOnlyProperties);
     91 
     92  private:
     93   // Stub generation entry points.
     94 
     95   void LoadIC(const LoadICParameters* p);
     96   void LoadICProtoArray(const LoadICParameters* p, Node* handler,
     97                         bool throw_reference_error_if_nonexistent);
     98   void LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode);
     99   void KeyedLoadIC(const LoadICParameters* p);
    100   void KeyedLoadICGeneric(const LoadICParameters* p);
    101   void StoreIC(const StoreICParameters* p);
    102   void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode);
    103 
    104   // IC dispatcher behavior.
    105 
    106   // Checks monomorphic case. Returns {feedback} entry of the vector.
    107   Node* TryMonomorphicCase(Node* slot, Node* vector, Node* receiver_map,
    108                            Label* if_handler, Variable* var_handler,
    109                            Label* if_miss);
    110   void HandlePolymorphicCase(Node* receiver_map, Node* feedback,
    111                              Label* if_handler, Variable* var_handler,
    112                              Label* if_miss, int unroll_count);
    113   void HandleKeyedStorePolymorphicCase(Node* receiver_map, Node* feedback,
    114                                        Label* if_handler, Variable* var_handler,
    115                                        Label* if_transition_handler,
    116                                        Variable* var_transition_map_cell,
    117                                        Label* if_miss);
    118 
    119   // LoadIC implementation.
    120 
    121   void HandleLoadICHandlerCase(
    122       const LoadICParameters* p, Node* handler, Label* miss,
    123       ElementSupport support_elements = kOnlyProperties);
    124 
    125   void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
    126                                   Node* smi_handler, Label* miss,
    127                                   ExitPoint* exit_point,
    128                                   ElementSupport support_elements);
    129 
    130   void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler,
    131                                     Variable* var_holder,
    132                                     Variable* var_smi_handler,
    133                                     Label* if_smi_handler, Label* miss,
    134                                     ExitPoint* exit_point,
    135                                     bool throw_reference_error_if_nonexistent);
    136 
    137   Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler,
    138                                   Node* handler_length, Node* handler_flags,
    139                                   Label* miss,
    140                                   bool throw_reference_error_if_nonexistent);
    141 
    142   // LoadGlobalIC implementation.
    143 
    144   void HandleLoadGlobalICHandlerCase(const LoadICParameters* p, Node* handler,
    145                                      Label* miss, ExitPoint* exit_point,
    146                                      bool throw_reference_error_if_nonexistent);
    147 
    148   // StoreIC implementation.
    149 
    150   void HandleStoreICElementHandlerCase(const StoreICParameters* p,
    151                                        Node* handler, Label* miss);
    152 
    153   void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler,
    154                                  Label* miss);
    155   // If |transition| is nullptr then the normal field store is generated or
    156   // transitioning store otherwise.
    157   void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
    158                                    Node* value, Node* transition, Label* miss);
    159   // If |transition| is nullptr then the normal field store is generated or
    160   // transitioning store otherwise.
    161   void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
    162                                  Representation representation, Node* value,
    163                                  Node* transition, Label* miss);
    164 
    165   // KeyedLoadIC_Generic implementation.
    166 
    167   void GenericElementLoad(Node* receiver, Node* receiver_map,
    168                           Node* instance_type, Node* index, Label* slow);
    169 
    170   void GenericPropertyLoad(Node* receiver, Node* receiver_map,
    171                            Node* instance_type, Node* key,
    172                            const LoadICParameters* p, Label* slow);
    173 
    174   // Low-level helpers.
    175 
    176   Node* PrepareValueForStore(Node* handler_word, Node* holder,
    177                              Representation representation, Node* transition,
    178                              Node* value, Label* bailout);
    179 
    180   // Extends properties backing store by JSObject::kFieldsAdded elements.
    181   void ExtendPropertiesBackingStore(Node* object);
    182 
    183   void StoreNamedField(Node* handler_word, Node* object, bool is_inobject,
    184                        Representation representation, Node* value,
    185                        bool transition_to_field, Label* bailout);
    186 
    187   void EmitFastElementsBoundsCheck(Node* object, Node* elements,
    188                                    Node* intptr_index,
    189                                    Node* is_jsarray_condition, Label* miss);
    190   void EmitElementLoad(Node* object, Node* elements, Node* elements_kind,
    191                        Node* key, Node* is_jsarray_condition, Label* if_hole,
    192                        Label* rebox_double, Variable* var_double_value,
    193                        Label* unimplemented_elements_kind, Label* out_of_bounds,
    194                        Label* miss, ExitPoint* exit_point);
    195   void CheckPrototype(Node* prototype_cell, Node* name, Label* miss);
    196   void NameDictionaryNegativeLookup(Node* object, Node* name, Label* miss);
    197 
    198   // Stub cache access helpers.
    199 
    200   // This enum is used here as a replacement for StubCache::Table to avoid
    201   // including stub cache header.
    202   enum StubCacheTable : int;
    203 
    204   Node* StubCachePrimaryOffset(Node* name, Node* map);
    205   Node* StubCacheSecondaryOffset(Node* name, Node* seed);
    206 
    207   void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
    208                               Node* entry_offset, Node* name, Node* map,
    209                               Label* if_handler, Variable* var_handler,
    210                               Label* if_miss);
    211 };
    212 
    213 // Abstraction over direct and indirect exit points. Direct exits correspond to
    214 // tailcalls and Return, while indirect exits store the result in a variable
    215 // and then jump to an exit label.
    216 class ExitPoint {
    217  private:
    218   typedef compiler::Node Node;
    219   typedef compiler::CodeAssemblerLabel CodeAssemblerLabel;
    220   typedef compiler::CodeAssemblerVariable CodeAssemblerVariable;
    221 
    222  public:
    223   explicit ExitPoint(CodeStubAssembler* assembler)
    224       : ExitPoint(assembler, nullptr, nullptr) {}
    225   ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out,
    226             CodeAssemblerVariable* var_result)
    227       : out_(out), var_result_(var_result), asm_(assembler) {
    228     DCHECK_EQ(out != nullptr, var_result != nullptr);
    229   }
    230 
    231   template <class... TArgs>
    232   void ReturnCallRuntime(Runtime::FunctionId function, Node* context,
    233                          TArgs... args) {
    234     if (IsDirect()) {
    235       asm_->TailCallRuntime(function, context, args...);
    236     } else {
    237       IndirectReturn(asm_->CallRuntime(function, context, args...));
    238     }
    239   }
    240 
    241   template <class... TArgs>
    242   void ReturnCallStub(Callable const& callable, Node* context, TArgs... args) {
    243     if (IsDirect()) {
    244       asm_->TailCallStub(callable, context, args...);
    245     } else {
    246       IndirectReturn(asm_->CallStub(callable, context, args...));
    247     }
    248   }
    249 
    250   template <class... TArgs>
    251   void ReturnCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
    252                       Node* context, TArgs... args) {
    253     if (IsDirect()) {
    254       asm_->TailCallStub(descriptor, target, context, args...);
    255     } else {
    256       IndirectReturn(asm_->CallStub(descriptor, target, context, args...));
    257     }
    258   }
    259 
    260   void Return(Node* const result) {
    261     if (IsDirect()) {
    262       asm_->Return(result);
    263     } else {
    264       IndirectReturn(result);
    265     }
    266   }
    267 
    268   bool IsDirect() const { return out_ == nullptr; }
    269 
    270  private:
    271   void IndirectReturn(Node* const result) {
    272     var_result_->Bind(result);
    273     asm_->Goto(out_);
    274   }
    275 
    276   CodeAssemblerLabel* const out_;
    277   CodeAssemblerVariable* const var_result_;
    278   CodeStubAssembler* const asm_;
    279 };
    280 
    281 }  // namespace internal
    282 }  // namespace v8
    283 
    284 #endif  // V8_SRC_IC_ACCESSOR_ASSEMBLER_H_
    285