1// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_IC_H_
29#define V8_IC_H_
30
31#include "macro-assembler.h"
32
33namespace v8 {
34namespace internal {
35
36
37// IC_UTIL_LIST defines all utility functions called from generated
38// inline caching code. The argument for the macro, ICU, is the function name.
39#define IC_UTIL_LIST(ICU)                             \
40  ICU(LoadIC_Miss)                                    \
41  ICU(KeyedLoadIC_Miss)                               \
42  ICU(CallIC_Miss)                                    \
43  ICU(KeyedCallIC_Miss)                               \
44  ICU(StoreIC_Miss)                                   \
45  ICU(StoreIC_ArrayLength)                            \
46  ICU(SharedStoreIC_ExtendStorage)                    \
47  ICU(KeyedStoreIC_Miss)                              \
48  /* Utilities for IC stubs. */                       \
49  ICU(LoadCallbackProperty)                           \
50  ICU(StoreCallbackProperty)                          \
51  ICU(LoadPropertyWithInterceptorOnly)                \
52  ICU(LoadPropertyWithInterceptorForLoad)             \
53  ICU(LoadPropertyWithInterceptorForCall)             \
54  ICU(KeyedLoadPropertyWithInterceptor)               \
55  ICU(StoreInterceptorProperty)                       \
56  ICU(TypeRecordingBinaryOp_Patch)                    \
57  ICU(CompareIC_Miss)
58//
59// IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
60// and KeyedStoreIC.
61//
62class IC {
63 public:
64
65  // The ids for utility called from the generated code.
66  enum UtilityId {
67  #define CONST_NAME(name) k##name,
68    IC_UTIL_LIST(CONST_NAME)
69  #undef CONST_NAME
70    kUtilityCount
71  };
72
73  // Looks up the address of the named utility.
74  static Address AddressFromUtilityId(UtilityId id);
75
76  // Alias the inline cache state type to make the IC code more readable.
77  typedef InlineCacheState State;
78
79  // The IC code is either invoked with no extra frames on the stack
80  // or with a single extra frame for supporting calls.
81  enum FrameDepth {
82    NO_EXTRA_FRAME = 0,
83    EXTRA_CALL_FRAME = 1
84  };
85
86  // Construct the IC structure with the given number of extra
87  // JavaScript frames on the stack.
88  IC(FrameDepth depth, Isolate* isolate);
89
90  // Get the call-site target; used for determining the state.
91  Code* target() { return GetTargetAtAddress(address()); }
92  inline Address address();
93
94  // Compute the current IC state based on the target stub, receiver and name.
95  static State StateFrom(Code* target, Object* receiver, Object* name);
96
97  // Clear the inline cache to initial state.
98  static void Clear(Address address);
99
100  // Computes the reloc info for this IC. This is a fairly expensive
101  // operation as it has to search through the heap to find the code
102  // object that contains this IC site.
103  RelocInfo::Mode ComputeMode();
104
105  // Returns if this IC is for contextual (no explicit receiver)
106  // access to properties.
107  bool IsContextual(Handle<Object> receiver) {
108    if (receiver->IsGlobalObject()) {
109      return SlowIsContextual();
110    } else {
111      ASSERT(!SlowIsContextual());
112      return false;
113    }
114  }
115
116  bool SlowIsContextual() {
117    return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT;
118  }
119
120  // Determines which map must be used for keeping the code stub.
121  // These methods should not be called with undefined or null.
122  static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object,
123                                                            JSObject* holder);
124  static inline InlineCacheHolderFlag GetCodeCacheForObject(JSObject* object,
125                                                            JSObject* holder);
126  static inline JSObject* GetCodeCacheHolder(Object* object,
127                                             InlineCacheHolderFlag holder);
128
129 protected:
130  Address fp() const { return fp_; }
131  Address pc() const { return *pc_address_; }
132  Isolate* isolate() const { return isolate_; }
133
134#ifdef ENABLE_DEBUGGER_SUPPORT
135  // Computes the address in the original code when the code running is
136  // containing break points (calls to DebugBreakXXX builtins).
137  Address OriginalCodeAddress();
138#endif
139
140  // Set the call-site target.
141  void set_target(Code* code) { SetTargetAtAddress(address(), code); }
142
143#ifdef DEBUG
144  static void TraceIC(const char* type,
145                      Handle<Object> name,
146                      State old_state,
147                      Code* new_target,
148                      const char* extra_info = "");
149#endif
150
151  Failure* TypeError(const char* type,
152                     Handle<Object> object,
153                     Handle<Object> key);
154  Failure* ReferenceError(const char* type, Handle<String> name);
155
156  // Access the target code for the given IC address.
157  static inline Code* GetTargetAtAddress(Address address);
158  static inline void SetTargetAtAddress(Address address, Code* target);
159
160 private:
161  // Frame pointer for the frame that uses (calls) the IC.
162  Address fp_;
163
164  // All access to the program counter of an IC structure is indirect
165  // to make the code GC safe. This feature is crucial since
166  // GetProperty and SetProperty are called and they in turn might
167  // invoke the garbage collector.
168  Address* pc_address_;
169
170  Isolate* isolate_;
171
172  DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
173};
174
175
176// An IC_Utility encapsulates IC::UtilityId. It exists mainly because you
177// cannot make forward declarations to an enum.
178class IC_Utility {
179 public:
180  explicit IC_Utility(IC::UtilityId id)
181    : address_(IC::AddressFromUtilityId(id)), id_(id) {}
182
183  Address address() const { return address_; }
184
185  IC::UtilityId id() const { return id_; }
186 private:
187  Address address_;
188  IC::UtilityId id_;
189};
190
191
192class CallICBase: public IC {
193 protected:
194  CallICBase(Code::Kind kind, Isolate* isolate)
195      : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {}
196
197 public:
198  MUST_USE_RESULT MaybeObject* LoadFunction(State state,
199                                            Code::ExtraICState extra_ic_state,
200                                            Handle<Object> object,
201                                            Handle<String> name);
202
203 protected:
204  Code::Kind kind_;
205
206  bool TryUpdateExtraICState(LookupResult* lookup,
207                             Handle<Object> object,
208                             Code::ExtraICState* extra_ic_state);
209
210  MUST_USE_RESULT MaybeObject* ComputeMonomorphicStub(
211      LookupResult* lookup,
212      State state,
213      Code::ExtraICState extra_ic_state,
214      Handle<Object> object,
215      Handle<String> name);
216
217  // Update the inline cache and the global stub cache based on the
218  // lookup result.
219  void UpdateCaches(LookupResult* lookup,
220                    State state,
221                    Code::ExtraICState extra_ic_state,
222                    Handle<Object> object,
223                    Handle<String> name);
224
225  // Returns a JSFunction if the object can be called as a function,
226  // and patches the stack to be ready for the call.
227  // Otherwise, it returns the undefined value.
228  Object* TryCallAsFunction(Object* object);
229
230  void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object);
231
232  static void Clear(Address address, Code* target);
233  friend class IC;
234};
235
236
237class CallIC: public CallICBase {
238 public:
239  explicit CallIC(Isolate* isolate) : CallICBase(Code::CALL_IC, isolate) {
240    ASSERT(target()->is_call_stub());
241  }
242
243  // Code generator routines.
244  static void GenerateInitialize(MacroAssembler* masm, int argc) {
245    GenerateMiss(masm, argc);
246  }
247  static void GenerateMiss(MacroAssembler* masm, int argc);
248  static void GenerateMegamorphic(MacroAssembler* masm, int argc);
249  static void GenerateNormal(MacroAssembler* masm, int argc);
250};
251
252
253class KeyedCallIC: public CallICBase {
254 public:
255  explicit KeyedCallIC(Isolate* isolate)
256      : CallICBase(Code::KEYED_CALL_IC, isolate) {
257    ASSERT(target()->is_keyed_call_stub());
258  }
259
260  MUST_USE_RESULT MaybeObject* LoadFunction(State state,
261                                            Handle<Object> object,
262                                            Handle<Object> key);
263
264  // Code generator routines.
265  static void GenerateInitialize(MacroAssembler* masm, int argc) {
266    GenerateMiss(masm, argc);
267  }
268  static void GenerateMiss(MacroAssembler* masm, int argc);
269  static void GenerateMegamorphic(MacroAssembler* masm, int argc);
270  static void GenerateNormal(MacroAssembler* masm, int argc);
271};
272
273
274class LoadIC: public IC {
275 public:
276  explicit LoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
277    ASSERT(target()->is_load_stub());
278  }
279
280  MUST_USE_RESULT MaybeObject* Load(State state,
281                                    Handle<Object> object,
282                                    Handle<String> name);
283
284  // Code generator routines.
285  static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
286  static void GeneratePreMonomorphic(MacroAssembler* masm) {
287    GenerateMiss(masm);
288  }
289  static void GenerateMiss(MacroAssembler* masm);
290  static void GenerateMegamorphic(MacroAssembler* masm);
291  static void GenerateNormal(MacroAssembler* masm);
292
293  // Specialized code generator routines.
294  static void GenerateArrayLength(MacroAssembler* masm);
295  static void GenerateStringLength(MacroAssembler* masm,
296                                   bool support_wrappers);
297  static void GenerateFunctionPrototype(MacroAssembler* masm);
298
299  // Clear the use of the inlined version.
300  static void ClearInlinedVersion(Address address);
301
302  // The offset from the inlined patch site to the start of the
303  // inlined load instruction.  It is architecture-dependent, and not
304  // used on ARM.
305  static const int kOffsetToLoadInstruction;
306
307 private:
308  // Update the inline cache and the global stub cache based on the
309  // lookup result.
310  void UpdateCaches(LookupResult* lookup,
311                    State state,
312                    Handle<Object> object,
313                    Handle<String> name);
314
315  // Stub accessors.
316  Code* megamorphic_stub() {
317    return isolate()->builtins()->builtin(
318        Builtins::kLoadIC_Megamorphic);
319  }
320  static Code* initialize_stub() {
321    return Isolate::Current()->builtins()->builtin(
322        Builtins::kLoadIC_Initialize);
323  }
324  Code* pre_monomorphic_stub() {
325    return isolate()->builtins()->builtin(
326        Builtins::kLoadIC_PreMonomorphic);
327  }
328
329  static void Clear(Address address, Code* target);
330
331  static bool PatchInlinedLoad(Address address, Object* map, int index);
332
333  static bool PatchInlinedContextualLoad(Address address,
334                                         Object* map,
335                                         Object* cell,
336                                         bool is_dont_delete);
337
338  friend class IC;
339};
340
341
342class KeyedLoadIC: public IC {
343 public:
344  explicit KeyedLoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
345    ASSERT(target()->is_keyed_load_stub());
346  }
347
348  MUST_USE_RESULT MaybeObject* Load(State state,
349                                    Handle<Object> object,
350                                    Handle<Object> key);
351
352  // Code generator routines.
353  static void GenerateMiss(MacroAssembler* masm);
354  static void GenerateRuntimeGetProperty(MacroAssembler* masm);
355  static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
356  static void GeneratePreMonomorphic(MacroAssembler* masm) {
357    GenerateMiss(masm);
358  }
359  static void GenerateGeneric(MacroAssembler* masm);
360  static void GenerateString(MacroAssembler* masm);
361
362  static void GenerateIndexedInterceptor(MacroAssembler* masm);
363
364  // Clear the use of the inlined version.
365  static void ClearInlinedVersion(Address address);
366
367  // Bit mask to be tested against bit field for the cases when
368  // generic stub should go into slow case.
369  // Access check is necessary explicitly since generic stub does not perform
370  // map checks.
371  static const int kSlowCaseBitFieldMask =
372      (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
373
374 private:
375  // Update the inline cache.
376  void UpdateCaches(LookupResult* lookup,
377                    State state,
378                    Handle<Object> object,
379                    Handle<String> name);
380
381  // Stub accessors.
382  static Code* initialize_stub() {
383    return Isolate::Current()->builtins()->builtin(
384        Builtins::kKeyedLoadIC_Initialize);
385  }
386  Code* megamorphic_stub() {
387    return isolate()->builtins()->builtin(
388        Builtins::kKeyedLoadIC_Generic);
389  }
390  Code* generic_stub() {
391    return isolate()->builtins()->builtin(
392        Builtins::kKeyedLoadIC_Generic);
393  }
394  Code* pre_monomorphic_stub() {
395    return isolate()->builtins()->builtin(
396        Builtins::kKeyedLoadIC_PreMonomorphic);
397  }
398  Code* string_stub() {
399    return isolate()->builtins()->builtin(
400        Builtins::kKeyedLoadIC_String);
401  }
402
403  Code* indexed_interceptor_stub() {
404    return isolate()->builtins()->builtin(
405        Builtins::kKeyedLoadIC_IndexedInterceptor);
406  }
407
408  static void Clear(Address address, Code* target);
409
410  // Support for patching the map that is checked in an inlined
411  // version of keyed load.
412  static bool PatchInlinedLoad(Address address, Object* map);
413
414  friend class IC;
415};
416
417
418class StoreIC: public IC {
419 public:
420  explicit StoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
421    ASSERT(target()->is_store_stub());
422  }
423
424  MUST_USE_RESULT MaybeObject* Store(State state,
425                                     StrictModeFlag strict_mode,
426                                     Handle<Object> object,
427                                     Handle<String> name,
428                                     Handle<Object> value);
429
430  // Code generators for stub routines. Only called once at startup.
431  static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
432  static void GenerateMiss(MacroAssembler* masm);
433  static void GenerateMegamorphic(MacroAssembler* masm,
434                                  StrictModeFlag strict_mode);
435  static void GenerateArrayLength(MacroAssembler* masm);
436  static void GenerateNormal(MacroAssembler* masm);
437  static void GenerateGlobalProxy(MacroAssembler* masm,
438                                  StrictModeFlag strict_mode);
439
440  // Clear the use of an inlined version.
441  static void ClearInlinedVersion(Address address);
442
443  // The offset from the inlined patch site to the start of the
444  // inlined store instruction.
445  static const int kOffsetToStoreInstruction;
446
447 private:
448  // Update the inline cache and the global stub cache based on the
449  // lookup result.
450  void UpdateCaches(LookupResult* lookup,
451                    State state,
452                    StrictModeFlag strict_mode,
453                    Handle<JSObject> receiver,
454                    Handle<String> name,
455                    Handle<Object> value);
456
457  void set_target(Code* code) {
458    // Strict mode must be preserved across IC patching.
459    ASSERT((code->extra_ic_state() & kStrictMode) ==
460           (target()->extra_ic_state() & kStrictMode));
461    IC::set_target(code);
462  }
463
464  // Stub accessors.
465  Code* megamorphic_stub() {
466    return isolate()->builtins()->builtin(
467        Builtins::kStoreIC_Megamorphic);
468  }
469  Code* megamorphic_stub_strict() {
470    return isolate()->builtins()->builtin(
471        Builtins::kStoreIC_Megamorphic_Strict);
472  }
473  static Code* initialize_stub() {
474    return Isolate::Current()->builtins()->builtin(
475        Builtins::kStoreIC_Initialize);
476  }
477  static Code* initialize_stub_strict() {
478    return Isolate::Current()->builtins()->builtin(
479        Builtins::kStoreIC_Initialize_Strict);
480  }
481  Code* global_proxy_stub() {
482    return isolate()->builtins()->builtin(
483        Builtins::kStoreIC_GlobalProxy);
484  }
485  Code* global_proxy_stub_strict() {
486    return isolate()->builtins()->builtin(
487        Builtins::kStoreIC_GlobalProxy_Strict);
488  }
489
490  static void Clear(Address address, Code* target);
491
492  // Support for patching the index and the map that is checked in an
493  // inlined version of the named store.
494  static bool PatchInlinedStore(Address address, Object* map, int index);
495
496  friend class IC;
497};
498
499
500class KeyedStoreIC: public IC {
501 public:
502  explicit KeyedStoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
503
504  MUST_USE_RESULT MaybeObject* Store(State state,
505                                     StrictModeFlag strict_mode,
506                                     Handle<Object> object,
507                                     Handle<Object> name,
508                                     Handle<Object> value);
509
510  // Code generators for stub routines.  Only called once at startup.
511  static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
512  static void GenerateMiss(MacroAssembler* masm);
513  static void GenerateRuntimeSetProperty(MacroAssembler* masm,
514                                         StrictModeFlag strict_mode);
515  static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode);
516
517  // Clear the inlined version so the IC is always hit.
518  static void ClearInlinedVersion(Address address);
519
520  // Restore the inlined version so the fast case can get hit.
521  static void RestoreInlinedVersion(Address address);
522
523 private:
524  // Update the inline cache.
525  void UpdateCaches(LookupResult* lookup,
526                    State state,
527                    StrictModeFlag strict_mode,
528                    Handle<JSObject> receiver,
529                    Handle<String> name,
530                    Handle<Object> value);
531
532  void set_target(Code* code) {
533    // Strict mode must be preserved across IC patching.
534    ASSERT((code->extra_ic_state() & kStrictMode) ==
535           (target()->extra_ic_state() & kStrictMode));
536    IC::set_target(code);
537  }
538
539  // Stub accessors.
540  static Code* initialize_stub() {
541    return Isolate::Current()->builtins()->builtin(
542        Builtins::kKeyedStoreIC_Initialize);
543  }
544  Code* megamorphic_stub() {
545    return isolate()->builtins()->builtin(
546        Builtins::kKeyedStoreIC_Generic);
547  }
548  static Code* initialize_stub_strict() {
549    return Isolate::Current()->builtins()->builtin(
550        Builtins::kKeyedStoreIC_Initialize_Strict);
551  }
552  Code* megamorphic_stub_strict() {
553    return isolate()->builtins()->builtin(
554        Builtins::kKeyedStoreIC_Generic_Strict);
555  }
556  Code* generic_stub() {
557    return isolate()->builtins()->builtin(
558        Builtins::kKeyedStoreIC_Generic);
559  }
560  Code* generic_stub_strict() {
561    return isolate()->builtins()->builtin(
562        Builtins::kKeyedStoreIC_Generic_Strict);
563  }
564
565  static void Clear(Address address, Code* target);
566
567  // Support for patching the map that is checked in an inlined
568  // version of keyed store.
569  // The address is the patch point for the IC call
570  // (Assembler::kCallTargetAddressOffset before the end of
571  // the call/return address).
572  // The map is the new map that the inlined code should check against.
573  static bool PatchInlinedStore(Address address, Object* map);
574
575  friend class IC;
576};
577
578
579// Type Recording BinaryOpIC, that records the types of the inputs and outputs.
580class TRBinaryOpIC: public IC {
581 public:
582
583  enum TypeInfo {
584    UNINITIALIZED,
585    SMI,
586    INT32,
587    HEAP_NUMBER,
588    ODDBALL,
589    STRING,  // Only used for addition operation.  At least one string operand.
590    GENERIC
591  };
592
593  explicit TRBinaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
594
595  void patch(Code* code);
596
597  static const char* GetName(TypeInfo type_info);
598
599  static State ToState(TypeInfo type_info);
600
601  static TypeInfo GetTypeInfo(Handle<Object> left, Handle<Object> right);
602
603  static TypeInfo JoinTypes(TypeInfo x, TypeInfo y);
604};
605
606
607class CompareIC: public IC {
608 public:
609  enum State {
610    UNINITIALIZED,
611    SMIS,
612    HEAP_NUMBERS,
613    OBJECTS,
614    GENERIC
615  };
616
617  CompareIC(Isolate* isolate, Token::Value op)
618      : IC(EXTRA_CALL_FRAME, isolate), op_(op) { }
619
620  // Update the inline cache for the given operands.
621  void UpdateCaches(Handle<Object> x, Handle<Object> y);
622
623  // Factory method for getting an uninitialized compare stub.
624  static Handle<Code> GetUninitialized(Token::Value op);
625
626  // Helper function for computing the condition for a compare operation.
627  static Condition ComputeCondition(Token::Value op);
628
629  // Helper function for determining the state of a compare IC.
630  static State ComputeState(Code* target);
631
632  static const char* GetStateName(State state);
633
634 private:
635  State TargetState(State state, bool has_inlined_smi_code,
636                    Handle<Object> x, Handle<Object> y);
637
638  bool strict() const { return op_ == Token::EQ_STRICT; }
639  Condition GetCondition() const { return ComputeCondition(op_); }
640  State GetState() { return ComputeState(target()); }
641
642  Token::Value op_;
643};
644
645// Helper for TRBinaryOpIC and CompareIC.
646void PatchInlinedSmiCode(Address address);
647
648} }  // namespace v8::internal
649
650#endif  // V8_IC_H_
651