• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
PropertyHandlerCompiler(Isolate * isolate,Code::Kind kind,Handle<Map> map,Handle<JSObject> holder,CacheHolderFlag cache_holder)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 
~PropertyHandlerCompiler()31   virtual ~PropertyHandlerCompiler() {}
32 
FrontendHeader(Register object_reg,Handle<Name> name,Label * miss,ReturnHolder return_what)33   virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
34                                   Label* miss, ReturnHolder return_what) {
35     UNREACHABLE();
36     return receiver();
37   }
38 
FrontendFooter(Handle<Name> name,Label * miss)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.
PushVectorAndSlot()49   void PushVectorAndSlot() { PushVectorAndSlot(vector(), slot()); }
50   void PushVectorAndSlot(Register vector, Register slot);
PopVectorAndSlot()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);
set_holder(Handle<JSObject> holder)102   void set_holder(Handle<JSObject> holder) { holder_ = holder; }
map()103   Handle<Map> map() const { return map_; }
set_map(Handle<Map> map)104   void set_map(Handle<Map> map) { map_ = map; }
holder()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:
NamedLoadHandlerCompiler(Isolate * isolate,Handle<Map> map,Handle<JSObject> holder,CacheHolderFlag cache_holder)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 
~NamedLoadHandlerCompiler()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 
GenerateLoadViaGetterForDeopt(MacroAssembler * masm)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 
scratch3()208   Register scratch3() { return registers_[4]; }
209 };
210 
211 
212 class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
213  public:
NamedStoreHandlerCompiler(Isolate * isolate,Handle<Map> map,Handle<JSObject> holder)214   explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map,
215                                      Handle<JSObject> holder)
216       : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder,
217                                 kCacheOnReceiver) {}
218 
~NamedStoreHandlerCompiler()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 
GenerateStoreViaSetterForDeopt(MacroAssembler * masm)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 
SlowBuiltin(Code::Kind kind)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:
ElementHandlerCompiler(Isolate * isolate)288   explicit ElementHandlerCompiler(Isolate* isolate)
289       : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
290                                 Handle<Map>::null(), Handle<JSObject>::null(),
291                                 kCacheOnReceiver) {}
292 
~ElementHandlerCompiler()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