JitFrames.h (26054B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_JitFrames_h 8 #define jit_JitFrames_h 9 10 #include "mozilla/Assertions.h" 11 12 #include <stddef.h> 13 #include <stdint.h> 14 15 #include "jit/CalleeToken.h" 16 #include "jit/MachineState.h" 17 #include "jit/Registers.h" 18 #include "js/Id.h" 19 #include "js/TypeDecls.h" 20 #include "js/Value.h" 21 22 namespace js { 23 24 namespace wasm { 25 class Instance; 26 } 27 28 namespace jit { 29 30 enum class FrameType; 31 enum class VMFunctionId; 32 class IonScript; 33 class JitActivation; 34 class JitFrameLayout; 35 struct SafepointSlotEntry; 36 struct VMFunctionData; 37 38 // [SMDOC] JIT Frame Layout 39 // 40 // Frame Headers: 41 // 42 // In between every two frames lies a small header describing both frames. This 43 // header, minimally, contains a returnAddress word and a descriptor word (See 44 // CommonFrameLayout). The descriptor describes the type of the older (caller) 45 // frame, whereas the returnAddress describes the address the newer (callee) 46 // frame will return to. For JitFrameLayout, the descriptor also stores the 47 // number of arguments passed from the caller to the callee frame. 48 // 49 // Special Frames: 50 // 51 // Two special frame types exist: 52 // - Entry frames begin a JitActivation, and therefore there is exactly one 53 // per activation of EnterJit or EnterBaseline. These reuse JitFrameLayout. 54 // - Exit frames are necessary to leave JIT code and enter C++, and thus, 55 // C++ code will always begin iterating from the topmost exit frame. 56 // 57 // Approximate Layout: 58 // 59 // The layout of an Ion frame on the C stack is roughly: 60 // argN _ 61 // ... \ - These are jsvals 62 // arg0 / 63 // -3 this _/ 64 // -2 callee 65 // -1 descriptor 66 // 0 returnAddress 67 // .. locals .. 68 69 // [SMDOC] Frame Descriptor Layout 70 // 71 // A frame descriptor word has the following data: 72 // 73 // high bits: [ numActualArgs | 74 // has-inlined-icscript bit | 75 // has-cached-saved-frame bit | 76 // low bits: frame type ] 77 // 78 79 // * numActualArgs: for JitFrameLayout, the number of arguments passed by the 80 // caller. 81 // * HasInlinedICScript: Set when passing a private ICScript to a trial-inlined 82 // script. 83 // * HasCachedSavedFrame: Used to power the LiveSavedFrameCache optimization. 84 // See the comment in Activation.h 85 // * Frame Type: BaselineJS, Exit, etc. (jit::FrameType) 86 // 87 88 class FrameDescriptor { 89 public: 90 static const uint32_t TypeBits = 4; 91 static const uint32_t TypeMask = (1 << TypeBits) - 1; 92 static const uint32_t HasCachedSavedFrame = 1 << TypeBits; 93 static const uint32_t HasInlinedICScript = 1 << (TypeBits + 1); 94 static const uint32_t NumActualArgsShift = TypeBits + 2; 95 96 explicit FrameDescriptor(FrameType type) : raw_(uint32_t(type)) {} 97 FrameDescriptor(FrameType type, uint32_t argc, bool hasInlined = false) 98 : raw_(argc << NumActualArgsShift | uint32_t(type)) { 99 if (hasInlined) { 100 setHasInlinedICScript(); 101 } 102 MOZ_ASSERT(numActualArgs() == argc, "argc must fit in descriptor"); 103 } 104 105 FrameType type() const { return FrameType(raw_ & TypeMask); } 106 void changeType(FrameType type) { 107 raw_ &= ~TypeMask; 108 raw_ |= uintptr_t(type); 109 } 110 111 uint32_t numActualArgs() const { return raw_ >> NumActualArgsShift; } 112 113 bool hasCachedSavedFrame() const { return raw_ & HasCachedSavedFrame; } 114 void setHasCachedSavedFrame() { raw_ |= HasCachedSavedFrame; } 115 void clearHasCachedSavedFrame() { raw_ &= ~HasCachedSavedFrame; } 116 117 bool hasInlinedICScript() const { return raw_ & HasInlinedICScript; } 118 void setHasInlinedICScript() { raw_ |= HasInlinedICScript; } 119 120 uint32_t value() const { 121 MOZ_ASSERT(raw_ == uint32_t(raw_)); 122 return raw_; 123 } 124 125 private: 126 uintptr_t raw_; 127 }; 128 129 static inline uint32_t MakeFrameDescriptor(FrameType type) { 130 FrameDescriptor descriptor(type); 131 return descriptor.value(); 132 } 133 134 // For JitFrameLayout, the descriptor also stores the number of arguments passed 135 // by the caller. Note that |type| is the type of the *older* frame and |argc| 136 // is the number of arguments passed to the *newer* frame. 137 static inline uint32_t MakeFrameDescriptorForJitCall(FrameType type, 138 uint32_t argc) { 139 FrameDescriptor descriptor(type, argc); 140 return descriptor.value(); 141 } 142 143 struct BaselineBailoutInfo; 144 145 enum class ExceptionResumeKind : int32_t { 146 // There is no exception handler in this activation. 147 // Return from the entry frame. 148 EntryFrame, 149 150 // The exception was caught in baseline. 151 // Restore state and jump to the catch block. 152 Catch, 153 154 // A finally block must be executed in baseline. 155 // Stash the exception on the stack and jump to the finally block. 156 Finally, 157 158 // We are forcing an early return with a specific return value. 159 // This is used by the debugger and when closing generators. 160 // Immediately return from the current frame with the given value. 161 ForcedReturnBaseline, 162 ForcedReturnIon, 163 164 // This frame is currently executing in Ion, but we must bail out 165 // to baseline before handling the exception. 166 // Jump to the bailout tail stub. 167 Bailout, 168 169 // Return to the wasm interpreter entry frame. 170 WasmInterpEntry, 171 172 // The exception was caught by a wasm catch handler. 173 // Restore state and jump to it. 174 WasmCatch 175 }; 176 177 // Data needed to recover from an exception. 178 struct ResumeFromException { 179 uint8_t* framePointer; 180 uint8_t* stackPointer; 181 uint8_t* target; 182 ExceptionResumeKind kind; 183 wasm::Instance* instance; 184 185 // Value to push when resuming into a |finally| block. 186 // Also used by Wasm to send the exception object to the throw stub. 187 JS::Value exception; 188 189 // Exception stack to push when resuming into a |finally| block. 190 JS::Value exceptionStack; 191 192 BaselineBailoutInfo* bailoutInfo; 193 194 static size_t offsetOfFramePointer() { 195 return offsetof(ResumeFromException, framePointer); 196 } 197 static size_t offsetOfStackPointer() { 198 return offsetof(ResumeFromException, stackPointer); 199 } 200 static size_t offsetOfTarget() { 201 return offsetof(ResumeFromException, target); 202 } 203 static size_t offsetOfKind() { return offsetof(ResumeFromException, kind); } 204 static size_t offsetOfInstance() { 205 return offsetof(ResumeFromException, instance); 206 } 207 static size_t offsetOfException() { 208 return offsetof(ResumeFromException, exception); 209 } 210 static size_t offsetOfExceptionStack() { 211 return offsetof(ResumeFromException, exceptionStack); 212 } 213 static size_t offsetOfBailoutInfo() { 214 return offsetof(ResumeFromException, bailoutInfo); 215 } 216 }; 217 218 #if defined(JS_CODEGEN_ARM64) 219 static_assert(sizeof(ResumeFromException) % 16 == 0, 220 "ResumeFromException should be aligned"); 221 #endif 222 223 void HandleException(ResumeFromException* rfe); 224 225 void EnsureUnwoundJitExitFrame(JitActivation* act, JitFrameLayout* frame); 226 227 void TraceJitActivations(JSContext* cx, JSTracer* trc); 228 229 // Trace weak pointers in baseline stubs in activations for zones that are 230 // currently being swept. 231 void TraceWeakJitActivationsInSweepingZones(JSContext* cx, JSTracer* trc); 232 233 void UpdateJitActivationsForMinorGC(JSRuntime* rt); 234 void UpdateJitActivationsForCompactingGC(JSRuntime* rt); 235 236 // Returns the JSScript associated with the topmost JIT frame. 237 JSScript* GetTopJitJSScript(JSContext* cx); 238 239 #if defined(JS_CODEGEN_ARM64) 240 uint8_t* alignDoubleSpill(uint8_t* pointer); 241 #else 242 inline uint8_t* alignDoubleSpill(uint8_t* pointer) { 243 // This is a no-op on most platforms. 244 return pointer; 245 } 246 #endif 247 248 // Layout of the frame prefix. This assumes the stack architecture grows down. 249 // If this is ever not the case, we'll have to refactor. 250 class CommonFrameLayout { 251 uint8_t* callerFramePtr_; 252 uint8_t* returnAddress_; 253 FrameDescriptor descriptor_; 254 255 public: 256 static constexpr size_t offsetOfDescriptor() { 257 return offsetof(CommonFrameLayout, descriptor_); 258 } 259 FrameDescriptor descriptor() const { return descriptor_; } 260 static constexpr size_t offsetOfReturnAddress() { 261 return offsetof(CommonFrameLayout, returnAddress_); 262 } 263 FrameType prevType() const { return descriptor_.type(); } 264 void changePrevType(FrameType type) { descriptor_.changeType(type); } 265 bool hasCachedSavedFrame() const { return descriptor_.hasCachedSavedFrame(); } 266 void setHasCachedSavedFrame() { descriptor_.setHasCachedSavedFrame(); } 267 void clearHasCachedSavedFrame() { descriptor_.clearHasCachedSavedFrame(); } 268 uint8_t* returnAddress() const { return returnAddress_; } 269 void setReturnAddress(uint8_t* addr) { returnAddress_ = addr; } 270 271 uint8_t* callerFramePtr() const { return callerFramePtr_; } 272 static constexpr size_t offsetOfCallerFramePtr() { 273 return offsetof(CommonFrameLayout, callerFramePtr_); 274 } 275 static constexpr size_t bytesPoppedAfterCall() { 276 // The return address and frame pointer are popped by the callee/call. 277 return 2 * sizeof(void*); 278 } 279 }; 280 281 class JitFrameLayout : public CommonFrameLayout { 282 CalleeToken calleeToken_; 283 284 public: 285 CalleeToken calleeToken() const { return calleeToken_; } 286 void replaceCalleeToken(CalleeToken calleeToken) { 287 calleeToken_ = calleeToken; 288 } 289 290 static constexpr size_t offsetOfCalleeToken() { 291 return offsetof(JitFrameLayout, calleeToken_); 292 } 293 static constexpr size_t offsetOfThis() { return sizeof(JitFrameLayout); } 294 static constexpr size_t offsetOfActualArgs() { 295 return offsetOfThis() + sizeof(JS::Value); 296 } 297 static constexpr size_t offsetOfActualArg(size_t arg) { 298 return offsetOfActualArgs() + arg * sizeof(JS::Value); 299 } 300 301 JS::Value& thisv() { 302 MOZ_ASSERT(CalleeTokenIsFunction(calleeToken())); 303 return thisAndActualArgs()[0]; 304 } 305 JS::Value* thisAndActualArgs() { 306 MOZ_ASSERT(CalleeTokenIsFunction(calleeToken())); 307 return (JS::Value*)(this + 1); 308 } 309 JS::Value* actualArgs() { return thisAndActualArgs() + 1; } 310 uintptr_t numActualArgs() const { return descriptor().numActualArgs(); } 311 312 // Computes a reference to a stack or argument slot, where a slot is a 313 // distance from the base frame pointer, as would be used for LStackSlot 314 // or LArgument. 315 uintptr_t* slotRef(SafepointSlotEntry where); 316 317 static inline size_t Size() { return sizeof(JitFrameLayout); } 318 }; 319 320 class BaselineInterpreterEntryFrameLayout : public JitFrameLayout { 321 public: 322 static inline size_t Size() { 323 return sizeof(BaselineInterpreterEntryFrameLayout); 324 } 325 }; 326 327 class TrampolineNativeFrameLayout : public JitFrameLayout { 328 public: 329 static inline size_t Size() { return sizeof(TrampolineNativeFrameLayout); } 330 331 template <typename T> 332 T* getFrameData() { 333 uint8_t* raw = reinterpret_cast<uint8_t*>(this) - sizeof(T); 334 return reinterpret_cast<T*>(raw); 335 } 336 }; 337 338 class WasmToJSJitFrameLayout : public JitFrameLayout { 339 public: 340 static inline size_t Size() { return sizeof(WasmToJSJitFrameLayout); } 341 }; 342 343 class IonICCallFrameLayout : public CommonFrameLayout { 344 protected: 345 // Pointer to root the stub's JitCode. 346 JitCode* stubCode_; 347 348 public: 349 static constexpr size_t LocallyTracedValueOffset = sizeof(void*); 350 351 JitCode** stubCode() { return &stubCode_; } 352 static size_t Size() { return sizeof(IonICCallFrameLayout); } 353 354 inline Value* locallyTracedValuePtr(size_t index) { 355 uint8_t* fp = reinterpret_cast<uint8_t*>(this); 356 return reinterpret_cast<Value*>(fp - LocallyTracedValueOffset - 357 index * sizeof(Value)); 358 } 359 }; 360 361 enum class ExitFrameType : uint8_t { 362 CallNative = 0x0, 363 ConstructNative = 0x1, 364 IonDOMGetter = 0x2, 365 IonDOMSetter = 0x3, 366 IonDOMMethod = 0x4, 367 IonOOLNative = 0x5, 368 IonOOLProxy = 0x6, 369 WasmGenericJitEntry = 0x7, 370 DirectWasmJitCall = 0x8, 371 UnwoundJit = 0x9, 372 InterpreterStub = 0xA, 373 LazyLink = 0xB, 374 Bare = 0xC, 375 376 // This must be the last value in this enum. See ExitFooterFrame::data_. 377 VMFunction = 0xD 378 }; 379 380 // GC related data used to keep alive data surrounding the Exit frame. 381 class ExitFooterFrame { 382 // Stores either the ExitFrameType or, for a VMFunction call, 383 // `ExitFrameType::VMFunction + VMFunctionId`. 384 uintptr_t data_; 385 386 #ifdef DEBUG 387 void assertValidVMFunctionId() const; 388 #else 389 void assertValidVMFunctionId() const {} 390 #endif 391 392 public: 393 static constexpr size_t Size() { return sizeof(ExitFooterFrame); } 394 void setUnwoundJitExitFrame() { 395 data_ = uintptr_t(ExitFrameType::UnwoundJit); 396 } 397 ExitFrameType type() const { 398 if (data_ >= uintptr_t(ExitFrameType::VMFunction)) { 399 return ExitFrameType::VMFunction; 400 } 401 return ExitFrameType(data_); 402 } 403 VMFunctionId functionId() const { 404 MOZ_ASSERT(type() == ExitFrameType::VMFunction); 405 assertValidVMFunctionId(); 406 return static_cast<VMFunctionId>(data_ - size_t(ExitFrameType::VMFunction)); 407 } 408 409 // This should only be called for function()->outParam == Type_Handle 410 template <typename T> 411 T* outParam() { 412 uint8_t* address = reinterpret_cast<uint8_t*>(this); 413 return reinterpret_cast<T*>(address - sizeof(T)); 414 } 415 }; 416 417 class NativeExitFrameLayout; 418 class IonOOLNativeExitFrameLayout; 419 class IonOOLProxyExitFrameLayout; 420 class IonDOMExitFrameLayout; 421 422 // this is the frame layout when we are exiting ion code, and about to enter 423 // platform ABI code 424 class ExitFrameLayout : public CommonFrameLayout { 425 inline uint8_t* top() { return reinterpret_cast<uint8_t*>(this + 1); } 426 427 public: 428 static constexpr size_t Size() { return sizeof(ExitFrameLayout); } 429 static constexpr size_t SizeWithFooter() { 430 return Size() + ExitFooterFrame::Size(); 431 } 432 433 inline ExitFooterFrame* footer() { 434 uint8_t* sp = reinterpret_cast<uint8_t*>(this); 435 return reinterpret_cast<ExitFooterFrame*>(sp - ExitFooterFrame::Size()); 436 } 437 438 // argBase targets the point which precedes the exit frame. Arguments of VM 439 // each wrapper are pushed before the exit frame. This correspond exactly 440 // to the value of the argBase register of the generateVMWrapper function. 441 inline uint8_t* argBase() { 442 MOZ_ASSERT(isWrapperExit()); 443 return top(); 444 } 445 446 inline bool isWrapperExit() { 447 return footer()->type() == ExitFrameType::VMFunction; 448 } 449 inline bool isBareExit() { return footer()->type() == ExitFrameType::Bare; } 450 inline bool isUnwoundJitExit() { 451 return footer()->type() == ExitFrameType::UnwoundJit; 452 } 453 454 // See the various exit frame layouts below. 455 template <typename T> 456 inline bool is() { 457 return footer()->type() == T::Type(); 458 } 459 template <typename T> 460 inline T* as() { 461 MOZ_ASSERT(this->is<T>()); 462 return reinterpret_cast<T*>(footer()); 463 } 464 }; 465 466 // Cannot inherit implementation since we need to extend the top of 467 // ExitFrameLayout. 468 class NativeExitFrameLayout { 469 protected: // only to silence a clang warning about unused private fields 470 ExitFooterFrame footer_; 471 ExitFrameLayout exit_; 472 uintptr_t argc_; 473 474 // We need to split the Value into 2 fields of 32 bits, otherwise the C++ 475 // compiler may add some padding between the fields. 476 uint32_t loCalleeResult_; 477 uint32_t hiCalleeResult_; 478 479 public: 480 static inline size_t Size() { return sizeof(NativeExitFrameLayout); } 481 482 static size_t offsetOfResult() { 483 return offsetof(NativeExitFrameLayout, loCalleeResult_); 484 } 485 inline JS::Value* vp() { 486 return reinterpret_cast<JS::Value*>(&loCalleeResult_); 487 } 488 inline uintptr_t argc() const { return argc_; } 489 }; 490 491 class CallNativeExitFrameLayout : public NativeExitFrameLayout { 492 public: 493 static ExitFrameType Type() { return ExitFrameType::CallNative; } 494 }; 495 496 class ConstructNativeExitFrameLayout : public NativeExitFrameLayout { 497 public: 498 static ExitFrameType Type() { return ExitFrameType::ConstructNative; } 499 }; 500 501 template <> 502 inline bool ExitFrameLayout::is<NativeExitFrameLayout>() { 503 return is<CallNativeExitFrameLayout>() || 504 is<ConstructNativeExitFrameLayout>(); 505 } 506 507 class IonOOLNativeExitFrameLayout { 508 protected: // only to silence a clang warning about unused private fields 509 ExitFooterFrame footer_; 510 ExitFrameLayout exit_; 511 512 // pointer to root the stub's JitCode 513 JitCode* stubCode_; 514 515 uintptr_t argc_; 516 517 // We need to split the Value into 2 fields of 32 bits, otherwise the C++ 518 // compiler may add some padding between the fields. 519 uint32_t loCalleeResult_; 520 uint32_t hiCalleeResult_; 521 522 // Split Value for |this| and args above. 523 uint32_t loThis_; 524 uint32_t hiThis_; 525 526 public: 527 static ExitFrameType Type() { return ExitFrameType::IonOOLNative; } 528 529 static inline size_t Size(size_t argc) { 530 // The frame accounts for the callee/result and |this|, so we only need 531 // args. 532 return sizeof(IonOOLNativeExitFrameLayout) + (argc * sizeof(JS::Value)); 533 } 534 535 static size_t offsetOfResult() { 536 return offsetof(IonOOLNativeExitFrameLayout, loCalleeResult_); 537 } 538 539 inline JitCode** stubCode() { return &stubCode_; } 540 inline JS::Value* vp() { 541 return reinterpret_cast<JS::Value*>(&loCalleeResult_); 542 } 543 inline JS::Value* thisp() { return reinterpret_cast<JS::Value*>(&loThis_); } 544 inline uintptr_t argc() const { return argc_; } 545 }; 546 547 // ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, 548 // MutableHandleValue vp) 549 // ProxyCallProperty(JSContext* cx, HandleObject proxy, HandleId id, 550 // MutableHandleValue vp) 551 // ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, 552 // MutableHandleValue vp, bool strict) 553 class IonOOLProxyExitFrameLayout { 554 protected: // only to silence a clang warning about unused private fields 555 ExitFooterFrame footer_; 556 ExitFrameLayout exit_; 557 558 // The proxy object. 559 JSObject* proxy_; 560 561 // id for HandleId 562 jsid id_; 563 564 // space for MutableHandleValue result 565 // use two uint32_t so compiler doesn't align. 566 uint32_t vp0_; 567 uint32_t vp1_; 568 569 // pointer to root the stub's JitCode 570 JitCode* stubCode_; 571 572 public: 573 static ExitFrameType Type() { return ExitFrameType::IonOOLProxy; } 574 575 static inline size_t Size() { return sizeof(IonOOLProxyExitFrameLayout); } 576 577 static size_t offsetOfResult() { 578 return offsetof(IonOOLProxyExitFrameLayout, vp0_); 579 } 580 581 inline JitCode** stubCode() { return &stubCode_; } 582 inline JS::Value* vp() { return reinterpret_cast<JS::Value*>(&vp0_); } 583 inline jsid* id() { return &id_; } 584 inline JSObject** proxy() { return &proxy_; } 585 }; 586 587 class IonDOMExitFrameLayout { 588 protected: // only to silence a clang warning about unused private fields 589 ExitFooterFrame footer_; 590 ExitFrameLayout exit_; 591 JSObject* thisObj; 592 593 // We need to split the Value into 2 fields of 32 bits, otherwise the C++ 594 // compiler may add some padding between the fields. 595 uint32_t loCalleeResult_; 596 uint32_t hiCalleeResult_; 597 598 public: 599 static ExitFrameType GetterType() { return ExitFrameType::IonDOMGetter; } 600 static ExitFrameType SetterType() { return ExitFrameType::IonDOMSetter; } 601 602 static inline size_t Size() { return sizeof(IonDOMExitFrameLayout); } 603 604 static size_t offsetOfResult() { 605 return offsetof(IonDOMExitFrameLayout, loCalleeResult_); 606 } 607 inline JS::Value* vp() { 608 return reinterpret_cast<JS::Value*>(&loCalleeResult_); 609 } 610 inline JSObject** thisObjAddress() { return &thisObj; } 611 inline bool isMethodFrame(); 612 }; 613 614 struct IonDOMMethodExitFrameLayoutTraits; 615 616 class IonDOMMethodExitFrameLayout { 617 protected: // only to silence a clang warning about unused private fields 618 ExitFooterFrame footer_; 619 ExitFrameLayout exit_; 620 // This must be the last thing pushed, so as to stay common with 621 // IonDOMExitFrameLayout. 622 JSObject* thisObj_; 623 JS::Value* argv_; 624 uintptr_t argc_; 625 626 // We need to split the Value into 2 fields of 32 bits, otherwise the C++ 627 // compiler may add some padding between the fields. 628 uint32_t loCalleeResult_; 629 uint32_t hiCalleeResult_; 630 631 friend struct IonDOMMethodExitFrameLayoutTraits; 632 633 public: 634 static ExitFrameType Type() { return ExitFrameType::IonDOMMethod; } 635 636 static inline size_t Size() { return sizeof(IonDOMMethodExitFrameLayout); } 637 638 static size_t offsetOfResult() { 639 return offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_); 640 } 641 642 inline JS::Value* vp() { 643 // The code in visitCallDOMNative depends on this static assert holding 644 static_assert( 645 offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_) == 646 (offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t))); 647 return reinterpret_cast<JS::Value*>(&loCalleeResult_); 648 } 649 inline JSObject** thisObjAddress() { return &thisObj_; } 650 inline uintptr_t argc() { return argc_; } 651 }; 652 653 inline bool IonDOMExitFrameLayout::isMethodFrame() { 654 return footer_.type() == IonDOMMethodExitFrameLayout::Type(); 655 } 656 657 template <> 658 inline bool ExitFrameLayout::is<IonDOMExitFrameLayout>() { 659 ExitFrameType type = footer()->type(); 660 return type == IonDOMExitFrameLayout::GetterType() || 661 type == IonDOMExitFrameLayout::SetterType() || 662 type == IonDOMMethodExitFrameLayout::Type(); 663 } 664 665 template <> 666 inline IonDOMExitFrameLayout* ExitFrameLayout::as<IonDOMExitFrameLayout>() { 667 MOZ_ASSERT(is<IonDOMExitFrameLayout>()); 668 return reinterpret_cast<IonDOMExitFrameLayout*>(footer()); 669 } 670 671 struct IonDOMMethodExitFrameLayoutTraits { 672 static const size_t offsetOfArgcFromArgv = 673 offsetof(IonDOMMethodExitFrameLayout, argc_) - 674 offsetof(IonDOMMethodExitFrameLayout, argv_); 675 }; 676 677 // Cannot inherit implementation since we need to extend the top of 678 // ExitFrameLayout. 679 class CalledFromJitExitFrameLayout { 680 protected: // silence clang warning about unused private fields 681 ExitFooterFrame footer_; 682 JitFrameLayout exit_; 683 684 public: 685 static inline size_t Size() { return sizeof(CalledFromJitExitFrameLayout); } 686 inline JitFrameLayout* jsFrame() { return &exit_; } 687 static size_t offsetOfExitFrame() { 688 return offsetof(CalledFromJitExitFrameLayout, exit_); 689 } 690 }; 691 692 class LazyLinkExitFrameLayout : public CalledFromJitExitFrameLayout { 693 public: 694 static ExitFrameType Type() { return ExitFrameType::LazyLink; } 695 }; 696 697 class InterpreterStubExitFrameLayout : public CalledFromJitExitFrameLayout { 698 public: 699 static ExitFrameType Type() { return ExitFrameType::InterpreterStub; } 700 }; 701 702 class WasmGenericJitEntryFrameLayout : CalledFromJitExitFrameLayout { 703 public: 704 static ExitFrameType Type() { return ExitFrameType::WasmGenericJitEntry; } 705 }; 706 707 template <> 708 inline bool ExitFrameLayout::is<CalledFromJitExitFrameLayout>() { 709 return is<InterpreterStubExitFrameLayout>() || 710 is<LazyLinkExitFrameLayout>() || is<WasmGenericJitEntryFrameLayout>(); 711 } 712 713 template <> 714 inline CalledFromJitExitFrameLayout* 715 ExitFrameLayout::as<CalledFromJitExitFrameLayout>() { 716 MOZ_ASSERT(is<CalledFromJitExitFrameLayout>()); 717 uint8_t* sp = reinterpret_cast<uint8_t*>(this); 718 sp -= CalledFromJitExitFrameLayout::offsetOfExitFrame(); 719 return reinterpret_cast<CalledFromJitExitFrameLayout*>(sp); 720 } 721 722 class DirectWasmJitCallFrameLayout { 723 protected: // silence clang warning about unused private fields 724 ExitFooterFrame footer_; 725 ExitFrameLayout exit_; 726 727 public: 728 static ExitFrameType Type() { return ExitFrameType::DirectWasmJitCall; } 729 }; 730 731 class ICStub; 732 733 class BaselineStubFrameLayout : public CommonFrameLayout { 734 // Info on the stack 735 // 736 // +-------------------------------------------+ 737 // |BaselineStubFrameLayout | 738 // +-------------------------------------------+ 739 // | - Descriptor | <= Marks end of 740 // | - Return address | FrameType::BaselineJS 741 // | - CallerFramePtr | <= Frame pointer points here 742 // +-------------------------------------------+ 743 // | - StubPtr | <= Technically these fields 744 // | - InlinedICScript or LocallyTracedValue | precede the FrameLayout in 745 // | LocallyTracedValue...| memory. 746 // +-------------------------------------------+ 747 // 748 // StubPtr is always present (but can be null; see generateDebugTrapHandler). 749 // InlinedICScript is only present if the HasInlinedICScript flag is set in 750 // the callee's frame descriptor (not shown in this diagram). Alternatively, 751 // we support up to 255 locally traced values (with the count stored in 752 // stub->jitCode()->localTracingSlots()). 753 public: 754 static constexpr size_t ICStubOffset = sizeof(void*); 755 static constexpr int ICStubOffsetFromFP = -int(ICStubOffset); 756 static constexpr int InlinedICScriptOffsetFromFP = 2 * -int(sizeof(void*)); 757 static constexpr size_t LocallyTracedValueOffset = 2 * sizeof(void*); 758 759 static inline size_t Size() { return sizeof(BaselineStubFrameLayout); } 760 761 ICStub* maybeStubPtr() { 762 uint8_t* fp = reinterpret_cast<uint8_t*>(this); 763 return *reinterpret_cast<ICStub**>(fp - ICStubOffset); 764 } 765 void setStubPtr(ICStub* stub) { 766 MOZ_ASSERT(stub); 767 uint8_t* fp = reinterpret_cast<uint8_t*>(this); 768 *reinterpret_cast<ICStub**>(fp - ICStubOffset) = stub; 769 } 770 771 inline Value* locallyTracedValuePtr(size_t index) { 772 uint8_t* fp = reinterpret_cast<uint8_t*>(this); 773 return reinterpret_cast<Value*>(fp - LocallyTracedValueOffset - 774 index * sizeof(Value)); 775 } 776 }; 777 778 // An invalidation bailout stack is at the stack pointer for the callee frame. 779 class InvalidationBailoutStack { 780 RegisterDump::FPUArray fpregs_; 781 RegisterDump::GPRArray regs_; 782 IonScript* ionScript_; 783 uint8_t* osiPointReturnAddress_; 784 785 public: 786 uint8_t* sp() const { 787 return (uint8_t*)this + sizeof(InvalidationBailoutStack); 788 } 789 JitFrameLayout* fp() const; 790 MachineState machine() { return MachineState::FromBailout(regs_, fpregs_); } 791 792 IonScript* ionScript() const { return ionScript_; } 793 uint8_t* osiPointReturnAddress() const { return osiPointReturnAddress_; } 794 static size_t offsetOfFpRegs() { 795 return offsetof(InvalidationBailoutStack, fpregs_); 796 } 797 static size_t offsetOfRegs() { 798 return offsetof(InvalidationBailoutStack, regs_); 799 } 800 801 void checkInvariants() const; 802 }; 803 804 // Baseline requires one slot for this/argument type checks. 805 static const uint32_t MinJITStackSize = 1; 806 807 } /* namespace jit */ 808 } /* namespace js */ 809 810 #endif /* jit_JitFrames_h */