• 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_IC_H_
6 #define V8_IC_IC_H_
7 
8 #include <vector>
9 
10 #include "src/feedback-vector.h"
11 #include "src/heap/factory.h"
12 #include "src/ic/stub-cache.h"
13 #include "src/isolate.h"
14 #include "src/macro-assembler.h"
15 #include "src/messages.h"
16 #include "src/objects/map.h"
17 #include "src/objects/maybe-object.h"
18 
19 namespace v8 {
20 namespace internal {
21 
22 //
23 // IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC.
24 //
25 class IC {
26  public:
27   // Alias the inline cache state type to make the IC code more readable.
28   typedef InlineCacheState State;
29 
30   static constexpr int kMaxKeyedPolymorphism = 4;
31 
32   // A polymorphic IC can handle at most 4 distinct maps before transitioning
33   // to megamorphic state.
34   static constexpr int kMaxPolymorphicMapCount = 4;
35 
36   // Construct the IC structure with the given number of extra
37   // JavaScript frames on the stack.
38   IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot);
~IC()39   virtual ~IC() {}
40 
state()41   State state() const { return state_; }
42   inline Address address() const;
43 
44   // Compute the current IC state based on the target stub, receiver and name.
45   void UpdateState(Handle<Object> receiver, Handle<Object> name);
46 
47   bool RecomputeHandlerForName(Handle<Object> name);
MarkRecomputeHandler(Handle<Object> name)48   void MarkRecomputeHandler(Handle<Object> name) {
49     DCHECK(RecomputeHandlerForName(name));
50     old_state_ = state_;
51     state_ = RECOMPUTE_HANDLER;
52   }
53 
IsAnyLoad()54   bool IsAnyLoad() const {
55     return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
56   }
IsAnyStore()57   bool IsAnyStore() const {
58     return IsStoreIC() || IsStoreOwnIC() || IsStoreGlobalIC() ||
59            IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind());
60   }
61 
62   static inline bool IsHandler(MaybeObject* object);
63 
64   // Nofity the IC system that a feedback has changed.
65   static void OnFeedbackChanged(Isolate* isolate, FeedbackVector* vector,
66                                 FeedbackSlot slot, JSFunction* host_function,
67                                 const char* reason);
68 
69   static void OnFeedbackChanged(Isolate* isolate, FeedbackNexus* nexus,
70                                 JSFunction* host_function, const char* reason);
71 
72  protected:
fp()73   Address fp() const { return fp_; }
pc()74   Address pc() const { return *pc_address_; }
75 
set_slow_stub_reason(const char * reason)76   void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; }
77 
isolate()78   Isolate* isolate() const { return isolate_; }
79 
80   // Get the caller function object.
81   JSFunction* GetHostFunction() const;
82 
83   inline bool AddressIsDeoptimizedCode() const;
84   inline static bool AddressIsDeoptimizedCode(Isolate* isolate,
85                                               Address address);
86 
is_vector_set()87   bool is_vector_set() { return vector_set_; }
vector_needs_update()88   bool vector_needs_update() {
89     return (!vector_set_ &&
90             (state() != MEGAMORPHIC ||
91              Smi::ToInt(nexus()->GetFeedbackExtra()->ToSmi()) != ELEMENT));
92   }
93 
94   // Configure for most states.
95   bool ConfigureVectorState(IC::State new_state, Handle<Object> key);
96   // Configure the vector for PREMONOMORPHIC.
97   void ConfigureVectorState(Handle<Map> map);
98   // Configure the vector for MONOMORPHIC.
99   void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
100                             Handle<Object> handler);
101   void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
102                             const MaybeObjectHandle& handler);
103   // Configure the vector for POLYMORPHIC.
104   void ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
105                             MaybeObjectHandles* handlers);
106 
107   char TransitionMarkFromState(IC::State state);
108   void TraceIC(const char* type, Handle<Object> name);
109   void TraceIC(const char* type, Handle<Object> name, State old_state,
110                State new_state);
111 
112   MaybeHandle<Object> TypeError(MessageTemplate::Template,
113                                 Handle<Object> object, Handle<Object> key);
114   MaybeHandle<Object> ReferenceError(Handle<Name> name);
115 
116   void TraceHandlerCacheHitStats(LookupIterator* lookup);
117 
118   void UpdateMonomorphicIC(const MaybeObjectHandle& handler, Handle<Name> name);
119   bool UpdatePolymorphicIC(Handle<Name> name, const MaybeObjectHandle& handler);
120   void UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
121                               const MaybeObjectHandle& handler);
122 
123   StubCache* stub_cache();
124 
125   void CopyICToMegamorphicCache(Handle<Name> name);
126   bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
127   void PatchCache(Handle<Name> name, Handle<Object> handler);
128   void PatchCache(Handle<Name> name, const MaybeObjectHandle& handler);
kind()129   FeedbackSlotKind kind() const { return kind_; }
IsGlobalIC()130   bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); }
IsLoadIC()131   bool IsLoadIC() const { return IsLoadICKind(kind_); }
IsLoadGlobalIC()132   bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
IsKeyedLoadIC()133   bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
IsStoreGlobalIC()134   bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); }
IsStoreIC()135   bool IsStoreIC() const { return IsStoreICKind(kind_); }
IsStoreOwnIC()136   bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
IsKeyedStoreIC()137   bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
is_keyed()138   bool is_keyed() const {
139     return IsKeyedLoadIC() || IsKeyedStoreIC() ||
140            IsStoreInArrayLiteralICKind(kind_);
141   }
142   bool ShouldRecomputeHandler(Handle<String> name);
143 
receiver_map()144   Handle<Map> receiver_map() { return receiver_map_; }
145   inline void update_receiver_map(Handle<Object> receiver);
146 
TargetMaps(MapHandles * list)147   void TargetMaps(MapHandles* list) {
148     FindTargetMaps();
149     for (Handle<Map> map : target_maps_) {
150       list->push_back(map);
151     }
152   }
153 
FirstTargetMap()154   Map* FirstTargetMap() {
155     FindTargetMaps();
156     return !target_maps_.empty() ? *target_maps_[0] : nullptr;
157   }
158 
saved_state()159   State saved_state() const {
160     return state() == RECOMPUTE_HANDLER ? old_state_ : state();
161   }
162 
nexus()163   const FeedbackNexus* nexus() const { return &nexus_; }
nexus()164   FeedbackNexus* nexus() { return &nexus_; }
165 
166  private:
167   inline Address constant_pool() const;
168   inline Address raw_constant_pool() const;
169 
FindTargetMaps()170   void FindTargetMaps() {
171     if (target_maps_set_) return;
172     target_maps_set_ = true;
173     nexus()->ExtractMaps(&target_maps_);
174   }
175 
176   // Frame pointer for the frame that uses (calls) the IC.
177   Address fp_;
178 
179   // All access to the program counter and constant pool of an IC structure is
180   // indirect to make the code GC safe. This feature is crucial since
181   // GetProperty and SetProperty are called and they in turn might
182   // invoke the garbage collector.
183   Address* pc_address_;
184 
185   // The constant pool of the code which originally called the IC (which might
186   // be for the breakpointed copy of the original code).
187   Address* constant_pool_address_;
188 
189   Isolate* isolate_;
190 
191   bool vector_set_;
192   State old_state_;  // For saving if we marked as prototype failure.
193   State state_;
194   FeedbackSlotKind kind_;
195   Handle<Map> receiver_map_;
196   MaybeObjectHandle maybe_handler_;
197 
198   MapHandles target_maps_;
199   bool target_maps_set_;
200 
201   const char* slow_stub_reason_;
202 
203   FeedbackNexus nexus_;
204 
205   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
206 };
207 
208 
209 class LoadIC : public IC {
210  public:
LoadIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)211   LoadIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
212       : IC(isolate, vector, slot) {
213     DCHECK(IsAnyLoad());
214   }
215 
ShouldThrowReferenceError(FeedbackSlotKind kind)216   static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
217     return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
218   }
219 
ShouldThrowReferenceError()220   bool ShouldThrowReferenceError() const {
221     return ShouldThrowReferenceError(kind());
222   }
223 
224   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Object> object,
225                                                  Handle<Name> name);
226 
227  protected:
slow_stub()228   virtual Handle<Code> slow_stub() const {
229     return BUILTIN_CODE(isolate(), LoadIC_Slow);
230   }
231 
232   // Update the inline cache and the global stub cache based on the
233   // lookup result.
234   void UpdateCaches(LookupIterator* lookup);
235 
236  private:
237   Handle<Object> ComputeHandler(LookupIterator* lookup);
238 
239   friend class IC;
240   friend class NamedLoadHandlerCompiler;
241 };
242 
243 class LoadGlobalIC : public LoadIC {
244  public:
LoadGlobalIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)245   LoadGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
246                FeedbackSlot slot)
247       : LoadIC(isolate, vector, slot) {}
248 
249   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name);
250 
251  protected:
slow_stub()252   Handle<Code> slow_stub() const override {
253     return BUILTIN_CODE(isolate(), LoadGlobalIC_Slow);
254   }
255 };
256 
257 class KeyedLoadIC : public LoadIC {
258  public:
KeyedLoadIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)259   KeyedLoadIC(Isolate* isolate, Handle<FeedbackVector> vector,
260               FeedbackSlot slot)
261       : LoadIC(isolate, vector, slot) {}
262 
263   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Object> object,
264                                                  Handle<Object> key);
265 
266  protected:
267   // receiver is HeapObject because it could be a String or a JSObject
268   void UpdateLoadElement(Handle<HeapObject> receiver,
269                          KeyedAccessLoadMode load_mode);
270 
271  private:
272   friend class IC;
273 
274   Handle<Object> LoadElementHandler(Handle<Map> receiver_map,
275                                     KeyedAccessLoadMode load_mode);
276 
277   void LoadElementPolymorphicHandlers(MapHandles* receiver_maps,
278                                       MaybeObjectHandles* handlers,
279                                       KeyedAccessLoadMode load_mode);
280 
281   // Returns true if the receiver_map has a kElement or kIndexedString
282   // handler in the nexus currently but didn't yet allow out of bounds
283   // accesses.
284   bool CanChangeToAllowOutOfBounds(Handle<Map> receiver_map);
285 };
286 
287 
288 class StoreIC : public IC {
289  public:
StoreIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)290   StoreIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
291       : IC(isolate, vector, slot) {
292     DCHECK(IsAnyStore());
293   }
294 
language_mode()295   LanguageMode language_mode() const { return nexus()->GetLanguageMode(); }
296 
297   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(
298       Handle<Object> object, Handle<Name> name, Handle<Object> value,
299       JSReceiver::StoreFromKeyed store_mode =
300           JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
301 
302   bool LookupForWrite(LookupIterator* it, Handle<Object> value,
303                       JSReceiver::StoreFromKeyed store_mode);
304 
305  protected:
306   // Stub accessors.
slow_stub()307   virtual Handle<Code> slow_stub() const {
308     // All StoreICs share the same slow stub.
309     return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
310   }
311 
312   // Update the inline cache and the global stub cache based on the
313   // lookup result.
314   void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
315                     JSReceiver::StoreFromKeyed store_mode);
316 
317  private:
318   MaybeObjectHandle ComputeHandler(LookupIterator* lookup);
319 
320   friend class IC;
321 };
322 
323 class StoreGlobalIC : public StoreIC {
324  public:
StoreGlobalIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)325   StoreGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
326                 FeedbackSlot slot)
327       : StoreIC(isolate, vector, slot) {}
328 
329   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Name> name,
330                                                   Handle<Object> value);
331 
332  protected:
slow_stub()333   Handle<Code> slow_stub() const override {
334     return BUILTIN_CODE(isolate(), StoreGlobalIC_Slow);
335   }
336 };
337 
338 enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
339 
340 
341 enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
342 
343 
344 class KeyedStoreIC : public StoreIC {
345  public:
GetKeyedAccessStoreMode()346   KeyedAccessStoreMode GetKeyedAccessStoreMode() {
347     return nexus()->GetKeyedAccessStoreMode();
348   }
349 
KeyedStoreIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)350   KeyedStoreIC(Isolate* isolate, Handle<FeedbackVector> vector,
351                FeedbackSlot slot)
352       : StoreIC(isolate, vector, slot) {}
353 
354   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Object> object,
355                                                   Handle<Object> name,
356                                                   Handle<Object> value);
357 
358  protected:
359   void UpdateStoreElement(Handle<Map> receiver_map,
360                           KeyedAccessStoreMode store_mode,
361                           bool receiver_was_cow);
362 
slow_stub()363   Handle<Code> slow_stub() const override {
364     return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
365   }
366 
367  private:
368   Handle<Map> ComputeTransitionedMap(Handle<Map> map,
369                                      KeyedAccessStoreMode store_mode);
370 
371   Handle<Object> StoreElementHandler(Handle<Map> receiver_map,
372                                      KeyedAccessStoreMode store_mode);
373 
374   void StoreElementPolymorphicHandlers(MapHandles* receiver_maps,
375                                        MaybeObjectHandles* handlers,
376                                        KeyedAccessStoreMode store_mode);
377 
378   friend class IC;
379 };
380 
381 class StoreInArrayLiteralIC : public KeyedStoreIC {
382  public:
StoreInArrayLiteralIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)383   StoreInArrayLiteralIC(Isolate* isolate, Handle<FeedbackVector> vector,
384                         FeedbackSlot slot)
385       : KeyedStoreIC(isolate, vector, slot) {
386     DCHECK(IsStoreInArrayLiteralICKind(kind()));
387   }
388 
389   void Store(Handle<JSArray> array, Handle<Object> index, Handle<Object> value);
390 
391  private:
slow_stub()392   Handle<Code> slow_stub() const override {
393     return BUILTIN_CODE(isolate(), StoreInArrayLiteralIC_Slow);
394   }
395 };
396 
397 }  // namespace internal
398 }  // namespace v8
399 
400 #endif  // V8_IC_IC_H_
401