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(StoreIC_Slow)                                   \
49  ICU(SharedStoreIC_ExtendStorage)                    \
50  ICU(KeyedStoreIC_Miss)                              \
51  ICU(KeyedStoreIC_MissForceGeneric)                  \
52  ICU(KeyedStoreIC_Slow)                              \
53  /* Utilities for IC stubs. */                       \
54  ICU(StoreCallbackProperty)                          \
55  ICU(LoadPropertyWithInterceptorOnly)                \
56  ICU(LoadPropertyWithInterceptorForLoad)             \
57  ICU(LoadPropertyWithInterceptorForCall)             \
58  ICU(KeyedLoadPropertyWithInterceptor)               \
59  ICU(StoreInterceptorProperty)                       \
60  ICU(BinaryOp_Patch)                                 \
61  ICU(CompareIC_Miss)                                 \
62  ICU(CompareNilIC_Miss)                              \
63  ICU(Unreachable)                                    \
64  ICU(ToBooleanIC_Miss)
65//
66// IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
67// and KeyedStoreIC.
68//
69class IC {
70 public:
71  // The ids for utility called from the generated code.
72  enum UtilityId {
73  #define CONST_NAME(name) k##name,
74    IC_UTIL_LIST(CONST_NAME)
75  #undef CONST_NAME
76    kUtilityCount
77  };
78
79  // Looks up the address of the named utility.
80  static Address AddressFromUtilityId(UtilityId id);
81
82  // Alias the inline cache state type to make the IC code more readable.
83  typedef InlineCacheState State;
84
85  // The IC code is either invoked with no extra frames on the stack
86  // or with a single extra frame for supporting calls.
87  enum FrameDepth {
88    NO_EXTRA_FRAME = 0,
89    EXTRA_CALL_FRAME = 1
90  };
91
92  // Construct the IC structure with the given number of extra
93  // JavaScript frames on the stack.
94  IC(FrameDepth depth, Isolate* isolate);
95  virtual ~IC() {}
96
97  // Get the call-site target; used for determining the state.
98  Code* target() const { return GetTargetAtAddress(address()); }
99  inline Address address() const;
100
101  // Compute the current IC state based on the target stub, receiver and name.
102  static State StateFrom(Code* target, Object* receiver, Object* name);
103
104  // Clear the inline cache to initial state.
105  static void Clear(Address address);
106
107  // Computes the reloc info for this IC. This is a fairly expensive
108  // operation as it has to search through the heap to find the code
109  // object that contains this IC site.
110  RelocInfo::Mode ComputeMode();
111
112  // Returns if this IC is for contextual (no explicit receiver)
113  // access to properties.
114  bool IsUndeclaredGlobal(Handle<Object> receiver) {
115    if (receiver->IsGlobalObject()) {
116      return SlowIsUndeclaredGlobal();
117    } else {
118      ASSERT(!SlowIsUndeclaredGlobal());
119      return false;
120    }
121  }
122
123  bool SlowIsUndeclaredGlobal() {
124    return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT;
125  }
126
127  // Determines which map must be used for keeping the code stub.
128  // These methods should not be called with undefined or null.
129  static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object,
130                                                            JSObject* holder);
131  static inline InlineCacheHolderFlag GetCodeCacheForObject(JSObject* object,
132                                                            JSObject* holder);
133  static inline JSObject* GetCodeCacheHolder(Isolate* isolate,
134                                             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  virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
171                                   Handle<Code> handler,
172                                   Handle<String> name,
173                                   StrictModeFlag strict_mode) {
174    set_target(*handler);
175  }
176  bool UpdatePolymorphicIC(State state,
177                           Handle<JSObject> receiver,
178                           Handle<String> name,
179                           Handle<Code> code,
180                           StrictModeFlag strict_mode);
181
182  virtual Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
183                                            CodeHandleList* handlers,
184                                            int number_of_valid_maps,
185                                            Handle<Name> name,
186                                            StrictModeFlag strict_mode) {
187    UNREACHABLE();
188    return Handle<Code>::null();
189  };
190
191  void CopyICToMegamorphicCache(Handle<String> name);
192  bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map);
193  void PatchCache(State state,
194                  StrictModeFlag strict_mode,
195                  Handle<JSObject> receiver,
196                  Handle<String> name,
197                  Handle<Code> code);
198  virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code);
199  virtual Handle<Code> megamorphic_stub() {
200    UNREACHABLE();
201    return Handle<Code>::null();
202  }
203  virtual Handle<Code> megamorphic_stub_strict() {
204    UNREACHABLE();
205    return Handle<Code>::null();
206  }
207  virtual Handle<Code> generic_stub() const {
208    UNREACHABLE();
209    return Handle<Code>::null();
210  }
211  virtual Handle<Code> generic_stub_strict() const {
212    UNREACHABLE();
213    return Handle<Code>::null();
214  }
215
216 private:
217  // Frame pointer for the frame that uses (calls) the IC.
218  Address fp_;
219
220  // All access to the program counter of an IC structure is indirect
221  // to make the code GC safe. This feature is crucial since
222  // GetProperty and SetProperty are called and they in turn might
223  // invoke the garbage collector.
224  Address* pc_address_;
225
226  Isolate* isolate_;
227
228  DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
229};
230
231
232// An IC_Utility encapsulates IC::UtilityId. It exists mainly because you
233// cannot make forward declarations to an enum.
234class IC_Utility {
235 public:
236  explicit IC_Utility(IC::UtilityId id)
237    : address_(IC::AddressFromUtilityId(id)), id_(id) {}
238
239  Address address() const { return address_; }
240
241  IC::UtilityId id() const { return id_; }
242 private:
243  Address address_;
244  IC::UtilityId id_;
245};
246
247
248class CallICBase: public IC {
249 public:
250  class Contextual: public BitField<bool, 0, 1> {};
251  class StringStubState: public BitField<StringStubFeedback, 1, 1> {};
252
253  // Returns a JSFunction or a Failure.
254  MUST_USE_RESULT MaybeObject* LoadFunction(State state,
255                                            Code::ExtraICState extra_ic_state,
256                                            Handle<Object> object,
257                                            Handle<String> name);
258
259 protected:
260  CallICBase(Code::Kind kind, Isolate* isolate)
261      : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {}
262
263  bool TryUpdateExtraICState(LookupResult* lookup,
264                             Handle<Object> object,
265                             Code::ExtraICState* extra_ic_state);
266
267  // Compute a monomorphic stub if possible, otherwise return a null handle.
268  Handle<Code> ComputeMonomorphicStub(LookupResult* lookup,
269                                      State state,
270                                      Code::ExtraICState extra_state,
271                                      Handle<Object> object,
272                                      Handle<String> name);
273
274  // Update the inline cache and the global stub cache based on the lookup
275  // result.
276  void UpdateCaches(LookupResult* lookup,
277                    State state,
278                    Code::ExtraICState extra_ic_state,
279                    Handle<Object> object,
280                    Handle<String> name);
281
282  // Returns a JSFunction if the object can be called as a function, and
283  // patches the stack to be ready for the call.  Otherwise, it returns the
284  // undefined value.
285  Handle<Object> TryCallAsFunction(Handle<Object> object);
286
287  void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object);
288
289  static void Clear(Address address, Code* target);
290
291  // Platform-specific code generation functions used by both call and
292  // keyed call.
293  static void GenerateMiss(MacroAssembler* masm,
294                           int argc,
295                           IC::UtilityId id,
296                           Code::ExtraICState extra_state);
297
298  static void GenerateNormal(MacroAssembler* masm, int argc);
299
300  static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
301                                            int argc,
302                                            Code::Kind kind,
303                                            Code::ExtraICState extra_state);
304
305  Code::Kind kind_;
306
307  friend class IC;
308};
309
310
311class CallIC: public CallICBase {
312 public:
313  explicit CallIC(Isolate* isolate) : CallICBase(Code::CALL_IC, isolate) {
314    ASSERT(target()->is_call_stub());
315  }
316
317  // Code generator routines.
318  static void GenerateInitialize(MacroAssembler* masm,
319                                 int argc,
320                                 Code::ExtraICState extra_state) {
321    GenerateMiss(masm, argc, extra_state);
322  }
323
324  static void GenerateMiss(MacroAssembler* masm,
325                           int argc,
326                           Code::ExtraICState extra_state) {
327    CallICBase::GenerateMiss(masm, argc, IC::kCallIC_Miss, extra_state);
328  }
329
330  static void GenerateMegamorphic(MacroAssembler* masm,
331                                  int argc,
332                                  Code::ExtraICState extra_ic_state);
333
334  static void GenerateNormal(MacroAssembler* masm, int argc) {
335    CallICBase::GenerateNormal(masm, argc);
336    GenerateMiss(masm, argc, Code::kNoExtraICState);
337  }
338};
339
340
341class KeyedCallIC: public CallICBase {
342 public:
343  explicit KeyedCallIC(Isolate* isolate)
344      : CallICBase(Code::KEYED_CALL_IC, isolate) {
345    ASSERT(target()->is_keyed_call_stub());
346  }
347
348  MUST_USE_RESULT MaybeObject* LoadFunction(State state,
349                                            Handle<Object> object,
350                                            Handle<Object> key);
351
352  // Code generator routines.
353  static void GenerateInitialize(MacroAssembler* masm, int argc) {
354    GenerateMiss(masm, argc);
355  }
356
357  static void GenerateMiss(MacroAssembler* masm, int argc) {
358    CallICBase::GenerateMiss(masm, argc, IC::kKeyedCallIC_Miss,
359                             Code::kNoExtraICState);
360  }
361
362  static void GenerateMegamorphic(MacroAssembler* masm, int argc);
363  static void GenerateNormal(MacroAssembler* masm, int argc);
364  static void GenerateNonStrictArguments(MacroAssembler* masm, int argc);
365};
366
367
368class LoadIC: public IC {
369 public:
370  explicit LoadIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) {
371    ASSERT(target()->is_load_stub() || target()->is_keyed_load_stub());
372  }
373
374  // Code generator routines.
375  static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
376  static void GeneratePreMonomorphic(MacroAssembler* masm) {
377    GenerateMiss(masm);
378  }
379  static void GenerateMiss(MacroAssembler* masm);
380  static void GenerateMegamorphic(MacroAssembler* masm);
381  static void GenerateNormal(MacroAssembler* masm);
382  static void GenerateRuntimeGetProperty(MacroAssembler* masm);
383
384  MUST_USE_RESULT MaybeObject* Load(State state,
385                                    Handle<Object> object,
386                                    Handle<String> name);
387
388 protected:
389  virtual Code::Kind kind() const { return Code::LOAD_IC; }
390
391  virtual Handle<Code> generic_stub() const {
392    return isolate()->builtins()->LoadIC_Slow();
393  }
394
395  virtual Handle<Code> megamorphic_stub() {
396    return isolate()->builtins()->LoadIC_Megamorphic();
397  }
398
399  // Update the inline cache and the global stub cache based on the
400  // lookup result.
401  void UpdateCaches(LookupResult* lookup,
402                    State state,
403                    Handle<Object> object,
404                    Handle<String> name);
405
406  virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
407                                   Handle<Code> handler,
408                                   Handle<String> name,
409                                   StrictModeFlag strict_mode);
410
411  virtual Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
412                                            CodeHandleList* handlers,
413                                            int number_of_valid_maps,
414                                            Handle<Name> name,
415                                            StrictModeFlag strict_mode);
416
417  virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
418                                          Handle<JSObject> receiver,
419                                          Handle<String> name);
420
421 private:
422  // Stub accessors.
423  static Handle<Code> initialize_stub() {
424    return Isolate::Current()->builtins()->LoadIC_Initialize();
425  }
426  virtual Handle<Code> pre_monomorphic_stub() {
427    return isolate()->builtins()->LoadIC_PreMonomorphic();
428  }
429
430  static void Clear(Address address, Code* target);
431
432  friend class IC;
433};
434
435
436enum ICMissMode {
437  MISS_FORCE_GENERIC,
438  MISS
439};
440
441
442class KeyedLoadIC: public LoadIC {
443 public:
444  explicit KeyedLoadIC(FrameDepth depth, Isolate* isolate)
445      : LoadIC(depth, isolate) {
446    ASSERT(target()->is_keyed_load_stub());
447  }
448
449  MUST_USE_RESULT MaybeObject* Load(State state,
450                                    Handle<Object> object,
451                                    Handle<Object> key,
452                                    ICMissMode force_generic);
453
454  // Code generator routines.
455  static void GenerateMiss(MacroAssembler* masm, ICMissMode force_generic);
456  static void GenerateRuntimeGetProperty(MacroAssembler* masm);
457  static void GenerateInitialize(MacroAssembler* masm) {
458    GenerateMiss(masm, MISS);
459  }
460  static void GeneratePreMonomorphic(MacroAssembler* masm) {
461    GenerateMiss(masm, MISS);
462  }
463  static void GenerateGeneric(MacroAssembler* masm);
464  static void GenerateString(MacroAssembler* masm);
465  static void GenerateIndexedInterceptor(MacroAssembler* masm);
466  static void GenerateNonStrictArguments(MacroAssembler* masm);
467
468  // Bit mask to be tested against bit field for the cases when
469  // generic stub should go into slow case.
470  // Access check is necessary explicitly since generic stub does not perform
471  // map checks.
472  static const int kSlowCaseBitFieldMask =
473      (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
474
475 protected:
476  virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
477
478  Handle<Code> LoadElementStub(Handle<JSObject> receiver);
479
480  virtual Handle<Code> megamorphic_stub() {
481    return isolate()->builtins()->KeyedLoadIC_Generic();
482  }
483  virtual Handle<Code> generic_stub() const {
484    return isolate()->builtins()->KeyedLoadIC_Generic();
485  }
486
487  // Update the inline cache.
488  virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
489                                   Handle<Code> handler,
490                                   Handle<String> name,
491                                   StrictModeFlag strict_mode);
492  virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
493                                          Handle<JSObject> receiver,
494                                          Handle<String> name);
495  virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { }
496
497 private:
498  // Stub accessors.
499  static Handle<Code> initialize_stub() {
500    return Isolate::Current()->builtins()->KeyedLoadIC_Initialize();
501  }
502  virtual Handle<Code> pre_monomorphic_stub() {
503    return isolate()->builtins()->KeyedLoadIC_PreMonomorphic();
504  }
505  Handle<Code> indexed_interceptor_stub() {
506    return isolate()->builtins()->KeyedLoadIC_IndexedInterceptor();
507  }
508  Handle<Code> non_strict_arguments_stub() {
509    return isolate()->builtins()->KeyedLoadIC_NonStrictArguments();
510  }
511  Handle<Code> string_stub() {
512    return isolate()->builtins()->KeyedLoadIC_String();
513  }
514
515  static void Clear(Address address, Code* target);
516
517  friend class IC;
518};
519
520
521class StoreIC: public IC {
522 public:
523  StoreIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) {
524    ASSERT(target()->is_store_stub() || target()->is_keyed_store_stub());
525  }
526
527  // Code generators for stub routines. Only called once at startup.
528  static void GenerateSlow(MacroAssembler* masm);
529  static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
530  static void GenerateMiss(MacroAssembler* masm);
531  static void GenerateMegamorphic(MacroAssembler* masm,
532                                  StrictModeFlag strict_mode);
533  static void GenerateNormal(MacroAssembler* masm);
534  static void GenerateRuntimeSetProperty(MacroAssembler* masm,
535                                         StrictModeFlag strict_mode);
536
537  MUST_USE_RESULT MaybeObject* Store(
538      State state,
539      StrictModeFlag strict_mode,
540      Handle<Object> object,
541      Handle<String> name,
542      Handle<Object> value,
543      JSReceiver::StoreFromKeyed store_mode =
544          JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
545
546 protected:
547  virtual Code::Kind kind() const { return Code::STORE_IC; }
548  virtual Handle<Code> megamorphic_stub() {
549    return isolate()->builtins()->StoreIC_Megamorphic();
550  }
551  // Stub accessors.
552  virtual Handle<Code> megamorphic_stub_strict() {
553    return isolate()->builtins()->StoreIC_Megamorphic_Strict();
554  }
555  virtual Handle<Code> generic_stub() const {
556    return isolate()->builtins()->StoreIC_Generic();
557  }
558  virtual Handle<Code> generic_stub_strict() const {
559    return isolate()->builtins()->StoreIC_Generic_Strict();
560  }
561  virtual Handle<Code> global_proxy_stub() {
562    return isolate()->builtins()->StoreIC_GlobalProxy();
563  }
564  virtual Handle<Code> global_proxy_stub_strict() {
565    return isolate()->builtins()->StoreIC_GlobalProxy_Strict();
566  }
567
568  virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
569                                   Handle<Code> handler,
570                                   Handle<String> name,
571                                   StrictModeFlag strict_mode);
572
573  virtual Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
574                                            CodeHandleList* handlers,
575                                            int number_of_valid_maps,
576                                            Handle<Name> name,
577                                            StrictModeFlag strict_mode);
578
579  // Update the inline cache and the global stub cache based on the
580  // lookup result.
581  void UpdateCaches(LookupResult* lookup,
582                    State state,
583                    StrictModeFlag strict_mode,
584                    Handle<JSObject> receiver,
585                    Handle<String> name,
586                    Handle<Object> value);
587  // Compute the code stub for this store; used for rewriting to
588  // monomorphic state and making sure that the code stub is in the
589  // stub cache.
590  virtual Handle<Code> ComputeStoreMonomorphic(LookupResult* lookup,
591                                               StrictModeFlag strict_mode,
592                                               Handle<JSObject> receiver,
593                                               Handle<String> name,
594                                               Handle<Object> value);
595
596 private:
597  void set_target(Code* code) {
598    // Strict mode must be preserved across IC patching.
599    ASSERT(Code::GetStrictMode(code->extra_ic_state()) ==
600           Code::GetStrictMode(target()->extra_ic_state()));
601    IC::set_target(code);
602  }
603
604  static Handle<Code> initialize_stub() {
605    return Isolate::Current()->builtins()->StoreIC_Initialize();
606  }
607  static Handle<Code> initialize_stub_strict() {
608    return Isolate::Current()->builtins()->StoreIC_Initialize_Strict();
609  }
610  static void Clear(Address address, Code* target);
611
612  friend class IC;
613};
614
615
616enum KeyedStoreCheckMap {
617  kDontCheckMap,
618  kCheckMap
619};
620
621
622enum KeyedStoreIncrementLength {
623  kDontIncrementLength,
624  kIncrementLength
625};
626
627
628class KeyedStoreIC: public StoreIC {
629 public:
630  KeyedStoreIC(FrameDepth depth, Isolate* isolate)
631      : StoreIC(depth, isolate) {
632    ASSERT(target()->is_keyed_store_stub());
633  }
634
635  MUST_USE_RESULT MaybeObject* Store(State state,
636                                     StrictModeFlag strict_mode,
637                                     Handle<Object> object,
638                                     Handle<Object> name,
639                                     Handle<Object> value,
640                                     ICMissMode force_generic);
641
642  // Code generators for stub routines.  Only called once at startup.
643  static void GenerateInitialize(MacroAssembler* masm) {
644    GenerateMiss(masm, MISS);
645  }
646  static void GenerateMiss(MacroAssembler* masm, ICMissMode force_generic);
647  static void GenerateSlow(MacroAssembler* masm);
648  static void GenerateRuntimeSetProperty(MacroAssembler* masm,
649                                         StrictModeFlag strict_mode);
650  static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode);
651  static void GenerateNonStrictArguments(MacroAssembler* masm);
652
653 protected:
654  virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
655
656  virtual Handle<Code> ComputeStoreMonomorphic(LookupResult* lookup,
657                                               StrictModeFlag strict_mode,
658                                               Handle<JSObject> receiver,
659                                               Handle<String> name,
660                                               Handle<Object> value);
661  virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { }
662
663  virtual Handle<Code> megamorphic_stub() {
664    return isolate()->builtins()->KeyedStoreIC_Generic();
665  }
666  virtual Handle<Code> megamorphic_stub_strict() {
667    return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
668  }
669
670  Handle<Code> StoreElementStub(Handle<JSObject> receiver,
671                                KeyedAccessStoreMode store_mode,
672                                StrictModeFlag strict_mode);
673
674  virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
675                                   Handle<Code> handler,
676                                   Handle<String> name,
677                                   StrictModeFlag strict_mode);
678
679 private:
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 Handle<Code> initialize_stub() {
689    return Isolate::Current()->builtins()->KeyedStoreIC_Initialize();
690  }
691  static Handle<Code> initialize_stub_strict() {
692    return Isolate::Current()->builtins()->KeyedStoreIC_Initialize_Strict();
693  }
694  Handle<Code> generic_stub() const {
695    return isolate()->builtins()->KeyedStoreIC_Generic();
696  }
697  Handle<Code> generic_stub_strict() const {
698    return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
699  }
700  Handle<Code> non_strict_arguments_stub() {
701    return isolate()->builtins()->KeyedStoreIC_NonStrictArguments();
702  }
703
704  static void Clear(Address address, Code* target);
705
706  KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
707                                    Handle<Object> key,
708                                    Handle<Object> value);
709
710  Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
711                                     KeyedAccessStoreMode store_mode);
712
713  friend class IC;
714};
715
716
717// Type Recording BinaryOpIC, that records the types of the inputs and outputs.
718class BinaryOpIC: public IC {
719 public:
720  enum TypeInfo {
721    UNINITIALIZED,
722    SMI,
723    INT32,
724    NUMBER,
725    ODDBALL,
726    STRING,  // Only used for addition operation.
727    GENERIC
728  };
729
730  static void StubInfoToType(int minor_key,
731                             Handle<Type>* left,
732                             Handle<Type>* right,
733                             Handle<Type>* result,
734                             Isolate* isolate);
735
736  explicit BinaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
737
738  void patch(Code* code);
739
740  static const char* GetName(TypeInfo type_info);
741
742  static State ToState(TypeInfo type_info);
743
744 private:
745  static Handle<Type> TypeInfoToType(TypeInfo binary_type, Isolate* isolate);
746};
747
748
749class CompareIC: public IC {
750 public:
751  // The type/state lattice is defined by the following inequations:
752  //   UNINITIALIZED < ...
753  //   ... < GENERIC
754  //   SMI < NUMBER
755  //   INTERNALIZED_STRING < STRING
756  //   KNOWN_OBJECT < OBJECT
757  enum State {
758    UNINITIALIZED,
759    SMI,
760    NUMBER,
761    STRING,
762    INTERNALIZED_STRING,
763    UNIQUE_NAME,    // Symbol or InternalizedString
764    OBJECT,         // JSObject
765    KNOWN_OBJECT,   // JSObject with specific map (faster check)
766    GENERIC
767  };
768
769  static State NewInputState(State old_state, Handle<Object> value);
770
771  static Handle<Type> StateToType(Isolate* isolate,
772                                  State state,
773                                  Handle<Map> map = Handle<Map>());
774
775  static void StubInfoToType(int stub_minor_key,
776                             Handle<Type>* left_type,
777                             Handle<Type>* right_type,
778                             Handle<Type>* overall_type,
779                             Handle<Map> map,
780                             Isolate* isolate);
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
789  // Factory method for getting an uninitialized compare stub.
790  static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op);
791
792  // Helper function for computing the condition for a compare operation.
793  static Condition ComputeCondition(Token::Value op);
794
795  static const char* GetStateName(State state);
796
797 private:
798  static bool HasInlinedSmiCode(Address address);
799
800  State TargetState(State old_state,
801                    State old_left,
802                    State old_right,
803                    bool has_inlined_smi_code,
804                    Handle<Object> x,
805                    Handle<Object> y);
806
807  bool strict() const { return op_ == Token::EQ_STRICT; }
808  Condition GetCondition() const { return ComputeCondition(op_); }
809
810  static Code* GetRawUninitialized(Token::Value op);
811
812  static void Clear(Address address, Code* target);
813
814  Token::Value op_;
815
816  friend class IC;
817};
818
819
820class CompareNilIC: public IC {
821 public:
822  explicit CompareNilIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
823
824  MUST_USE_RESULT MaybeObject* CompareNil(Handle<Object> object);
825
826  static Handle<Code> GetUninitialized();
827
828  static void Clear(Address address, Code* target);
829
830  static MUST_USE_RESULT MaybeObject* DoCompareNilSlow(NilValue nil,
831                                                       Handle<Object> object);
832};
833
834
835class ToBooleanIC: public IC {
836 public:
837  explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
838
839  MaybeObject* ToBoolean(Handle<Object> object, Code::ExtraICState state);
840};
841
842
843// Helper for BinaryOpIC and CompareIC.
844enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
845void PatchInlinedSmiCode(Address address, InlinedSmiCheck check);
846
847DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure);
848DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure);
849DECLARE_RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss);
850DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure);
851DECLARE_RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss);
852DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss);
853DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss);
854
855
856} }  // namespace v8::internal
857
858#endif  // V8_IC_H_
859