michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_IonFrames_h michael@0: #define jit_IonFrames_h michael@0: michael@0: #ifdef JS_ION michael@0: michael@0: #include michael@0: michael@0: #include "jscntxt.h" michael@0: #include "jsfun.h" michael@0: michael@0: #include "jit/JitFrameIterator.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: typedef void * CalleeToken; michael@0: michael@0: enum CalleeTokenTag michael@0: { michael@0: CalleeToken_Function = 0x0, // untagged michael@0: CalleeToken_Script = 0x1 michael@0: }; michael@0: michael@0: static inline CalleeTokenTag michael@0: GetCalleeTokenTag(CalleeToken token) michael@0: { michael@0: CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3); michael@0: JS_ASSERT(tag <= CalleeToken_Script); michael@0: return tag; michael@0: } michael@0: static inline CalleeToken michael@0: CalleeToToken(JSFunction *fun) michael@0: { michael@0: return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_Function)); michael@0: } michael@0: static inline CalleeToken michael@0: CalleeToToken(JSScript *script) michael@0: { michael@0: return CalleeToken(uintptr_t(script) | uintptr_t(CalleeToken_Script)); michael@0: } michael@0: static inline bool michael@0: CalleeTokenIsFunction(CalleeToken token) michael@0: { michael@0: return GetCalleeTokenTag(token) == CalleeToken_Function; michael@0: } michael@0: static inline JSFunction * michael@0: CalleeTokenToFunction(CalleeToken token) michael@0: { michael@0: JS_ASSERT(CalleeTokenIsFunction(token)); michael@0: return (JSFunction *)token; michael@0: } michael@0: static inline JSScript * michael@0: CalleeTokenToScript(CalleeToken token) michael@0: { michael@0: JS_ASSERT(GetCalleeTokenTag(token) == CalleeToken_Script); michael@0: return (JSScript *)(uintptr_t(token) & ~uintptr_t(0x3)); michael@0: } michael@0: michael@0: static inline JSScript * michael@0: ScriptFromCalleeToken(CalleeToken token) michael@0: { michael@0: switch (GetCalleeTokenTag(token)) { michael@0: case CalleeToken_Script: michael@0: return CalleeTokenToScript(token); michael@0: case CalleeToken_Function: michael@0: return CalleeTokenToFunction(token)->nonLazyScript(); michael@0: } michael@0: MOZ_ASSUME_UNREACHABLE("invalid callee token tag"); michael@0: } michael@0: michael@0: // In between every two frames lies a small header describing both frames. This michael@0: // header, minimally, contains a returnAddress word and a descriptor word. The michael@0: // descriptor describes the size and type of the previous frame, whereas the michael@0: // returnAddress describes the address the newer frame (the callee) will return michael@0: // to. The exact mechanism in which frames are laid out is architecture michael@0: // dependent. michael@0: // michael@0: // Two special frame types exist. Entry frames begin an ion activation, and michael@0: // therefore there is exactly one per activation of jit::Cannon. Exit frames michael@0: // are necessary to leave JIT code and enter C++, and thus, C++ code will michael@0: // always begin iterating from the topmost exit frame. michael@0: michael@0: class LSafepoint; michael@0: michael@0: // Two-tuple that lets you look up the safepoint entry given the michael@0: // displacement of a call instruction within the JIT code. michael@0: class SafepointIndex michael@0: { michael@0: // The displacement is the distance from the first byte of the JIT'd code michael@0: // to the return address (of the call that the safepoint was generated for). michael@0: uint32_t displacement_; michael@0: michael@0: union { michael@0: LSafepoint *safepoint_; michael@0: michael@0: // Offset to the start of the encoded safepoint in the safepoint stream. michael@0: uint32_t safepointOffset_; michael@0: }; michael@0: michael@0: #ifdef DEBUG michael@0: bool resolved; michael@0: #endif michael@0: michael@0: public: michael@0: SafepointIndex(uint32_t displacement, LSafepoint *safepoint) michael@0: : displacement_(displacement), michael@0: safepoint_(safepoint) michael@0: #ifdef DEBUG michael@0: , resolved(false) michael@0: #endif michael@0: { } michael@0: michael@0: void resolve(); michael@0: michael@0: LSafepoint *safepoint() { michael@0: JS_ASSERT(!resolved); michael@0: return safepoint_; michael@0: } michael@0: uint32_t displacement() const { michael@0: return displacement_; michael@0: } michael@0: uint32_t safepointOffset() const { michael@0: return safepointOffset_; michael@0: } michael@0: void adjustDisplacement(uint32_t offset) { michael@0: JS_ASSERT(offset >= displacement_); michael@0: displacement_ = offset; michael@0: } michael@0: inline SnapshotOffset snapshotOffset() const; michael@0: inline bool hasSnapshotOffset() const; michael@0: }; michael@0: michael@0: class MacroAssembler; michael@0: // The OSI point is patched to a call instruction. Therefore, the michael@0: // returnPoint for an OSI call is the address immediately following that michael@0: // call instruction. The displacement of that point within the assembly michael@0: // buffer is the |returnPointDisplacement|. michael@0: class OsiIndex michael@0: { michael@0: uint32_t callPointDisplacement_; michael@0: uint32_t snapshotOffset_; michael@0: michael@0: public: michael@0: OsiIndex(uint32_t callPointDisplacement, uint32_t snapshotOffset) michael@0: : callPointDisplacement_(callPointDisplacement), michael@0: snapshotOffset_(snapshotOffset) michael@0: { } michael@0: michael@0: uint32_t returnPointDisplacement() const; michael@0: uint32_t callPointDisplacement() const { michael@0: return callPointDisplacement_; michael@0: } michael@0: uint32_t snapshotOffset() const { michael@0: return snapshotOffset_; michael@0: } michael@0: void fixUpOffset(MacroAssembler &masm); michael@0: }; michael@0: michael@0: // The layout of an Ion frame on the C stack is roughly: michael@0: // argN _ michael@0: // ... \ - These are jsvals michael@0: // arg0 / michael@0: // -3 this _/ michael@0: // -2 callee michael@0: // -1 descriptor michael@0: // 0 returnAddress michael@0: // .. locals .. michael@0: michael@0: // The descriptor is organized into three sections: michael@0: // [ frame size | constructing bit | frame type ] michael@0: // < highest - - - - - - - - - - - - - - lowest > michael@0: static const uintptr_t FRAMESIZE_SHIFT = 4; michael@0: static const uintptr_t FRAMETYPE_BITS = 4; michael@0: static const uintptr_t FRAMETYPE_MASK = (1 << FRAMETYPE_BITS) - 1; michael@0: michael@0: // Ion frames have a few important numbers associated with them: michael@0: // Local depth: The number of bytes required to spill local variables. michael@0: // Argument depth: The number of bytes required to push arguments and make michael@0: // a function call. michael@0: // Slack: A frame may temporarily use extra stack to resolve cycles. michael@0: // michael@0: // The (local + argument) depth determines the "fixed frame size". The fixed michael@0: // frame size is the distance between the stack pointer and the frame header. michael@0: // Thus, fixed >= (local + argument). michael@0: // michael@0: // In order to compress guards, we create shared jump tables that recover the michael@0: // script from the stack and recover a snapshot pointer based on which jump was michael@0: // taken. Thus, we create a jump table for each fixed frame size. michael@0: // michael@0: // Jump tables are big. To control the amount of jump tables we generate, each michael@0: // platform chooses how to segregate stack size classes based on its michael@0: // architecture. michael@0: // michael@0: // On some architectures, these jump tables are not used at all, or frame michael@0: // size segregation is not needed. Thus, there is an option for a frame to not michael@0: // have any frame size class, and to be totally dynamic. michael@0: static const uint32_t NO_FRAME_SIZE_CLASS_ID = uint32_t(-1); michael@0: michael@0: class FrameSizeClass michael@0: { michael@0: uint32_t class_; michael@0: michael@0: explicit FrameSizeClass(uint32_t class_) : class_(class_) michael@0: { } michael@0: michael@0: public: michael@0: FrameSizeClass() michael@0: { } michael@0: michael@0: static FrameSizeClass None() { michael@0: return FrameSizeClass(NO_FRAME_SIZE_CLASS_ID); michael@0: } michael@0: static FrameSizeClass FromClass(uint32_t class_) { michael@0: return FrameSizeClass(class_); michael@0: } michael@0: michael@0: // These functions are implemented in specific CodeGenerator-* files. michael@0: static FrameSizeClass FromDepth(uint32_t frameDepth); michael@0: static FrameSizeClass ClassLimit(); michael@0: uint32_t frameSize() const; michael@0: michael@0: uint32_t classId() const { michael@0: JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID); michael@0: return class_; michael@0: } michael@0: michael@0: bool operator ==(const FrameSizeClass &other) const { michael@0: return class_ == other.class_; michael@0: } michael@0: bool operator !=(const FrameSizeClass &other) const { michael@0: return class_ != other.class_; michael@0: } michael@0: }; michael@0: michael@0: struct BaselineBailoutInfo; michael@0: michael@0: // Data needed to recover from an exception. michael@0: struct ResumeFromException michael@0: { michael@0: static const uint32_t RESUME_ENTRY_FRAME = 0; michael@0: static const uint32_t RESUME_CATCH = 1; michael@0: static const uint32_t RESUME_FINALLY = 2; michael@0: static const uint32_t RESUME_FORCED_RETURN = 3; michael@0: static const uint32_t RESUME_BAILOUT = 4; michael@0: michael@0: uint8_t *framePointer; michael@0: uint8_t *stackPointer; michael@0: uint8_t *target; michael@0: uint32_t kind; michael@0: michael@0: // Value to push when resuming into a |finally| block. michael@0: Value exception; michael@0: michael@0: BaselineBailoutInfo *bailoutInfo; michael@0: }; michael@0: michael@0: void HandleException(ResumeFromException *rfe); michael@0: void HandleParallelFailure(ResumeFromException *rfe); michael@0: michael@0: void EnsureExitFrame(IonCommonFrameLayout *frame); michael@0: michael@0: void MarkJitActivations(JSRuntime *rt, JSTracer *trc); michael@0: void MarkIonCompilerRoots(JSTracer *trc); michael@0: michael@0: #ifdef JSGC_GENERATIONAL michael@0: void UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc); michael@0: #endif michael@0: michael@0: static inline uint32_t michael@0: MakeFrameDescriptor(uint32_t frameSize, FrameType type) michael@0: { michael@0: return (frameSize << FRAMESIZE_SHIFT) | type; michael@0: } michael@0: michael@0: // Returns the JSScript associated with the topmost Ion frame. michael@0: inline JSScript * michael@0: GetTopIonJSScript(uint8_t *ionTop, void **returnAddrOut, ExecutionMode mode) michael@0: { michael@0: JitFrameIterator iter(ionTop, mode); michael@0: JS_ASSERT(iter.type() == JitFrame_Exit); michael@0: ++iter; michael@0: michael@0: JS_ASSERT(iter.returnAddressToFp() != nullptr); michael@0: if (returnAddrOut) michael@0: *returnAddrOut = (void *) iter.returnAddressToFp(); michael@0: michael@0: if (iter.isBaselineStub()) { michael@0: ++iter; michael@0: JS_ASSERT(iter.isBaselineJS()); michael@0: } michael@0: michael@0: JS_ASSERT(iter.isScripted()); michael@0: return iter.script(); michael@0: } michael@0: michael@0: static JitCode *const ION_FRAME_DOMGETTER = (JitCode *)0x1; michael@0: static JitCode *const ION_FRAME_DOMSETTER = (JitCode *)0x2; michael@0: static JitCode *const ION_FRAME_DOMMETHOD = (JitCode *)0x3; michael@0: static JitCode *const ION_FRAME_OOL_NATIVE = (JitCode *)0x4; michael@0: static JitCode *const ION_FRAME_OOL_PROPERTY_OP = (JitCode *)0x5; michael@0: static JitCode *const ION_FRAME_OOL_PROXY = (JitCode *)0x6; michael@0: michael@0: // Layout of the frame prefix. This assumes the stack architecture grows down. michael@0: // If this is ever not the case, we'll have to refactor. michael@0: class IonCommonFrameLayout michael@0: { michael@0: uint8_t *returnAddress_; michael@0: uintptr_t descriptor_; michael@0: michael@0: static const uintptr_t FrameTypeMask = (1 << FRAMETYPE_BITS) - 1; michael@0: michael@0: public: michael@0: static size_t offsetOfDescriptor() { michael@0: return offsetof(IonCommonFrameLayout, descriptor_); michael@0: } michael@0: static size_t offsetOfReturnAddress() { michael@0: return offsetof(IonCommonFrameLayout, returnAddress_); michael@0: } michael@0: FrameType prevType() const { michael@0: return FrameType(descriptor_ & FrameTypeMask); michael@0: } michael@0: void changePrevType(FrameType type) { michael@0: descriptor_ &= ~FrameTypeMask; michael@0: descriptor_ |= type; michael@0: } michael@0: size_t prevFrameLocalSize() const { michael@0: return descriptor_ >> FRAMESIZE_SHIFT; michael@0: } michael@0: void setFrameDescriptor(size_t size, FrameType type) { michael@0: descriptor_ = (size << FRAMESIZE_SHIFT) | type; michael@0: } michael@0: uint8_t *returnAddress() const { michael@0: return returnAddress_; michael@0: } michael@0: void setReturnAddress(uint8_t *addr) { michael@0: returnAddress_ = addr; michael@0: } michael@0: }; michael@0: michael@0: class IonJSFrameLayout : public IonCommonFrameLayout michael@0: { michael@0: CalleeToken calleeToken_; michael@0: uintptr_t numActualArgs_; michael@0: michael@0: public: michael@0: CalleeToken calleeToken() const { michael@0: return calleeToken_; michael@0: } michael@0: void replaceCalleeToken(CalleeToken calleeToken) { michael@0: calleeToken_ = calleeToken; michael@0: } michael@0: michael@0: static size_t offsetOfCalleeToken() { michael@0: return offsetof(IonJSFrameLayout, calleeToken_); michael@0: } michael@0: static size_t offsetOfNumActualArgs() { michael@0: return offsetof(IonJSFrameLayout, numActualArgs_); michael@0: } michael@0: static size_t offsetOfThis() { michael@0: IonJSFrameLayout *base = nullptr; michael@0: return reinterpret_cast(&base->argv()[0]); michael@0: } michael@0: static size_t offsetOfActualArgs() { michael@0: IonJSFrameLayout *base = nullptr; michael@0: // +1 to skip |this|. michael@0: return reinterpret_cast(&base->argv()[1]); michael@0: } michael@0: static size_t offsetOfActualArg(size_t arg) { michael@0: return offsetOfActualArgs() + arg * sizeof(Value); michael@0: } michael@0: michael@0: Value thisv() { michael@0: return argv()[0]; michael@0: } michael@0: Value *argv() { michael@0: return (Value *)(this + 1); michael@0: } michael@0: uintptr_t numActualArgs() const { michael@0: return numActualArgs_; michael@0: } michael@0: michael@0: // Computes a reference to a slot, where a slot is a distance from the base michael@0: // frame pointer (as would be used for LStackSlot). michael@0: uintptr_t *slotRef(uint32_t slot) { michael@0: return (uintptr_t *)((uint8_t *)this - slot); michael@0: } michael@0: michael@0: static inline size_t Size() { michael@0: return sizeof(IonJSFrameLayout); michael@0: } michael@0: }; michael@0: michael@0: // this is the layout of the frame that is used when we enter Ion code from platform ABI code michael@0: class IonEntryFrameLayout : public IonJSFrameLayout michael@0: { michael@0: public: michael@0: static inline size_t Size() { michael@0: return sizeof(IonEntryFrameLayout); michael@0: } michael@0: }; michael@0: michael@0: class IonRectifierFrameLayout : public IonJSFrameLayout michael@0: { michael@0: public: michael@0: static inline size_t Size() { michael@0: return sizeof(IonRectifierFrameLayout); michael@0: } michael@0: }; michael@0: michael@0: // The callee token is now dead. michael@0: class IonUnwoundRectifierFrameLayout : public IonRectifierFrameLayout michael@0: { michael@0: public: michael@0: static inline size_t Size() { michael@0: // It is not necessary to accout for an extra callee token here because michael@0: // sizeof(IonExitFrameLayout) == sizeof(IonRectifierFrameLayout) due to michael@0: // extra padding. michael@0: return sizeof(IonUnwoundRectifierFrameLayout); michael@0: } michael@0: }; michael@0: michael@0: // GC related data used to keep alive data surrounding the Exit frame. michael@0: class IonExitFooterFrame michael@0: { michael@0: const VMFunction *function_; michael@0: JitCode *jitCode_; michael@0: michael@0: public: michael@0: static inline size_t Size() { michael@0: return sizeof(IonExitFooterFrame); michael@0: } michael@0: inline JitCode *jitCode() const { michael@0: return jitCode_; michael@0: } michael@0: inline JitCode **addressOfJitCode() { michael@0: return &jitCode_; michael@0: } michael@0: inline const VMFunction *function() const { michael@0: return function_; michael@0: } michael@0: michael@0: // This should only be called for function()->outParam == Type_Handle michael@0: template michael@0: T *outParam() { michael@0: return reinterpret_cast(reinterpret_cast(this) - sizeof(T)); michael@0: } michael@0: }; michael@0: michael@0: class IonNativeExitFrameLayout; michael@0: class IonOOLNativeExitFrameLayout; michael@0: class IonOOLPropertyOpExitFrameLayout; michael@0: class IonOOLProxyExitFrameLayout; michael@0: class IonDOMExitFrameLayout; michael@0: michael@0: // this is the frame layout when we are exiting ion code, and about to enter platform ABI code michael@0: class IonExitFrameLayout : public IonCommonFrameLayout michael@0: { michael@0: inline uint8_t *top() { michael@0: return reinterpret_cast(this + 1); michael@0: } michael@0: michael@0: public: michael@0: static inline size_t Size() { michael@0: return sizeof(IonExitFrameLayout); michael@0: } michael@0: static inline size_t SizeWithFooter() { michael@0: return Size() + IonExitFooterFrame::Size(); michael@0: } michael@0: michael@0: inline IonExitFooterFrame *footer() { michael@0: uint8_t *sp = reinterpret_cast(this); michael@0: return reinterpret_cast(sp - IonExitFooterFrame::Size()); michael@0: } michael@0: michael@0: // argBase targets the point which precedes the exit frame. Arguments of VM michael@0: // each wrapper are pushed before the exit frame. This correspond exactly michael@0: // to the value of the argBase register of the generateVMWrapper function. michael@0: inline uint8_t *argBase() { michael@0: JS_ASSERT(footer()->jitCode() != nullptr); michael@0: return top(); michael@0: } michael@0: michael@0: inline bool isWrapperExit() { michael@0: return footer()->function() != nullptr; michael@0: } michael@0: inline bool isNativeExit() { michael@0: return footer()->jitCode() == nullptr; michael@0: } michael@0: inline bool isOOLNativeExit() { michael@0: return footer()->jitCode() == ION_FRAME_OOL_NATIVE; michael@0: } michael@0: inline bool isOOLPropertyOpExit() { michael@0: return footer()->jitCode() == ION_FRAME_OOL_PROPERTY_OP; michael@0: } michael@0: inline bool isOOLProxyExit() { michael@0: return footer()->jitCode() == ION_FRAME_OOL_PROXY; michael@0: } michael@0: inline bool isDomExit() { michael@0: JitCode *code = footer()->jitCode(); michael@0: return michael@0: code == ION_FRAME_DOMGETTER || michael@0: code == ION_FRAME_DOMSETTER || michael@0: code == ION_FRAME_DOMMETHOD; michael@0: } michael@0: michael@0: inline IonNativeExitFrameLayout *nativeExit() { michael@0: // see CodeGenerator::visitCallNative michael@0: JS_ASSERT(isNativeExit()); michael@0: return reinterpret_cast(footer()); michael@0: } michael@0: inline IonOOLNativeExitFrameLayout *oolNativeExit() { michael@0: JS_ASSERT(isOOLNativeExit()); michael@0: return reinterpret_cast(footer()); michael@0: } michael@0: inline IonOOLPropertyOpExitFrameLayout *oolPropertyOpExit() { michael@0: JS_ASSERT(isOOLPropertyOpExit()); michael@0: return reinterpret_cast(footer()); michael@0: } michael@0: inline IonOOLProxyExitFrameLayout *oolProxyExit() { michael@0: JS_ASSERT(isOOLProxyExit()); michael@0: return reinterpret_cast(footer()); michael@0: } michael@0: inline IonDOMExitFrameLayout *DOMExit() { michael@0: JS_ASSERT(isDomExit()); michael@0: return reinterpret_cast(footer()); michael@0: } michael@0: }; michael@0: michael@0: // Cannot inherit implementa(&loCalleeResult_); michael@0: } michael@0: inline uintptr_t argc() const { michael@0: return argc_; michael@0: } michael@0: }; michael@0: michael@0: class IonOOLNativeExitFrameLayout michael@0: { michael@0: protected: // only to silence a clang warning about unused private fields michael@0: IonExitFooterFrame footer_; michael@0: IonExitFrameLayout exit_; michael@0: michael@0: // pointer to root the stub's JitCode michael@0: JitCode *stubCode_; michael@0: michael@0: uintptr_t argc_; michael@0: michael@0: // We need to split the Value into 2 fields of 32 bits, otherwise the C++ michael@0: // compiler may add some padding between the fields. michael@0: uint32_t loCalleeResult_; michael@0: uint32_t hiCalleeResult_; michael@0: michael@0: // Split Value for |this| and args above. michael@0: uint32_t loThis_; michael@0: uint32_t hiThis_; michael@0: michael@0: public: michael@0: static inline size_t Size(size_t argc) { michael@0: // The frame accounts for the callee/result and |this|, so we only need args. michael@0: return sizeof(IonOOLNativeExitFrameLayout) + (argc * sizeof(Value)); michael@0: } michael@0: michael@0: static size_t offsetOfResult() { michael@0: return offsetof(IonOOLNativeExitFrameLayout, loCalleeResult_); michael@0: } michael@0: michael@0: inline JitCode **stubCode() { michael@0: return &stubCode_; michael@0: } michael@0: inline Value *vp() { michael@0: return reinterpret_cast(&loCalleeResult_); michael@0: } michael@0: inline Value *thisp() { michael@0: return reinterpret_cast(&loThis_); michael@0: } michael@0: inline uintptr_t argc() const { michael@0: return argc_; michael@0: } michael@0: }; michael@0: michael@0: class IonOOLPropertyOpExitFrameLayout michael@0: { michael@0: protected: // only to silence a clang warning about unused private fields michael@0: IonExitFooterFrame footer_; michael@0: IonExitFrameLayout exit_; michael@0: michael@0: // Object for HandleObject michael@0: JSObject *obj_; michael@0: michael@0: // id for HandleId michael@0: jsid id_; michael@0: michael@0: // space for MutableHandleValue result michael@0: // use two uint32_t so compiler doesn't align. michael@0: uint32_t vp0_; michael@0: uint32_t vp1_; michael@0: michael@0: // pointer to root the stub's JitCode michael@0: JitCode *stubCode_; michael@0: michael@0: public: michael@0: static inline size_t Size() { michael@0: return sizeof(IonOOLPropertyOpExitFrameLayout); michael@0: } michael@0: michael@0: static size_t offsetOfResult() { michael@0: return offsetof(IonOOLPropertyOpExitFrameLayout, vp0_); michael@0: } michael@0: michael@0: inline JitCode **stubCode() { michael@0: return &stubCode_; michael@0: } michael@0: inline Value *vp() { michael@0: return reinterpret_cast(&vp0_); michael@0: } michael@0: inline jsid *id() { michael@0: return &id_; michael@0: } michael@0: inline JSObject **obj() { michael@0: return &obj_; michael@0: } michael@0: }; michael@0: michael@0: // Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, michael@0: // MutableHandleValue vp) michael@0: // Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, michael@0: // bool strict, MutableHandleValue vp) michael@0: class IonOOLProxyExitFrameLayout michael@0: { michael@0: protected: // only to silence a clang warning about unused private fields michael@0: IonExitFooterFrame footer_; michael@0: IonExitFrameLayout exit_; michael@0: michael@0: // The proxy object. michael@0: JSObject *proxy_; michael@0: michael@0: // Object for HandleObject michael@0: JSObject *receiver_; michael@0: michael@0: // id for HandleId michael@0: jsid id_; michael@0: michael@0: // space for MutableHandleValue result michael@0: // use two uint32_t so compiler doesn't align. michael@0: uint32_t vp0_; michael@0: uint32_t vp1_; michael@0: michael@0: // pointer to root the stub's JitCode michael@0: JitCode *stubCode_; michael@0: michael@0: public: michael@0: static inline size_t Size() { michael@0: return sizeof(IonOOLProxyExitFrameLayout); michael@0: } michael@0: michael@0: static size_t offsetOfResult() { michael@0: return offsetof(IonOOLProxyExitFrameLayout, vp0_); michael@0: } michael@0: michael@0: inline JitCode **stubCode() { michael@0: return &stubCode_; michael@0: } michael@0: inline Value *vp() { michael@0: return reinterpret_cast(&vp0_); michael@0: } michael@0: inline jsid *id() { michael@0: return &id_; michael@0: } michael@0: inline JSObject **receiver() { michael@0: return &receiver_; michael@0: } michael@0: inline JSObject **proxy() { michael@0: return &proxy_; michael@0: } michael@0: }; michael@0: michael@0: class IonDOMExitFrameLayout michael@0: { michael@0: protected: // only to silence a clang warning about unused private fields michael@0: IonExitFooterFrame footer_; michael@0: IonExitFrameLayout exit_; michael@0: JSObject *thisObj; michael@0: michael@0: // We need to split the Value into 2 fields of 32 bits, otherwise the C++ michael@0: // compiler may add some padding between the fields. michael@0: uint32_t loCalleeResult_; michael@0: uint32_t hiCalleeResult_; michael@0: michael@0: public: michael@0: static inline size_t Size() { michael@0: return sizeof(IonDOMExitFrameLayout); michael@0: } michael@0: michael@0: static size_t offsetOfResult() { michael@0: return offsetof(IonDOMExitFrameLayout, loCalleeResult_); michael@0: } michael@0: inline Value *vp() { michael@0: return reinterpret_cast(&loCalleeResult_); michael@0: } michael@0: inline JSObject **thisObjAddress() { michael@0: return &thisObj; michael@0: } michael@0: inline bool isMethodFrame() { michael@0: return footer_.jitCode() == ION_FRAME_DOMMETHOD; michael@0: } michael@0: }; michael@0: michael@0: struct IonDOMMethodExitFrameLayoutTraits; michael@0: michael@0: class IonDOMMethodExitFrameLayout michael@0: { michael@0: protected: // only to silence a clang warning about unused private fields michael@0: IonExitFooterFrame footer_; michael@0: IonExitFrameLayout exit_; michael@0: // This must be the last thing pushed, so as to stay common with michael@0: // IonDOMExitFrameLayout. michael@0: JSObject *thisObj_; michael@0: Value *argv_; michael@0: uintptr_t argc_; michael@0: michael@0: // We need to split the Value into 2 fields of 32 bits, otherwise the C++ michael@0: // compiler may add some padding between the fields. michael@0: uint32_t loCalleeResult_; michael@0: uint32_t hiCalleeResult_; michael@0: michael@0: friend struct IonDOMMethodExitFrameLayoutTraits; michael@0: michael@0: public: michael@0: static inline size_t Size() { michael@0: return sizeof(IonDOMMethodExitFrameLayout); michael@0: } michael@0: michael@0: static size_t offsetOfResult() { michael@0: return offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_); michael@0: } michael@0: michael@0: inline Value *vp() { michael@0: // The code in visitCallDOMNative depends on this static assert holding michael@0: JS_STATIC_ASSERT(offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_) == michael@0: (offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t))); michael@0: return reinterpret_cast(&loCalleeResult_); michael@0: } michael@0: inline JSObject **thisObjAddress() { michael@0: return &thisObj_; michael@0: } michael@0: inline uintptr_t argc() { michael@0: return argc_; michael@0: } michael@0: }; michael@0: michael@0: struct IonDOMMethodExitFrameLayoutTraits { michael@0: static const size_t offsetOfArgcFromArgv = michael@0: offsetof(IonDOMMethodExitFrameLayout, argc_) - michael@0: offsetof(IonDOMMethodExitFrameLayout, argv_); michael@0: }; michael@0: michael@0: class ICStub; michael@0: michael@0: class IonBaselineStubFrameLayout : public IonCommonFrameLayout michael@0: { michael@0: public: michael@0: static inline size_t Size() { michael@0: return sizeof(IonBaselineStubFrameLayout); michael@0: } michael@0: michael@0: static inline int reverseOffsetOfStubPtr() { michael@0: return -int(sizeof(void *)); michael@0: } michael@0: static inline int reverseOffsetOfSavedFramePtr() { michael@0: return -int(2 * sizeof(void *)); michael@0: } michael@0: michael@0: inline ICStub *maybeStubPtr() { michael@0: uint8_t *fp = reinterpret_cast(this); michael@0: return *reinterpret_cast(fp + reverseOffsetOfStubPtr()); michael@0: } michael@0: inline void setStubPtr(ICStub *stub) { michael@0: uint8_t *fp = reinterpret_cast(this); michael@0: *reinterpret_cast(fp + reverseOffsetOfStubPtr()) = stub; michael@0: } michael@0: }; michael@0: michael@0: // An invalidation bailout stack is at the stack pointer for the callee frame. michael@0: class InvalidationBailoutStack michael@0: { michael@0: mozilla::Array fpregs_; michael@0: mozilla::Array regs_; michael@0: IonScript *ionScript_; michael@0: uint8_t *osiPointReturnAddress_; michael@0: michael@0: public: michael@0: uint8_t *sp() const { michael@0: return (uint8_t *) this + sizeof(InvalidationBailoutStack); michael@0: } michael@0: IonJSFrameLayout *fp() const; michael@0: MachineState machine() { michael@0: return MachineState::FromBailout(regs_, fpregs_); michael@0: } michael@0: michael@0: IonScript *ionScript() const { michael@0: return ionScript_; michael@0: } michael@0: uint8_t *osiPointReturnAddress() const { michael@0: return osiPointReturnAddress_; michael@0: } michael@0: michael@0: void checkInvariants() const; michael@0: }; michael@0: michael@0: void michael@0: GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes); michael@0: michael@0: CalleeToken michael@0: MarkCalleeToken(JSTracer *trc, CalleeToken token); michael@0: michael@0: } /* namespace jit */ michael@0: } /* namespace js */ michael@0: michael@0: #endif // JS_ION michael@0: michael@0: #endif /* jit_IonFrames_h */