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, Code::StubType type);
     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, Code::StubType type, 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<ExecutableAccessorInfo> 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,
    184                             Handle<ExecutableAccessorInfo> callback);
    185   void GenerateLoadCallback(const CallOptimization& call_optimization,
    186                             Handle<Map> receiver_map);
    187 
    188   // Helper emits no code if vector-ics are disabled.
    189   void InterceptorVectorSlotPush(Register holder_reg);
    190   enum PopMode { POP, DISCARD };
    191   void InterceptorVectorSlotPop(Register holder_reg, PopMode mode = POP);
    192 
    193   void GenerateLoadInterceptor(Register holder_reg);
    194   void GenerateLoadInterceptorWithFollowup(LookupIterator* it,
    195                                            Register holder_reg);
    196   void GenerateLoadPostInterceptor(LookupIterator* it, Register reg);
    197 
    198   // Generates prototype loading code that uses the objects from the
    199   // context we were in when this function was called. If the context
    200   // has changed, a jump to miss is performed. This ties the generated
    201   // code to a particular context and so must not be used in cases
    202   // where the generated code is not allowed to have references to
    203   // objects from a context.
    204   static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
    205                                                         int index,
    206                                                         Register prototype,
    207                                                         Label* miss);
    208 
    209 
    210   Register scratch4() { return registers_[5]; }
    211 };
    212 
    213 
    214 class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
    215  public:
    216   explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map,
    217                                      Handle<JSObject> holder)
    218       : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder,
    219                                 kCacheOnReceiver) {}
    220 
    221   virtual ~NamedStoreHandlerCompiler() {}
    222 
    223   Handle<Code> CompileStoreTransition(Handle<Map> transition,
    224                                       Handle<Name> name);
    225   Handle<Code> CompileStoreField(LookupIterator* it);
    226   Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
    227                                     Handle<ExecutableAccessorInfo> callback);
    228   Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
    229                                     const CallOptimization& call_optimization,
    230                                     int accessor_index);
    231   Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name,
    232                                      int accessor_index,
    233                                      int expected_arguments);
    234   Handle<Code> CompileStoreInterceptor(Handle<Name> name);
    235 
    236   static void GenerateStoreViaSetter(MacroAssembler* masm, Handle<Map> map,
    237                                      Register receiver, Register holder,
    238                                      int accessor_index, int expected_arguments,
    239                                      Register scratch);
    240 
    241   static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) {
    242     GenerateStoreViaSetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1,
    243                            no_reg);
    244   }
    245 
    246   static void GenerateSlow(MacroAssembler* masm);
    247 
    248  protected:
    249   virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
    250                                   Label* miss, ReturnHolder return_what);
    251 
    252   virtual void FrontendFooter(Handle<Name> name, Label* miss);
    253   void GenerateRestoreName(Label* label, Handle<Name> name);
    254 
    255   // Pop the vector and slot into appropriate registers, moving the map in
    256   // the process. (This is an accomodation for register pressure on ia32).
    257   void RearrangeVectorAndSlot(Register current_map, Register destination_map);
    258 
    259  private:
    260   void GenerateRestoreName(Handle<Name> name);
    261   void GenerateRestoreMap(Handle<Map> transition, Register map_reg,
    262                           Register scratch, Label* miss);
    263 
    264   void GenerateConstantCheck(Register map_reg, int descriptor,
    265                              Register value_reg, Register scratch,
    266                              Label* miss_label);
    267 
    268   bool RequiresFieldTypeChecks(HeapType* field_type) const;
    269   void GenerateFieldTypeChecks(HeapType* field_type, Register value_reg,
    270                                Label* miss_label);
    271 
    272   static Builtins::Name SlowBuiltin(Code::Kind kind) {
    273     switch (kind) {
    274       case Code::STORE_IC:
    275         return Builtins::kStoreIC_Slow;
    276       case Code::KEYED_STORE_IC:
    277         return Builtins::kKeyedStoreIC_Slow;
    278       default:
    279         UNREACHABLE();
    280     }
    281     return Builtins::kStoreIC_Slow;
    282   }
    283 
    284   static Register value();
    285 };
    286 
    287 
    288 class ElementHandlerCompiler : public PropertyHandlerCompiler {
    289  public:
    290   explicit ElementHandlerCompiler(Isolate* isolate)
    291       : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
    292                                 Handle<Map>::null(), Handle<JSObject>::null(),
    293                                 kCacheOnReceiver) {}
    294 
    295   virtual ~ElementHandlerCompiler() {}
    296 
    297   void CompileElementHandlers(MapHandleList* receiver_maps,
    298                               CodeHandleList* handlers,
    299                               LanguageMode language_mode);
    300 
    301   static void GenerateStoreSlow(MacroAssembler* masm);
    302 };
    303 }  // namespace internal
    304 }  // namespace v8
    305 
    306 #endif  // V8_IC_HANDLER_COMPILER_H_
    307