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