1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_IC_H_
6 #define V8_IC_H_
7 
8 #include "src/ic/ic-state.h"
9 #include "src/macro-assembler.h"
10 #include "src/messages.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 //
16 // IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC.
17 //
18 class IC {
19  public:
20   // Alias the inline cache state type to make the IC code more readable.
21   typedef InlineCacheState State;
22 
23   // The IC code is either invoked with no extra frames on the stack
24   // or with a single extra frame for supporting calls.
25   enum FrameDepth { NO_EXTRA_FRAME = 0, EXTRA_CALL_FRAME = 1 };
26 
27   // Construct the IC structure with the given number of extra
28   // JavaScript frames on the stack.
29   IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL);
~IC()30   virtual ~IC() {}
31 
state()32   State state() const { return state_; }
33   inline Address address() const;
34 
35   // Compute the current IC state based on the target stub, receiver and name.
36   void UpdateState(Handle<Object> receiver, Handle<Object> name);
37 
38   bool RecomputeHandlerForName(Handle<Object> name);
MarkRecomputeHandler(Handle<Object> name)39   void MarkRecomputeHandler(Handle<Object> name) {
40     DCHECK(RecomputeHandlerForName(name));
41     old_state_ = state_;
42     state_ = RECOMPUTE_HANDLER;
43   }
44 
45   // Clear the inline cache to initial state.
46   static void Clear(Isolate* isolate, Address address, Address constant_pool);
47 
48 #ifdef DEBUG
IsLoadStub()49   bool IsLoadStub() const {
50     return kind_ == Code::LOAD_IC || kind_ == Code::LOAD_GLOBAL_IC ||
51            kind_ == Code::KEYED_LOAD_IC;
52   }
IsStoreStub()53   bool IsStoreStub() const {
54     return kind_ == Code::STORE_IC || kind_ == Code::KEYED_STORE_IC;
55   }
IsCallStub()56   bool IsCallStub() const { return kind_ == Code::CALL_IC; }
57 #endif
58 
59   static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map,
60                                                   bool receiver_is_holder,
61                                                   Isolate* isolate,
62                                                   CacheHolderFlag* flag);
63   static inline Handle<Map> GetICCacheHolder(Handle<Map> receiver_map,
64                                              Isolate* isolate,
65                                              CacheHolderFlag* flag);
66 
IsCleared(FeedbackNexus * nexus)67   static bool IsCleared(FeedbackNexus* nexus) {
68     InlineCacheState state = nexus->StateFromFeedback();
69     return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC;
70   }
71 
ICUseVector(Code::Kind kind)72   static bool ICUseVector(Code::Kind kind) {
73     return kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
74            kind == Code::KEYED_LOAD_IC || kind == Code::CALL_IC ||
75            kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC;
76   }
77 
78   // The ICs that don't pass slot and vector through the stack have to
79   // save/restore them in the dispatcher.
80   static bool ShouldPushPopSlotAndVector(Code::Kind kind);
81 
82   static InlineCacheState StateFromCode(Code* code);
83 
84   static inline bool IsHandler(Object* object);
85 
86  protected:
fp()87   Address fp() const { return fp_; }
pc()88   Address pc() const { return *pc_address_; }
isolate()89   Isolate* isolate() const { return isolate_; }
90 
91   // Get the shared function info of the caller.
92   SharedFunctionInfo* GetSharedFunctionInfo() const;
93   // Get the code object of the caller.
94   Code* GetCode() const;
95 
96   inline bool AddressIsDeoptimizedCode() const;
97   inline static bool AddressIsDeoptimizedCode(Isolate* isolate,
98                                               Address address);
99 
100   // Set the call-site target.
101   inline void set_target(Code* code);
is_vector_set()102   bool is_vector_set() { return vector_set_; }
103 
UseVector()104   bool UseVector() const {
105     bool use = ICUseVector(kind());
106     // If we are supposed to use the nexus, verify the nexus is non-null.
107     DCHECK(!use || nexus_ != nullptr);
108     return use;
109   }
110 
111   // Configure for most states.
112   void ConfigureVectorState(IC::State new_state, Handle<Object> key);
113   // Configure the vector for MONOMORPHIC.
114   void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
115                             Handle<Object> handler);
116   // Configure the vector for POLYMORPHIC.
117   void ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
118                             List<Handle<Object>>* handlers);
119   // Configure the vector for POLYMORPHIC with transitions (only for element
120   // keyed stores).
121   void ConfigureVectorState(MapHandleList* maps,
122                             MapHandleList* transitioned_maps,
123                             CodeHandleList* handlers);
124 
125   char TransitionMarkFromState(IC::State state);
126   void TraceIC(const char* type, Handle<Object> name);
127   void TraceIC(const char* type, Handle<Object> name, State old_state,
128                State new_state);
129 
130   MaybeHandle<Object> TypeError(MessageTemplate::Template,
131                                 Handle<Object> object, Handle<Object> key);
132   MaybeHandle<Object> ReferenceError(Handle<Name> name);
133 
134   // Access the target code for the given IC address.
135   static inline Code* GetTargetAtAddress(Address address,
136                                          Address constant_pool);
137   static inline void SetTargetAtAddress(Address address, Code* target,
138                                         Address constant_pool);
139   // As a vector-based IC, type feedback must be updated differently.
140   static void OnTypeFeedbackChanged(Isolate* isolate, Code* host);
141   static void PostPatching(Address address, Code* target, Code* old_target);
142 
143   void TraceHandlerCacheHitStats(LookupIterator* lookup);
144 
145   // Compute the handler either by compiling or by retrieving a cached version.
146   Handle<Object> ComputeHandler(LookupIterator* lookup,
147                                 Handle<Object> value = Handle<Code>::null());
GetMapIndependentHandler(LookupIterator * lookup)148   virtual Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) {
149     UNREACHABLE();
150     return Handle<Code>::null();
151   }
CompileHandler(LookupIterator * lookup,Handle<Object> value,CacheHolderFlag cache_holder)152   virtual Handle<Object> CompileHandler(LookupIterator* lookup,
153                                         Handle<Object> value,
154                                         CacheHolderFlag cache_holder) {
155     UNREACHABLE();
156     return Handle<Object>::null();
157   }
158 
159   void UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name);
160   bool UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code);
161   void UpdateMegamorphicCache(Map* map, Name* name, Object* code);
162 
163   StubCache* stub_cache();
164 
165   void CopyICToMegamorphicCache(Handle<Name> name);
166   bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
167   void PatchCache(Handle<Name> name, Handle<Object> code);
kind()168   Code::Kind kind() const { return kind_; }
is_keyed()169   bool is_keyed() const {
170     return kind_ == Code::KEYED_LOAD_IC || kind_ == Code::KEYED_STORE_IC;
171   }
handler_kind()172   Code::Kind handler_kind() const {
173     if (kind_ == Code::KEYED_LOAD_IC) return Code::LOAD_IC;
174     DCHECK(kind_ == Code::LOAD_IC || kind_ == Code::STORE_IC ||
175            kind_ == Code::KEYED_STORE_IC);
176     return kind_;
177   }
178   bool ShouldRecomputeHandler(Handle<String> name);
179 
extra_ic_state()180   ExtraICState extra_ic_state() const { return extra_ic_state_; }
181 
receiver_map()182   Handle<Map> receiver_map() { return receiver_map_; }
update_receiver_map(Handle<Object> receiver)183   void update_receiver_map(Handle<Object> receiver) {
184     if (receiver->IsSmi()) {
185       receiver_map_ = isolate_->factory()->heap_number_map();
186     } else {
187       receiver_map_ = handle(HeapObject::cast(*receiver)->map());
188     }
189   }
190 
TargetMaps(MapHandleList * list)191   void TargetMaps(MapHandleList* list) {
192     FindTargetMaps();
193     for (int i = 0; i < target_maps_.length(); i++) {
194       list->Add(target_maps_.at(i));
195     }
196   }
197 
FirstTargetMap()198   Map* FirstTargetMap() {
199     FindTargetMaps();
200     return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL;
201   }
202 
vector()203   Handle<TypeFeedbackVector> vector() const { return nexus()->vector_handle(); }
slot()204   FeedbackVectorSlot slot() const { return nexus()->slot(); }
saved_state()205   State saved_state() const {
206     return state() == RECOMPUTE_HANDLER ? old_state_ : state();
207   }
208 
209   template <class NexusClass>
casted_nexus()210   NexusClass* casted_nexus() {
211     return static_cast<NexusClass*>(nexus_);
212   }
nexus()213   FeedbackNexus* nexus() const { return nexus_; }
214 
215   inline Code* get_host();
216   inline Code* target() const;
217 
218  private:
219   inline Address constant_pool() const;
220   inline Address raw_constant_pool() const;
221 
FindTargetMaps()222   void FindTargetMaps() {
223     if (target_maps_set_) return;
224     target_maps_set_ = true;
225     DCHECK(UseVector());
226     nexus()->ExtractMaps(&target_maps_);
227   }
228 
229   // Frame pointer for the frame that uses (calls) the IC.
230   Address fp_;
231 
232   // All access to the program counter and constant pool of an IC structure is
233   // indirect to make the code GC safe. This feature is crucial since
234   // GetProperty and SetProperty are called and they in turn might
235   // invoke the garbage collector.
236   Address* pc_address_;
237 
238   // The constant pool of the code which originally called the IC (which might
239   // be for the breakpointed copy of the original code).
240   Address* constant_pool_address_;
241 
242   Isolate* isolate_;
243 
244   bool vector_set_;
245   State old_state_;  // For saving if we marked as prototype failure.
246   State state_;
247   Code::Kind kind_;
248   Handle<Map> receiver_map_;
249   MaybeHandle<Object> maybe_handler_;
250 
251   ExtraICState extra_ic_state_;
252   MapHandleList target_maps_;
253   bool target_maps_set_;
254 
255   FeedbackNexus* nexus_;
256 
257   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
258 };
259 
260 
261 class CallIC : public IC {
262  public:
CallIC(Isolate * isolate,CallICNexus * nexus)263   CallIC(Isolate* isolate, CallICNexus* nexus)
264       : IC(EXTRA_CALL_FRAME, isolate, nexus) {
265     DCHECK(nexus != NULL);
266   }
267 
268   void HandleMiss(Handle<Object> function);
269 
270   static void Clear(Isolate* isolate, Code* host, CallICNexus* nexus);
271 };
272 
273 
274 class LoadIC : public IC {
275  public:
276   LoadIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
IC(depth,isolate,nexus)277       : IC(depth, isolate, nexus) {
278     DCHECK(nexus != NULL);
279     DCHECK(IsLoadStub());
280   }
281 
ShouldThrowReferenceError()282   bool ShouldThrowReferenceError() const {
283     return kind() == Code::LOAD_GLOBAL_IC &&
284            LoadGlobalICState::GetTypeofMode(extra_ic_state()) ==
285                NOT_INSIDE_TYPEOF;
286   }
287 
288   // Code generator routines.
289 
290   static void GenerateMiss(MacroAssembler* masm);
291   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
292   static void GenerateNormal(MacroAssembler* masm);
293 
294   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
295                                            Handle<Name> name);
296 
297   static void Clear(Isolate* isolate, Code* host, LoadICNexus* nexus);
298 
299  protected:
slow_stub()300   virtual Handle<Code> slow_stub() const {
301     return isolate()->builtins()->LoadIC_Slow();
302   }
303 
304   // Update the inline cache and the global stub cache based on the
305   // lookup result.
306   void UpdateCaches(LookupIterator* lookup);
307 
308   Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
309 
310   Handle<Object> CompileHandler(LookupIterator* lookup, Handle<Object> unused,
311                                 CacheHolderFlag cache_holder) override;
312 
313  private:
314   // Creates a data handler that represents a load of a field by given index.
315   Handle<Object> SimpleFieldLoad(FieldIndex index);
316 
317   // Creates a data handler that represents a prototype chain check followed
318   // by given Smi-handler that encoded a load from the holder.
319   // Can be used only if GetPrototypeCheckCount() returns non negative value.
320   Handle<Object> LoadFromPrototype(Handle<Map> receiver_map,
321                                    Handle<JSObject> holder, Handle<Name> name,
322                                    Handle<Object> smi_handler);
323 
324   // Creates a data handler that represents a load of a non-existent property.
325   Handle<Object> LoadNonExistent(Handle<Map> receiver_map, Handle<Name> name);
326 
327   friend class IC;
328 };
329 
330 class LoadGlobalIC : public LoadIC {
331  public:
332   LoadGlobalIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
LoadIC(depth,isolate,nexus)333       : LoadIC(depth, isolate, nexus) {}
334 
335   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Name> name);
336 
337   static void Clear(Isolate* isolate, Code* host, LoadGlobalICNexus* nexus);
338 
339  protected:
slow_stub()340   Handle<Code> slow_stub() const override {
341     return isolate()->builtins()->LoadGlobalIC_Slow();
342   }
343 };
344 
345 class KeyedLoadIC : public LoadIC {
346  public:
347   KeyedLoadIC(FrameDepth depth, Isolate* isolate,
348               KeyedLoadICNexus* nexus = NULL)
LoadIC(depth,isolate,nexus)349       : LoadIC(depth, isolate, nexus) {
350     DCHECK(nexus != NULL);
351   }
352 
353   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
354                                            Handle<Object> key);
355 
356   // Code generator routines.
357   static void GenerateMiss(MacroAssembler* masm);
358   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
359 
360   static void Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus);
361 
362  protected:
363   // receiver is HeapObject because it could be a String or a JSObject
364   void UpdateLoadElement(Handle<HeapObject> receiver);
365 
366  private:
367   friend class IC;
368 };
369 
370 
371 class StoreIC : public IC {
372  public:
373   StoreIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
IC(depth,isolate,nexus)374       : IC(depth, isolate, nexus) {
375     DCHECK(IsStoreStub());
376   }
377 
language_mode()378   LanguageMode language_mode() const {
379     return StoreICState::GetLanguageMode(extra_ic_state());
380   }
381 
382   // Code generators for stub routines. Only called once at startup.
383   static void GenerateSlow(MacroAssembler* masm);
384   static void GenerateMiss(MacroAssembler* masm);
385   static void GenerateNormal(MacroAssembler* masm);
386 
387   MUST_USE_RESULT MaybeHandle<Object> Store(
388       Handle<Object> object, Handle<Name> name, Handle<Object> value,
389       JSReceiver::StoreFromKeyed store_mode =
390           JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
391 
392   bool LookupForWrite(LookupIterator* it, Handle<Object> value,
393                       JSReceiver::StoreFromKeyed store_mode);
394 
395   static void Clear(Isolate* isolate, Code* host, StoreICNexus* nexus);
396 
397  protected:
398   // Stub accessors.
slow_stub()399   Handle<Code> slow_stub() const {
400     switch (language_mode()) {
401       case SLOPPY:
402         return isolate()->builtins()->StoreIC_SlowSloppy();
403       case STRICT:
404         return isolate()->builtins()->StoreIC_SlowStrict();
405       default:
406         UNREACHABLE();
407         return Handle<Code>();
408     }
409   }
410 
411   // Update the inline cache and the global stub cache based on the
412   // lookup result.
413   void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
414                     JSReceiver::StoreFromKeyed store_mode);
415   Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
416   Handle<Object> CompileHandler(LookupIterator* lookup, Handle<Object> value,
417                                 CacheHolderFlag cache_holder) override;
418 
419  private:
420   Handle<Object> StoreTransition(Handle<Map> receiver_map,
421                                  Handle<JSObject> holder,
422                                  Handle<Map> transition, Handle<Name> name);
423 
424   friend class IC;
425 };
426 
427 
428 enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
429 
430 
431 enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
432 
433 
434 class KeyedStoreIC : public StoreIC {
435  public:
GetKeyedAccessStoreMode()436   KeyedAccessStoreMode GetKeyedAccessStoreMode() {
437     return casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
438   }
439 
440   KeyedStoreIC(FrameDepth depth, Isolate* isolate,
441                KeyedStoreICNexus* nexus = NULL)
StoreIC(depth,isolate,nexus)442       : StoreIC(depth, isolate, nexus) {}
443 
444   MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
445                                             Handle<Object> name,
446                                             Handle<Object> value);
447 
448   // Code generators for stub routines.  Only called once at startup.
449   static void GenerateMiss(MacroAssembler* masm);
450   static void GenerateSlow(MacroAssembler* masm);
451   static void GenerateMegamorphic(MacroAssembler* masm,
452                                   LanguageMode language_mode);
453 
454   static Handle<Code> ChooseMegamorphicStub(Isolate* isolate,
455                                             ExtraICState extra_state);
456 
457   static void Clear(Isolate* isolate, Code* host, KeyedStoreICNexus* nexus);
458 
459  protected:
460   void UpdateStoreElement(Handle<Map> receiver_map,
461                           KeyedAccessStoreMode store_mode);
462 
463  private:
464   Handle<Map> ComputeTransitionedMap(Handle<Map> map,
465                                      KeyedAccessStoreMode store_mode);
466 
467   friend class IC;
468 };
469 
470 
471 // Type Recording BinaryOpIC, that records the types of the inputs and outputs.
472 class BinaryOpIC : public IC {
473  public:
BinaryOpIC(Isolate * isolate)474   explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
475 
476   MaybeHandle<Object> Transition(Handle<AllocationSite> allocation_site,
477                                  Handle<Object> left,
478                                  Handle<Object> right) WARN_UNUSED_RESULT;
479 };
480 
481 
482 class CompareIC : public IC {
483  public:
CompareIC(Isolate * isolate,Token::Value op)484   CompareIC(Isolate* isolate, Token::Value op)
485       : IC(EXTRA_CALL_FRAME, isolate), op_(op) {}
486 
487   // Update the inline cache for the given operands.
488   Code* UpdateCaches(Handle<Object> x, Handle<Object> y);
489 
490   // Helper function for computing the condition for a compare operation.
491   static Condition ComputeCondition(Token::Value op);
492 
493  private:
494   static bool HasInlinedSmiCode(Address address);
495 
strict()496   bool strict() const { return op_ == Token::EQ_STRICT; }
GetCondition()497   Condition GetCondition() const { return ComputeCondition(op_); }
498 
499   static Code* GetRawUninitialized(Isolate* isolate, Token::Value op);
500 
501   static void Clear(Isolate* isolate, Address address, Code* target,
502                     Address constant_pool);
503 
504   Token::Value op_;
505 
506   friend class IC;
507 };
508 
509 
510 class ToBooleanIC : public IC {
511  public:
ToBooleanIC(Isolate * isolate)512   explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
513 
514   Handle<Object> ToBoolean(Handle<Object> object);
515 };
516 
517 
518 // Helper for BinaryOpIC and CompareIC.
519 enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
520 void PatchInlinedSmiCode(Isolate* isolate, Address address,
521                          InlinedSmiCheck check);
522 
523 }  // namespace internal
524 }  // namespace v8
525 
526 #endif  // V8_IC_H_
527