• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_IC_H_
29 #define V8_IC_H_
30 
31 #include "macro-assembler.h"
32 #include "type-info.h"
33 
34 namespace v8 {
35 namespace internal {
36 
37 
38 // IC_UTIL_LIST defines all utility functions called from generated
39 // inline caching code. The argument for the macro, ICU, is the function name.
40 #define IC_UTIL_LIST(ICU)                             \
41   ICU(LoadIC_Miss)                                    \
42   ICU(KeyedLoadIC_Miss)                               \
43   ICU(CallIC_Miss)                                    \
44   ICU(KeyedCallIC_Miss)                               \
45   ICU(StoreIC_Miss)                                   \
46   ICU(StoreIC_ArrayLength)                            \
47   ICU(StoreIC_Slow)                                   \
48   ICU(SharedStoreIC_ExtendStorage)                    \
49   ICU(KeyedStoreIC_Miss)                              \
50   ICU(KeyedStoreIC_Slow)                              \
51   /* Utilities for IC stubs. */                       \
52   ICU(StoreCallbackProperty)                          \
53   ICU(LoadPropertyWithInterceptorOnly)                \
54   ICU(LoadPropertyWithInterceptorForLoad)             \
55   ICU(LoadPropertyWithInterceptorForCall)             \
56   ICU(KeyedLoadPropertyWithInterceptor)               \
57   ICU(StoreInterceptorProperty)                       \
58   ICU(CompareIC_Miss)                                 \
59   ICU(BinaryOpIC_Miss)                                \
60   ICU(CompareNilIC_Miss)                              \
61   ICU(Unreachable)                                    \
62   ICU(ToBooleanIC_Miss)
63 //
64 // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
65 // and KeyedStoreIC.
66 //
67 class IC {
68  public:
69   // The ids for utility called from the generated code.
70   enum UtilityId {
71   #define CONST_NAME(name) k##name,
72     IC_UTIL_LIST(CONST_NAME)
73   #undef CONST_NAME
74     kUtilityCount
75   };
76 
77   // Looks up the address of the named utility.
78   static Address AddressFromUtilityId(UtilityId id);
79 
80   // Alias the inline cache state type to make the IC code more readable.
81   typedef InlineCacheState State;
82 
83   // The IC code is either invoked with no extra frames on the stack
84   // or with a single extra frame for supporting calls.
85   enum FrameDepth {
86     NO_EXTRA_FRAME = 0,
87     EXTRA_CALL_FRAME = 1
88   };
89 
90   // Construct the IC structure with the given number of extra
91   // JavaScript frames on the stack.
92   IC(FrameDepth depth, Isolate* isolate);
~IC()93   virtual ~IC() {}
94 
state()95   State state() const { return state_; }
96   inline Address address() const;
97 
98   // Compute the current IC state based on the target stub, receiver and name.
99   void UpdateState(Handle<Object> receiver, Handle<Object> name);
MarkMonomorphicPrototypeFailure()100   void MarkMonomorphicPrototypeFailure() {
101     state_ = MONOMORPHIC_PROTOTYPE_FAILURE;
102   }
103 
104   // Clear the inline cache to initial state.
105   static void Clear(Isolate* isolate, 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.
IsUndeclaredGlobal(Handle<Object> receiver)114   bool IsUndeclaredGlobal(Handle<Object> receiver) {
115     if (receiver->IsGlobalObject()) {
116       return SlowIsUndeclaredGlobal();
117     } else {
118       ASSERT(!SlowIsUndeclaredGlobal());
119       return false;
120     }
121   }
122 
SlowIsUndeclaredGlobal()123   bool SlowIsUndeclaredGlobal() {
124     return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT;
125   }
126 
127 #ifdef DEBUG
IsLoadStub()128   bool IsLoadStub() {
129     return target()->is_load_stub() || target()->is_keyed_load_stub();
130   }
131 
IsStoreStub()132   bool IsStoreStub() {
133     return target()->is_store_stub() || target()->is_keyed_store_stub();
134   }
135 
IsCallStub()136   bool IsCallStub() {
137     return target()->is_call_stub() || target()->is_keyed_call_stub();
138   }
139 #endif
140 
141   // Determines which map must be used for keeping the code stub.
142   // These methods should not be called with undefined or null.
143   static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object);
144   // TODO(verwaest): This currently returns a HeapObject rather than JSObject*
145   // since loading the IC for loading the length from strings are stored on
146   // the string map directly, rather than on the JSObject-typed prototype.
147   static inline HeapObject* GetCodeCacheHolder(Isolate* isolate,
148                                                Object* object,
149                                                InlineCacheHolderFlag holder);
150 
151   static inline InlineCacheHolderFlag GetCodeCacheFlag(Type* type);
152   static inline Handle<Map> GetCodeCacheHolder(InlineCacheHolderFlag flag,
153                                                Type* type,
154                                                Isolate* isolate);
155 
IsCleared(Code * code)156   static bool IsCleared(Code* code) {
157     InlineCacheState state = code->ic_state();
158     return state == UNINITIALIZED || state == PREMONOMORPHIC;
159   }
160 
161   // Utility functions to convert maps to types and back. There are two special
162   // cases:
163   // - The heap_number_map is used as a marker which includes heap numbers as
164   //   well as smis.
165   // - The oddball map is only used for booleans.
166   static Handle<Map> TypeToMap(Type* type, Isolate* isolate);
167   static Type* MapToType(Handle<Map> type);
168   static Handle<Type> CurrentTypeOf(Handle<Object> object, Isolate* isolate);
169 
170  protected:
171   // Get the call-site target; used for determining the state.
target()172   Handle<Code> target() const { return target_; }
173 
fp()174   Address fp() const { return fp_; }
pc()175   Address pc() const { return *pc_address_; }
isolate()176   Isolate* isolate() const { return isolate_; }
177 
178 #ifdef ENABLE_DEBUGGER_SUPPORT
179   // Computes the address in the original code when the code running is
180   // containing break points (calls to DebugBreakXXX builtins).
181   Address OriginalCodeAddress() const;
182 #endif
183 
184   // Set the call-site target.
set_target(Code * code)185   void set_target(Code* code) {
186     SetTargetAtAddress(address(), code);
187     target_set_ = true;
188   }
189 
is_target_set()190   bool is_target_set() { return target_set_; }
191 
192 #ifdef DEBUG
193   char TransitionMarkFromState(IC::State state);
194 
195   void TraceIC(const char* type, Handle<Object> name);
196 #endif
197 
198   Failure* TypeError(const char* type,
199                      Handle<Object> object,
200                      Handle<Object> key);
201   Failure* ReferenceError(const char* type, Handle<String> name);
202 
203   // Access the target code for the given IC address.
204   static inline Code* GetTargetAtAddress(Address address);
205   static inline void SetTargetAtAddress(Address address, Code* target);
206   static void PostPatching(Address address, Code* target, Code* old_target);
207 
208   // Compute the handler either by compiling or by retrieving a cached version.
209   Handle<Code> ComputeHandler(LookupResult* lookup,
210                               Handle<Object> object,
211                               Handle<String> name,
212                               Handle<Object> value = Handle<Code>::null());
CompileHandler(LookupResult * lookup,Handle<Object> object,Handle<String> name,Handle<Object> value,InlineCacheHolderFlag cache_holder)213   virtual Handle<Code> CompileHandler(LookupResult* lookup,
214                                       Handle<Object> object,
215                                       Handle<String> name,
216                                       Handle<Object> value,
217                                       InlineCacheHolderFlag cache_holder) {
218     UNREACHABLE();
219     return Handle<Code>::null();
220   }
221 
222   void UpdateMonomorphicIC(Handle<Type> type,
223                            Handle<Code> handler,
224                            Handle<String> name);
225 
226   bool UpdatePolymorphicIC(Handle<Type> type,
227                            Handle<String> name,
228                            Handle<Code> code);
229 
230   virtual void UpdateMegamorphicCache(Type* type, Name* name, Code* code);
231 
232   void CopyICToMegamorphicCache(Handle<String> name);
233   bool IsTransitionOfMonomorphicTarget(Type* type);
234   void PatchCache(Handle<Type> type,
235                   Handle<String> name,
236                   Handle<Code> code);
kind()237   virtual Code::Kind kind() const {
238     UNREACHABLE();
239     return Code::STUB;
240   }
slow_stub()241   virtual Handle<Code> slow_stub() const {
242     UNREACHABLE();
243     return Handle<Code>::null();
244   }
megamorphic_stub()245   virtual Handle<Code> megamorphic_stub() {
246     UNREACHABLE();
247     return Handle<Code>::null();
248   }
generic_stub()249   virtual Handle<Code> generic_stub() const {
250     UNREACHABLE();
251     return Handle<Code>::null();
252   }
253 
254   bool TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
255                                               Handle<String> name);
256   void TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name);
257 
extra_ic_state()258   virtual ExtraICState extra_ic_state() { return kNoExtraICState; }
259 
260  private:
raw_target()261   Code* raw_target() const { return GetTargetAtAddress(address()); }
262 
263   // Frame pointer for the frame that uses (calls) the IC.
264   Address fp_;
265 
266   // All access to the program counter of an IC structure is indirect
267   // to make the code GC safe. This feature is crucial since
268   // GetProperty and SetProperty are called and they in turn might
269   // invoke the garbage collector.
270   Address* pc_address_;
271 
272   Isolate* isolate_;
273 
274   // The original code target that missed.
275   Handle<Code> target_;
276   State state_;
277   bool target_set_;
278 
279   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
280 };
281 
282 
283 // An IC_Utility encapsulates IC::UtilityId. It exists mainly because you
284 // cannot make forward declarations to an enum.
285 class IC_Utility {
286  public:
IC_Utility(IC::UtilityId id)287   explicit IC_Utility(IC::UtilityId id)
288     : address_(IC::AddressFromUtilityId(id)), id_(id) {}
289 
address()290   Address address() const { return address_; }
291 
id()292   IC::UtilityId id() const { return id_; }
293  private:
294   Address address_;
295   IC::UtilityId id_;
296 };
297 
298 
299 class CallICBase: public IC {
300  public:
301   // ExtraICState bits
302   class Contextual: public BitField<ContextualMode, 0, 1> {};
303   class StringStubState: public BitField<StringStubFeedback, 1, 1> {};
ComputeExtraICState(ContextualMode mode,StringStubFeedback feedback)304   static ExtraICState ComputeExtraICState(ContextualMode mode,
305                                           StringStubFeedback feedback) {
306     return Contextual::encode(mode) | StringStubState::encode(feedback);
307   }
308 
309   // Returns a JSFunction or a Failure.
310   MUST_USE_RESULT MaybeObject* LoadFunction(Handle<Object> object,
311                                             Handle<String> name);
312 
313  protected:
CallICBase(Code::Kind kind,Isolate * isolate)314   CallICBase(Code::Kind kind, Isolate* isolate)
315       : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {}
316 
317   // Compute a monomorphic stub if possible, otherwise return a null handle.
318   Handle<Code> ComputeMonomorphicStub(LookupResult* lookup,
319                                       Handle<Object> object,
320                                       Handle<String> name);
321 
322   // Update the inline cache and the global stub cache based on the lookup
323   // result.
324   void UpdateCaches(LookupResult* lookup,
325                     Handle<Object> object,
326                     Handle<String> name);
327 
328   // Returns a JSFunction if the object can be called as a function, and
329   // patches the stack to be ready for the call.  Otherwise, it returns the
330   // undefined value.
331   Handle<Object> TryCallAsFunction(Handle<Object> object);
332 
333   void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object);
334 
335   static void Clear(Address address, Code* target);
336 
337   // Platform-specific code generation functions used by both call and
338   // keyed call.
339   static void GenerateMiss(MacroAssembler* masm,
340                            int argc,
341                            IC::UtilityId id,
342                            ExtraICState extra_state);
343 
344   static void GenerateNormal(MacroAssembler* masm, int argc);
345 
346   static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
347                                             int argc,
348                                             Code::Kind kind,
349                                             ExtraICState extra_state);
350 
351   virtual Handle<Code> megamorphic_stub();
352   virtual Handle<Code> pre_monomorphic_stub();
353 
354   Code::Kind kind_;
355 
356   friend class IC;
357 };
358 
359 
360 class CallIC: public CallICBase {
361  public:
CallIC(Isolate * isolate)362   explicit CallIC(Isolate* isolate)
363       : CallICBase(Code::CALL_IC, isolate),
364         extra_ic_state_(target()->extra_ic_state()) {
365     ASSERT(target()->is_call_stub());
366   }
367 
368   // Code generator routines.
GenerateInitialize(MacroAssembler * masm,int argc,ExtraICState extra_state)369   static void GenerateInitialize(MacroAssembler* masm,
370                                  int argc,
371                                  ExtraICState extra_state) {
372     GenerateMiss(masm, argc, extra_state);
373   }
374 
GenerateMiss(MacroAssembler * masm,int argc,ExtraICState extra_state)375   static void GenerateMiss(MacroAssembler* masm,
376                            int argc,
377                            ExtraICState extra_state) {
378     CallICBase::GenerateMiss(masm, argc, IC::kCallIC_Miss, extra_state);
379   }
380 
381   static void GenerateMegamorphic(MacroAssembler* masm,
382                                   int argc,
383                                   ExtraICState extra_ic_state);
384 
GenerateNormal(MacroAssembler * masm,int argc)385   static void GenerateNormal(MacroAssembler* masm, int argc) {
386     CallICBase::GenerateNormal(masm, argc);
387     GenerateMiss(masm, argc, kNoExtraICState);
388   }
389   bool TryUpdateExtraICState(LookupResult* lookup, Handle<Object> object);
390 
391  protected:
extra_ic_state()392   virtual ExtraICState extra_ic_state() { return extra_ic_state_; }
393 
394  private:
395   ExtraICState extra_ic_state_;
396 };
397 
398 
399 class KeyedCallIC: public CallICBase {
400  public:
KeyedCallIC(Isolate * isolate)401   explicit KeyedCallIC(Isolate* isolate)
402       : CallICBase(Code::KEYED_CALL_IC, isolate) {
403     ASSERT(target()->is_keyed_call_stub());
404   }
405 
406   MUST_USE_RESULT MaybeObject* LoadFunction(Handle<Object> object,
407                                             Handle<Object> key);
408 
409   // Code generator routines.
GenerateInitialize(MacroAssembler * masm,int argc)410   static void GenerateInitialize(MacroAssembler* masm, int argc) {
411     GenerateMiss(masm, argc);
412   }
413 
GenerateMiss(MacroAssembler * masm,int argc)414   static void GenerateMiss(MacroAssembler* masm, int argc) {
415     CallICBase::GenerateMiss(masm, argc, IC::kKeyedCallIC_Miss,
416                              kNoExtraICState);
417   }
418 
419   static void GenerateMegamorphic(MacroAssembler* masm, int argc);
420   static void GenerateNormal(MacroAssembler* masm, int argc);
421   static void GenerateNonStrictArguments(MacroAssembler* masm, int argc);
422 };
423 
424 
425 class LoadIC: public IC {
426  public:
LoadIC(FrameDepth depth,Isolate * isolate)427   explicit LoadIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) {
428     ASSERT(IsLoadStub());
429   }
430 
431   // Code generator routines.
GenerateInitialize(MacroAssembler * masm)432   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
GeneratePreMonomorphic(MacroAssembler * masm)433   static void GeneratePreMonomorphic(MacroAssembler* masm) {
434     GenerateMiss(masm);
435   }
436   static void GenerateMiss(MacroAssembler* masm);
437   static void GenerateMegamorphic(MacroAssembler* masm);
438   static void GenerateNormal(MacroAssembler* masm);
439   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
440 
441   MUST_USE_RESULT MaybeObject* Load(Handle<Object> object,
442                                     Handle<String> name);
443 
444  protected:
kind()445   virtual Code::Kind kind() const { return Code::LOAD_IC; }
446 
slow_stub()447   virtual Handle<Code> slow_stub() const {
448     return isolate()->builtins()->LoadIC_Slow();
449   }
450 
megamorphic_stub()451   virtual Handle<Code> megamorphic_stub() {
452     return isolate()->builtins()->LoadIC_Megamorphic();
453   }
454 
455   // Update the inline cache and the global stub cache based on the
456   // lookup result.
457   void UpdateCaches(LookupResult* lookup,
458                     Handle<Object> object,
459                     Handle<String> name);
460 
461   virtual Handle<Code> CompileHandler(LookupResult* lookup,
462                                       Handle<Object> object,
463                                       Handle<String> name,
464                                       Handle<Object> unused,
465                                       InlineCacheHolderFlag cache_holder);
466 
467  private:
468   // Stub accessors.
initialize_stub(Isolate * isolate)469   static Handle<Code> initialize_stub(Isolate* isolate) {
470     return isolate->builtins()->LoadIC_Initialize();
471   }
472 
pre_monomorphic_stub(Isolate * isolate)473   static Handle<Code> pre_monomorphic_stub(Isolate* isolate) {
474     return isolate->builtins()->LoadIC_PreMonomorphic();
475   }
476 
pre_monomorphic_stub()477   virtual Handle<Code> pre_monomorphic_stub() {
478     return pre_monomorphic_stub(isolate());
479   }
480 
481   Handle<Code> SimpleFieldLoad(int offset,
482                                bool inobject = true,
483                                Representation representation =
484                                     Representation::Tagged());
485 
486   static void Clear(Isolate* isolate, Address address, Code* target);
487 
488   friend class IC;
489 };
490 
491 
492 class KeyedLoadIC: public LoadIC {
493  public:
KeyedLoadIC(FrameDepth depth,Isolate * isolate)494   explicit KeyedLoadIC(FrameDepth depth, Isolate* isolate)
495       : LoadIC(depth, isolate) {
496     ASSERT(target()->is_keyed_load_stub());
497   }
498 
499   MUST_USE_RESULT MaybeObject* Load(Handle<Object> object,
500                                     Handle<Object> key);
501 
502   // Code generator routines.
503   static void GenerateMiss(MacroAssembler* masm);
504   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
GenerateInitialize(MacroAssembler * masm)505   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
GeneratePreMonomorphic(MacroAssembler * masm)506   static void GeneratePreMonomorphic(MacroAssembler* masm) {
507     GenerateMiss(masm);
508   }
509   static void GenerateGeneric(MacroAssembler* masm);
510   static void GenerateString(MacroAssembler* masm);
511   static void GenerateIndexedInterceptor(MacroAssembler* masm);
512   static void GenerateNonStrictArguments(MacroAssembler* masm);
513 
514   // Bit mask to be tested against bit field for the cases when
515   // generic stub should go into slow case.
516   // Access check is necessary explicitly since generic stub does not perform
517   // map checks.
518   static const int kSlowCaseBitFieldMask =
519       (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
520 
521  protected:
kind()522   virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
523 
524   Handle<Code> LoadElementStub(Handle<JSObject> receiver);
525 
megamorphic_stub()526   virtual Handle<Code> megamorphic_stub() {
527     return isolate()->builtins()->KeyedLoadIC_Generic();
528   }
generic_stub()529   virtual Handle<Code> generic_stub() const {
530     return isolate()->builtins()->KeyedLoadIC_Generic();
531   }
slow_stub()532   virtual Handle<Code> slow_stub() const {
533     return isolate()->builtins()->KeyedLoadIC_Slow();
534   }
535 
UpdateMegamorphicCache(Type * type,Name * name,Code * code)536   virtual void UpdateMegamorphicCache(Type* type, Name* name, Code* code) { }
537 
538  private:
539   // Stub accessors.
initialize_stub(Isolate * isolate)540   static Handle<Code> initialize_stub(Isolate* isolate) {
541     return isolate->builtins()->KeyedLoadIC_Initialize();
542   }
pre_monomorphic_stub(Isolate * isolate)543   static Handle<Code> pre_monomorphic_stub(Isolate* isolate) {
544     return isolate->builtins()->KeyedLoadIC_PreMonomorphic();
545   }
pre_monomorphic_stub()546   virtual Handle<Code> pre_monomorphic_stub() {
547     return pre_monomorphic_stub(isolate());
548   }
indexed_interceptor_stub()549   Handle<Code> indexed_interceptor_stub() {
550     return isolate()->builtins()->KeyedLoadIC_IndexedInterceptor();
551   }
non_strict_arguments_stub()552   Handle<Code> non_strict_arguments_stub() {
553     return isolate()->builtins()->KeyedLoadIC_NonStrictArguments();
554   }
string_stub()555   Handle<Code> string_stub() {
556     return isolate()->builtins()->KeyedLoadIC_String();
557   }
558 
559   static void Clear(Isolate* isolate, Address address, Code* target);
560 
561   friend class IC;
562 };
563 
564 
565 class StoreIC: public IC {
566  public:
567   // ExtraICState bits
568   class StrictModeState: public BitField<StrictModeFlag, 0, 1> {};
ComputeExtraICState(StrictModeFlag flag)569   static ExtraICState ComputeExtraICState(StrictModeFlag flag) {
570     return StrictModeState::encode(flag);
571   }
572 
GetStrictMode(ExtraICState state)573   static StrictModeFlag GetStrictMode(ExtraICState state) {
574     return StrictModeState::decode(state);
575   }
576 
577   // For convenience, a statically declared encoding of strict mode extra
578   // IC state.
579   static const ExtraICState kStrictModeState =
580       1 << StrictModeState::kShift;
581 
StoreIC(FrameDepth depth,Isolate * isolate)582   StoreIC(FrameDepth depth, Isolate* isolate)
583       : IC(depth, isolate),
584         strict_mode_(GetStrictMode(target()->extra_ic_state())) {
585     ASSERT(IsStoreStub());
586   }
587 
strict_mode()588   StrictModeFlag strict_mode() const { return strict_mode_; }
589 
590   // Code generators for stub routines. Only called once at startup.
591   static void GenerateSlow(MacroAssembler* masm);
GenerateInitialize(MacroAssembler * masm)592   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
GeneratePreMonomorphic(MacroAssembler * masm)593   static void GeneratePreMonomorphic(MacroAssembler* masm) {
594     GenerateMiss(masm);
595   }
596   static void GenerateMiss(MacroAssembler* masm);
597   static void GenerateMegamorphic(MacroAssembler* masm,
598                                   ExtraICState extra_ic_state);
599   static void GenerateNormal(MacroAssembler* masm);
600   static void GenerateRuntimeSetProperty(MacroAssembler* masm,
601                                          StrictModeFlag strict_mode);
602 
603   MUST_USE_RESULT MaybeObject* Store(
604       Handle<Object> object,
605       Handle<String> name,
606       Handle<Object> value,
607       JSReceiver::StoreFromKeyed store_mode =
608           JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
609 
610  protected:
kind()611   virtual Code::Kind kind() const { return Code::STORE_IC; }
megamorphic_stub()612   virtual Handle<Code> megamorphic_stub() {
613     if (strict_mode() == kStrictMode) {
614       return isolate()->builtins()->StoreIC_Megamorphic_Strict();
615     } else {
616       return isolate()->builtins()->StoreIC_Megamorphic();
617     }
618   }
619   // Stub accessors.
generic_stub()620   virtual Handle<Code> generic_stub() const {
621     if (strict_mode() == kStrictMode) {
622       return isolate()->builtins()->StoreIC_Generic_Strict();
623     } else {
624       return isolate()->builtins()->StoreIC_Generic();
625     }
626   }
627 
slow_stub()628   virtual Handle<Code> slow_stub() const {
629     return isolate()->builtins()->StoreIC_Slow();
630   }
631 
pre_monomorphic_stub()632   virtual Handle<Code> pre_monomorphic_stub() {
633     return pre_monomorphic_stub(isolate(), strict_mode());
634   }
635 
pre_monomorphic_stub(Isolate * isolate,StrictModeFlag strict_mode)636   static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
637                                            StrictModeFlag strict_mode) {
638     if (strict_mode == kStrictMode) {
639       return isolate->builtins()->StoreIC_PreMonomorphic_Strict();
640     } else {
641       return isolate->builtins()->StoreIC_PreMonomorphic();
642     }
643   }
644 
645   // Update the inline cache and the global stub cache based on the
646   // lookup result.
647   void UpdateCaches(LookupResult* lookup,
648                     Handle<JSObject> receiver,
649                     Handle<String> name,
650                     Handle<Object> value);
651   virtual Handle<Code> CompileHandler(LookupResult* lookup,
652                                       Handle<Object> object,
653                                       Handle<String> name,
654                                       Handle<Object> value,
655                                       InlineCacheHolderFlag cache_holder);
656 
extra_ic_state()657   virtual ExtraICState extra_ic_state() {
658     return ComputeExtraICState(strict_mode());
659   }
660 
661  private:
set_target(Code * code)662   void set_target(Code* code) {
663     // Strict mode must be preserved across IC patching.
664     ASSERT(GetStrictMode(code->extra_ic_state()) ==
665            GetStrictMode(target()->extra_ic_state()));
666     IC::set_target(code);
667   }
668 
initialize_stub(Isolate * isolate,StrictModeFlag strict_mode)669   static Handle<Code> initialize_stub(Isolate* isolate,
670                                       StrictModeFlag strict_mode) {
671     if (strict_mode == kStrictMode) {
672       return isolate->builtins()->StoreIC_Initialize_Strict();
673     } else {
674       return isolate->builtins()->StoreIC_Initialize();
675     }
676   }
677 
678   static void Clear(Isolate* isolate, Address address, Code* target);
679 
680   StrictModeFlag strict_mode_;
681 
682   friend class IC;
683 };
684 
685 
686 enum KeyedStoreCheckMap {
687   kDontCheckMap,
688   kCheckMap
689 };
690 
691 
692 enum KeyedStoreIncrementLength {
693   kDontIncrementLength,
694   kIncrementLength
695 };
696 
697 
698 class KeyedStoreIC: public StoreIC {
699  public:
700   // ExtraICState bits (building on IC)
701   // ExtraICState bits
702   class ExtraICStateKeyedAccessStoreMode:
703       public BitField<KeyedAccessStoreMode, 1, 4> {};  // NOLINT
704 
ComputeExtraICState(StrictModeFlag flag,KeyedAccessStoreMode mode)705   static ExtraICState ComputeExtraICState(StrictModeFlag flag,
706                                                 KeyedAccessStoreMode mode) {
707     return StrictModeState::encode(flag) |
708         ExtraICStateKeyedAccessStoreMode::encode(mode);
709   }
710 
GetKeyedAccessStoreMode(ExtraICState extra_state)711   static KeyedAccessStoreMode GetKeyedAccessStoreMode(
712       ExtraICState extra_state) {
713     return ExtraICStateKeyedAccessStoreMode::decode(extra_state);
714   }
715 
KeyedStoreIC(FrameDepth depth,Isolate * isolate)716   KeyedStoreIC(FrameDepth depth, Isolate* isolate)
717       : StoreIC(depth, isolate) {
718     ASSERT(target()->is_keyed_store_stub());
719   }
720 
721   MUST_USE_RESULT MaybeObject* Store(Handle<Object> object,
722                                      Handle<Object> name,
723                                      Handle<Object> value);
724 
725   // Code generators for stub routines.  Only called once at startup.
GenerateInitialize(MacroAssembler * masm)726   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
GeneratePreMonomorphic(MacroAssembler * masm)727   static void GeneratePreMonomorphic(MacroAssembler* masm) {
728     GenerateMiss(masm);
729   }
730   static void GenerateMiss(MacroAssembler* masm);
731   static void GenerateSlow(MacroAssembler* masm);
732   static void GenerateRuntimeSetProperty(MacroAssembler* masm,
733                                          StrictModeFlag strict_mode);
734   static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode);
735   static void GenerateNonStrictArguments(MacroAssembler* masm);
736 
737  protected:
kind()738   virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
739 
UpdateMegamorphicCache(Type * type,Name * name,Code * code)740   virtual void UpdateMegamorphicCache(Type* type, Name* name, Code* code) { }
741 
extra_ic_state()742   virtual ExtraICState extra_ic_state() {
743     return ComputeExtraICState(strict_mode(), STANDARD_STORE);
744   }
745 
pre_monomorphic_stub()746   virtual Handle<Code> pre_monomorphic_stub() {
747     return pre_monomorphic_stub(isolate(), strict_mode());
748   }
pre_monomorphic_stub(Isolate * isolate,StrictModeFlag strict_mode)749   static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
750                                            StrictModeFlag strict_mode) {
751     if (strict_mode == kStrictMode) {
752       return isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict();
753     } else {
754       return isolate->builtins()->KeyedStoreIC_PreMonomorphic();
755     }
756   }
slow_stub()757   virtual Handle<Code> slow_stub() const {
758     return isolate()->builtins()->KeyedStoreIC_Slow();
759   }
megamorphic_stub()760   virtual Handle<Code> megamorphic_stub() {
761     if (strict_mode() == kStrictMode) {
762       return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
763     } else {
764       return isolate()->builtins()->KeyedStoreIC_Generic();
765     }
766   }
767 
768   Handle<Code> StoreElementStub(Handle<JSObject> receiver,
769                                 KeyedAccessStoreMode store_mode);
770 
771  private:
set_target(Code * code)772   void set_target(Code* code) {
773     // Strict mode must be preserved across IC patching.
774     ASSERT(GetStrictMode(code->extra_ic_state()) == strict_mode());
775     IC::set_target(code);
776   }
777 
778   // Stub accessors.
initialize_stub(Isolate * isolate,StrictModeFlag strict_mode)779   static Handle<Code> initialize_stub(Isolate* isolate,
780                                       StrictModeFlag strict_mode) {
781     if (strict_mode == kStrictMode) {
782       return isolate->builtins()->KeyedStoreIC_Initialize_Strict();
783     } else {
784       return isolate->builtins()->KeyedStoreIC_Initialize();
785     }
786   }
787 
generic_stub()788   virtual Handle<Code> generic_stub() const {
789     if (strict_mode() == kStrictMode) {
790       return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
791     } else {
792       return isolate()->builtins()->KeyedStoreIC_Generic();
793     }
794   }
795 
non_strict_arguments_stub()796   Handle<Code> non_strict_arguments_stub() {
797     return isolate()->builtins()->KeyedStoreIC_NonStrictArguments();
798   }
799 
800   static void Clear(Isolate* isolate, Address address, Code* target);
801 
802   KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
803                                     Handle<Object> key,
804                                     Handle<Object> value);
805 
806   Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
807                                      KeyedAccessStoreMode store_mode);
808 
809   friend class IC;
810 };
811 
812 
813 // Mode to overwrite BinaryExpression values.
814 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
815 
816 // Type Recording BinaryOpIC, that records the types of the inputs and outputs.
817 class BinaryOpIC: public IC {
818  public:
819   class State V8_FINAL BASE_EMBEDDED {
820    public:
821     explicit State(ExtraICState extra_ic_state);
822 
State(Token::Value op,OverwriteMode mode)823     State(Token::Value op, OverwriteMode mode)
824         : op_(op), mode_(mode), left_kind_(NONE), right_kind_(NONE),
825           result_kind_(NONE) {
826       ASSERT_LE(FIRST_TOKEN, op);
827       ASSERT_LE(op, LAST_TOKEN);
828     }
829 
GetICState()830     InlineCacheState GetICState() const {
831       if (Max(left_kind_, right_kind_) == NONE) {
832         return ::v8::internal::UNINITIALIZED;
833       }
834       if (Max(left_kind_, right_kind_) == GENERIC) {
835         return ::v8::internal::MEGAMORPHIC;
836       }
837       if (Min(left_kind_, right_kind_) == GENERIC) {
838         return ::v8::internal::GENERIC;
839       }
840       return ::v8::internal::MONOMORPHIC;
841     }
842 
843     ExtraICState GetExtraICState() const;
844 
845     static void GenerateAheadOfTime(
846         Isolate*, void (*Generate)(Isolate*, const State&));
847 
CanReuseDoubleBox()848     bool CanReuseDoubleBox() const {
849       return (result_kind_ > SMI && result_kind_ <= NUMBER) &&
850           ((mode_ == OVERWRITE_LEFT &&
851             left_kind_ > SMI && left_kind_ <= NUMBER) ||
852            (mode_ == OVERWRITE_RIGHT &&
853             right_kind_ > SMI && right_kind_ <= NUMBER));
854     }
855 
HasSideEffects()856     bool HasSideEffects() const {
857       return Max(left_kind_, right_kind_) == GENERIC;
858     }
859 
UseInlinedSmiCode()860     bool UseInlinedSmiCode() const {
861       return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_);
862     }
863 
864     static const int FIRST_TOKEN = Token::BIT_OR;
865     static const int LAST_TOKEN = Token::MOD;
866 
op()867     Token::Value op() const { return op_; }
mode()868     OverwriteMode mode() const { return mode_; }
fixed_right_arg()869     Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
870 
GetLeftType(Isolate * isolate)871     Handle<Type> GetLeftType(Isolate* isolate) const {
872       return KindToType(left_kind_, isolate);
873     }
GetRightType(Isolate * isolate)874     Handle<Type> GetRightType(Isolate* isolate) const {
875       return KindToType(right_kind_, isolate);
876     }
877     Handle<Type> GetResultType(Isolate* isolate) const;
878 
879     void Print(StringStream* stream) const;
880 
881     void Update(Handle<Object> left,
882                 Handle<Object> right,
883                 Handle<Object> result);
884 
885    private:
886     enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
887 
888     Kind UpdateKind(Handle<Object> object, Kind kind) const;
889 
890     static const char* KindToString(Kind kind);
891     static Handle<Type> KindToType(Kind kind, Isolate* isolate);
KindMaybeSmi(Kind kind)892     static bool KindMaybeSmi(Kind kind) {
893       return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
894     }
895 
896     // We truncate the last bit of the token.
897     STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4));
898     class OpField:                 public BitField<int, 0, 4> {};
899     class OverwriteModeField:      public BitField<OverwriteMode, 4, 2> {};
900     class SSE2Field:               public BitField<bool, 6, 1> {};
901     class ResultKindField:         public BitField<Kind, 7, 3> {};
902     class LeftKindField:           public BitField<Kind, 10,  3> {};
903     // When fixed right arg is set, we don't need to store the right kind.
904     // Thus the two fields can overlap.
905     class HasFixedRightArgField:   public BitField<bool, 13, 1> {};
906     class FixedRightArgValueField: public BitField<int,  14, 4> {};
907     class RightKindField:          public BitField<Kind, 14, 3> {};
908 
909     Token::Value op_;
910     OverwriteMode mode_;
911     Kind left_kind_;
912     Kind right_kind_;
913     Kind result_kind_;
914     Maybe<int> fixed_right_arg_;
915   };
916 
BinaryOpIC(Isolate * isolate)917   explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
918 
919   static Builtins::JavaScript TokenToJSBuiltin(Token::Value op);
920 
921   MUST_USE_RESULT MaybeObject* Transition(Handle<Object> left,
922                                           Handle<Object> right);
923 };
924 
925 
926 class CompareIC: public IC {
927  public:
928   // The type/state lattice is defined by the following inequations:
929   //   UNINITIALIZED < ...
930   //   ... < GENERIC
931   //   SMI < NUMBER
932   //   INTERNALIZED_STRING < STRING
933   //   KNOWN_OBJECT < OBJECT
934   enum State {
935     UNINITIALIZED,
936     SMI,
937     NUMBER,
938     STRING,
939     INTERNALIZED_STRING,
940     UNIQUE_NAME,    // Symbol or InternalizedString
941     OBJECT,         // JSObject
942     KNOWN_OBJECT,   // JSObject with specific map (faster check)
943     GENERIC
944   };
945 
946   static State NewInputState(State old_state, Handle<Object> value);
947 
948   static Handle<Type> StateToType(Isolate* isolate,
949                                   State state,
950                                   Handle<Map> map = Handle<Map>());
951 
952   static void StubInfoToType(int stub_minor_key,
953                              Handle<Type>* left_type,
954                              Handle<Type>* right_type,
955                              Handle<Type>* overall_type,
956                              Handle<Map> map,
957                              Isolate* isolate);
958 
CompareIC(Isolate * isolate,Token::Value op)959   CompareIC(Isolate* isolate, Token::Value op)
960       : IC(EXTRA_CALL_FRAME, isolate), op_(op) { }
961 
962   // Update the inline cache for the given operands.
963   Code* UpdateCaches(Handle<Object> x, Handle<Object> y);
964 
965 
966   // Factory method for getting an uninitialized compare stub.
967   static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op);
968 
969   // Helper function for computing the condition for a compare operation.
970   static Condition ComputeCondition(Token::Value op);
971 
972   static const char* GetStateName(State state);
973 
974  private:
975   static bool HasInlinedSmiCode(Address address);
976 
977   State TargetState(State old_state,
978                     State old_left,
979                     State old_right,
980                     bool has_inlined_smi_code,
981                     Handle<Object> x,
982                     Handle<Object> y);
983 
strict()984   bool strict() const { return op_ == Token::EQ_STRICT; }
GetCondition()985   Condition GetCondition() const { return ComputeCondition(op_); }
986 
987   static Code* GetRawUninitialized(Isolate* isolate, Token::Value op);
988 
989   static void Clear(Isolate* isolate, Address address, Code* target);
990 
991   Token::Value op_;
992 
993   friend class IC;
994 };
995 
996 
997 class CompareNilIC: public IC {
998  public:
CompareNilIC(Isolate * isolate)999   explicit CompareNilIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
1000 
1001   MUST_USE_RESULT MaybeObject* CompareNil(Handle<Object> object);
1002 
1003   static Handle<Code> GetUninitialized();
1004 
1005   static void Clear(Address address, Code* target);
1006 
1007   static MUST_USE_RESULT MaybeObject* DoCompareNilSlow(NilValue nil,
1008                                                        Handle<Object> object);
1009 };
1010 
1011 
1012 class ToBooleanIC: public IC {
1013  public:
ToBooleanIC(Isolate * isolate)1014   explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
1015 
1016   MaybeObject* ToBoolean(Handle<Object> object);
1017 };
1018 
1019 
1020 // Helper for BinaryOpIC and CompareIC.
1021 enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
1022 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check);
1023 
1024 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure);
1025 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure);
1026 DECLARE_RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss);
1027 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure);
1028 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_MissFromStubFailure);
1029 DECLARE_RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss);
1030 DECLARE_RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss);
1031 DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss);
1032 DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss);
1033 
1034 
1035 } }  // namespace v8::internal
1036 
1037 #endif  // V8_IC_H_
1038