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