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
34namespace v8 {
35namespace 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//
68class 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  // Returns if this IC is for contextual (no explicit receiver)
114  // access to properties.
115  bool IsContextual(Handle<Object> receiver) {
116    if (receiver->IsGlobalObject()) {
117      return SlowIsContextual();
118    } else {
119      ASSERT(!SlowIsContextual());
120      return false;
121    }
122  }
123
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:
138  Address fp() const { return fp_; }
139  Address pc() const { return *pc_address_; }
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.
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.
188class IC_Utility {
189 public:
190  explicit IC_Utility(IC::UtilityId id)
191    : address_(IC::AddressFromUtilityId(id)), id_(id) {}
192
193  Address address() const { return address_; }
194
195  IC::UtilityId id() const { return id_; }
196 private:
197  Address address_;
198  IC::UtilityId id_;
199};
200
201
202class 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:
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
265class CallIC: public CallICBase {
266 public:
267  explicit CallIC(Isolate* isolate) : CallICBase(Code::CALL_IC, isolate) {
268    ASSERT(target()->is_call_stub());
269  }
270
271  // Code generator routines.
272  static void GenerateInitialize(MacroAssembler* masm,
273                                 int argc,
274                                 Code::ExtraICState extra_state) {
275    GenerateMiss(masm, argc, extra_state);
276  }
277
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
288  static void GenerateNormal(MacroAssembler* masm, int argc) {
289    CallICBase::GenerateNormal(masm, argc);
290    GenerateMiss(masm, argc, Code::kNoExtraICState);
291  }
292};
293
294
295class KeyedCallIC: public CallICBase {
296 public:
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.
307  static void GenerateInitialize(MacroAssembler* masm, int argc) {
308    GenerateMiss(masm, argc);
309  }
310
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
322class LoadIC: public IC {
323 public:
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.
333  static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(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.
356  Handle<Code> megamorphic_stub() {
357    return isolate()->builtins()->LoadIC_Megamorphic();
358  }
359  static Code* initialize_stub() {
360    return Isolate::Current()->builtins()->builtin(
361        Builtins::kLoadIC_Initialize);
362  }
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
373class 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
399  explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {}
400  virtual ~KeyedIC() {}
401
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
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:
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
456  static bool IsTransitionStubKind(StubKind stub_kind) {
457    return stub_kind > STORE_NO_TRANSITION &&
458        stub_kind != STORE_AND_GROW_NO_TRANSITION;
459  }
460
461  static bool IsGrowStubKind(StubKind stub_kind) {
462    return stub_kind >= STORE_AND_GROW_NO_TRANSITION;
463  }
464};
465
466
467class KeyedLoadIC: public KeyedIC {
468 public:
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);
481  static void GenerateInitialize(MacroAssembler* masm) {
482    GenerateMiss(masm, false);
483  }
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
504  virtual bool IsGeneric() const {
505    return target() == *generic_stub();
506  }
507
508 protected:
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
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.
527  static Code* initialize_stub() {
528    return Isolate::Current()->builtins()->builtin(
529        Builtins::kKeyedLoadIC_Initialize);
530  }
531  Handle<Code> megamorphic_stub() {
532    return isolate()->builtins()->KeyedLoadIC_Generic();
533  }
534  Handle<Code> generic_stub() const {
535    return isolate()->builtins()->KeyedLoadIC_Generic();
536  }
537  Handle<Code> pre_monomorphic_stub() {
538    return isolate()->builtins()->KeyedLoadIC_PreMonomorphic();
539  }
540  Handle<Code> indexed_interceptor_stub() {
541    return isolate()->builtins()->KeyedLoadIC_IndexedInterceptor();
542  }
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
553class StoreIC: public IC {
554 public:
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.
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
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.
593  Code* megamorphic_stub() {
594    return isolate()->builtins()->builtin(
595        Builtins::kStoreIC_Megamorphic);
596  }
597  Code* megamorphic_stub_strict() {
598    return isolate()->builtins()->builtin(
599        Builtins::kStoreIC_Megamorphic_Strict);
600  }
601  static Code* initialize_stub() {
602    return Isolate::Current()->builtins()->builtin(
603        Builtins::kStoreIC_Initialize);
604  }
605  static Code* initialize_stub_strict() {
606    return Isolate::Current()->builtins()->builtin(
607        Builtins::kStoreIC_Initialize_Strict);
608  }
609  Handle<Code> global_proxy_stub() {
610    return isolate()->builtins()->StoreIC_GlobalProxy();
611  }
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
622class KeyedStoreIC: public KeyedIC {
623 public:
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.
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
653  virtual bool IsGeneric() const {
654    return target() == *generic_stub() ||
655        target() == *generic_stub_strict();
656  }
657
658 protected:
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
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.
682  static Code* initialize_stub() {
683    return Isolate::Current()->builtins()->builtin(
684        Builtins::kKeyedStoreIC_Initialize);
685  }
686  static Code* initialize_stub_strict() {
687    return Isolate::Current()->builtins()->builtin(
688        Builtins::kKeyedStoreIC_Initialize_Strict);
689  }
690  Handle<Code> megamorphic_stub() {
691    return isolate()->builtins()->KeyedStoreIC_Generic();
692  }
693  Handle<Code> megamorphic_stub_strict() {
694    return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
695  }
696  Handle<Code> generic_stub() const {
697    return isolate()->builtins()->KeyedStoreIC_Generic();
698  }
699  Handle<Code> generic_stub_strict() const {
700    return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
701  }
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
716class 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
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.
742class 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
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
769class 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
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
803  bool strict() const { return op_ == Token::EQ_STRICT; }
804  Condition GetCondition() const { return ComputeCondition(op_); }
805  State GetState() { return ComputeState(target()); }
806
807  Token::Value op_;
808};
809
810
811class ToBooleanIC: public IC {
812 public:
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.
820void PatchInlinedSmiCode(Address address);
821
822} }  // namespace v8::internal
823
824#endif  // V8_IC_H_
825