• 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/common/message-template.h"
11 #include "src/execution/isolate.h"
12 #include "src/heap/factory.h"
13 #include "src/ic/stub-cache.h"
14 #include "src/objects/feedback-vector.h"
15 #include "src/objects/map.h"
16 #include "src/objects/maybe-object.h"
17 #include "src/objects/smi.h"
18 
19 namespace v8 {
20 namespace internal {
21 
22 enum class NamedPropertyType : bool { kNotOwn, kOwn };
23 
24 //
25 // IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC.
26 //
27 class IC {
28  public:
29   // Alias the inline cache state type to make the IC code more readable.
30   using State = InlineCacheState;
31 
32   // Construct the IC structure with the given number of extra
33   // JavaScript frames on the stack.
34   IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
35      FeedbackSlotKind kind);
36   virtual ~IC() = default;
37 
state()38   State state() const { return state_; }
39 
40   // Compute the current IC state based on the target stub, lookup_start_object
41   // and name.
42   void UpdateState(Handle<Object> lookup_start_object, Handle<Object> name);
43 
44   bool RecomputeHandlerForName(Handle<Object> name);
MarkRecomputeHandler(Handle<Object> name)45   void MarkRecomputeHandler(Handle<Object> name) {
46     DCHECK(RecomputeHandlerForName(name));
47     old_state_ = state_;
48     state_ = RECOMPUTE_HANDLER;
49   }
50 
IsAnyHas()51   bool IsAnyHas() const { return IsKeyedHasIC(); }
IsAnyLoad()52   bool IsAnyLoad() const {
53     return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
54   }
IsAnyStore()55   bool IsAnyStore() const {
56     return IsStoreIC() || IsStoreOwnIC() || IsStoreGlobalIC() ||
57            IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind());
58   }
59 
60   static inline bool IsHandler(MaybeObject object);
61 
62   // Nofity the IC system that a feedback has changed.
63   static void OnFeedbackChanged(Isolate* isolate, FeedbackVector vector,
64                                 FeedbackSlot slot, const char* reason);
65 
66   void OnFeedbackChanged(const char* reason);
67 
68  protected:
set_slow_stub_reason(const char * reason)69   void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; }
70 
isolate()71   Isolate* isolate() const { return isolate_; }
72 
is_vector_set()73   bool is_vector_set() { return vector_set_; }
74   inline bool vector_needs_update();
75 
76   // Configure for most states.
77   bool ConfigureVectorState(IC::State new_state, Handle<Object> key);
78   // Configure the vector for MONOMORPHIC.
79   void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
80                             Handle<Object> handler);
81   void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
82                             const MaybeObjectHandle& handler);
83   // Configure the vector for POLYMORPHIC.
84   void ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
85                             MaybeObjectHandles* handlers);
86   void ConfigureVectorState(
87       Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers);
88 
89   char TransitionMarkFromState(IC::State state);
90   void TraceIC(const char* type, Handle<Object> name);
91   void TraceIC(const char* type, Handle<Object> name, State old_state,
92                State new_state);
93 
94   MaybeHandle<Object> TypeError(MessageTemplate, Handle<Object> object,
95                                 Handle<Object> key);
96   MaybeHandle<Object> ReferenceError(Handle<Name> name);
97 
98   void UpdateMonomorphicIC(const MaybeObjectHandle& handler, Handle<Name> name);
99   bool UpdatePolymorphicIC(Handle<Name> name, const MaybeObjectHandle& handler);
100   void UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
101                               const MaybeObjectHandle& handler);
102 
103   StubCache* stub_cache();
104 
105   void CopyICToMegamorphicCache(Handle<Name> name);
106   bool IsTransitionOfMonomorphicTarget(Map source_map, Map target_map);
107   void SetCache(Handle<Name> name, Handle<Object> handler);
108   void SetCache(Handle<Name> name, const MaybeObjectHandle& handler);
kind()109   FeedbackSlotKind kind() const { return kind_; }
IsGlobalIC()110   bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); }
IsLoadIC()111   bool IsLoadIC() const { return IsLoadICKind(kind_); }
IsLoadGlobalIC()112   bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
IsKeyedLoadIC()113   bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
IsStoreGlobalIC()114   bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); }
IsStoreIC()115   bool IsStoreIC() const { return IsStoreICKind(kind_); }
IsStoreOwnIC()116   bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
IsKeyedStoreIC()117   bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
IsKeyedHasIC()118   bool IsKeyedHasIC() const { return IsKeyedHasICKind(kind_); }
is_keyed()119   bool is_keyed() const {
120     return IsKeyedLoadIC() || IsKeyedStoreIC() ||
121            IsStoreInArrayLiteralICKind(kind_) || IsKeyedHasIC();
122   }
123   bool ShouldRecomputeHandler(Handle<String> name);
124 
lookup_start_object_map()125   Handle<Map> lookup_start_object_map() { return lookup_start_object_map_; }
126   inline void update_lookup_start_object_map(Handle<Object> object);
127 
TargetMaps(MapHandles * list)128   void TargetMaps(MapHandles* list) {
129     FindTargetMaps();
130     for (Handle<Map> map : target_maps_) {
131       list->push_back(map);
132     }
133   }
134 
FirstTargetMap()135   Map FirstTargetMap() {
136     FindTargetMaps();
137     return !target_maps_.empty() ? *target_maps_[0] : Map();
138   }
139 
nexus()140   const FeedbackNexus* nexus() const { return &nexus_; }
nexus()141   FeedbackNexus* nexus() { return &nexus_; }
142 
143  private:
FindTargetMaps()144   void FindTargetMaps() {
145     if (target_maps_set_) return;
146     target_maps_set_ = true;
147     nexus()->ExtractMaps(&target_maps_);
148   }
149 
150   Isolate* isolate_;
151 
152   bool vector_set_;
153   State old_state_;  // For saving if we marked as prototype failure.
154   State state_;
155   FeedbackSlotKind kind_;
156   Handle<Map> lookup_start_object_map_;
157 
158   MapHandles target_maps_;
159   bool target_maps_set_;
160 
161   const char* slow_stub_reason_;
162 
163   FeedbackNexus nexus_;
164 
165   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
166 };
167 
168 class LoadIC : public IC {
169  public:
LoadIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot,FeedbackSlotKind kind)170   LoadIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
171          FeedbackSlotKind kind)
172       : IC(isolate, vector, slot, kind) {
173     DCHECK(IsAnyLoad() || IsAnyHas());
174   }
175 
ShouldThrowReferenceError(FeedbackSlotKind kind)176   static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
177     return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
178   }
179 
ShouldThrowReferenceError()180   bool ShouldThrowReferenceError() const {
181     return ShouldThrowReferenceError(kind());
182   }
183 
184   // If receiver is empty, use object as the receiver.
185   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(
186       Handle<Object> object, Handle<Name> name, bool update_feedback = true,
187       Handle<Object> receiver = Handle<Object>());
188 
189  protected:
190   // Update the inline cache and the global stub cache based on the
191   // lookup result.
192   void UpdateCaches(LookupIterator* lookup);
193 
194  private:
195   Handle<Object> ComputeHandler(LookupIterator* lookup);
196 
197   friend class IC;
198   friend class NamedLoadHandlerCompiler;
199 };
200 
201 class LoadGlobalIC : public LoadIC {
202  public:
LoadGlobalIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot,FeedbackSlotKind kind)203   LoadGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
204                FeedbackSlot slot, FeedbackSlotKind kind)
205       : LoadIC(isolate, vector, slot, kind) {}
206 
207   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name,
208                                                  bool update_feedback = true);
209 };
210 
211 class KeyedLoadIC : public LoadIC {
212  public:
KeyedLoadIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot,FeedbackSlotKind kind)213   KeyedLoadIC(Isolate* isolate, Handle<FeedbackVector> vector,
214               FeedbackSlot slot, FeedbackSlotKind kind)
215       : LoadIC(isolate, vector, slot, kind) {}
216 
217   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Object> object,
218                                                  Handle<Object> key);
219 
220  protected:
221   V8_WARN_UNUSED_RESULT MaybeHandle<Object> RuntimeLoad(Handle<Object> object,
222                                                         Handle<Object> key);
223 
224   // receiver is HeapObject because it could be a String or a JSObject
225   void UpdateLoadElement(Handle<HeapObject> receiver,
226                          KeyedAccessLoadMode load_mode);
227 
228  private:
229   friend class IC;
230 
231   Handle<Object> LoadElementHandler(Handle<Map> receiver_map,
232                                     KeyedAccessLoadMode load_mode);
233 
234   void LoadElementPolymorphicHandlers(MapHandles* receiver_maps,
235                                       MaybeObjectHandles* handlers,
236                                       KeyedAccessLoadMode load_mode);
237 
238   // Returns true if the receiver_map has a kElement or kIndexedString
239   // handler in the nexus currently but didn't yet allow out of bounds
240   // accesses.
241   bool CanChangeToAllowOutOfBounds(Handle<Map> receiver_map);
242 };
243 
244 class StoreIC : public IC {
245  public:
StoreIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot,FeedbackSlotKind kind)246   StoreIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
247           FeedbackSlotKind kind)
248       : IC(isolate, vector, slot, kind) {
249     DCHECK(IsAnyStore());
250   }
251 
252   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(
253       Handle<Object> object, Handle<Name> name, Handle<Object> value,
254       StoreOrigin store_origin = StoreOrigin::kNamed);
255 
256   bool LookupForWrite(LookupIterator* it, Handle<Object> value,
257                       StoreOrigin store_origin);
258 
259  protected:
260   // Stub accessors.
261   // Update the inline cache and the global stub cache based on the
262   // lookup result.
263   void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
264                     StoreOrigin store_origin);
265 
266  private:
267   MaybeObjectHandle ComputeHandler(LookupIterator* lookup);
268 
269   friend class IC;
270 };
271 
272 class StoreGlobalIC : public StoreIC {
273  public:
StoreGlobalIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot,FeedbackSlotKind kind)274   StoreGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
275                 FeedbackSlot slot, FeedbackSlotKind kind)
276       : StoreIC(isolate, vector, slot, kind) {}
277 
278   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Name> name,
279                                                   Handle<Object> value);
280 };
281 
282 enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
283 
284 enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
285 
286 enum class TransitionMode {
287   kNoTransition,
288   kTransitionToDouble,
289   kTransitionToObject
290 };
291 
292 class KeyedStoreIC : public StoreIC {
293  public:
GetKeyedAccessStoreMode()294   KeyedAccessStoreMode GetKeyedAccessStoreMode() {
295     return nexus()->GetKeyedAccessStoreMode();
296   }
297 
KeyedStoreIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot,FeedbackSlotKind kind)298   KeyedStoreIC(Isolate* isolate, Handle<FeedbackVector> vector,
299                FeedbackSlot slot, FeedbackSlotKind kind)
300       : StoreIC(isolate, vector, slot, kind) {}
301 
302   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Object> object,
303                                                   Handle<Object> name,
304                                                   Handle<Object> value);
305 
306  protected:
307   void UpdateStoreElement(Handle<Map> receiver_map,
308                           KeyedAccessStoreMode store_mode,
309                           Handle<Map> new_receiver_map);
310 
311  private:
312   Handle<Map> ComputeTransitionedMap(Handle<Map> map,
313                                      TransitionMode transition_mode);
314 
315   Handle<Object> StoreElementHandler(
316       Handle<Map> receiver_map, KeyedAccessStoreMode store_mode,
317       MaybeHandle<Object> prev_validity_cell = MaybeHandle<Object>());
318 
319   void StoreElementPolymorphicHandlers(
320       std::vector<MapAndHandler>* receiver_maps_and_handlers,
321       KeyedAccessStoreMode store_mode);
322 
323   friend class IC;
324 };
325 
326 class StoreInArrayLiteralIC : public KeyedStoreIC {
327  public:
StoreInArrayLiteralIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)328   StoreInArrayLiteralIC(Isolate* isolate, Handle<FeedbackVector> vector,
329                         FeedbackSlot slot)
330       : KeyedStoreIC(isolate, vector, slot,
331                      FeedbackSlotKind::kStoreInArrayLiteral) {
332     DCHECK(IsStoreInArrayLiteralICKind(kind()));
333   }
334 
335   void Store(Handle<JSArray> array, Handle<Object> index, Handle<Object> value);
336 };
337 
338 }  // namespace internal
339 }  // namespace v8
340 
341 #endif  // V8_IC_IC_H_
342