Line data Source code
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/message-template.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 : typedef InlineCacheState State;
31 :
32 : static constexpr int kMaxKeyedPolymorphism = 4;
33 :
34 : // A polymorphic IC can handle at most 4 distinct maps before transitioning
35 : // to megamorphic state.
36 : static constexpr int kMaxPolymorphicMapCount = 4;
37 :
38 : // Construct the IC structure with the given number of extra
39 : // JavaScript frames on the stack.
40 : IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
41 : FeedbackSlotKind kind);
42 6853648 : virtual ~IC() = default;
43 :
44 : State state() const { return state_; }
45 : inline Address address() const;
46 :
47 : // Compute the current IC state based on the target stub, receiver and name.
48 : void UpdateState(Handle<Object> receiver, Handle<Object> name);
49 :
50 : bool RecomputeHandlerForName(Handle<Object> name);
51 : void MarkRecomputeHandler(Handle<Object> name) {
52 : DCHECK(RecomputeHandlerForName(name));
53 56655 : old_state_ = state_;
54 56655 : state_ = RECOMPUTE_HANDLER;
55 : }
56 :
57 705759 : bool IsAnyLoad() const {
58 1129976 : return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
59 : }
60 : bool IsAnyStore() const {
61 : return IsStoreIC() || IsStoreOwnIC() || IsStoreGlobalIC() ||
62 : IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind());
63 : }
64 :
65 : static inline bool IsHandler(MaybeObject object);
66 :
67 : // Nofity the IC system that a feedback has changed.
68 : static void OnFeedbackChanged(Isolate* isolate, FeedbackVector vector,
69 : FeedbackSlot slot, JSFunction host_function,
70 : const char* reason);
71 :
72 : static void OnFeedbackChanged(Isolate* isolate, FeedbackNexus* nexus,
73 : JSFunction host_function, const char* reason);
74 :
75 : protected:
76 : Address fp() const { return fp_; }
77 0 : Address pc() const { return *pc_address_; }
78 :
79 39552 : void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; }
80 :
81 : Isolate* isolate() const { return isolate_; }
82 :
83 : // Get the caller function object.
84 : JSFunction GetHostFunction() const;
85 :
86 : inline bool AddressIsDeoptimizedCode() const;
87 : inline static bool AddressIsDeoptimizedCode(Isolate* isolate,
88 : Address address);
89 :
90 : bool is_vector_set() { return vector_set_; }
91 : inline bool vector_needs_update();
92 :
93 : // Configure for most states.
94 : bool ConfigureVectorState(IC::State new_state, Handle<Object> key);
95 : // Configure the vector for PREMONOMORPHIC.
96 : void ConfigureVectorState(Handle<Map> map);
97 : // Configure the vector for MONOMORPHIC.
98 : void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
99 : Handle<Object> handler);
100 : void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
101 : const MaybeObjectHandle& handler);
102 : // Configure the vector for POLYMORPHIC.
103 : void ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
104 : MaybeObjectHandles* handlers);
105 :
106 : char TransitionMarkFromState(IC::State state);
107 : void TraceIC(const char* type, Handle<Object> name);
108 : void TraceIC(const char* type, Handle<Object> name, State old_state,
109 : State new_state);
110 :
111 : MaybeHandle<Object> TypeError(MessageTemplate, Handle<Object> object,
112 : Handle<Object> key);
113 : MaybeHandle<Object> ReferenceError(Handle<Name> name);
114 :
115 : void TraceHandlerCacheHitStats(LookupIterator* lookup);
116 :
117 : void UpdateMonomorphicIC(const MaybeObjectHandle& handler, Handle<Name> name);
118 : bool UpdatePolymorphicIC(Handle<Name> name, const MaybeObjectHandle& handler);
119 : void UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
120 : const MaybeObjectHandle& handler);
121 :
122 : StubCache* stub_cache();
123 :
124 : void CopyICToMegamorphicCache(Handle<Name> name);
125 : bool IsTransitionOfMonomorphicTarget(Map source_map, Map target_map);
126 : void PatchCache(Handle<Name> name, Handle<Object> handler);
127 : void PatchCache(Handle<Name> name, const MaybeObjectHandle& handler);
128 : FeedbackSlotKind kind() const { return kind_; }
129 6695779 : bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); }
130 : bool IsLoadIC() const { return IsLoadICKind(kind_); }
131 : bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
132 : bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
133 : bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); }
134 : bool IsStoreIC() const { return IsStoreICKind(kind_); }
135 : bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
136 : bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
137 1220073 : bool is_keyed() const {
138 5403789 : return IsKeyedLoadIC() || IsKeyedStoreIC() ||
139 : IsStoreInArrayLiteralICKind(kind_);
140 : }
141 : bool ShouldRecomputeHandler(Handle<String> name);
142 :
143 : Handle<Map> receiver_map() { return receiver_map_; }
144 : inline void update_receiver_map(Handle<Object> receiver);
145 :
146 719557 : void TargetMaps(MapHandles* list) {
147 : FindTargetMaps();
148 1942538 : for (Handle<Map> map : target_maps_) {
149 503412 : list->push_back(map);
150 : }
151 719565 : }
152 :
153 329278 : Map FirstTargetMap() {
154 : FindTargetMaps();
155 887145 : return !target_maps_.empty() ? *target_maps_[0] : Map();
156 : }
157 :
158 : State saved_state() const {
159 : return state() == RECOMPUTE_HANDLER ? old_state_ : state();
160 : }
161 :
162 : const FeedbackNexus* nexus() const { return &nexus_; }
163 : FeedbackNexus* nexus() { return &nexus_; }
164 :
165 : private:
166 : inline Address constant_pool() const;
167 : inline Address raw_constant_pool() const;
168 :
169 : void FindTargetMaps() {
170 1048835 : if (target_maps_set_) return;
171 706844 : target_maps_set_ = true;
172 706844 : nexus()->ExtractMaps(&target_maps_);
173 : }
174 :
175 : // Frame pointer for the frame that uses (calls) the IC.
176 : Address fp_;
177 :
178 : // All access to the program counter and constant pool of an IC structure is
179 : // indirect to make the code GC safe. This feature is crucial since
180 : // GetProperty and SetProperty are called and they in turn might
181 : // invoke the garbage collector.
182 : Address* pc_address_;
183 :
184 : // The constant pool of the code which originally called the IC (which might
185 : // be for the breakpointed copy of the original code).
186 : Address* constant_pool_address_;
187 :
188 : Isolate* isolate_;
189 :
190 : bool vector_set_;
191 : State old_state_; // For saving if we marked as prototype failure.
192 : State state_;
193 : FeedbackSlotKind kind_;
194 : Handle<Map> receiver_map_;
195 : MaybeObjectHandle maybe_handler_;
196 :
197 : MapHandles target_maps_;
198 : bool target_maps_set_;
199 :
200 : const char* slow_stub_reason_;
201 :
202 : FeedbackNexus nexus_;
203 :
204 : DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
205 : };
206 :
207 :
208 4871886 : class LoadIC : public IC {
209 : public:
210 1291948 : LoadIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
211 : FeedbackSlotKind kind)
212 3579899 : : IC(isolate, vector, slot, kind) {
213 : DCHECK(IsAnyLoad());
214 1291954 : }
215 :
216 6437 : static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
217 6437 : return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
218 : }
219 :
220 : bool ShouldThrowReferenceError() const {
221 325837 : return ShouldThrowReferenceError(kind());
222 : }
223 :
224 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Object> object,
225 : Handle<Name> name);
226 :
227 : protected:
228 1385 : virtual Handle<Code> slow_stub() const {
229 1385 : 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 4145734 : class LoadGlobalIC : public LoadIC {
244 : public:
245 2072861 : LoadGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
246 : FeedbackSlot slot, FeedbackSlotKind kind)
247 2072862 : : LoadIC(isolate, vector, slot, kind) {}
248 :
249 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name);
250 :
251 : protected:
252 550 : Handle<Code> slow_stub() const override {
253 550 : return BUILTIN_CODE(isolate(), LoadGlobalIC_Slow);
254 : }
255 : };
256 :
257 430180 : class KeyedLoadIC : public LoadIC {
258 : public:
259 215090 : KeyedLoadIC(Isolate* isolate, Handle<FeedbackVector> vector,
260 : FeedbackSlot slot, FeedbackSlotKind kind)
261 215089 : : LoadIC(isolate, vector, slot, kind) {}
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 4569916 : class StoreIC : public IC {
289 : public:
290 1296189 : StoreIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
291 : FeedbackSlotKind kind, LanguageMode language_mode)
292 3273726 : : IC(isolate, vector, slot, kind), language_mode_(language_mode) {
293 : DCHECK(IsAnyStore());
294 1296191 : }
295 :
296 : LanguageMode language_mode() const { return language_mode_; }
297 :
298 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(
299 : Handle<Object> object, Handle<Name> name, Handle<Object> value,
300 : StoreOrigin store_origin = StoreOrigin::kNamed);
301 :
302 : bool LookupForWrite(LookupIterator* it, Handle<Object> value,
303 : StoreOrigin store_origin);
304 :
305 : protected:
306 : // Stub accessors.
307 27285 : virtual Handle<Code> slow_stub() const {
308 : // All StoreICs share the same slow stub.
309 27285 : 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 : StoreOrigin store_origin);
316 :
317 : // TODO(v8:8580): Instead of storing the language mode, compute it lazily
318 : // from the closure and context when needed. We only need it when throwing
319 : // exceptions, so it is OK to be slow.
320 : LanguageMode language_mode_;
321 :
322 : private:
323 : MaybeObjectHandle ComputeHandler(LookupIterator* lookup);
324 :
325 : friend class IC;
326 : };
327 :
328 3291840 : class StoreGlobalIC : public StoreIC {
329 : public:
330 1645920 : StoreGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
331 : FeedbackSlot slot, FeedbackSlotKind kind,
332 : LanguageMode language_mode)
333 1645920 : : StoreIC(isolate, vector, slot, kind, language_mode) {}
334 :
335 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Name> name,
336 : Handle<Object> value);
337 :
338 : protected:
339 658 : Handle<Code> slow_stub() const override {
340 658 : return BUILTIN_CODE(isolate(), StoreGlobalIC_Slow);
341 : }
342 : };
343 :
344 : enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
345 :
346 :
347 : enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
348 :
349 :
350 492281 : class KeyedStoreIC : public StoreIC {
351 : public:
352 : KeyedAccessStoreMode GetKeyedAccessStoreMode() {
353 11853 : return nexus()->GetKeyedAccessStoreMode();
354 : }
355 :
356 160665 : KeyedStoreIC(Isolate* isolate, Handle<FeedbackVector> vector,
357 : FeedbackSlot slot, FeedbackSlotKind kind,
358 : LanguageMode language_mode)
359 331615 : : StoreIC(isolate, vector, slot, kind, language_mode) {}
360 :
361 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Object> object,
362 : Handle<Object> name,
363 : Handle<Object> value);
364 :
365 : protected:
366 : void UpdateStoreElement(Handle<Map> receiver_map,
367 : KeyedAccessStoreMode store_mode,
368 : bool receiver_was_cow);
369 :
370 484 : Handle<Code> slow_stub() const override {
371 484 : return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
372 : }
373 :
374 : private:
375 : Handle<Map> ComputeTransitionedMap(Handle<Map> map,
376 : KeyedAccessStoreMode store_mode);
377 :
378 : Handle<Object> StoreElementHandler(Handle<Map> receiver_map,
379 : KeyedAccessStoreMode store_mode);
380 :
381 : void StoreElementPolymorphicHandlers(MapHandles* receiver_maps,
382 : MaybeObjectHandles* handlers,
383 : KeyedAccessStoreMode store_mode);
384 :
385 : friend class IC;
386 : };
387 :
388 341902 : class StoreInArrayLiteralIC : public KeyedStoreIC {
389 : public:
390 170952 : StoreInArrayLiteralIC(Isolate* isolate, Handle<FeedbackVector> vector,
391 : FeedbackSlot slot)
392 : : KeyedStoreIC(isolate, vector, slot,
393 : FeedbackSlotKind::kStoreInArrayLiteral,
394 170950 : LanguageMode::kStrict) {
395 : DCHECK(IsStoreInArrayLiteralICKind(kind()));
396 170950 : }
397 :
398 : void Store(Handle<JSArray> array, Handle<Object> index, Handle<Object> value);
399 :
400 : private:
401 36 : Handle<Code> slow_stub() const override {
402 36 : return BUILTIN_CODE(isolate(), StoreInArrayLiteralIC_Slow);
403 : }
404 : };
405 :
406 : } // namespace internal
407 : } // namespace v8
408 :
409 : #endif // V8_IC_IC_H_
|