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