Home | History | Annotate | Download | only in ic
      1 // Copyright 2014 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_HANDLER_COMPILER_H_
      6 #define V8_IC_HANDLER_COMPILER_H_
      7 
      8 #include "src/ic/access-compiler.h"
      9 #include "src/ic/ic-state.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 class CallOptimization;
     15 
     16 enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
     17 enum ReturnHolder { RETURN_HOLDER, DONT_RETURN_ANYTHING };
     18 
     19 class PropertyHandlerCompiler : public PropertyAccessCompiler {
     20  public:
     21   static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind,
     22                            CacheHolderFlag cache_holder);
     23 
     24  protected:
     25   PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind, Handle<Map> map,
     26                           Handle<JSObject> holder, CacheHolderFlag cache_holder)
     27       : PropertyAccessCompiler(isolate, kind, cache_holder),
     28         map_(map),
     29         holder_(holder) {}
     30 
     31   virtual ~PropertyHandlerCompiler() {}
     32 
     33   virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
     34                                   Label* miss, ReturnHolder return_what) {
     35     UNREACHABLE();
     36     return receiver();
     37   }
     38 
     39   virtual void FrontendFooter(Handle<Name> name, Label* miss) { UNREACHABLE(); }
     40 
     41   // Frontend loads from receiver(), returns holder register which may be
     42   // different.
     43   Register Frontend(Handle<Name> name);
     44   void NonexistentFrontendHeader(Handle<Name> name, Label* miss,
     45                                  Register scratch1, Register scratch2);
     46 
     47   // When FLAG_vector_ics is true, handlers that have the possibility of missing
     48   // will need to save and pass these to miss handlers.
     49   void PushVectorAndSlot() { PushVectorAndSlot(vector(), slot()); }
     50   void PushVectorAndSlot(Register vector, Register slot);
     51   void PopVectorAndSlot() { PopVectorAndSlot(vector(), slot()); }
     52   void PopVectorAndSlot(Register vector, Register slot);
     53 
     54   void DiscardVectorAndSlot();
     55 
     56   // TODO(verwaest): Make non-static.
     57   static void GenerateApiAccessorCall(MacroAssembler* masm,
     58                                       const CallOptimization& optimization,
     59                                       Handle<Map> receiver_map,
     60                                       Register receiver, Register scratch,
     61                                       bool is_store, Register store_parameter,
     62                                       Register accessor_holder,
     63                                       int accessor_index);
     64 
     65   // Helper function used to check that the dictionary doesn't contain
     66   // the property. This function may return false negatives, so miss_label
     67   // must always call a backup property check that is complete.
     68   // This function is safe to call if the receiver has fast properties.
     69   // Name must be unique and receiver must be a heap object.
     70   static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
     71                                                Label* miss_label,
     72                                                Register receiver,
     73                                                Handle<Name> name, Register r0,
     74                                                Register r1);
     75 
     76   // Generate code to check that a global property cell is empty. Create
     77   // the property cell at compilation time if no cell exists for the
     78   // property.
     79   static void GenerateCheckPropertyCell(MacroAssembler* masm,
     80                                         Handle<JSGlobalObject> global,
     81                                         Handle<Name> name, Register scratch,
     82                                         Label* miss);
     83 
     84   // Generates code that verifies that the property holder has not changed
     85   // (checking maps of objects in the prototype chain for fast and global
     86   // objects or doing negative lookup for slow objects, ensures that the
     87   // property cells for global objects are still empty) and checks that the map
     88   // of the holder has not changed. If necessary the function also generates
     89   // code for security check in case of global object holders. Helps to make
     90   // sure that the current IC is still valid.
     91   //
     92   // The scratch and holder registers are always clobbered, but the object
     93   // register is only clobbered if it the same as the holder register. The
     94   // function returns a register containing the holder - either object_reg or
     95   // holder_reg.
     96   Register CheckPrototypes(Register object_reg, Register holder_reg,
     97                            Register scratch1, Register scratch2,
     98                            Handle<Name> name, Label* miss,
     99                            PrototypeCheckType check, ReturnHolder return_what);
    100 
    101   Handle<Code> GetCode(Code::Kind kind, Handle<Name> name);
    102   void set_holder(Handle<JSObject> holder) { holder_ = holder; }
    103   Handle<Map> map() const { return map_; }
    104   void set_map(Handle<Map> map) { map_ = map; }
    105   Handle<JSObject> holder() const { return holder_; }
    106 
    107  private:
    108   Handle<Map> map_;
    109   Handle<JSObject> holder_;
    110 };
    111 
    112 
    113 class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
    114  public:
    115   NamedLoadHandlerCompiler(Isolate* isolate, Handle<Map> map,
    116                            Handle<JSObject> holder,
    117                            CacheHolderFlag cache_holder)
    118       : PropertyHandlerCompiler(isolate, Code::LOAD_IC, map, holder,
    119                                 cache_holder) {}
    120 
    121   virtual ~NamedLoadHandlerCompiler() {}
    122 
    123   Handle<Code> CompileLoadField(Handle<Name> name, FieldIndex index);
    124 
    125   Handle<Code> CompileLoadCallback(Handle<Name> name,
    126                                    Handle<AccessorInfo> callback);
    127 
    128   Handle<Code> CompileLoadCallback(Handle<Name> name,
    129                                    const CallOptimization& call_optimization,
    130                                    int accessor_index);
    131 
    132   Handle<Code> CompileLoadConstant(Handle<Name> name, int constant_index);
    133 
    134   // The LookupIterator is used to perform a lookup behind the interceptor. If
    135   // the iterator points to a LookupIterator::PROPERTY, its access will be
    136   // inlined.
    137   Handle<Code> CompileLoadInterceptor(LookupIterator* it);
    138 
    139   Handle<Code> CompileLoadViaGetter(Handle<Name> name, int accessor_index,
    140                                     int expected_arguments);
    141 
    142   Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name,
    143                                  bool is_configurable);
    144 
    145   // Static interface
    146   static Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
    147                                              Handle<Map> map);
    148 
    149   static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<Map> map,
    150                                     Register receiver, Register holder,
    151                                     int accessor_index, int expected_arguments,
    152                                     Register scratch);
    153 
    154   static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) {
    155     GenerateLoadViaGetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1,
    156                           no_reg);
    157   }
    158 
    159   static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
    160                                             Register receiver,
    161                                             Register scratch1,
    162                                             Register scratch2,
    163                                             Label* miss_label);
    164 
    165   // These constants describe the structure of the interceptor arguments on the
    166   // stack. The arguments are pushed by the (platform-specific)
    167   // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
    168   // LoadWithInterceptor.
    169   static const int kInterceptorArgsNameIndex = 0;
    170   static const int kInterceptorArgsThisIndex = 1;
    171   static const int kInterceptorArgsHolderIndex = 2;
    172   static const int kInterceptorArgsLength = 3;
    173 
    174  protected:
    175   virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
    176                                   Label* miss, ReturnHolder return_what);
    177 
    178   virtual void FrontendFooter(Handle<Name> name, Label* miss);
    179 
    180  private:
    181   Handle<Code> CompileLoadNonexistent(Handle<Name> name);
    182   void GenerateLoadConstant(Handle<Object> value);
    183   void GenerateLoadCallback(Register reg, Handle<AccessorInfo> callback);
    184   void GenerateLoadCallback(const CallOptimization& call_optimization,
    185                             Handle<Map> receiver_map);
    186 
    187   // Helper emits no code if vector-ics are disabled.
    188   void InterceptorVectorSlotPush(Register holder_reg);
    189   enum PopMode { POP, DISCARD };
    190   void InterceptorVectorSlotPop(Register holder_reg, PopMode mode = POP);
    191 
    192   void GenerateLoadInterceptor(Register holder_reg);
    193   void GenerateLoadInterceptorWithFollowup(LookupIterator* it,
    194                                            Register holder_reg);
    195   void GenerateLoadPostInterceptor(LookupIterator* it, Register reg);
    196 
    197   // Generates prototype loading code that uses the objects from the
    198   // context we were in when this function was called. If the context
    199   // has changed, a jump to miss is performed. This ties the generated
    200   // code to a particular context and so must not be used in cases
    201   // where the generated code is not allowed to have references to
    202   // objects from a context.
    203   static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
    204                                                         int index,
    205                                                         Register prototype,
    206                                                         Label* miss);
    207 
    208   Register scratch3() { return registers_[4]; }
    209 };
    210 
    211 
    212 class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
    213  public:
    214   explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map,
    215                                      Handle<JSObject> holder)
    216       : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder,
    217                                 kCacheOnReceiver) {}
    218 
    219   virtual ~NamedStoreHandlerCompiler() {}
    220 
    221   Handle<Code> CompileStoreTransition(Handle<Map> transition,
    222                                       Handle<Name> name);
    223   Handle<Code> CompileStoreField(LookupIterator* it);
    224   Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
    225                                     Handle<AccessorInfo> callback,
    226                                     LanguageMode language_mode);
    227   Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
    228                                     const CallOptimization& call_optimization,
    229                                     int accessor_index);
    230   Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name,
    231                                      int accessor_index,
    232                                      int expected_arguments);
    233 
    234   static void GenerateStoreViaSetter(MacroAssembler* masm, Handle<Map> map,
    235                                      Register receiver, Register holder,
    236                                      int accessor_index, int expected_arguments,
    237                                      Register scratch);
    238 
    239   static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) {
    240     GenerateStoreViaSetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1,
    241                            no_reg);
    242   }
    243 
    244   static void GenerateSlow(MacroAssembler* masm);
    245 
    246  protected:
    247   virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
    248                                   Label* miss, ReturnHolder return_what);
    249 
    250   virtual void FrontendFooter(Handle<Name> name, Label* miss);
    251   void GenerateRestoreName(Label* label, Handle<Name> name);
    252 
    253   // Pop the vector and slot into appropriate registers, moving the map in
    254   // the process. (This is an accomodation for register pressure on ia32).
    255   void RearrangeVectorAndSlot(Register current_map, Register destination_map);
    256 
    257  private:
    258   void GenerateRestoreName(Handle<Name> name);
    259   void GenerateRestoreMap(Handle<Map> transition, Register map_reg,
    260                           Register scratch, Label* miss);
    261 
    262   void GenerateConstantCheck(Register map_reg, int descriptor,
    263                              Register value_reg, Register scratch,
    264                              Label* miss_label);
    265 
    266   bool RequiresFieldTypeChecks(FieldType* field_type) const;
    267   void GenerateFieldTypeChecks(FieldType* field_type, Register value_reg,
    268                                Label* miss_label);
    269 
    270   static Builtins::Name SlowBuiltin(Code::Kind kind) {
    271     switch (kind) {
    272       case Code::STORE_IC:
    273         return Builtins::kStoreIC_Slow;
    274       case Code::KEYED_STORE_IC:
    275         return Builtins::kKeyedStoreIC_Slow;
    276       default:
    277         UNREACHABLE();
    278     }
    279     return Builtins::kStoreIC_Slow;
    280   }
    281 
    282   static Register value();
    283 };
    284 
    285 
    286 class ElementHandlerCompiler : public PropertyHandlerCompiler {
    287  public:
    288   explicit ElementHandlerCompiler(Isolate* isolate)
    289       : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
    290                                 Handle<Map>::null(), Handle<JSObject>::null(),
    291                                 kCacheOnReceiver) {}
    292 
    293   virtual ~ElementHandlerCompiler() {}
    294 
    295   void CompileElementHandlers(MapHandleList* receiver_maps,
    296                               CodeHandleList* handlers);
    297 
    298   static void GenerateStoreSlow(MacroAssembler* masm);
    299 };
    300 }  // namespace internal
    301 }  // namespace v8
    302 
    303 #endif  // V8_IC_HANDLER_COMPILER_H_
    304