1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_IC_H_ 29 #define V8_IC_H_ 30 31 #include "macro-assembler.h" 32 33 namespace v8 { 34 namespace internal { 35 36 37 // IC_UTIL_LIST defines all utility functions called from generated 38 // inline caching code. The argument for the macro, ICU, is the function name. 39 #define IC_UTIL_LIST(ICU) \ 40 ICU(LoadIC_Miss) \ 41 ICU(KeyedLoadIC_Miss) \ 42 ICU(CallIC_Miss) \ 43 ICU(KeyedCallIC_Miss) \ 44 ICU(StoreIC_Miss) \ 45 ICU(StoreIC_ArrayLength) \ 46 ICU(SharedStoreIC_ExtendStorage) \ 47 ICU(KeyedStoreIC_Miss) \ 48 /* Utilities for IC stubs. */ \ 49 ICU(LoadCallbackProperty) \ 50 ICU(StoreCallbackProperty) \ 51 ICU(LoadPropertyWithInterceptorOnly) \ 52 ICU(LoadPropertyWithInterceptorForLoad) \ 53 ICU(LoadPropertyWithInterceptorForCall) \ 54 ICU(KeyedLoadPropertyWithInterceptor) \ 55 ICU(StoreInterceptorProperty) \ 56 ICU(TypeRecordingBinaryOp_Patch) \ 57 ICU(CompareIC_Miss) 58 // 59 // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC, 60 // and KeyedStoreIC. 61 // 62 class IC { 63 public: 64 65 // The ids for utility called from the generated code. 66 enum UtilityId { 67 #define CONST_NAME(name) k##name, 68 IC_UTIL_LIST(CONST_NAME) 69 #undef CONST_NAME 70 kUtilityCount 71 }; 72 73 // Looks up the address of the named utility. 74 static Address AddressFromUtilityId(UtilityId id); 75 76 // Alias the inline cache state type to make the IC code more readable. 77 typedef InlineCacheState State; 78 79 // The IC code is either invoked with no extra frames on the stack 80 // or with a single extra frame for supporting calls. 81 enum FrameDepth { 82 NO_EXTRA_FRAME = 0, 83 EXTRA_CALL_FRAME = 1 84 }; 85 86 // Construct the IC structure with the given number of extra 87 // JavaScript frames on the stack. 88 IC(FrameDepth depth, Isolate* isolate); 89 90 // Get the call-site target; used for determining the state. 91 Code* target() { return GetTargetAtAddress(address()); } 92 inline Address address(); 93 94 // Compute the current IC state based on the target stub, receiver and name. 95 static State StateFrom(Code* target, Object* receiver, Object* name); 96 97 // Clear the inline cache to initial state. 98 static void Clear(Address address); 99 100 // Computes the reloc info for this IC. This is a fairly expensive 101 // operation as it has to search through the heap to find the code 102 // object that contains this IC site. 103 RelocInfo::Mode ComputeMode(); 104 105 // Returns if this IC is for contextual (no explicit receiver) 106 // access to properties. 107 bool IsContextual(Handle<Object> receiver) { 108 if (receiver->IsGlobalObject()) { 109 return SlowIsContextual(); 110 } else { 111 ASSERT(!SlowIsContextual()); 112 return false; 113 } 114 } 115 116 bool SlowIsContextual() { 117 return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT; 118 } 119 120 // Determines which map must be used for keeping the code stub. 121 // These methods should not be called with undefined or null. 122 static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object, 123 JSObject* holder); 124 static inline InlineCacheHolderFlag GetCodeCacheForObject(JSObject* object, 125 JSObject* holder); 126 static inline JSObject* GetCodeCacheHolder(Object* object, 127 InlineCacheHolderFlag holder); 128 129 protected: 130 Address fp() const { return fp_; } 131 Address pc() const { return *pc_address_; } 132 Isolate* isolate() const { return isolate_; } 133 134 #ifdef ENABLE_DEBUGGER_SUPPORT 135 // Computes the address in the original code when the code running is 136 // containing break points (calls to DebugBreakXXX builtins). 137 Address OriginalCodeAddress(); 138 #endif 139 140 // Set the call-site target. 141 void set_target(Code* code) { SetTargetAtAddress(address(), code); } 142 143 #ifdef DEBUG 144 static void TraceIC(const char* type, 145 Handle<Object> name, 146 State old_state, 147 Code* new_target, 148 const char* extra_info = ""); 149 #endif 150 151 Failure* TypeError(const char* type, 152 Handle<Object> object, 153 Handle<Object> key); 154 Failure* ReferenceError(const char* type, Handle<String> name); 155 156 // Access the target code for the given IC address. 157 static inline Code* GetTargetAtAddress(Address address); 158 static inline void SetTargetAtAddress(Address address, Code* target); 159 160 private: 161 // Frame pointer for the frame that uses (calls) the IC. 162 Address fp_; 163 164 // All access to the program counter of an IC structure is indirect 165 // to make the code GC safe. This feature is crucial since 166 // GetProperty and SetProperty are called and they in turn might 167 // invoke the garbage collector. 168 Address* pc_address_; 169 170 Isolate* isolate_; 171 172 DISALLOW_IMPLICIT_CONSTRUCTORS(IC); 173 }; 174 175 176 // An IC_Utility encapsulates IC::UtilityId. It exists mainly because you 177 // cannot make forward declarations to an enum. 178 class IC_Utility { 179 public: 180 explicit IC_Utility(IC::UtilityId id) 181 : address_(IC::AddressFromUtilityId(id)), id_(id) {} 182 183 Address address() const { return address_; } 184 185 IC::UtilityId id() const { return id_; } 186 private: 187 Address address_; 188 IC::UtilityId id_; 189 }; 190 191 192 class CallICBase: public IC { 193 protected: 194 CallICBase(Code::Kind kind, Isolate* isolate) 195 : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {} 196 197 public: 198 MUST_USE_RESULT MaybeObject* LoadFunction(State state, 199 Code::ExtraICState extra_ic_state, 200 Handle<Object> object, 201 Handle<String> name); 202 203 protected: 204 Code::Kind kind_; 205 206 bool TryUpdateExtraICState(LookupResult* lookup, 207 Handle<Object> object, 208 Code::ExtraICState* extra_ic_state); 209 210 MUST_USE_RESULT MaybeObject* ComputeMonomorphicStub( 211 LookupResult* lookup, 212 State state, 213 Code::ExtraICState extra_ic_state, 214 Handle<Object> object, 215 Handle<String> name); 216 217 // Update the inline cache and the global stub cache based on the 218 // lookup result. 219 void UpdateCaches(LookupResult* lookup, 220 State state, 221 Code::ExtraICState extra_ic_state, 222 Handle<Object> object, 223 Handle<String> name); 224 225 // Returns a JSFunction if the object can be called as a function, 226 // and patches the stack to be ready for the call. 227 // Otherwise, it returns the undefined value. 228 Object* TryCallAsFunction(Object* object); 229 230 void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object); 231 232 static void Clear(Address address, Code* target); 233 friend class IC; 234 }; 235 236 237 class CallIC: public CallICBase { 238 public: 239 explicit CallIC(Isolate* isolate) : CallICBase(Code::CALL_IC, isolate) { 240 ASSERT(target()->is_call_stub()); 241 } 242 243 // Code generator routines. 244 static void GenerateInitialize(MacroAssembler* masm, int argc) { 245 GenerateMiss(masm, argc); 246 } 247 static void GenerateMiss(MacroAssembler* masm, int argc); 248 static void GenerateMegamorphic(MacroAssembler* masm, int argc); 249 static void GenerateNormal(MacroAssembler* masm, int argc); 250 }; 251 252 253 class KeyedCallIC: public CallICBase { 254 public: 255 explicit KeyedCallIC(Isolate* isolate) 256 : CallICBase(Code::KEYED_CALL_IC, isolate) { 257 ASSERT(target()->is_keyed_call_stub()); 258 } 259 260 MUST_USE_RESULT MaybeObject* LoadFunction(State state, 261 Handle<Object> object, 262 Handle<Object> key); 263 264 // Code generator routines. 265 static void GenerateInitialize(MacroAssembler* masm, int argc) { 266 GenerateMiss(masm, argc); 267 } 268 static void GenerateMiss(MacroAssembler* masm, int argc); 269 static void GenerateMegamorphic(MacroAssembler* masm, int argc); 270 static void GenerateNormal(MacroAssembler* masm, int argc); 271 }; 272 273 274 class LoadIC: public IC { 275 public: 276 explicit LoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { 277 ASSERT(target()->is_load_stub()); 278 } 279 280 MUST_USE_RESULT MaybeObject* Load(State state, 281 Handle<Object> object, 282 Handle<String> name); 283 284 // Code generator routines. 285 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } 286 static void GeneratePreMonomorphic(MacroAssembler* masm) { 287 GenerateMiss(masm); 288 } 289 static void GenerateMiss(MacroAssembler* masm); 290 static void GenerateMegamorphic(MacroAssembler* masm); 291 static void GenerateNormal(MacroAssembler* masm); 292 293 // Specialized code generator routines. 294 static void GenerateArrayLength(MacroAssembler* masm); 295 static void GenerateStringLength(MacroAssembler* masm, 296 bool support_wrappers); 297 static void GenerateFunctionPrototype(MacroAssembler* masm); 298 299 // Clear the use of the inlined version. 300 static void ClearInlinedVersion(Address address); 301 302 // The offset from the inlined patch site to the start of the 303 // inlined load instruction. It is architecture-dependent, and not 304 // used on ARM. 305 static const int kOffsetToLoadInstruction; 306 307 private: 308 // Update the inline cache and the global stub cache based on the 309 // lookup result. 310 void UpdateCaches(LookupResult* lookup, 311 State state, 312 Handle<Object> object, 313 Handle<String> name); 314 315 // Stub accessors. 316 Code* megamorphic_stub() { 317 return isolate()->builtins()->builtin( 318 Builtins::kLoadIC_Megamorphic); 319 } 320 static Code* initialize_stub() { 321 return Isolate::Current()->builtins()->builtin( 322 Builtins::kLoadIC_Initialize); 323 } 324 Code* pre_monomorphic_stub() { 325 return isolate()->builtins()->builtin( 326 Builtins::kLoadIC_PreMonomorphic); 327 } 328 329 static void Clear(Address address, Code* target); 330 331 static bool PatchInlinedLoad(Address address, Object* map, int index); 332 333 static bool PatchInlinedContextualLoad(Address address, 334 Object* map, 335 Object* cell, 336 bool is_dont_delete); 337 338 friend class IC; 339 }; 340 341 342 class KeyedLoadIC: public IC { 343 public: 344 explicit KeyedLoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { 345 ASSERT(target()->is_keyed_load_stub()); 346 } 347 348 MUST_USE_RESULT MaybeObject* Load(State state, 349 Handle<Object> object, 350 Handle<Object> key); 351 352 // Code generator routines. 353 static void GenerateMiss(MacroAssembler* masm); 354 static void GenerateRuntimeGetProperty(MacroAssembler* masm); 355 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } 356 static void GeneratePreMonomorphic(MacroAssembler* masm) { 357 GenerateMiss(masm); 358 } 359 static void GenerateGeneric(MacroAssembler* masm); 360 static void GenerateString(MacroAssembler* masm); 361 362 static void GenerateIndexedInterceptor(MacroAssembler* masm); 363 364 // Clear the use of the inlined version. 365 static void ClearInlinedVersion(Address address); 366 367 // Bit mask to be tested against bit field for the cases when 368 // generic stub should go into slow case. 369 // Access check is necessary explicitly since generic stub does not perform 370 // map checks. 371 static const int kSlowCaseBitFieldMask = 372 (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor); 373 374 private: 375 // Update the inline cache. 376 void UpdateCaches(LookupResult* lookup, 377 State state, 378 Handle<Object> object, 379 Handle<String> name); 380 381 // Stub accessors. 382 static Code* initialize_stub() { 383 return Isolate::Current()->builtins()->builtin( 384 Builtins::kKeyedLoadIC_Initialize); 385 } 386 Code* megamorphic_stub() { 387 return isolate()->builtins()->builtin( 388 Builtins::kKeyedLoadIC_Generic); 389 } 390 Code* generic_stub() { 391 return isolate()->builtins()->builtin( 392 Builtins::kKeyedLoadIC_Generic); 393 } 394 Code* pre_monomorphic_stub() { 395 return isolate()->builtins()->builtin( 396 Builtins::kKeyedLoadIC_PreMonomorphic); 397 } 398 Code* string_stub() { 399 return isolate()->builtins()->builtin( 400 Builtins::kKeyedLoadIC_String); 401 } 402 403 Code* indexed_interceptor_stub() { 404 return isolate()->builtins()->builtin( 405 Builtins::kKeyedLoadIC_IndexedInterceptor); 406 } 407 408 static void Clear(Address address, Code* target); 409 410 // Support for patching the map that is checked in an inlined 411 // version of keyed load. 412 static bool PatchInlinedLoad(Address address, Object* map); 413 414 friend class IC; 415 }; 416 417 418 class StoreIC: public IC { 419 public: 420 explicit StoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { 421 ASSERT(target()->is_store_stub()); 422 } 423 424 MUST_USE_RESULT MaybeObject* Store(State state, 425 StrictModeFlag strict_mode, 426 Handle<Object> object, 427 Handle<String> name, 428 Handle<Object> value); 429 430 // Code generators for stub routines. Only called once at startup. 431 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } 432 static void GenerateMiss(MacroAssembler* masm); 433 static void GenerateMegamorphic(MacroAssembler* masm, 434 StrictModeFlag strict_mode); 435 static void GenerateArrayLength(MacroAssembler* masm); 436 static void GenerateNormal(MacroAssembler* masm); 437 static void GenerateGlobalProxy(MacroAssembler* masm, 438 StrictModeFlag strict_mode); 439 440 // Clear the use of an inlined version. 441 static void ClearInlinedVersion(Address address); 442 443 // The offset from the inlined patch site to the start of the 444 // inlined store instruction. 445 static const int kOffsetToStoreInstruction; 446 447 private: 448 // Update the inline cache and the global stub cache based on the 449 // lookup result. 450 void UpdateCaches(LookupResult* lookup, 451 State state, 452 StrictModeFlag strict_mode, 453 Handle<JSObject> receiver, 454 Handle<String> name, 455 Handle<Object> value); 456 457 void set_target(Code* code) { 458 // Strict mode must be preserved across IC patching. 459 ASSERT((code->extra_ic_state() & kStrictMode) == 460 (target()->extra_ic_state() & kStrictMode)); 461 IC::set_target(code); 462 } 463 464 // Stub accessors. 465 Code* megamorphic_stub() { 466 return isolate()->builtins()->builtin( 467 Builtins::kStoreIC_Megamorphic); 468 } 469 Code* megamorphic_stub_strict() { 470 return isolate()->builtins()->builtin( 471 Builtins::kStoreIC_Megamorphic_Strict); 472 } 473 static Code* initialize_stub() { 474 return Isolate::Current()->builtins()->builtin( 475 Builtins::kStoreIC_Initialize); 476 } 477 static Code* initialize_stub_strict() { 478 return Isolate::Current()->builtins()->builtin( 479 Builtins::kStoreIC_Initialize_Strict); 480 } 481 Code* global_proxy_stub() { 482 return isolate()->builtins()->builtin( 483 Builtins::kStoreIC_GlobalProxy); 484 } 485 Code* global_proxy_stub_strict() { 486 return isolate()->builtins()->builtin( 487 Builtins::kStoreIC_GlobalProxy_Strict); 488 } 489 490 static void Clear(Address address, Code* target); 491 492 // Support for patching the index and the map that is checked in an 493 // inlined version of the named store. 494 static bool PatchInlinedStore(Address address, Object* map, int index); 495 496 friend class IC; 497 }; 498 499 500 class KeyedStoreIC: public IC { 501 public: 502 explicit KeyedStoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { } 503 504 MUST_USE_RESULT MaybeObject* Store(State state, 505 StrictModeFlag strict_mode, 506 Handle<Object> object, 507 Handle<Object> name, 508 Handle<Object> value); 509 510 // Code generators for stub routines. Only called once at startup. 511 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } 512 static void GenerateMiss(MacroAssembler* masm); 513 static void GenerateRuntimeSetProperty(MacroAssembler* masm, 514 StrictModeFlag strict_mode); 515 static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode); 516 517 // Clear the inlined version so the IC is always hit. 518 static void ClearInlinedVersion(Address address); 519 520 // Restore the inlined version so the fast case can get hit. 521 static void RestoreInlinedVersion(Address address); 522 523 private: 524 // Update the inline cache. 525 void UpdateCaches(LookupResult* lookup, 526 State state, 527 StrictModeFlag strict_mode, 528 Handle<JSObject> receiver, 529 Handle<String> name, 530 Handle<Object> value); 531 532 void set_target(Code* code) { 533 // Strict mode must be preserved across IC patching. 534 ASSERT((code->extra_ic_state() & kStrictMode) == 535 (target()->extra_ic_state() & kStrictMode)); 536 IC::set_target(code); 537 } 538 539 // Stub accessors. 540 static Code* initialize_stub() { 541 return Isolate::Current()->builtins()->builtin( 542 Builtins::kKeyedStoreIC_Initialize); 543 } 544 Code* megamorphic_stub() { 545 return isolate()->builtins()->builtin( 546 Builtins::kKeyedStoreIC_Generic); 547 } 548 static Code* initialize_stub_strict() { 549 return Isolate::Current()->builtins()->builtin( 550 Builtins::kKeyedStoreIC_Initialize_Strict); 551 } 552 Code* megamorphic_stub_strict() { 553 return isolate()->builtins()->builtin( 554 Builtins::kKeyedStoreIC_Generic_Strict); 555 } 556 Code* generic_stub() { 557 return isolate()->builtins()->builtin( 558 Builtins::kKeyedStoreIC_Generic); 559 } 560 Code* generic_stub_strict() { 561 return isolate()->builtins()->builtin( 562 Builtins::kKeyedStoreIC_Generic_Strict); 563 } 564 565 static void Clear(Address address, Code* target); 566 567 // Support for patching the map that is checked in an inlined 568 // version of keyed store. 569 // The address is the patch point for the IC call 570 // (Assembler::kCallTargetAddressOffset before the end of 571 // the call/return address). 572 // The map is the new map that the inlined code should check against. 573 static bool PatchInlinedStore(Address address, Object* map); 574 575 friend class IC; 576 }; 577 578 579 // Type Recording BinaryOpIC, that records the types of the inputs and outputs. 580 class TRBinaryOpIC: public IC { 581 public: 582 583 enum TypeInfo { 584 UNINITIALIZED, 585 SMI, 586 INT32, 587 HEAP_NUMBER, 588 ODDBALL, 589 STRING, // Only used for addition operation. At least one string operand. 590 GENERIC 591 }; 592 593 explicit TRBinaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { } 594 595 void patch(Code* code); 596 597 static const char* GetName(TypeInfo type_info); 598 599 static State ToState(TypeInfo type_info); 600 601 static TypeInfo GetTypeInfo(Handle<Object> left, Handle<Object> right); 602 603 static TypeInfo JoinTypes(TypeInfo x, TypeInfo y); 604 }; 605 606 607 class CompareIC: public IC { 608 public: 609 enum State { 610 UNINITIALIZED, 611 SMIS, 612 HEAP_NUMBERS, 613 OBJECTS, 614 GENERIC 615 }; 616 617 CompareIC(Isolate* isolate, Token::Value op) 618 : IC(EXTRA_CALL_FRAME, isolate), op_(op) { } 619 620 // Update the inline cache for the given operands. 621 void UpdateCaches(Handle<Object> x, Handle<Object> y); 622 623 // Factory method for getting an uninitialized compare stub. 624 static Handle<Code> GetUninitialized(Token::Value op); 625 626 // Helper function for computing the condition for a compare operation. 627 static Condition ComputeCondition(Token::Value op); 628 629 // Helper function for determining the state of a compare IC. 630 static State ComputeState(Code* target); 631 632 static const char* GetStateName(State state); 633 634 private: 635 State TargetState(State state, bool has_inlined_smi_code, 636 Handle<Object> x, Handle<Object> y); 637 638 bool strict() const { return op_ == Token::EQ_STRICT; } 639 Condition GetCondition() const { return ComputeCondition(op_); } 640 State GetState() { return ComputeState(target()); } 641 642 Token::Value op_; 643 }; 644 645 // Helper for TRBinaryOpIC and CompareIC. 646 void PatchInlinedSmiCode(Address address); 647 648 } } // namespace v8::internal 649 650 #endif // V8_IC_H_ 651