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