• 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, Code::StubType type);
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, Code::StubType type, 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<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 
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,
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 
scratch4()210   Register scratch4() { return registers_[5]; }
211 };
212 
213 
214 class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
215  public:
NamedStoreHandlerCompiler(Isolate * isolate,Handle<Map> map,Handle<JSObject> holder)216   explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map,
217                                      Handle<JSObject> holder)
218       : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder,
219                                 kCacheOnReceiver) {}
220 
~NamedStoreHandlerCompiler()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 
GenerateStoreViaSetterForDeopt(MacroAssembler * masm)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 
SlowBuiltin(Code::Kind kind)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:
ElementHandlerCompiler(Isolate * isolate)290   explicit ElementHandlerCompiler(Isolate* isolate)
291       : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
292                                 Handle<Map>::null(), Handle<JSObject>::null(),
293                                 kCacheOnReceiver) {}
294 
~ElementHandlerCompiler()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