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
11namespace v8 {
12namespace internal {
13
14class CallOptimization;
15
16enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
17
18class 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:
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
31  virtual ~PropertyHandlerCompiler() {}
32
33  virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
34                                  Label* miss) {
35    UNREACHABLE();
36    return receiver();
37  }
38
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);
90  void set_holder(Handle<JSObject> holder) { holder_ = holder; }
91  Handle<HeapType> type() const { return type_; }
92  Handle<JSObject> holder() const { return holder_; }
93
94 private:
95  Handle<HeapType> type_;
96  Handle<JSObject> holder_;
97};
98
99
100class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
101 public:
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
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
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
190  Register scratch4() { return registers_[5]; }
191};
192
193
194class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
195 public:
196  explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<HeapType> type,
197                                     Handle<JSObject> holder)
198      : PropertyHandlerCompiler(isolate, Code::STORE_IC, type, holder,
199                                kCacheOnReceiver) {}
200
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
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
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
258class ElementHandlerCompiler : public PropertyHandlerCompiler {
259 public:
260  explicit ElementHandlerCompiler(Isolate* isolate)
261      : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
262                                Handle<HeapType>::null(),
263                                Handle<JSObject>::null(), kCacheOnReceiver) {}
264
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