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/macro-assembler.h" 15 #include "src/messages.h" 16 #include "src/objects/map.h" 17 #include "src/objects/maybe-object.h" 18 19 namespace v8 { 20 namespace internal { 21 22 // 23 // IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC. 24 // 25 class IC { 26 public: 27 // Alias the inline cache state type to make the IC code more readable. 28 typedef InlineCacheState State; 29 30 static constexpr int kMaxKeyedPolymorphism = 4; 31 32 // A polymorphic IC can handle at most 4 distinct maps before transitioning 33 // to megamorphic state. 34 static constexpr int kMaxPolymorphicMapCount = 4; 35 36 // Construct the IC structure with the given number of extra 37 // JavaScript frames on the stack. 38 IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot); ~IC()39 virtual ~IC() {} 40 state()41 State state() const { return state_; } 42 inline Address address() const; 43 44 // Compute the current IC state based on the target stub, receiver and name. 45 void UpdateState(Handle<Object> receiver, Handle<Object> name); 46 47 bool RecomputeHandlerForName(Handle<Object> name); MarkRecomputeHandler(Handle<Object> name)48 void MarkRecomputeHandler(Handle<Object> name) { 49 DCHECK(RecomputeHandlerForName(name)); 50 old_state_ = state_; 51 state_ = RECOMPUTE_HANDLER; 52 } 53 IsAnyLoad()54 bool IsAnyLoad() const { 55 return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC(); 56 } IsAnyStore()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: fp()73 Address fp() const { return fp_; } pc()74 Address pc() const { return *pc_address_; } 75 set_slow_stub_reason(const char * reason)76 void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; } 77 isolate()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 is_vector_set()87 bool is_vector_set() { return vector_set_; } vector_needs_update()88 bool vector_needs_update() { 89 return (!vector_set_ && 90 (state() != MEGAMORPHIC || 91 Smi::ToInt(nexus()->GetFeedbackExtra()->ToSmi()) != ELEMENT)); 92 } 93 94 // Configure for most states. 95 bool ConfigureVectorState(IC::State new_state, Handle<Object> key); 96 // Configure the vector for PREMONOMORPHIC. 97 void ConfigureVectorState(Handle<Map> map); 98 // Configure the vector for MONOMORPHIC. 99 void ConfigureVectorState(Handle<Name> name, Handle<Map> map, 100 Handle<Object> handler); 101 void ConfigureVectorState(Handle<Name> name, Handle<Map> map, 102 const MaybeObjectHandle& handler); 103 // Configure the vector for POLYMORPHIC. 104 void ConfigureVectorState(Handle<Name> name, MapHandles const& maps, 105 MaybeObjectHandles* handlers); 106 107 char TransitionMarkFromState(IC::State state); 108 void TraceIC(const char* type, Handle<Object> name); 109 void TraceIC(const char* type, Handle<Object> name, State old_state, 110 State new_state); 111 112 MaybeHandle<Object> TypeError(MessageTemplate::Template, 113 Handle<Object> object, Handle<Object> key); 114 MaybeHandle<Object> ReferenceError(Handle<Name> name); 115 116 void TraceHandlerCacheHitStats(LookupIterator* lookup); 117 118 void UpdateMonomorphicIC(const MaybeObjectHandle& handler, Handle<Name> name); 119 bool UpdatePolymorphicIC(Handle<Name> name, const MaybeObjectHandle& handler); 120 void UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name, 121 const MaybeObjectHandle& handler); 122 123 StubCache* stub_cache(); 124 125 void CopyICToMegamorphicCache(Handle<Name> name); 126 bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map); 127 void PatchCache(Handle<Name> name, Handle<Object> handler); 128 void PatchCache(Handle<Name> name, const MaybeObjectHandle& handler); kind()129 FeedbackSlotKind kind() const { return kind_; } IsGlobalIC()130 bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); } IsLoadIC()131 bool IsLoadIC() const { return IsLoadICKind(kind_); } IsLoadGlobalIC()132 bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); } IsKeyedLoadIC()133 bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); } IsStoreGlobalIC()134 bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); } IsStoreIC()135 bool IsStoreIC() const { return IsStoreICKind(kind_); } IsStoreOwnIC()136 bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); } IsKeyedStoreIC()137 bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); } is_keyed()138 bool is_keyed() const { 139 return IsKeyedLoadIC() || IsKeyedStoreIC() || 140 IsStoreInArrayLiteralICKind(kind_); 141 } 142 bool ShouldRecomputeHandler(Handle<String> name); 143 receiver_map()144 Handle<Map> receiver_map() { return receiver_map_; } 145 inline void update_receiver_map(Handle<Object> receiver); 146 TargetMaps(MapHandles * list)147 void TargetMaps(MapHandles* list) { 148 FindTargetMaps(); 149 for (Handle<Map> map : target_maps_) { 150 list->push_back(map); 151 } 152 } 153 FirstTargetMap()154 Map* FirstTargetMap() { 155 FindTargetMaps(); 156 return !target_maps_.empty() ? *target_maps_[0] : nullptr; 157 } 158 saved_state()159 State saved_state() const { 160 return state() == RECOMPUTE_HANDLER ? old_state_ : state(); 161 } 162 nexus()163 const FeedbackNexus* nexus() const { return &nexus_; } nexus()164 FeedbackNexus* nexus() { return &nexus_; } 165 166 private: 167 inline Address constant_pool() const; 168 inline Address raw_constant_pool() const; 169 FindTargetMaps()170 void FindTargetMaps() { 171 if (target_maps_set_) return; 172 target_maps_set_ = true; 173 nexus()->ExtractMaps(&target_maps_); 174 } 175 176 // Frame pointer for the frame that uses (calls) the IC. 177 Address fp_; 178 179 // All access to the program counter and constant pool of an IC structure is 180 // indirect to make the code GC safe. This feature is crucial since 181 // GetProperty and SetProperty are called and they in turn might 182 // invoke the garbage collector. 183 Address* pc_address_; 184 185 // The constant pool of the code which originally called the IC (which might 186 // be for the breakpointed copy of the original code). 187 Address* constant_pool_address_; 188 189 Isolate* isolate_; 190 191 bool vector_set_; 192 State old_state_; // For saving if we marked as prototype failure. 193 State state_; 194 FeedbackSlotKind kind_; 195 Handle<Map> receiver_map_; 196 MaybeObjectHandle maybe_handler_; 197 198 MapHandles target_maps_; 199 bool target_maps_set_; 200 201 const char* slow_stub_reason_; 202 203 FeedbackNexus nexus_; 204 205 DISALLOW_IMPLICIT_CONSTRUCTORS(IC); 206 }; 207 208 209 class LoadIC : public IC { 210 public: LoadIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)211 LoadIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot) 212 : IC(isolate, vector, slot) { 213 DCHECK(IsAnyLoad()); 214 } 215 ShouldThrowReferenceError(FeedbackSlotKind kind)216 static bool ShouldThrowReferenceError(FeedbackSlotKind kind) { 217 return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof; 218 } 219 ShouldThrowReferenceError()220 bool ShouldThrowReferenceError() const { 221 return ShouldThrowReferenceError(kind()); 222 } 223 224 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Object> object, 225 Handle<Name> name); 226 227 protected: slow_stub()228 virtual Handle<Code> slow_stub() const { 229 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 class LoadGlobalIC : public LoadIC { 244 public: LoadGlobalIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)245 LoadGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector, 246 FeedbackSlot slot) 247 : LoadIC(isolate, vector, slot) {} 248 249 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name); 250 251 protected: slow_stub()252 Handle<Code> slow_stub() const override { 253 return BUILTIN_CODE(isolate(), LoadGlobalIC_Slow); 254 } 255 }; 256 257 class KeyedLoadIC : public LoadIC { 258 public: KeyedLoadIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)259 KeyedLoadIC(Isolate* isolate, Handle<FeedbackVector> vector, 260 FeedbackSlot slot) 261 : LoadIC(isolate, vector, slot) {} 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 class StoreIC : public IC { 289 public: StoreIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)290 StoreIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot) 291 : IC(isolate, vector, slot) { 292 DCHECK(IsAnyStore()); 293 } 294 language_mode()295 LanguageMode language_mode() const { return nexus()->GetLanguageMode(); } 296 297 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store( 298 Handle<Object> object, Handle<Name> name, Handle<Object> value, 299 JSReceiver::StoreFromKeyed store_mode = 300 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED); 301 302 bool LookupForWrite(LookupIterator* it, Handle<Object> value, 303 JSReceiver::StoreFromKeyed store_mode); 304 305 protected: 306 // Stub accessors. slow_stub()307 virtual Handle<Code> slow_stub() const { 308 // All StoreICs share the same slow stub. 309 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 JSReceiver::StoreFromKeyed store_mode); 316 317 private: 318 MaybeObjectHandle ComputeHandler(LookupIterator* lookup); 319 320 friend class IC; 321 }; 322 323 class StoreGlobalIC : public StoreIC { 324 public: StoreGlobalIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)325 StoreGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector, 326 FeedbackSlot slot) 327 : StoreIC(isolate, vector, slot) {} 328 329 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Name> name, 330 Handle<Object> value); 331 332 protected: slow_stub()333 Handle<Code> slow_stub() const override { 334 return BUILTIN_CODE(isolate(), StoreGlobalIC_Slow); 335 } 336 }; 337 338 enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap }; 339 340 341 enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength }; 342 343 344 class KeyedStoreIC : public StoreIC { 345 public: GetKeyedAccessStoreMode()346 KeyedAccessStoreMode GetKeyedAccessStoreMode() { 347 return nexus()->GetKeyedAccessStoreMode(); 348 } 349 KeyedStoreIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)350 KeyedStoreIC(Isolate* isolate, Handle<FeedbackVector> vector, 351 FeedbackSlot slot) 352 : StoreIC(isolate, vector, slot) {} 353 354 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Object> object, 355 Handle<Object> name, 356 Handle<Object> value); 357 358 protected: 359 void UpdateStoreElement(Handle<Map> receiver_map, 360 KeyedAccessStoreMode store_mode, 361 bool receiver_was_cow); 362 slow_stub()363 Handle<Code> slow_stub() const override { 364 return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow); 365 } 366 367 private: 368 Handle<Map> ComputeTransitionedMap(Handle<Map> map, 369 KeyedAccessStoreMode store_mode); 370 371 Handle<Object> StoreElementHandler(Handle<Map> receiver_map, 372 KeyedAccessStoreMode store_mode); 373 374 void StoreElementPolymorphicHandlers(MapHandles* receiver_maps, 375 MaybeObjectHandles* handlers, 376 KeyedAccessStoreMode store_mode); 377 378 friend class IC; 379 }; 380 381 class StoreInArrayLiteralIC : public KeyedStoreIC { 382 public: StoreInArrayLiteralIC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)383 StoreInArrayLiteralIC(Isolate* isolate, Handle<FeedbackVector> vector, 384 FeedbackSlot slot) 385 : KeyedStoreIC(isolate, vector, slot) { 386 DCHECK(IsStoreInArrayLiteralICKind(kind())); 387 } 388 389 void Store(Handle<JSArray> array, Handle<Object> index, Handle<Object> value); 390 391 private: slow_stub()392 Handle<Code> slow_stub() const override { 393 return BUILTIN_CODE(isolate(), StoreInArrayLiteralIC_Slow); 394 } 395 }; 396 397 } // namespace internal 398 } // namespace v8 399 400 #endif // V8_IC_IC_H_ 401