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 };
17enum ReturnHolder { RETURN_HOLDER, DONT_RETURN_ANYTHING };
18
19class 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:
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
31  virtual ~PropertyHandlerCompiler() {}
32
33  virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
34                                  Label* miss, ReturnHolder return_what) {
35    UNREACHABLE();
36    return receiver();
37  }
38
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.
49  void PushVectorAndSlot() { PushVectorAndSlot(vector(), slot()); }
50  void PushVectorAndSlot(Register vector, Register slot);
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);
102  void set_holder(Handle<JSObject> holder) { holder_ = holder; }
103  Handle<Map> map() const { return map_; }
104  void set_map(Handle<Map> map) { map_ = map; }
105  Handle<JSObject> holder() const { return holder_; }
106
107 private:
108  Handle<Map> map_;
109  Handle<JSObject> holder_;
110};
111
112
113class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
114 public:
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
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
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
208  Register scratch3() { return registers_[4]; }
209};
210
211
212class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
213 public:
214  explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map,
215                                     Handle<JSObject> holder)
216      : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder,
217                                kCacheOnReceiver) {}
218
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
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
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
286class ElementHandlerCompiler : public PropertyHandlerCompiler {
287 public:
288  explicit ElementHandlerCompiler(Isolate* isolate)
289      : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
290                                Handle<Map>::null(), Handle<JSObject>::null(),
291                                kCacheOnReceiver) {}
292
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