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