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 : using State = InlineCacheState;
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 15321802 : 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 48840 : old_state_ = state_;
50 48840 : state_ = RECOMPUTE_HANDLER;
51 : }
52 :
53 : bool IsAnyHas() const { return IsKeyedHasIC(); }
54 : bool IsAnyLoad() const {
55 1125392 : return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
56 : }
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:
73 : Address fp() const { return fp_; }
74 0 : Address pc() const { return *pc_address_; }
75 :
76 39602 : void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; }
77 :
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 :
87 : bool is_vector_set() { return vector_set_; }
88 : inline bool vector_needs_update();
89 :
90 : // Configure for most states.
91 : bool ConfigureVectorState(IC::State new_state, Handle<Object> key);
92 : // Configure the vector for PREMONOMORPHIC.
93 : void ConfigureVectorState(Handle<Map> map);
94 : // Configure the vector for MONOMORPHIC.
95 : void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
96 : Handle<Object> handler);
97 : void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
98 : const MaybeObjectHandle& handler);
99 : // Configure the vector for POLYMORPHIC.
100 : void ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
101 : MaybeObjectHandles* handlers);
102 :
103 : char TransitionMarkFromState(IC::State state);
104 : void TraceIC(const char* type, Handle<Object> name);
105 : void TraceIC(const char* type, Handle<Object> name, State old_state,
106 : State new_state);
107 :
108 : MaybeHandle<Object> TypeError(MessageTemplate, Handle<Object> object,
109 : Handle<Object> key);
110 : MaybeHandle<Object> ReferenceError(Handle<Name> name);
111 :
112 : void TraceHandlerCacheHitStats(LookupIterator* lookup);
113 :
114 : void UpdateMonomorphicIC(const MaybeObjectHandle& handler, Handle<Name> name);
115 : bool UpdatePolymorphicIC(Handle<Name> name, const MaybeObjectHandle& handler);
116 : void UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
117 : const MaybeObjectHandle& handler);
118 :
119 : StubCache* stub_cache();
120 :
121 : void CopyICToMegamorphicCache(Handle<Name> name);
122 : bool IsTransitionOfMonomorphicTarget(Map source_map, Map target_map);
123 : void PatchCache(Handle<Name> name, Handle<Object> handler);
124 : void PatchCache(Handle<Name> name, const MaybeObjectHandle& handler);
125 : FeedbackSlotKind kind() const { return kind_; }
126 5406053 : bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); }
127 : bool IsLoadIC() const { return IsLoadICKind(kind_); }
128 : bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
129 : bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
130 : bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); }
131 : bool IsStoreIC() const { return IsStoreICKind(kind_); }
132 : bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
133 : bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
134 : bool IsKeyedHasIC() const { return IsKeyedHasICKind(kind_); }
135 : bool is_keyed() const {
136 3086962 : return IsKeyedLoadIC() || IsKeyedStoreIC() ||
137 6092593 : IsStoreInArrayLiteralICKind(kind_) || IsKeyedHasIC();
138 : }
139 : bool ShouldRecomputeHandler(Handle<String> name);
140 :
141 : Handle<Map> receiver_map() { return receiver_map_; }
142 : inline void update_receiver_map(Handle<Object> receiver);
143 :
144 777588 : void TargetMaps(MapHandles* list) {
145 : FindTargetMaps();
146 1273692 : for (Handle<Map> map : target_maps_) {
147 496095 : list->push_back(map);
148 : }
149 777597 : }
150 :
151 363934 : Map FirstTargetMap() {
152 : FindTargetMaps();
153 946329 : return !target_maps_.empty() ? *target_maps_[0] : Map();
154 : }
155 :
156 : State saved_state() const {
157 : return state() == RECOMPUTE_HANDLER ? old_state_ : state();
158 : }
159 :
160 : const FeedbackNexus* nexus() const { return &nexus_; }
161 10369264 : FeedbackNexus* nexus() { return &nexus_; }
162 :
163 : private:
164 : inline Address constant_pool() const;
165 : inline Address raw_constant_pool() const;
166 :
167 : void FindTargetMaps() {
168 1141522 : if (target_maps_set_) return;
169 764597 : target_maps_set_ = true;
170 1529194 : nexus()->ExtractMaps(&target_maps_);
171 : }
172 :
173 : // Frame pointer for the frame that uses (calls) the IC.
174 : Address fp_;
175 :
176 : // All access to the program counter and constant pool of an IC structure is
177 : // indirect to make the code GC safe. This feature is crucial since
178 : // GetProperty and SetProperty are called and they in turn might
179 : // invoke the garbage collector.
180 : Address* pc_address_;
181 :
182 : // The constant pool of the code which originally called the IC (which might
183 : // be for the breakpointed copy of the original code).
184 : Address* constant_pool_address_;
185 :
186 : Isolate* isolate_;
187 :
188 : bool vector_set_;
189 : State old_state_; // For saving if we marked as prototype failure.
190 : State state_;
191 : FeedbackSlotKind kind_;
192 : Handle<Map> receiver_map_;
193 : MaybeObjectHandle maybe_handler_;
194 :
195 : MapHandles target_maps_;
196 : bool target_maps_set_;
197 :
198 : const char* slow_stub_reason_;
199 :
200 : FeedbackNexus nexus_;
201 :
202 : DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
203 : };
204 :
205 7782034 : class LoadIC : public IC {
206 : public:
207 1389500 : LoadIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
208 : FeedbackSlotKind kind)
209 3891046 : : IC(isolate, vector, slot, kind) {
210 : DCHECK(IsAnyLoad() || IsAnyHas());
211 1389489 : }
212 :
213 : static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
214 : return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
215 : }
216 :
217 : bool ShouldThrowReferenceError() const {
218 : return ShouldThrowReferenceError(kind());
219 : }
220 :
221 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Object> object,
222 : Handle<Name> name);
223 :
224 : protected:
225 1424 : virtual Handle<Code> slow_stub() const {
226 : return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIC_Slow)
227 2848 : : BUILTIN_CODE(isolate(), LoadIC_Slow);
228 : }
229 :
230 : // Update the inline cache and the global stub cache based on the
231 : // lookup result.
232 : void UpdateCaches(LookupIterator* lookup);
233 :
234 : private:
235 : Handle<Object> ComputeHandler(LookupIterator* lookup);
236 :
237 : friend class IC;
238 : friend class NamedLoadHandlerCompiler;
239 : };
240 :
241 4569772 : class LoadGlobalIC : public LoadIC {
242 : public:
243 2284887 : LoadGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
244 : FeedbackSlot slot, FeedbackSlotKind kind)
245 2284886 : : LoadIC(isolate, vector, slot, kind) {}
246 :
247 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name);
248 :
249 : protected:
250 550 : Handle<Code> slow_stub() const override {
251 550 : return BUILTIN_CODE(isolate(), LoadGlobalIC_Slow);
252 : }
253 : };
254 :
255 433318 : class KeyedLoadIC : public LoadIC {
256 : public:
257 216659 : KeyedLoadIC(Isolate* isolate, Handle<FeedbackVector> vector,
258 : FeedbackSlot slot, FeedbackSlotKind kind)
259 216659 : : LoadIC(isolate, vector, slot, kind) {}
260 :
261 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Object> object,
262 : Handle<Object> key);
263 :
264 : protected:
265 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> RuntimeLoad(Handle<Object> object,
266 : Handle<Object> key);
267 :
268 : // receiver is HeapObject because it could be a String or a JSObject
269 : void UpdateLoadElement(Handle<HeapObject> receiver,
270 : KeyedAccessLoadMode load_mode);
271 :
272 : private:
273 : friend class IC;
274 :
275 : Handle<Object> LoadElementHandler(Handle<Map> receiver_map,
276 : KeyedAccessLoadMode load_mode);
277 :
278 : void LoadElementPolymorphicHandlers(MapHandles* receiver_maps,
279 : MaybeObjectHandles* handlers,
280 : KeyedAccessLoadMode load_mode);
281 :
282 : // Returns true if the receiver_map has a kElement or kIndexedString
283 : // handler in the nexus currently but didn't yet allow out of bounds
284 : // accesses.
285 : bool CanChangeToAllowOutOfBounds(Handle<Map> receiver_map);
286 : };
287 :
288 7539768 : class StoreIC : public IC {
289 : public:
290 1685148 : StoreIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
291 : FeedbackSlotKind kind)
292 3769889 : : IC(isolate, vector, slot, kind) {
293 : DCHECK(IsAnyStore());
294 1685153 : }
295 :
296 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(
297 : Handle<Object> object, Handle<Name> name, Handle<Object> value,
298 : StoreOrigin store_origin = StoreOrigin::kNamed);
299 :
300 : bool LookupForWrite(LookupIterator* it, Handle<Object> value,
301 : StoreOrigin store_origin);
302 :
303 : protected:
304 : // Stub accessors.
305 27250 : virtual Handle<Code> slow_stub() const {
306 : // All StoreICs share the same slow stub.
307 27250 : return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
308 : }
309 :
310 : // Update the inline cache and the global stub cache based on the
311 : // lookup result.
312 : void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
313 : StoreOrigin store_origin);
314 :
315 : private:
316 : MaybeObjectHandle ComputeHandler(LookupIterator* lookup);
317 :
318 : friend class IC;
319 : };
320 :
321 3454720 : class StoreGlobalIC : public StoreIC {
322 : public:
323 1727360 : StoreGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
324 : FeedbackSlot slot, FeedbackSlotKind kind)
325 1727360 : : StoreIC(isolate, vector, slot, kind) {}
326 :
327 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Name> name,
328 : Handle<Object> value);
329 :
330 : protected:
331 652 : Handle<Code> slow_stub() const override {
332 652 : return BUILTIN_CODE(isolate(), StoreGlobalIC_Slow);
333 : }
334 : };
335 :
336 : enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
337 :
338 : enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
339 :
340 714764 : class KeyedStoreIC : public StoreIC {
341 : public:
342 : KeyedAccessStoreMode GetKeyedAccessStoreMode() {
343 11793 : return nexus()->GetKeyedAccessStoreMode();
344 : }
345 :
346 163688 : KeyedStoreIC(Isolate* isolate, Handle<FeedbackVector> vector,
347 : FeedbackSlot slot, FeedbackSlotKind kind)
348 357381 : : StoreIC(isolate, vector, slot, kind) {}
349 :
350 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Object> object,
351 : Handle<Object> name,
352 : Handle<Object> value);
353 :
354 : protected:
355 : void UpdateStoreElement(Handle<Map> receiver_map,
356 : KeyedAccessStoreMode store_mode,
357 : bool receiver_was_cow);
358 :
359 484 : Handle<Code> slow_stub() const override {
360 484 : return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
361 : }
362 :
363 : private:
364 : Handle<Map> ComputeTransitionedMap(Handle<Map> map,
365 : KeyedAccessStoreMode store_mode);
366 :
367 : Handle<Object> StoreElementHandler(Handle<Map> receiver_map,
368 : KeyedAccessStoreMode store_mode);
369 :
370 : void StoreElementPolymorphicHandlers(MapHandles* receiver_maps,
371 : MaybeObjectHandles* handlers,
372 : KeyedAccessStoreMode store_mode);
373 :
374 : friend class IC;
375 : };
376 :
377 387388 : class StoreInArrayLiteralIC : public KeyedStoreIC {
378 : public:
379 193693 : StoreInArrayLiteralIC(Isolate* isolate, Handle<FeedbackVector> vector,
380 : FeedbackSlot slot)
381 : : KeyedStoreIC(isolate, vector, slot,
382 193693 : FeedbackSlotKind::kStoreInArrayLiteral) {
383 : DCHECK(IsStoreInArrayLiteralICKind(kind()));
384 193693 : }
385 :
386 : void Store(Handle<JSArray> array, Handle<Object> index, Handle<Object> value);
387 :
388 : private:
389 54 : Handle<Code> slow_stub() const override {
390 54 : return BUILTIN_CODE(isolate(), StoreInArrayLiteralIC_Slow);
391 : }
392 : };
393 :
394 : } // namespace internal
395 : } // namespace v8
396 :
397 : #endif // V8_IC_IC_H_
|