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 "src/ic/ic-state.h" 9 #include "src/macro-assembler.h" 10 #include "src/messages.h" 11 12 namespace v8 { 13 namespace internal { 14 15 // 16 // IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC. 17 // 18 class IC { 19 public: 20 // Alias the inline cache state type to make the IC code more readable. 21 typedef InlineCacheState State; 22 23 // The IC code is either invoked with no extra frames on the stack 24 // or with a single extra frame for supporting calls. 25 enum FrameDepth { NO_EXTRA_FRAME = 0, EXTRA_CALL_FRAME = 1 }; 26 27 // Construct the IC structure with the given number of extra 28 // JavaScript frames on the stack. 29 IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL); ~IC()30 virtual ~IC() {} 31 state()32 State state() const { return state_; } 33 inline Address address() const; 34 35 // Compute the current IC state based on the target stub, receiver and name. 36 void UpdateState(Handle<Object> receiver, Handle<Object> name); 37 38 bool RecomputeHandlerForName(Handle<Object> name); MarkRecomputeHandler(Handle<Object> name)39 void MarkRecomputeHandler(Handle<Object> name) { 40 DCHECK(RecomputeHandlerForName(name)); 41 old_state_ = state_; 42 state_ = RECOMPUTE_HANDLER; 43 } 44 45 // Clear the inline cache to initial state. 46 static void Clear(Isolate* isolate, Address address, Address constant_pool); 47 48 #ifdef DEBUG IsLoadStub()49 bool IsLoadStub() const { 50 return kind_ == Code::LOAD_IC || kind_ == Code::LOAD_GLOBAL_IC || 51 kind_ == Code::KEYED_LOAD_IC; 52 } IsStoreStub()53 bool IsStoreStub() const { 54 return kind_ == Code::STORE_IC || kind_ == Code::KEYED_STORE_IC; 55 } IsCallStub()56 bool IsCallStub() const { return kind_ == Code::CALL_IC; } 57 #endif 58 59 static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map, 60 bool receiver_is_holder, 61 Isolate* isolate, 62 CacheHolderFlag* flag); 63 static inline Handle<Map> GetICCacheHolder(Handle<Map> receiver_map, 64 Isolate* isolate, 65 CacheHolderFlag* flag); 66 IsCleared(FeedbackNexus * nexus)67 static bool IsCleared(FeedbackNexus* nexus) { 68 InlineCacheState state = nexus->StateFromFeedback(); 69 return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC; 70 } 71 ICUseVector(Code::Kind kind)72 static bool ICUseVector(Code::Kind kind) { 73 return kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC || 74 kind == Code::KEYED_LOAD_IC || kind == Code::CALL_IC || 75 kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC; 76 } 77 78 // The ICs that don't pass slot and vector through the stack have to 79 // save/restore them in the dispatcher. 80 static bool ShouldPushPopSlotAndVector(Code::Kind kind); 81 82 static InlineCacheState StateFromCode(Code* code); 83 84 static inline bool IsHandler(Object* object); 85 86 protected: fp()87 Address fp() const { return fp_; } pc()88 Address pc() const { return *pc_address_; } isolate()89 Isolate* isolate() const { return isolate_; } 90 91 // Get the shared function info of the caller. 92 SharedFunctionInfo* GetSharedFunctionInfo() const; 93 // Get the code object of the caller. 94 Code* GetCode() const; 95 96 inline bool AddressIsDeoptimizedCode() const; 97 inline static bool AddressIsDeoptimizedCode(Isolate* isolate, 98 Address address); 99 100 // Set the call-site target. 101 inline void set_target(Code* code); is_vector_set()102 bool is_vector_set() { return vector_set_; } 103 UseVector()104 bool UseVector() const { 105 bool use = ICUseVector(kind()); 106 // If we are supposed to use the nexus, verify the nexus is non-null. 107 DCHECK(!use || nexus_ != nullptr); 108 return use; 109 } 110 111 // Configure for most states. 112 void ConfigureVectorState(IC::State new_state, Handle<Object> key); 113 // Configure the vector for MONOMORPHIC. 114 void ConfigureVectorState(Handle<Name> name, Handle<Map> map, 115 Handle<Object> handler); 116 // Configure the vector for POLYMORPHIC. 117 void ConfigureVectorState(Handle<Name> name, MapHandleList* maps, 118 List<Handle<Object>>* handlers); 119 // Configure the vector for POLYMORPHIC with transitions (only for element 120 // keyed stores). 121 void ConfigureVectorState(MapHandleList* maps, 122 MapHandleList* transitioned_maps, 123 CodeHandleList* handlers); 124 125 char TransitionMarkFromState(IC::State state); 126 void TraceIC(const char* type, Handle<Object> name); 127 void TraceIC(const char* type, Handle<Object> name, State old_state, 128 State new_state); 129 130 MaybeHandle<Object> TypeError(MessageTemplate::Template, 131 Handle<Object> object, Handle<Object> key); 132 MaybeHandle<Object> ReferenceError(Handle<Name> name); 133 134 // Access the target code for the given IC address. 135 static inline Code* GetTargetAtAddress(Address address, 136 Address constant_pool); 137 static inline void SetTargetAtAddress(Address address, Code* target, 138 Address constant_pool); 139 // As a vector-based IC, type feedback must be updated differently. 140 static void OnTypeFeedbackChanged(Isolate* isolate, Code* host); 141 static void PostPatching(Address address, Code* target, Code* old_target); 142 143 void TraceHandlerCacheHitStats(LookupIterator* lookup); 144 145 // Compute the handler either by compiling or by retrieving a cached version. 146 Handle<Object> ComputeHandler(LookupIterator* lookup, 147 Handle<Object> value = Handle<Code>::null()); GetMapIndependentHandler(LookupIterator * lookup)148 virtual Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) { 149 UNREACHABLE(); 150 return Handle<Code>::null(); 151 } CompileHandler(LookupIterator * lookup,Handle<Object> value,CacheHolderFlag cache_holder)152 virtual Handle<Object> CompileHandler(LookupIterator* lookup, 153 Handle<Object> value, 154 CacheHolderFlag cache_holder) { 155 UNREACHABLE(); 156 return Handle<Object>::null(); 157 } 158 159 void UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name); 160 bool UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code); 161 void UpdateMegamorphicCache(Map* map, Name* name, Object* code); 162 163 StubCache* stub_cache(); 164 165 void CopyICToMegamorphicCache(Handle<Name> name); 166 bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map); 167 void PatchCache(Handle<Name> name, Handle<Object> code); kind()168 Code::Kind kind() const { return kind_; } is_keyed()169 bool is_keyed() const { 170 return kind_ == Code::KEYED_LOAD_IC || kind_ == Code::KEYED_STORE_IC; 171 } handler_kind()172 Code::Kind handler_kind() const { 173 if (kind_ == Code::KEYED_LOAD_IC) return Code::LOAD_IC; 174 DCHECK(kind_ == Code::LOAD_IC || kind_ == Code::STORE_IC || 175 kind_ == Code::KEYED_STORE_IC); 176 return kind_; 177 } 178 bool ShouldRecomputeHandler(Handle<String> name); 179 extra_ic_state()180 ExtraICState extra_ic_state() const { return extra_ic_state_; } 181 receiver_map()182 Handle<Map> receiver_map() { return receiver_map_; } update_receiver_map(Handle<Object> receiver)183 void update_receiver_map(Handle<Object> receiver) { 184 if (receiver->IsSmi()) { 185 receiver_map_ = isolate_->factory()->heap_number_map(); 186 } else { 187 receiver_map_ = handle(HeapObject::cast(*receiver)->map()); 188 } 189 } 190 TargetMaps(MapHandleList * list)191 void TargetMaps(MapHandleList* list) { 192 FindTargetMaps(); 193 for (int i = 0; i < target_maps_.length(); i++) { 194 list->Add(target_maps_.at(i)); 195 } 196 } 197 FirstTargetMap()198 Map* FirstTargetMap() { 199 FindTargetMaps(); 200 return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL; 201 } 202 vector()203 Handle<TypeFeedbackVector> vector() const { return nexus()->vector_handle(); } slot()204 FeedbackVectorSlot slot() const { return nexus()->slot(); } saved_state()205 State saved_state() const { 206 return state() == RECOMPUTE_HANDLER ? old_state_ : state(); 207 } 208 209 template <class NexusClass> casted_nexus()210 NexusClass* casted_nexus() { 211 return static_cast<NexusClass*>(nexus_); 212 } nexus()213 FeedbackNexus* nexus() const { return nexus_; } 214 215 inline Code* get_host(); 216 inline Code* target() const; 217 218 private: 219 inline Address constant_pool() const; 220 inline Address raw_constant_pool() const; 221 FindTargetMaps()222 void FindTargetMaps() { 223 if (target_maps_set_) return; 224 target_maps_set_ = true; 225 DCHECK(UseVector()); 226 nexus()->ExtractMaps(&target_maps_); 227 } 228 229 // Frame pointer for the frame that uses (calls) the IC. 230 Address fp_; 231 232 // All access to the program counter and constant pool of an IC structure is 233 // indirect to make the code GC safe. This feature is crucial since 234 // GetProperty and SetProperty are called and they in turn might 235 // invoke the garbage collector. 236 Address* pc_address_; 237 238 // The constant pool of the code which originally called the IC (which might 239 // be for the breakpointed copy of the original code). 240 Address* constant_pool_address_; 241 242 Isolate* isolate_; 243 244 bool vector_set_; 245 State old_state_; // For saving if we marked as prototype failure. 246 State state_; 247 Code::Kind kind_; 248 Handle<Map> receiver_map_; 249 MaybeHandle<Object> maybe_handler_; 250 251 ExtraICState extra_ic_state_; 252 MapHandleList target_maps_; 253 bool target_maps_set_; 254 255 FeedbackNexus* nexus_; 256 257 DISALLOW_IMPLICIT_CONSTRUCTORS(IC); 258 }; 259 260 261 class CallIC : public IC { 262 public: CallIC(Isolate * isolate,CallICNexus * nexus)263 CallIC(Isolate* isolate, CallICNexus* nexus) 264 : IC(EXTRA_CALL_FRAME, isolate, nexus) { 265 DCHECK(nexus != NULL); 266 } 267 268 void HandleMiss(Handle<Object> function); 269 270 static void Clear(Isolate* isolate, Code* host, CallICNexus* nexus); 271 }; 272 273 274 class LoadIC : public IC { 275 public: 276 LoadIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL) IC(depth,isolate,nexus)277 : IC(depth, isolate, nexus) { 278 DCHECK(nexus != NULL); 279 DCHECK(IsLoadStub()); 280 } 281 ShouldThrowReferenceError()282 bool ShouldThrowReferenceError() const { 283 return kind() == Code::LOAD_GLOBAL_IC && 284 LoadGlobalICState::GetTypeofMode(extra_ic_state()) == 285 NOT_INSIDE_TYPEOF; 286 } 287 288 // Code generator routines. 289 290 static void GenerateMiss(MacroAssembler* masm); 291 static void GenerateRuntimeGetProperty(MacroAssembler* masm); 292 static void GenerateNormal(MacroAssembler* masm); 293 294 MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object, 295 Handle<Name> name); 296 297 static void Clear(Isolate* isolate, Code* host, LoadICNexus* nexus); 298 299 protected: slow_stub()300 virtual Handle<Code> slow_stub() const { 301 return isolate()->builtins()->LoadIC_Slow(); 302 } 303 304 // Update the inline cache and the global stub cache based on the 305 // lookup result. 306 void UpdateCaches(LookupIterator* lookup); 307 308 Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override; 309 310 Handle<Object> CompileHandler(LookupIterator* lookup, Handle<Object> unused, 311 CacheHolderFlag cache_holder) override; 312 313 private: 314 // Creates a data handler that represents a load of a field by given index. 315 Handle<Object> SimpleFieldLoad(FieldIndex index); 316 317 // Creates a data handler that represents a prototype chain check followed 318 // by given Smi-handler that encoded a load from the holder. 319 // Can be used only if GetPrototypeCheckCount() returns non negative value. 320 Handle<Object> LoadFromPrototype(Handle<Map> receiver_map, 321 Handle<JSObject> holder, Handle<Name> name, 322 Handle<Object> smi_handler); 323 324 // Creates a data handler that represents a load of a non-existent property. 325 Handle<Object> LoadNonExistent(Handle<Map> receiver_map, Handle<Name> name); 326 327 friend class IC; 328 }; 329 330 class LoadGlobalIC : public LoadIC { 331 public: 332 LoadGlobalIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL) LoadIC(depth,isolate,nexus)333 : LoadIC(depth, isolate, nexus) {} 334 335 MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Name> name); 336 337 static void Clear(Isolate* isolate, Code* host, LoadGlobalICNexus* nexus); 338 339 protected: slow_stub()340 Handle<Code> slow_stub() const override { 341 return isolate()->builtins()->LoadGlobalIC_Slow(); 342 } 343 }; 344 345 class KeyedLoadIC : public LoadIC { 346 public: 347 KeyedLoadIC(FrameDepth depth, Isolate* isolate, 348 KeyedLoadICNexus* nexus = NULL) LoadIC(depth,isolate,nexus)349 : LoadIC(depth, isolate, nexus) { 350 DCHECK(nexus != NULL); 351 } 352 353 MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object, 354 Handle<Object> key); 355 356 // Code generator routines. 357 static void GenerateMiss(MacroAssembler* masm); 358 static void GenerateRuntimeGetProperty(MacroAssembler* masm); 359 360 static void Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus); 361 362 protected: 363 // receiver is HeapObject because it could be a String or a JSObject 364 void UpdateLoadElement(Handle<HeapObject> receiver); 365 366 private: 367 friend class IC; 368 }; 369 370 371 class StoreIC : public IC { 372 public: 373 StoreIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL) IC(depth,isolate,nexus)374 : IC(depth, isolate, nexus) { 375 DCHECK(IsStoreStub()); 376 } 377 language_mode()378 LanguageMode language_mode() const { 379 return StoreICState::GetLanguageMode(extra_ic_state()); 380 } 381 382 // Code generators for stub routines. Only called once at startup. 383 static void GenerateSlow(MacroAssembler* masm); 384 static void GenerateMiss(MacroAssembler* masm); 385 static void GenerateNormal(MacroAssembler* masm); 386 387 MUST_USE_RESULT MaybeHandle<Object> Store( 388 Handle<Object> object, Handle<Name> name, Handle<Object> value, 389 JSReceiver::StoreFromKeyed store_mode = 390 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED); 391 392 bool LookupForWrite(LookupIterator* it, Handle<Object> value, 393 JSReceiver::StoreFromKeyed store_mode); 394 395 static void Clear(Isolate* isolate, Code* host, StoreICNexus* nexus); 396 397 protected: 398 // Stub accessors. slow_stub()399 Handle<Code> slow_stub() const { 400 switch (language_mode()) { 401 case SLOPPY: 402 return isolate()->builtins()->StoreIC_SlowSloppy(); 403 case STRICT: 404 return isolate()->builtins()->StoreIC_SlowStrict(); 405 default: 406 UNREACHABLE(); 407 return Handle<Code>(); 408 } 409 } 410 411 // Update the inline cache and the global stub cache based on the 412 // lookup result. 413 void UpdateCaches(LookupIterator* lookup, Handle<Object> value, 414 JSReceiver::StoreFromKeyed store_mode); 415 Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override; 416 Handle<Object> CompileHandler(LookupIterator* lookup, Handle<Object> value, 417 CacheHolderFlag cache_holder) override; 418 419 private: 420 Handle<Object> StoreTransition(Handle<Map> receiver_map, 421 Handle<JSObject> holder, 422 Handle<Map> transition, Handle<Name> name); 423 424 friend class IC; 425 }; 426 427 428 enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap }; 429 430 431 enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength }; 432 433 434 class KeyedStoreIC : public StoreIC { 435 public: GetKeyedAccessStoreMode()436 KeyedAccessStoreMode GetKeyedAccessStoreMode() { 437 return casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode(); 438 } 439 440 KeyedStoreIC(FrameDepth depth, Isolate* isolate, 441 KeyedStoreICNexus* nexus = NULL) StoreIC(depth,isolate,nexus)442 : StoreIC(depth, isolate, nexus) {} 443 444 MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object, 445 Handle<Object> name, 446 Handle<Object> value); 447 448 // Code generators for stub routines. Only called once at startup. 449 static void GenerateMiss(MacroAssembler* masm); 450 static void GenerateSlow(MacroAssembler* masm); 451 static void GenerateMegamorphic(MacroAssembler* masm, 452 LanguageMode language_mode); 453 454 static Handle<Code> ChooseMegamorphicStub(Isolate* isolate, 455 ExtraICState extra_state); 456 457 static void Clear(Isolate* isolate, Code* host, KeyedStoreICNexus* nexus); 458 459 protected: 460 void UpdateStoreElement(Handle<Map> receiver_map, 461 KeyedAccessStoreMode store_mode); 462 463 private: 464 Handle<Map> ComputeTransitionedMap(Handle<Map> map, 465 KeyedAccessStoreMode store_mode); 466 467 friend class IC; 468 }; 469 470 471 // Type Recording BinaryOpIC, that records the types of the inputs and outputs. 472 class BinaryOpIC : public IC { 473 public: BinaryOpIC(Isolate * isolate)474 explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {} 475 476 MaybeHandle<Object> Transition(Handle<AllocationSite> allocation_site, 477 Handle<Object> left, 478 Handle<Object> right) WARN_UNUSED_RESULT; 479 }; 480 481 482 class CompareIC : public IC { 483 public: CompareIC(Isolate * isolate,Token::Value op)484 CompareIC(Isolate* isolate, Token::Value op) 485 : IC(EXTRA_CALL_FRAME, isolate), op_(op) {} 486 487 // Update the inline cache for the given operands. 488 Code* UpdateCaches(Handle<Object> x, Handle<Object> y); 489 490 // Helper function for computing the condition for a compare operation. 491 static Condition ComputeCondition(Token::Value op); 492 493 private: 494 static bool HasInlinedSmiCode(Address address); 495 strict()496 bool strict() const { return op_ == Token::EQ_STRICT; } GetCondition()497 Condition GetCondition() const { return ComputeCondition(op_); } 498 499 static Code* GetRawUninitialized(Isolate* isolate, Token::Value op); 500 501 static void Clear(Isolate* isolate, Address address, Code* target, 502 Address constant_pool); 503 504 Token::Value op_; 505 506 friend class IC; 507 }; 508 509 510 class ToBooleanIC : public IC { 511 public: ToBooleanIC(Isolate * isolate)512 explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {} 513 514 Handle<Object> ToBoolean(Handle<Object> object); 515 }; 516 517 518 // Helper for BinaryOpIC and CompareIC. 519 enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK }; 520 void PatchInlinedSmiCode(Isolate* isolate, Address address, 521 InlinedSmiCheck check); 522 523 } // namespace internal 524 } // namespace v8 525 526 #endif // V8_IC_H_ 527