• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 #include "type-info.h"
33 
34 namespace v8 {
35 namespace internal {
36 
37 
38 // IC_UTIL_LIST defines all utility functions called from generated
39 // inline caching code. The argument for the macro, ICU, is the function name.
40 #define IC_UTIL_LIST(ICU)                             \
41   ICU(LoadIC_Miss)                                    \
42   ICU(KeyedLoadIC_Miss)                               \
43   ICU(KeyedLoadIC_MissForceGeneric)                   \
44   ICU(CallIC_Miss)                                    \
45   ICU(KeyedCallIC_Miss)                               \
46   ICU(StoreIC_Miss)                                   \
47   ICU(StoreIC_ArrayLength)                            \
48   ICU(SharedStoreIC_ExtendStorage)                    \
49   ICU(KeyedStoreIC_Miss)                              \
50   ICU(KeyedStoreIC_MissForceGeneric)                  \
51   ICU(KeyedStoreIC_Slow)                              \
52   /* Utilities for IC stubs. */                       \
53   ICU(LoadCallbackProperty)                           \
54   ICU(StoreCallbackProperty)                          \
55   ICU(LoadPropertyWithInterceptorOnly)                \
56   ICU(LoadPropertyWithInterceptorForLoad)             \
57   ICU(LoadPropertyWithInterceptorForCall)             \
58   ICU(KeyedLoadPropertyWithInterceptor)               \
59   ICU(StoreInterceptorProperty)                       \
60   ICU(UnaryOp_Patch)                                  \
61   ICU(BinaryOp_Patch)                                 \
62   ICU(CompareIC_Miss)                                 \
63   ICU(ToBoolean_Patch)
64 //
65 // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
66 // and KeyedStoreIC.
67 //
68 class IC {
69  public:
70   // The ids for utility called from the generated code.
71   enum UtilityId {
72   #define CONST_NAME(name) k##name,
73     IC_UTIL_LIST(CONST_NAME)
74   #undef CONST_NAME
75     kUtilityCount
76   };
77 
78   // Looks up the address of the named utility.
79   static Address AddressFromUtilityId(UtilityId id);
80 
81   // Alias the inline cache state type to make the IC code more readable.
82   typedef InlineCacheState State;
83 
84   // The IC code is either invoked with no extra frames on the stack
85   // or with a single extra frame for supporting calls.
86   enum FrameDepth {
87     NO_EXTRA_FRAME = 0,
88     EXTRA_CALL_FRAME = 1
89   };
90 
91   // Construct the IC structure with the given number of extra
92   // JavaScript frames on the stack.
93   IC(FrameDepth depth, Isolate* isolate);
~IC()94   virtual ~IC() {}
95 
96   // Get the call-site target; used for determining the state.
target()97   Code* target() const { return GetTargetAtAddress(address()); }
98   inline Address address() const;
99 
IsGeneric()100   virtual bool IsGeneric() const { return false; }
101 
102   // Compute the current IC state based on the target stub, receiver and name.
103   static State StateFrom(Code* target, Object* receiver, Object* name);
104 
105   // Clear the inline cache to initial state.
106   static void Clear(Address address);
107 
108   // Computes the reloc info for this IC. This is a fairly expensive
109   // operation as it has to search through the heap to find the code
110   // object that contains this IC site.
111   RelocInfo::Mode ComputeMode();
112 
113   // Returns if this IC is for contextual (no explicit receiver)
114   // access to properties.
IsContextual(Handle<Object> receiver)115   bool IsContextual(Handle<Object> receiver) {
116     if (receiver->IsGlobalObject()) {
117       return SlowIsContextual();
118     } else {
119       ASSERT(!SlowIsContextual());
120       return false;
121     }
122   }
123 
SlowIsContextual()124   bool SlowIsContextual() {
125     return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT;
126   }
127 
128   // Determines which map must be used for keeping the code stub.
129   // These methods should not be called with undefined or null.
130   static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object,
131                                                             JSObject* holder);
132   static inline InlineCacheHolderFlag GetCodeCacheForObject(JSObject* object,
133                                                             JSObject* holder);
134   static inline JSObject* GetCodeCacheHolder(Object* object,
135                                              InlineCacheHolderFlag holder);
136 
137  protected:
fp()138   Address fp() const { return fp_; }
pc()139   Address pc() const { return *pc_address_; }
isolate()140   Isolate* isolate() const { return isolate_; }
141 
142 #ifdef ENABLE_DEBUGGER_SUPPORT
143   // Computes the address in the original code when the code running is
144   // containing break points (calls to DebugBreakXXX builtins).
145   Address OriginalCodeAddress() const;
146 #endif
147 
148   // Set the call-site target.
set_target(Code * code)149   void set_target(Code* code) { SetTargetAtAddress(address(), code); }
150 
151 #ifdef DEBUG
152   char TransitionMarkFromState(IC::State state);
153 
154   void TraceIC(const char* type,
155                Handle<Object> name,
156                State old_state,
157                Code* new_target);
158 #endif
159 
160   Failure* TypeError(const char* type,
161                      Handle<Object> object,
162                      Handle<Object> key);
163   Failure* ReferenceError(const char* type, Handle<String> name);
164 
165   // Access the target code for the given IC address.
166   static inline Code* GetTargetAtAddress(Address address);
167   static inline void SetTargetAtAddress(Address address, Code* target);
168   static void PostPatching(Address address, Code* target, Code* old_target);
169 
170  private:
171   // Frame pointer for the frame that uses (calls) the IC.
172   Address fp_;
173 
174   // All access to the program counter of an IC structure is indirect
175   // to make the code GC safe. This feature is crucial since
176   // GetProperty and SetProperty are called and they in turn might
177   // invoke the garbage collector.
178   Address* pc_address_;
179 
180   Isolate* isolate_;
181 
182   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
183 };
184 
185 
186 // An IC_Utility encapsulates IC::UtilityId. It exists mainly because you
187 // cannot make forward declarations to an enum.
188 class IC_Utility {
189  public:
IC_Utility(IC::UtilityId id)190   explicit IC_Utility(IC::UtilityId id)
191     : address_(IC::AddressFromUtilityId(id)), id_(id) {}
192 
address()193   Address address() const { return address_; }
194 
id()195   IC::UtilityId id() const { return id_; }
196  private:
197   Address address_;
198   IC::UtilityId id_;
199 };
200 
201 
202 class CallICBase: public IC {
203  public:
204   class Contextual: public BitField<bool, 0, 1> {};
205   class StringStubState: public BitField<StringStubFeedback, 1, 1> {};
206 
207   // Returns a JSFunction or a Failure.
208   MUST_USE_RESULT MaybeObject* LoadFunction(State state,
209                                             Code::ExtraICState extra_ic_state,
210                                             Handle<Object> object,
211                                             Handle<String> name);
212 
213  protected:
CallICBase(Code::Kind kind,Isolate * isolate)214   CallICBase(Code::Kind kind, Isolate* isolate)
215       : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {}
216 
217   bool TryUpdateExtraICState(LookupResult* lookup,
218                              Handle<Object> object,
219                              Code::ExtraICState* extra_ic_state);
220 
221   // Compute a monomorphic stub if possible, otherwise return a null handle.
222   Handle<Code> ComputeMonomorphicStub(LookupResult* lookup,
223                                       State state,
224                                       Code::ExtraICState extra_state,
225                                       Handle<Object> object,
226                                       Handle<String> name);
227 
228   // Update the inline cache and the global stub cache based on the lookup
229   // result.
230   void UpdateCaches(LookupResult* lookup,
231                     State state,
232                     Code::ExtraICState extra_ic_state,
233                     Handle<Object> object,
234                     Handle<String> name);
235 
236   // Returns a JSFunction if the object can be called as a function, and
237   // patches the stack to be ready for the call.  Otherwise, it returns the
238   // undefined value.
239   Handle<Object> TryCallAsFunction(Handle<Object> object);
240 
241   void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object);
242 
243   static void Clear(Address address, Code* target);
244 
245   // Platform-specific code generation functions used by both call and
246   // keyed call.
247   static void GenerateMiss(MacroAssembler* masm,
248                            int argc,
249                            IC::UtilityId id,
250                            Code::ExtraICState extra_state);
251 
252   static void GenerateNormal(MacroAssembler* masm, int argc);
253 
254   static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
255                                             int argc,
256                                             Code::Kind kind,
257                                             Code::ExtraICState extra_state);
258 
259   Code::Kind kind_;
260 
261   friend class IC;
262 };
263 
264 
265 class CallIC: public CallICBase {
266  public:
CallIC(Isolate * isolate)267   explicit CallIC(Isolate* isolate) : CallICBase(Code::CALL_IC, isolate) {
268     ASSERT(target()->is_call_stub());
269   }
270 
271   // Code generator routines.
GenerateInitialize(MacroAssembler * masm,int argc,Code::ExtraICState extra_state)272   static void GenerateInitialize(MacroAssembler* masm,
273                                  int argc,
274                                  Code::ExtraICState extra_state) {
275     GenerateMiss(masm, argc, extra_state);
276   }
277 
GenerateMiss(MacroAssembler * masm,int argc,Code::ExtraICState extra_state)278   static void GenerateMiss(MacroAssembler* masm,
279                            int argc,
280                            Code::ExtraICState extra_state) {
281     CallICBase::GenerateMiss(masm, argc, IC::kCallIC_Miss, extra_state);
282   }
283 
284   static void GenerateMegamorphic(MacroAssembler* masm,
285                                   int argc,
286                                   Code::ExtraICState extra_ic_state);
287 
GenerateNormal(MacroAssembler * masm,int argc)288   static void GenerateNormal(MacroAssembler* masm, int argc) {
289     CallICBase::GenerateNormal(masm, argc);
290     GenerateMiss(masm, argc, Code::kNoExtraICState);
291   }
292 };
293 
294 
295 class KeyedCallIC: public CallICBase {
296  public:
KeyedCallIC(Isolate * isolate)297   explicit KeyedCallIC(Isolate* isolate)
298       : CallICBase(Code::KEYED_CALL_IC, isolate) {
299     ASSERT(target()->is_keyed_call_stub());
300   }
301 
302   MUST_USE_RESULT MaybeObject* LoadFunction(State state,
303                                             Handle<Object> object,
304                                             Handle<Object> key);
305 
306   // Code generator routines.
GenerateInitialize(MacroAssembler * masm,int argc)307   static void GenerateInitialize(MacroAssembler* masm, int argc) {
308     GenerateMiss(masm, argc);
309   }
310 
GenerateMiss(MacroAssembler * masm,int argc)311   static void GenerateMiss(MacroAssembler* masm, int argc) {
312     CallICBase::GenerateMiss(masm, argc, IC::kKeyedCallIC_Miss,
313                              Code::kNoExtraICState);
314   }
315 
316   static void GenerateMegamorphic(MacroAssembler* masm, int argc);
317   static void GenerateNormal(MacroAssembler* masm, int argc);
318   static void GenerateNonStrictArguments(MacroAssembler* masm, int argc);
319 };
320 
321 
322 class LoadIC: public IC {
323  public:
LoadIC(Isolate * isolate)324   explicit LoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
325     ASSERT(target()->is_load_stub());
326   }
327 
328   MUST_USE_RESULT MaybeObject* Load(State state,
329                                     Handle<Object> object,
330                                     Handle<String> name);
331 
332   // Code generator routines.
GenerateInitialize(MacroAssembler * masm)333   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
GeneratePreMonomorphic(MacroAssembler * masm)334   static void GeneratePreMonomorphic(MacroAssembler* masm) {
335     GenerateMiss(masm);
336   }
337   static void GenerateMiss(MacroAssembler* masm);
338   static void GenerateMegamorphic(MacroAssembler* masm);
339   static void GenerateNormal(MacroAssembler* masm);
340 
341   // Specialized code generator routines.
342   static void GenerateArrayLength(MacroAssembler* masm);
343   static void GenerateStringLength(MacroAssembler* masm,
344                                    bool support_wrappers);
345   static void GenerateFunctionPrototype(MacroAssembler* masm);
346 
347  private:
348   // Update the inline cache and the global stub cache based on the
349   // lookup result.
350   void UpdateCaches(LookupResult* lookup,
351                     State state,
352                     Handle<Object> object,
353                     Handle<String> name);
354 
355   // Stub accessors.
megamorphic_stub()356   Handle<Code> megamorphic_stub() {
357     return isolate()->builtins()->LoadIC_Megamorphic();
358   }
initialize_stub()359   static Code* initialize_stub() {
360     return Isolate::Current()->builtins()->builtin(
361         Builtins::kLoadIC_Initialize);
362   }
pre_monomorphic_stub()363   Handle<Code> pre_monomorphic_stub() {
364     return isolate()->builtins()->LoadIC_PreMonomorphic();
365   }
366 
367   static void Clear(Address address, Code* target);
368 
369   friend class IC;
370 };
371 
372 
373 class KeyedIC: public IC {
374  public:
375   enum StubKind {
376     LOAD,
377     STORE_NO_TRANSITION,
378     STORE_TRANSITION_SMI_TO_OBJECT,
379     STORE_TRANSITION_SMI_TO_DOUBLE,
380     STORE_TRANSITION_DOUBLE_TO_OBJECT,
381     STORE_AND_GROW_NO_TRANSITION,
382     STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT,
383     STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE,
384     STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT
385   };
386 
387   static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION -
388       STORE_NO_TRANSITION;
389   STATIC_ASSERT(kGrowICDelta ==
390                 STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT -
391                 STORE_TRANSITION_SMI_TO_OBJECT);
392   STATIC_ASSERT(kGrowICDelta ==
393                 STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE -
394                 STORE_TRANSITION_SMI_TO_DOUBLE);
395   STATIC_ASSERT(kGrowICDelta ==
396                 STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT -
397                 STORE_TRANSITION_DOUBLE_TO_OBJECT);
398 
KeyedIC(Isolate * isolate)399   explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {}
~KeyedIC()400   virtual ~KeyedIC() {}
401 
GetGrowModeFromStubKind(StubKind stub_kind)402   static inline KeyedAccessGrowMode GetGrowModeFromStubKind(
403       StubKind stub_kind) {
404     return (stub_kind >= STORE_AND_GROW_NO_TRANSITION)
405         ? ALLOW_JSARRAY_GROWTH
406         : DO_NOT_ALLOW_JSARRAY_GROWTH;
407   }
408 
GetGrowStubKind(StubKind stub_kind)409   static inline StubKind GetGrowStubKind(StubKind stub_kind) {
410     ASSERT(stub_kind != LOAD);
411     if (stub_kind < STORE_AND_GROW_NO_TRANSITION) {
412       stub_kind = static_cast<StubKind>(static_cast<int>(stub_kind) +
413                                         kGrowICDelta);
414     }
415     return stub_kind;
416   }
417 
418   virtual Handle<Code> GetElementStubWithoutMapCheck(
419       bool is_js_array,
420       ElementsKind elements_kind,
421       KeyedAccessGrowMode grow_mode) = 0;
422 
423  protected:
string_stub()424   virtual Handle<Code> string_stub() {
425     return Handle<Code>::null();
426   }
427 
428   virtual Code::Kind kind() const = 0;
429 
430   Handle<Code> ComputeStub(Handle<JSObject> receiver,
431                            StubKind stub_kind,
432                            StrictModeFlag strict_mode,
433                            Handle<Code> default_stub);
434 
435   virtual Handle<Code> ComputePolymorphicStub(
436       MapHandleList* receiver_maps,
437       StrictModeFlag strict_mode,
438       KeyedAccessGrowMode grow_mode) = 0;
439 
440   Handle<Code> ComputeMonomorphicStubWithoutMapCheck(
441       Handle<Map> receiver_map,
442       StrictModeFlag strict_mode,
443       KeyedAccessGrowMode grow_mode);
444 
445  private:
446   void GetReceiverMapsForStub(Handle<Code> stub, MapHandleList* result);
447 
448   Handle<Code> ComputeMonomorphicStub(Handle<JSObject> receiver,
449                                       StubKind stub_kind,
450                                       StrictModeFlag strict_mode,
451                                       Handle<Code> default_stub);
452 
453   Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
454                                      StubKind stub_kind);
455 
IsTransitionStubKind(StubKind stub_kind)456   static bool IsTransitionStubKind(StubKind stub_kind) {
457     return stub_kind > STORE_NO_TRANSITION &&
458         stub_kind != STORE_AND_GROW_NO_TRANSITION;
459   }
460 
IsGrowStubKind(StubKind stub_kind)461   static bool IsGrowStubKind(StubKind stub_kind) {
462     return stub_kind >= STORE_AND_GROW_NO_TRANSITION;
463   }
464 };
465 
466 
467 class KeyedLoadIC: public KeyedIC {
468  public:
KeyedLoadIC(Isolate * isolate)469   explicit KeyedLoadIC(Isolate* isolate) : KeyedIC(isolate) {
470     ASSERT(target()->is_keyed_load_stub());
471   }
472 
473   MUST_USE_RESULT MaybeObject* Load(State state,
474                                     Handle<Object> object,
475                                     Handle<Object> key,
476                                     bool force_generic_stub);
477 
478   // Code generator routines.
479   static void GenerateMiss(MacroAssembler* masm, bool force_generic);
480   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
GenerateInitialize(MacroAssembler * masm)481   static void GenerateInitialize(MacroAssembler* masm) {
482     GenerateMiss(masm, false);
483   }
GeneratePreMonomorphic(MacroAssembler * masm)484   static void GeneratePreMonomorphic(MacroAssembler* masm) {
485     GenerateMiss(masm, false);
486   }
487   static void GenerateGeneric(MacroAssembler* masm);
488   static void GenerateString(MacroAssembler* masm);
489   static void GenerateIndexedInterceptor(MacroAssembler* masm);
490   static void GenerateNonStrictArguments(MacroAssembler* masm);
491 
492   // Bit mask to be tested against bit field for the cases when
493   // generic stub should go into slow case.
494   // Access check is necessary explicitly since generic stub does not perform
495   // map checks.
496   static const int kSlowCaseBitFieldMask =
497       (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
498 
499   virtual Handle<Code> GetElementStubWithoutMapCheck(
500       bool is_js_array,
501       ElementsKind elements_kind,
502       KeyedAccessGrowMode grow_mode);
503 
IsGeneric()504   virtual bool IsGeneric() const {
505     return target() == *generic_stub();
506   }
507 
508  protected:
kind()509   virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
510 
511   virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
512                                               StrictModeFlag strict_mode,
513                                               KeyedAccessGrowMode grow_mode);
514 
string_stub()515   virtual Handle<Code> string_stub() {
516     return isolate()->builtins()->KeyedLoadIC_String();
517   }
518 
519  private:
520   // Update the inline cache.
521   void UpdateCaches(LookupResult* lookup,
522                     State state,
523                     Handle<Object> object,
524                     Handle<String> name);
525 
526   // Stub accessors.
initialize_stub()527   static Code* initialize_stub() {
528     return Isolate::Current()->builtins()->builtin(
529         Builtins::kKeyedLoadIC_Initialize);
530   }
megamorphic_stub()531   Handle<Code> megamorphic_stub() {
532     return isolate()->builtins()->KeyedLoadIC_Generic();
533   }
generic_stub()534   Handle<Code> generic_stub() const {
535     return isolate()->builtins()->KeyedLoadIC_Generic();
536   }
pre_monomorphic_stub()537   Handle<Code> pre_monomorphic_stub() {
538     return isolate()->builtins()->KeyedLoadIC_PreMonomorphic();
539   }
indexed_interceptor_stub()540   Handle<Code> indexed_interceptor_stub() {
541     return isolate()->builtins()->KeyedLoadIC_IndexedInterceptor();
542   }
non_strict_arguments_stub()543   Handle<Code> non_strict_arguments_stub() {
544     return isolate()->builtins()->KeyedLoadIC_NonStrictArguments();
545   }
546 
547   static void Clear(Address address, Code* target);
548 
549   friend class IC;
550 };
551 
552 
553 class StoreIC: public IC {
554  public:
StoreIC(Isolate * isolate)555   explicit StoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
556     ASSERT(target()->is_store_stub());
557   }
558 
559   MUST_USE_RESULT MaybeObject* Store(State state,
560                                      StrictModeFlag strict_mode,
561                                      Handle<Object> object,
562                                      Handle<String> name,
563                                      Handle<Object> value);
564 
565   // Code generators for stub routines. Only called once at startup.
GenerateInitialize(MacroAssembler * masm)566   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
567   static void GenerateMiss(MacroAssembler* masm);
568   static void GenerateMegamorphic(MacroAssembler* masm,
569                                   StrictModeFlag strict_mode);
570   static void GenerateArrayLength(MacroAssembler* masm);
571   static void GenerateNormal(MacroAssembler* masm);
572   static void GenerateGlobalProxy(MacroAssembler* masm,
573                                   StrictModeFlag strict_mode);
574 
575  private:
576   // Update the inline cache and the global stub cache based on the
577   // lookup result.
578   void UpdateCaches(LookupResult* lookup,
579                     State state,
580                     StrictModeFlag strict_mode,
581                     Handle<JSObject> receiver,
582                     Handle<String> name,
583                     Handle<Object> value);
584 
set_target(Code * code)585   void set_target(Code* code) {
586     // Strict mode must be preserved across IC patching.
587     ASSERT(Code::GetStrictMode(code->extra_ic_state()) ==
588            Code::GetStrictMode(target()->extra_ic_state()));
589     IC::set_target(code);
590   }
591 
592   // Stub accessors.
megamorphic_stub()593   Code* megamorphic_stub() {
594     return isolate()->builtins()->builtin(
595         Builtins::kStoreIC_Megamorphic);
596   }
megamorphic_stub_strict()597   Code* megamorphic_stub_strict() {
598     return isolate()->builtins()->builtin(
599         Builtins::kStoreIC_Megamorphic_Strict);
600   }
initialize_stub()601   static Code* initialize_stub() {
602     return Isolate::Current()->builtins()->builtin(
603         Builtins::kStoreIC_Initialize);
604   }
initialize_stub_strict()605   static Code* initialize_stub_strict() {
606     return Isolate::Current()->builtins()->builtin(
607         Builtins::kStoreIC_Initialize_Strict);
608   }
global_proxy_stub()609   Handle<Code> global_proxy_stub() {
610     return isolate()->builtins()->StoreIC_GlobalProxy();
611   }
global_proxy_stub_strict()612   Handle<Code> global_proxy_stub_strict() {
613     return isolate()->builtins()->StoreIC_GlobalProxy_Strict();
614   }
615 
616   static void Clear(Address address, Code* target);
617 
618   friend class IC;
619 };
620 
621 
622 class KeyedStoreIC: public KeyedIC {
623  public:
KeyedStoreIC(Isolate * isolate)624   explicit KeyedStoreIC(Isolate* isolate) : KeyedIC(isolate) {
625     ASSERT(target()->is_keyed_store_stub());
626   }
627 
628   MUST_USE_RESULT MaybeObject* Store(State state,
629                                    StrictModeFlag strict_mode,
630                                      Handle<Object> object,
631                                      Handle<Object> name,
632                                      Handle<Object> value,
633                                      bool force_generic);
634 
635   // Code generators for stub routines.  Only called once at startup.
GenerateInitialize(MacroAssembler * masm)636   static void GenerateInitialize(MacroAssembler* masm) {
637     GenerateMiss(masm, false);
638   }
639   static void GenerateMiss(MacroAssembler* masm, bool force_generic);
640   static void GenerateSlow(MacroAssembler* masm);
641   static void GenerateRuntimeSetProperty(MacroAssembler* masm,
642                                          StrictModeFlag strict_mode);
643   static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode);
644   static void GenerateNonStrictArguments(MacroAssembler* masm);
645   static void GenerateTransitionElementsSmiToDouble(MacroAssembler* masm);
646   static void GenerateTransitionElementsDoubleToObject(MacroAssembler* masm);
647 
648   virtual Handle<Code> GetElementStubWithoutMapCheck(
649       bool is_js_array,
650       ElementsKind elements_kind,
651       KeyedAccessGrowMode grow_mode);
652 
IsGeneric()653   virtual bool IsGeneric() const {
654     return target() == *generic_stub() ||
655         target() == *generic_stub_strict();
656   }
657 
658  protected:
kind()659   virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
660 
661   virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
662                                               StrictModeFlag strict_mode,
663                                               KeyedAccessGrowMode grow_mode);
664 
665   private:
666   // Update the inline cache.
667   void UpdateCaches(LookupResult* lookup,
668                     State state,
669                     StrictModeFlag strict_mode,
670                     Handle<JSObject> receiver,
671                     Handle<String> name,
672                     Handle<Object> value);
673 
set_target(Code * code)674   void set_target(Code* code) {
675     // Strict mode must be preserved across IC patching.
676     ASSERT(Code::GetStrictMode(code->extra_ic_state()) ==
677            Code::GetStrictMode(target()->extra_ic_state()));
678     IC::set_target(code);
679   }
680 
681   // Stub accessors.
initialize_stub()682   static Code* initialize_stub() {
683     return Isolate::Current()->builtins()->builtin(
684         Builtins::kKeyedStoreIC_Initialize);
685   }
initialize_stub_strict()686   static Code* initialize_stub_strict() {
687     return Isolate::Current()->builtins()->builtin(
688         Builtins::kKeyedStoreIC_Initialize_Strict);
689   }
megamorphic_stub()690   Handle<Code> megamorphic_stub() {
691     return isolate()->builtins()->KeyedStoreIC_Generic();
692   }
megamorphic_stub_strict()693   Handle<Code> megamorphic_stub_strict() {
694     return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
695   }
generic_stub()696   Handle<Code> generic_stub() const {
697     return isolate()->builtins()->KeyedStoreIC_Generic();
698   }
generic_stub_strict()699   Handle<Code> generic_stub_strict() const {
700     return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
701   }
non_strict_arguments_stub()702   Handle<Code> non_strict_arguments_stub() {
703     return isolate()->builtins()->KeyedStoreIC_NonStrictArguments();
704   }
705 
706   static void Clear(Address address, Code* target);
707 
708   StubKind GetStubKind(Handle<JSObject> receiver,
709                        Handle<Object> key,
710                        Handle<Object> value);
711 
712   friend class IC;
713 };
714 
715 
716 class UnaryOpIC: public IC {
717  public:
718   // sorted: increasingly more unspecific (ignoring UNINITIALIZED)
719   // TODO(svenpanne) Using enums+switch is an antipattern, use a class instead.
720   enum TypeInfo {
721     UNINITIALIZED,
722     SMI,
723     HEAP_NUMBER,
724     GENERIC
725   };
726 
UnaryOpIC(Isolate * isolate)727   explicit UnaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
728 
729   void patch(Code* code);
730 
731   static const char* GetName(TypeInfo type_info);
732 
733   static State ToState(TypeInfo type_info);
734 
735   static TypeInfo GetTypeInfo(Handle<Object> operand);
736 
737   static TypeInfo ComputeNewType(TypeInfo type, TypeInfo previous);
738 };
739 
740 
741 // Type Recording BinaryOpIC, that records the types of the inputs and outputs.
742 class BinaryOpIC: public IC {
743  public:
744   enum TypeInfo {
745     UNINITIALIZED,
746     SMI,
747     INT32,
748     HEAP_NUMBER,
749     ODDBALL,
750     BOTH_STRING,  // Only used for addition operation.
751     STRING,  // Only used for addition operation.  At least one string operand.
752     GENERIC
753   };
754 
BinaryOpIC(Isolate * isolate)755   explicit BinaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
756 
757   void patch(Code* code);
758 
759   static const char* GetName(TypeInfo type_info);
760 
761   static State ToState(TypeInfo type_info);
762 
763   static TypeInfo GetTypeInfo(Handle<Object> left, Handle<Object> right);
764 
765   static TypeInfo JoinTypes(TypeInfo x, TypeInfo y);
766 };
767 
768 
769 class CompareIC: public IC {
770  public:
771   enum State {
772     UNINITIALIZED,
773     SMIS,
774     HEAP_NUMBERS,
775     SYMBOLS,
776     STRINGS,
777     OBJECTS,
778     KNOWN_OBJECTS,
779     GENERIC
780   };
781 
CompareIC(Isolate * isolate,Token::Value op)782   CompareIC(Isolate* isolate, Token::Value op)
783       : IC(EXTRA_CALL_FRAME, isolate), op_(op) { }
784 
785   // Update the inline cache for the given operands.
786   void UpdateCaches(Handle<Object> x, Handle<Object> y);
787 
788   // Factory method for getting an uninitialized compare stub.
789   static Handle<Code> GetUninitialized(Token::Value op);
790 
791   // Helper function for computing the condition for a compare operation.
792   static Condition ComputeCondition(Token::Value op);
793 
794   // Helper function for determining the state of a compare IC.
795   static State ComputeState(Code* target);
796 
797   static const char* GetStateName(State state);
798 
799  private:
800   State TargetState(State state, bool has_inlined_smi_code,
801                     Handle<Object> x, Handle<Object> y);
802 
strict()803   bool strict() const { return op_ == Token::EQ_STRICT; }
GetCondition()804   Condition GetCondition() const { return ComputeCondition(op_); }
GetState()805   State GetState() { return ComputeState(target()); }
806 
807   Token::Value op_;
808 };
809 
810 
811 class ToBooleanIC: public IC {
812  public:
ToBooleanIC(Isolate * isolate)813   explicit ToBooleanIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
814 
815   void patch(Code* code);
816 };
817 
818 
819 // Helper for BinaryOpIC and CompareIC.
820 void PatchInlinedSmiCode(Address address);
821 
822 } }  // namespace v8::internal
823 
824 #endif  // V8_IC_H_
825