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