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 
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, Code::StubType type);
22 
23  protected:
PropertyHandlerCompiler(Isolate * isolate,Code::Kind kind,Handle<HeapType> type,Handle<JSObject> holder,CacheHolderFlag cache_holder)24   PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind,
25                           Handle<HeapType> type, Handle<JSObject> holder,
26                           CacheHolderFlag cache_holder)
27       : PropertyAccessCompiler(isolate, kind, cache_holder),
28         type_(type),
29         holder_(holder) {}
30 
~PropertyHandlerCompiler()31   virtual ~PropertyHandlerCompiler() {}
32 
FrontendHeader(Register object_reg,Handle<Name> name,Label * miss)33   virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
34                                   Label* miss) {
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   Register Frontend(Register object_reg, Handle<Name> name);
42   void NonexistentFrontendHeader(Handle<Name> name, Label* miss,
43                                  Register scratch1, Register scratch2);
44 
45   // TODO(verwaest): Make non-static.
46   static void GenerateFastApiCall(MacroAssembler* masm,
47                                   const CallOptimization& optimization,
48                                   Handle<Map> receiver_map, Register receiver,
49                                   Register scratch, bool is_store, int argc,
50                                   Register* values);
51 
52   // Helper function used to check that the dictionary doesn't contain
53   // the property. This function may return false negatives, so miss_label
54   // must always call a backup property check that is complete.
55   // This function is safe to call if the receiver has fast properties.
56   // Name must be unique and receiver must be a heap object.
57   static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
58                                                Label* miss_label,
59                                                Register receiver,
60                                                Handle<Name> name, Register r0,
61                                                Register r1);
62 
63   // Generate code to check that a global property cell is empty. Create
64   // the property cell at compilation time if no cell exists for the
65   // property.
66   static void GenerateCheckPropertyCell(MacroAssembler* masm,
67                                         Handle<JSGlobalObject> global,
68                                         Handle<Name> name, Register scratch,
69                                         Label* miss);
70 
71   // Generates code that verifies that the property holder has not changed
72   // (checking maps of objects in the prototype chain for fast and global
73   // objects or doing negative lookup for slow objects, ensures that the
74   // property cells for global objects are still empty) and checks that the map
75   // of the holder has not changed. If necessary the function also generates
76   // code for security check in case of global object holders. Helps to make
77   // sure that the current IC is still valid.
78   //
79   // The scratch and holder registers are always clobbered, but the object
80   // register is only clobbered if it the same as the holder register. The
81   // function returns a register containing the holder - either object_reg or
82   // holder_reg.
83   Register CheckPrototypes(Register object_reg, Register holder_reg,
84                            Register scratch1, Register scratch2,
85                            Handle<Name> name, Label* miss,
86                            PrototypeCheckType check = CHECK_ALL_MAPS);
87 
88   Handle<Code> GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name);
89   void set_type_for_object(Handle<Object> object);
set_holder(Handle<JSObject> holder)90   void set_holder(Handle<JSObject> holder) { holder_ = holder; }
type()91   Handle<HeapType> type() const { return type_; }
holder()92   Handle<JSObject> holder() const { return holder_; }
93 
94  private:
95   Handle<HeapType> type_;
96   Handle<JSObject> holder_;
97 };
98 
99 
100 class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
101  public:
NamedLoadHandlerCompiler(Isolate * isolate,Handle<HeapType> type,Handle<JSObject> holder,CacheHolderFlag cache_holder)102   NamedLoadHandlerCompiler(Isolate* isolate, Handle<HeapType> type,
103                            Handle<JSObject> holder,
104                            CacheHolderFlag cache_holder)
105       : PropertyHandlerCompiler(isolate, Code::LOAD_IC, type, holder,
106                                 cache_holder) {}
107 
~NamedLoadHandlerCompiler()108   virtual ~NamedLoadHandlerCompiler() {}
109 
110   Handle<Code> CompileLoadField(Handle<Name> name, FieldIndex index);
111 
112   Handle<Code> CompileLoadCallback(Handle<Name> name,
113                                    Handle<ExecutableAccessorInfo> callback);
114 
115   Handle<Code> CompileLoadCallback(Handle<Name> name,
116                                    const CallOptimization& call_optimization);
117 
118   Handle<Code> CompileLoadConstant(Handle<Name> name, int constant_index);
119 
120   // The LookupIterator is used to perform a lookup behind the interceptor. If
121   // the iterator points to a LookupIterator::PROPERTY, its access will be
122   // inlined.
123   Handle<Code> CompileLoadInterceptor(LookupIterator* it);
124 
125   Handle<Code> CompileLoadViaGetter(Handle<Name> name,
126                                     Handle<JSFunction> getter);
127 
128   Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name,
129                                  bool is_configurable);
130 
131   // Static interface
132   static Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
133                                              Handle<HeapType> type);
134 
135   static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<HeapType> type,
136                                     Register receiver,
137                                     Handle<JSFunction> getter);
138 
GenerateLoadViaGetterForDeopt(MacroAssembler * masm)139   static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) {
140     GenerateLoadViaGetter(masm, Handle<HeapType>::null(), no_reg,
141                           Handle<JSFunction>());
142   }
143 
144   static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
145                                             Register receiver,
146                                             Register scratch1,
147                                             Register scratch2,
148                                             Label* miss_label);
149 
150   // These constants describe the structure of the interceptor arguments on the
151   // stack. The arguments are pushed by the (platform-specific)
152   // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
153   // LoadWithInterceptor.
154   static const int kInterceptorArgsNameIndex = 0;
155   static const int kInterceptorArgsInfoIndex = 1;
156   static const int kInterceptorArgsThisIndex = 2;
157   static const int kInterceptorArgsHolderIndex = 3;
158   static const int kInterceptorArgsLength = 4;
159 
160  protected:
161   virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
162                                   Label* miss);
163 
164   virtual void FrontendFooter(Handle<Name> name, Label* miss);
165 
166  private:
167   Handle<Code> CompileLoadNonexistent(Handle<Name> name);
168   void GenerateLoadConstant(Handle<Object> value);
169   void GenerateLoadCallback(Register reg,
170                             Handle<ExecutableAccessorInfo> callback);
171   void GenerateLoadCallback(const CallOptimization& call_optimization,
172                             Handle<Map> receiver_map);
173   void GenerateLoadInterceptor(Register holder_reg);
174   void GenerateLoadInterceptorWithFollowup(LookupIterator* it,
175                                            Register holder_reg);
176   void GenerateLoadPostInterceptor(LookupIterator* it, Register reg);
177 
178   // Generates prototype loading code that uses the objects from the
179   // context we were in when this function was called. If the context
180   // has changed, a jump to miss is performed. This ties the generated
181   // code to a particular context and so must not be used in cases
182   // where the generated code is not allowed to have references to
183   // objects from a context.
184   static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
185                                                         int index,
186                                                         Register prototype,
187                                                         Label* miss);
188 
189 
scratch4()190   Register scratch4() { return registers_[5]; }
191 };
192 
193 
194 class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
195  public:
NamedStoreHandlerCompiler(Isolate * isolate,Handle<HeapType> type,Handle<JSObject> holder)196   explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<HeapType> type,
197                                      Handle<JSObject> holder)
198       : PropertyHandlerCompiler(isolate, Code::STORE_IC, type, holder,
199                                 kCacheOnReceiver) {}
200 
~NamedStoreHandlerCompiler()201   virtual ~NamedStoreHandlerCompiler() {}
202 
203   Handle<Code> CompileStoreTransition(Handle<Map> transition,
204                                       Handle<Name> name);
205   Handle<Code> CompileStoreField(LookupIterator* it);
206   Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
207                                     Handle<ExecutableAccessorInfo> callback);
208   Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
209                                     const CallOptimization& call_optimization);
210   Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name,
211                                      Handle<JSFunction> setter);
212   Handle<Code> CompileStoreInterceptor(Handle<Name> name);
213 
214   static void GenerateStoreViaSetter(MacroAssembler* masm,
215                                      Handle<HeapType> type, Register receiver,
216                                      Handle<JSFunction> setter);
217 
GenerateStoreViaSetterForDeopt(MacroAssembler * masm)218   static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) {
219     GenerateStoreViaSetter(masm, Handle<HeapType>::null(), no_reg,
220                            Handle<JSFunction>());
221   }
222 
223   static void GenerateSlow(MacroAssembler* masm);
224 
225  protected:
226   virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
227                                   Label* miss);
228 
229   virtual void FrontendFooter(Handle<Name> name, Label* miss);
230   void GenerateRestoreName(Label* label, Handle<Name> name);
231 
232  private:
233   void GenerateStoreTransition(Handle<Map> transition, Handle<Name> name,
234                                Register receiver_reg, Register name_reg,
235                                Register value_reg, Register scratch1,
236                                Register scratch2, Register scratch3,
237                                Label* miss_label, Label* slow);
238 
239   void GenerateStoreField(LookupIterator* lookup, Register value_reg,
240                           Label* miss_label);
241 
SlowBuiltin(Code::Kind kind)242   static Builtins::Name SlowBuiltin(Code::Kind kind) {
243     switch (kind) {
244       case Code::STORE_IC:
245         return Builtins::kStoreIC_Slow;
246       case Code::KEYED_STORE_IC:
247         return Builtins::kKeyedStoreIC_Slow;
248       default:
249         UNREACHABLE();
250     }
251     return Builtins::kStoreIC_Slow;
252   }
253 
254   static Register value();
255 };
256 
257 
258 class ElementHandlerCompiler : public PropertyHandlerCompiler {
259  public:
ElementHandlerCompiler(Isolate * isolate)260   explicit ElementHandlerCompiler(Isolate* isolate)
261       : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
262                                 Handle<HeapType>::null(),
263                                 Handle<JSObject>::null(), kCacheOnReceiver) {}
264 
~ElementHandlerCompiler()265   virtual ~ElementHandlerCompiler() {}
266 
267   void CompileElementHandlers(MapHandleList* receiver_maps,
268                               CodeHandleList* handlers);
269 
270   static void GenerateStoreSlow(MacroAssembler* masm);
271 };
272 }
273 }  // namespace v8::internal
274 
275 #endif  // V8_IC_HANDLER_COMPILER_H_
276