summaryrefslogtreecommitdiffstats
path: root/js/src/jit/JitFrames.h
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /js/src/jit/JitFrames.h
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/jit/JitFrames.h')
-rw-r--r--js/src/jit/JitFrames.h1044
1 files changed, 1044 insertions, 0 deletions
diff --git a/js/src/jit/JitFrames.h b/js/src/jit/JitFrames.h
new file mode 100644
index 000000000..e8faf9787
--- /dev/null
+++ b/js/src/jit/JitFrames.h
@@ -0,0 +1,1044 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_JitFrames_h
+#define jit_JitFrames_h
+
+#include <stdint.h>
+
+#include "jscntxt.h"
+#include "jsfun.h"
+
+#include "jit/JitFrameIterator.h"
+#include "jit/Safepoints.h"
+
+namespace js {
+namespace jit {
+
+enum CalleeTokenTag
+{
+ CalleeToken_Function = 0x0, // untagged
+ CalleeToken_FunctionConstructing = 0x1,
+ CalleeToken_Script = 0x2
+};
+
+static const uintptr_t CalleeTokenMask = ~uintptr_t(0x3);
+
+static inline CalleeTokenTag
+GetCalleeTokenTag(CalleeToken token)
+{
+ CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3);
+ MOZ_ASSERT(tag <= CalleeToken_Script);
+ return tag;
+}
+static inline CalleeToken
+CalleeToToken(JSFunction* fun, bool constructing)
+{
+ CalleeTokenTag tag = constructing ? CalleeToken_FunctionConstructing : CalleeToken_Function;
+ return CalleeToken(uintptr_t(fun) | uintptr_t(tag));
+}
+static inline CalleeToken
+CalleeToToken(JSScript* script)
+{
+ return CalleeToken(uintptr_t(script) | uintptr_t(CalleeToken_Script));
+}
+static inline bool
+CalleeTokenIsFunction(CalleeToken token)
+{
+ CalleeTokenTag tag = GetCalleeTokenTag(token);
+ return tag == CalleeToken_Function || tag == CalleeToken_FunctionConstructing;
+}
+static inline bool
+CalleeTokenIsConstructing(CalleeToken token)
+{
+ return GetCalleeTokenTag(token) == CalleeToken_FunctionConstructing;
+}
+static inline JSFunction*
+CalleeTokenToFunction(CalleeToken token)
+{
+ MOZ_ASSERT(CalleeTokenIsFunction(token));
+ return (JSFunction*)(uintptr_t(token) & CalleeTokenMask);
+}
+static inline JSScript*
+CalleeTokenToScript(CalleeToken token)
+{
+ MOZ_ASSERT(GetCalleeTokenTag(token) == CalleeToken_Script);
+ return (JSScript*)(uintptr_t(token) & CalleeTokenMask);
+}
+static inline bool
+CalleeTokenIsModuleScript(CalleeToken token)
+{
+ CalleeTokenTag tag = GetCalleeTokenTag(token);
+ return tag == CalleeToken_Script && CalleeTokenToScript(token)->module();
+}
+
+static inline JSScript*
+ScriptFromCalleeToken(CalleeToken token)
+{
+ switch (GetCalleeTokenTag(token)) {
+ case CalleeToken_Script:
+ return CalleeTokenToScript(token);
+ case CalleeToken_Function:
+ case CalleeToken_FunctionConstructing:
+ return CalleeTokenToFunction(token)->nonLazyScript();
+ }
+ MOZ_CRASH("invalid callee token tag");
+}
+
+// In between every two frames lies a small header describing both frames. This
+// header, minimally, contains a returnAddress word and a descriptor word. The
+// descriptor describes the size and type of the previous frame, whereas the
+// returnAddress describes the address the newer frame (the callee) will return
+// to. The exact mechanism in which frames are laid out is architecture
+// dependent.
+//
+// Two special frame types exist. Entry frames begin an ion activation, and
+// therefore there is exactly one per activation of jit::Cannon. Exit frames
+// are necessary to leave JIT code and enter C++, and thus, C++ code will
+// always begin iterating from the topmost exit frame.
+
+class LSafepoint;
+
+// Two-tuple that lets you look up the safepoint entry given the
+// displacement of a call instruction within the JIT code.
+class SafepointIndex
+{
+ // The displacement is the distance from the first byte of the JIT'd code
+ // to the return address (of the call that the safepoint was generated for).
+ uint32_t displacement_;
+
+ union {
+ LSafepoint* safepoint_;
+
+ // Offset to the start of the encoded safepoint in the safepoint stream.
+ uint32_t safepointOffset_;
+ };
+
+#ifdef DEBUG
+ bool resolved;
+#endif
+
+ public:
+ SafepointIndex(uint32_t displacement, LSafepoint* safepoint)
+ : displacement_(displacement),
+ safepoint_(safepoint)
+#ifdef DEBUG
+ , resolved(false)
+#endif
+ { }
+
+ void resolve();
+
+ LSafepoint* safepoint() {
+ MOZ_ASSERT(!resolved);
+ return safepoint_;
+ }
+ uint32_t displacement() const {
+ return displacement_;
+ }
+ uint32_t safepointOffset() const {
+ return safepointOffset_;
+ }
+ void adjustDisplacement(uint32_t offset) {
+ MOZ_ASSERT(offset >= displacement_);
+ displacement_ = offset;
+ }
+ inline SnapshotOffset snapshotOffset() const;
+ inline bool hasSnapshotOffset() const;
+};
+
+class MacroAssembler;
+// The OSI point is patched to a call instruction. Therefore, the
+// returnPoint for an OSI call is the address immediately following that
+// call instruction. The displacement of that point within the assembly
+// buffer is the |returnPointDisplacement|.
+class OsiIndex
+{
+ uint32_t callPointDisplacement_;
+ uint32_t snapshotOffset_;
+
+ public:
+ OsiIndex(uint32_t callPointDisplacement, uint32_t snapshotOffset)
+ : callPointDisplacement_(callPointDisplacement),
+ snapshotOffset_(snapshotOffset)
+ { }
+
+ uint32_t returnPointDisplacement() const;
+ uint32_t callPointDisplacement() const {
+ return callPointDisplacement_;
+ }
+ uint32_t snapshotOffset() const {
+ return snapshotOffset_;
+ }
+};
+
+// The layout of an Ion frame on the C stack is roughly:
+// argN _
+// ... \ - These are jsvals
+// arg0 /
+// -3 this _/
+// -2 callee
+// -1 descriptor
+// 0 returnAddress
+// .. locals ..
+
+// The descriptor is organized into four sections:
+// [ frame size | has cached saved frame bit | frame header size | frame type ]
+// < highest - - - - - - - - - - - - - - lowest >
+static const uintptr_t FRAMETYPE_BITS = 4;
+static const uintptr_t FRAME_HEADER_SIZE_SHIFT = FRAMETYPE_BITS;
+static const uintptr_t FRAME_HEADER_SIZE_BITS = 3;
+static const uintptr_t FRAME_HEADER_SIZE_MASK = (1 << FRAME_HEADER_SIZE_BITS) - 1;
+static const uintptr_t HASCACHEDSAVEDFRAME_BIT = 1 << (FRAMETYPE_BITS + FRAME_HEADER_SIZE_BITS);
+static const uintptr_t FRAMESIZE_SHIFT = FRAMETYPE_BITS +
+ FRAME_HEADER_SIZE_BITS +
+ 1 /* cached saved frame bit */;
+static const uintptr_t FRAMESIZE_BITS = 32 - FRAMESIZE_SHIFT;
+static const uintptr_t FRAMESIZE_MASK = (1 << FRAMESIZE_BITS) - 1;
+
+// Ion frames have a few important numbers associated with them:
+// Local depth: The number of bytes required to spill local variables.
+// Argument depth: The number of bytes required to push arguments and make
+// a function call.
+// Slack: A frame may temporarily use extra stack to resolve cycles.
+//
+// The (local + argument) depth determines the "fixed frame size". The fixed
+// frame size is the distance between the stack pointer and the frame header.
+// Thus, fixed >= (local + argument).
+//
+// In order to compress guards, we create shared jump tables that recover the
+// script from the stack and recover a snapshot pointer based on which jump was
+// taken. Thus, we create a jump table for each fixed frame size.
+//
+// Jump tables are big. To control the amount of jump tables we generate, each
+// platform chooses how to segregate stack size classes based on its
+// architecture.
+//
+// On some architectures, these jump tables are not used at all, or frame
+// size segregation is not needed. Thus, there is an option for a frame to not
+// have any frame size class, and to be totally dynamic.
+static const uint32_t NO_FRAME_SIZE_CLASS_ID = uint32_t(-1);
+
+class FrameSizeClass
+{
+ uint32_t class_;
+
+ explicit FrameSizeClass(uint32_t class_) : class_(class_)
+ { }
+
+ public:
+ FrameSizeClass()
+ { }
+
+ static FrameSizeClass None() {
+ return FrameSizeClass(NO_FRAME_SIZE_CLASS_ID);
+ }
+ static FrameSizeClass FromClass(uint32_t class_) {
+ return FrameSizeClass(class_);
+ }
+
+ // These functions are implemented in specific CodeGenerator-* files.
+ static FrameSizeClass FromDepth(uint32_t frameDepth);
+ static FrameSizeClass ClassLimit();
+ uint32_t frameSize() const;
+
+ uint32_t classId() const {
+ MOZ_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
+ return class_;
+ }
+
+ bool operator ==(const FrameSizeClass& other) const {
+ return class_ == other.class_;
+ }
+ bool operator !=(const FrameSizeClass& other) const {
+ return class_ != other.class_;
+ }
+};
+
+struct BaselineBailoutInfo;
+
+// Data needed to recover from an exception.
+struct ResumeFromException
+{
+ static const uint32_t RESUME_ENTRY_FRAME = 0;
+ static const uint32_t RESUME_CATCH = 1;
+ static const uint32_t RESUME_FINALLY = 2;
+ static const uint32_t RESUME_FORCED_RETURN = 3;
+ static const uint32_t RESUME_BAILOUT = 4;
+
+ uint8_t* framePointer;
+ uint8_t* stackPointer;
+ uint8_t* target;
+ uint32_t kind;
+
+ // Value to push when resuming into a |finally| block.
+ Value exception;
+
+ BaselineBailoutInfo* bailoutInfo;
+};
+
+void HandleException(ResumeFromException* rfe);
+
+void EnsureBareExitFrame(JSContext* cx, JitFrameLayout* frame);
+
+void MarkJitActivations(JSRuntime* rt, JSTracer* trc);
+
+JSCompartment*
+TopmostIonActivationCompartment(JSRuntime* rt);
+
+void UpdateJitActivationsForMinorGC(JSRuntime* rt, JSTracer* trc);
+
+static inline uint32_t
+EncodeFrameHeaderSize(size_t headerSize)
+{
+ MOZ_ASSERT((headerSize % sizeof(uintptr_t)) == 0);
+
+ uint32_t headerSizeWords = headerSize / sizeof(uintptr_t);
+ MOZ_ASSERT(headerSizeWords <= FRAME_HEADER_SIZE_MASK);
+ return headerSizeWords;
+}
+
+static inline uint32_t
+MakeFrameDescriptor(uint32_t frameSize, FrameType type, uint32_t headerSize)
+{
+ MOZ_ASSERT(headerSize < FRAMESIZE_MASK);
+ headerSize = EncodeFrameHeaderSize(headerSize);
+ return 0 | (frameSize << FRAMESIZE_SHIFT) | (headerSize << FRAME_HEADER_SIZE_SHIFT) | type;
+}
+
+// Returns the JSScript associated with the topmost JIT frame.
+inline JSScript*
+GetTopJitJSScript(JSContext* cx)
+{
+ JitFrameIterator iter(cx);
+ MOZ_ASSERT(iter.type() == JitFrame_Exit);
+ ++iter;
+
+ if (iter.isBaselineStub()) {
+ ++iter;
+ MOZ_ASSERT(iter.isBaselineJS());
+ }
+
+ MOZ_ASSERT(iter.isScripted());
+ return iter.script();
+}
+
+#ifdef JS_CODEGEN_MIPS32
+uint8_t* alignDoubleSpillWithOffset(uint8_t* pointer, int32_t offset);
+#else
+inline uint8_t*
+alignDoubleSpillWithOffset(uint8_t* pointer, int32_t offset)
+{
+ // This is NO-OP on non-MIPS platforms.
+ return pointer;
+}
+#endif
+
+// Layout of the frame prefix. This assumes the stack architecture grows down.
+// If this is ever not the case, we'll have to refactor.
+class CommonFrameLayout
+{
+ uint8_t* returnAddress_;
+ uintptr_t descriptor_;
+
+ static const uintptr_t FrameTypeMask = (1 << FRAMETYPE_BITS) - 1;
+
+ public:
+ static size_t offsetOfDescriptor() {
+ return offsetof(CommonFrameLayout, descriptor_);
+ }
+ uintptr_t descriptor() const {
+ return descriptor_;
+ }
+ static size_t offsetOfReturnAddress() {
+ return offsetof(CommonFrameLayout, returnAddress_);
+ }
+ FrameType prevType() const {
+ return FrameType(descriptor_ & FrameTypeMask);
+ }
+ void changePrevType(FrameType type) {
+ descriptor_ &= ~FrameTypeMask;
+ descriptor_ |= type;
+ }
+ size_t prevFrameLocalSize() const {
+ return descriptor_ >> FRAMESIZE_SHIFT;
+ }
+ size_t headerSize() const {
+ return sizeof(uintptr_t) *
+ ((descriptor_ >> FRAME_HEADER_SIZE_SHIFT) & FRAME_HEADER_SIZE_MASK);
+ }
+ bool hasCachedSavedFrame() const {
+ return descriptor_ & HASCACHEDSAVEDFRAME_BIT;
+ }
+ void setHasCachedSavedFrame() {
+ descriptor_ |= HASCACHEDSAVEDFRAME_BIT;
+ }
+ uint8_t* returnAddress() const {
+ return returnAddress_;
+ }
+ void setReturnAddress(uint8_t* addr) {
+ returnAddress_ = addr;
+ }
+};
+
+class JitFrameLayout : public CommonFrameLayout
+{
+ CalleeToken calleeToken_;
+ uintptr_t numActualArgs_;
+
+ public:
+ CalleeToken calleeToken() const {
+ return calleeToken_;
+ }
+ void replaceCalleeToken(CalleeToken calleeToken) {
+ calleeToken_ = calleeToken;
+ }
+
+ static size_t offsetOfCalleeToken() {
+ return offsetof(JitFrameLayout, calleeToken_);
+ }
+ static size_t offsetOfNumActualArgs() {
+ return offsetof(JitFrameLayout, numActualArgs_);
+ }
+ static size_t offsetOfThis() {
+ return sizeof(JitFrameLayout);
+ }
+ static size_t offsetOfEvalNewTarget() {
+ return sizeof(JitFrameLayout);
+ }
+ static size_t offsetOfActualArgs() {
+ return offsetOfThis() + sizeof(Value);
+ }
+ static size_t offsetOfActualArg(size_t arg) {
+ return offsetOfActualArgs() + arg * sizeof(Value);
+ }
+
+ Value thisv() {
+ MOZ_ASSERT(CalleeTokenIsFunction(calleeToken()));
+ return argv()[0];
+ }
+ Value* argv() {
+ MOZ_ASSERT(CalleeTokenIsFunction(calleeToken()));
+ return (Value*)(this + 1);
+ }
+ uintptr_t numActualArgs() const {
+ return numActualArgs_;
+ }
+
+ // Computes a reference to a stack or argument slot, where a slot is a
+ // distance from the base frame pointer, as would be used for LStackSlot
+ // or LArgument.
+ uintptr_t* slotRef(SafepointSlotEntry where);
+
+ static inline size_t Size() {
+ return sizeof(JitFrameLayout);
+ }
+};
+
+// this is the layout of the frame that is used when we enter Ion code from platform ABI code
+class EntryFrameLayout : public JitFrameLayout
+{
+ public:
+ static inline size_t Size() {
+ return sizeof(EntryFrameLayout);
+ }
+};
+
+class RectifierFrameLayout : public JitFrameLayout
+{
+ public:
+ static inline size_t Size() {
+ return sizeof(RectifierFrameLayout);
+ }
+};
+
+class IonAccessorICFrameLayout : public CommonFrameLayout
+{
+ protected:
+ // Pointer to root the stub's JitCode.
+ JitCode* stubCode_;
+
+ public:
+ JitCode** stubCode() {
+ return &stubCode_;
+ }
+ static size_t Size() {
+ return sizeof(IonAccessorICFrameLayout);
+ }
+};
+
+// GC related data used to keep alive data surrounding the Exit frame.
+class ExitFooterFrame
+{
+ const VMFunction* function_;
+ JitCode* jitCode_;
+
+ public:
+ static inline size_t Size() {
+ return sizeof(ExitFooterFrame);
+ }
+ inline JitCode* jitCode() const {
+ return jitCode_;
+ }
+ inline JitCode** addressOfJitCode() {
+ return &jitCode_;
+ }
+ inline const VMFunction* function() const {
+ return function_;
+ }
+
+ // This should only be called for function()->outParam == Type_Handle
+ template <typename T>
+ T* outParam() {
+ uint8_t* address = reinterpret_cast<uint8_t*>(this);
+ address = alignDoubleSpillWithOffset(address, sizeof(intptr_t));
+ return reinterpret_cast<T*>(address - sizeof(T));
+ }
+};
+
+class NativeExitFrameLayout;
+class IonOOLNativeExitFrameLayout;
+class IonOOLPropertyOpExitFrameLayout;
+class IonOOLProxyExitFrameLayout;
+class IonDOMExitFrameLayout;
+
+enum ExitFrameTokenValues
+{
+ CallNativeExitFrameLayoutToken = 0x0,
+ ConstructNativeExitFrameLayoutToken = 0x1,
+ IonDOMExitFrameLayoutGetterToken = 0x2,
+ IonDOMExitFrameLayoutSetterToken = 0x3,
+ IonDOMMethodExitFrameLayoutToken = 0x4,
+ IonOOLNativeExitFrameLayoutToken = 0x5,
+ IonOOLPropertyOpExitFrameLayoutToken = 0x6,
+ IonOOLSetterOpExitFrameLayoutToken = 0x7,
+ IonOOLProxyExitFrameLayoutToken = 0x8,
+ LazyLinkExitFrameLayoutToken = 0xFE,
+ ExitFrameLayoutBareToken = 0xFF
+};
+
+// this is the frame layout when we are exiting ion code, and about to enter platform ABI code
+class ExitFrameLayout : public CommonFrameLayout
+{
+ inline uint8_t* top() {
+ return reinterpret_cast<uint8_t*>(this + 1);
+ }
+
+ public:
+ // Pushed for "bare" fake exit frames that have no GC things on stack to be
+ // marked.
+ static JitCode* BareToken() { return (JitCode*)ExitFrameLayoutBareToken; }
+
+ static inline size_t Size() {
+ return sizeof(ExitFrameLayout);
+ }
+ static inline size_t SizeWithFooter() {
+ return Size() + ExitFooterFrame::Size();
+ }
+
+ inline ExitFooterFrame* footer() {
+ uint8_t* sp = reinterpret_cast<uint8_t*>(this);
+ return reinterpret_cast<ExitFooterFrame*>(sp - ExitFooterFrame::Size());
+ }
+
+ // argBase targets the point which precedes the exit frame. Arguments of VM
+ // each wrapper are pushed before the exit frame. This correspond exactly
+ // to the value of the argBase register of the generateVMWrapper function.
+ inline uint8_t* argBase() {
+ MOZ_ASSERT(footer()->jitCode() != nullptr);
+ return top();
+ }
+
+ inline bool isWrapperExit() {
+ return footer()->function() != nullptr;
+ }
+ inline bool isBareExit() {
+ return footer()->jitCode() == BareToken();
+ }
+
+ // See the various exit frame layouts below.
+ template <typename T> inline bool is() {
+ return footer()->jitCode() == T::Token();
+ }
+ template <typename T> inline T* as() {
+ MOZ_ASSERT(this->is<T>());
+ return reinterpret_cast<T*>(footer());
+ }
+};
+
+// Cannot inherit implementation since we need to extend the top of
+// ExitFrameLayout.
+class NativeExitFrameLayout
+{
+ protected: // only to silence a clang warning about unused private fields
+ ExitFooterFrame footer_;
+ ExitFrameLayout exit_;
+ uintptr_t argc_;
+
+ // We need to split the Value into 2 fields of 32 bits, otherwise the C++
+ // compiler may add some padding between the fields.
+ uint32_t loCalleeResult_;
+ uint32_t hiCalleeResult_;
+
+ public:
+ static inline size_t Size() {
+ return sizeof(NativeExitFrameLayout);
+ }
+
+ static size_t offsetOfResult() {
+ return offsetof(NativeExitFrameLayout, loCalleeResult_);
+ }
+ inline Value* vp() {
+ return reinterpret_cast<Value*>(&loCalleeResult_);
+ }
+ inline uintptr_t argc() const {
+ return argc_;
+ }
+};
+
+class CallNativeExitFrameLayout : public NativeExitFrameLayout
+{
+ public:
+ static JitCode* Token() { return (JitCode*)CallNativeExitFrameLayoutToken; }
+};
+
+class ConstructNativeExitFrameLayout : public NativeExitFrameLayout
+{
+ public:
+ static JitCode* Token() { return (JitCode*)ConstructNativeExitFrameLayoutToken; }
+};
+
+template<>
+inline bool
+ExitFrameLayout::is<NativeExitFrameLayout>()
+{
+ return is<CallNativeExitFrameLayout>() || is<ConstructNativeExitFrameLayout>();
+}
+
+class IonOOLNativeExitFrameLayout
+{
+ protected: // only to silence a clang warning about unused private fields
+ ExitFooterFrame footer_;
+ ExitFrameLayout exit_;
+
+ // pointer to root the stub's JitCode
+ JitCode* stubCode_;
+
+ uintptr_t argc_;
+
+ // We need to split the Value into 2 fields of 32 bits, otherwise the C++
+ // compiler may add some padding between the fields.
+ uint32_t loCalleeResult_;
+ uint32_t hiCalleeResult_;
+
+ // Split Value for |this| and args above.
+ uint32_t loThis_;
+ uint32_t hiThis_;
+
+ public:
+ static JitCode* Token() { return (JitCode*)IonOOLNativeExitFrameLayoutToken; }
+
+ static inline size_t Size(size_t argc) {
+ // The frame accounts for the callee/result and |this|, so we only need args.
+ return sizeof(IonOOLNativeExitFrameLayout) + (argc * sizeof(Value));
+ }
+
+ static size_t offsetOfResult() {
+ return offsetof(IonOOLNativeExitFrameLayout, loCalleeResult_);
+ }
+
+ inline JitCode** stubCode() {
+ return &stubCode_;
+ }
+ inline Value* vp() {
+ return reinterpret_cast<Value*>(&loCalleeResult_);
+ }
+ inline Value* thisp() {
+ return reinterpret_cast<Value*>(&loThis_);
+ }
+ inline uintptr_t argc() const {
+ return argc_;
+ }
+};
+
+class IonOOLPropertyOpExitFrameLayout
+{
+ protected:
+ ExitFooterFrame footer_;
+ ExitFrameLayout exit_;
+
+ // Object for HandleObject
+ JSObject* obj_;
+
+ // id for HandleId
+ jsid id_;
+
+ // space for MutableHandleValue result
+ // use two uint32_t so compiler doesn't align.
+ uint32_t vp0_;
+ uint32_t vp1_;
+
+ // pointer to root the stub's JitCode
+ JitCode* stubCode_;
+
+ public:
+ static JitCode* Token() { return (JitCode*)IonOOLPropertyOpExitFrameLayoutToken; }
+
+ static inline size_t Size() {
+ return sizeof(IonOOLPropertyOpExitFrameLayout);
+ }
+
+ static size_t offsetOfObject() {
+ return offsetof(IonOOLPropertyOpExitFrameLayout, obj_);
+ }
+
+ static size_t offsetOfId() {
+ return offsetof(IonOOLPropertyOpExitFrameLayout, id_);
+ }
+
+ static size_t offsetOfResult() {
+ return offsetof(IonOOLPropertyOpExitFrameLayout, vp0_);
+ }
+
+ inline JitCode** stubCode() {
+ return &stubCode_;
+ }
+ inline Value* vp() {
+ return reinterpret_cast<Value*>(&vp0_);
+ }
+ inline jsid* id() {
+ return &id_;
+ }
+ inline JSObject** obj() {
+ return &obj_;
+ }
+};
+
+class IonOOLSetterOpExitFrameLayout : public IonOOLPropertyOpExitFrameLayout
+{
+ protected: // only to silence a clang warning about unused private fields
+ JS::ObjectOpResult result_;
+
+ public:
+ static JitCode* Token() { return (JitCode*)IonOOLSetterOpExitFrameLayoutToken; }
+
+ static size_t offsetOfObjectOpResult() {
+ return offsetof(IonOOLSetterOpExitFrameLayout, result_);
+ }
+
+ static size_t Size() {
+ return sizeof(IonOOLSetterOpExitFrameLayout);
+ }
+};
+
+// ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
+// ProxyCallProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
+// ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp,
+// bool strict)
+class IonOOLProxyExitFrameLayout
+{
+ protected: // only to silence a clang warning about unused private fields
+ ExitFooterFrame footer_;
+ ExitFrameLayout exit_;
+
+ // The proxy object.
+ JSObject* proxy_;
+
+ // id for HandleId
+ jsid id_;
+
+ // space for MutableHandleValue result
+ // use two uint32_t so compiler doesn't align.
+ uint32_t vp0_;
+ uint32_t vp1_;
+
+ // pointer to root the stub's JitCode
+ JitCode* stubCode_;
+
+ public:
+ static JitCode* Token() { return (JitCode*)IonOOLProxyExitFrameLayoutToken; }
+
+ static inline size_t Size() {
+ return sizeof(IonOOLProxyExitFrameLayout);
+ }
+
+ static size_t offsetOfResult() {
+ return offsetof(IonOOLProxyExitFrameLayout, vp0_);
+ }
+
+ inline JitCode** stubCode() {
+ return &stubCode_;
+ }
+ inline Value* vp() {
+ return reinterpret_cast<Value*>(&vp0_);
+ }
+ inline jsid* id() {
+ return &id_;
+ }
+ inline JSObject** proxy() {
+ return &proxy_;
+ }
+};
+
+class IonDOMExitFrameLayout
+{
+ protected: // only to silence a clang warning about unused private fields
+ ExitFooterFrame footer_;
+ ExitFrameLayout exit_;
+ JSObject* thisObj;
+
+ // We need to split the Value into 2 fields of 32 bits, otherwise the C++
+ // compiler may add some padding between the fields.
+ uint32_t loCalleeResult_;
+ uint32_t hiCalleeResult_;
+
+ public:
+ static JitCode* GetterToken() { return (JitCode*)IonDOMExitFrameLayoutGetterToken; }
+ static JitCode* SetterToken() { return (JitCode*)IonDOMExitFrameLayoutSetterToken; }
+
+ static inline size_t Size() {
+ return sizeof(IonDOMExitFrameLayout);
+ }
+
+ static size_t offsetOfResult() {
+ return offsetof(IonDOMExitFrameLayout, loCalleeResult_);
+ }
+ inline Value* vp() {
+ return reinterpret_cast<Value*>(&loCalleeResult_);
+ }
+ inline JSObject** thisObjAddress() {
+ return &thisObj;
+ }
+ inline bool isMethodFrame();
+};
+
+struct IonDOMMethodExitFrameLayoutTraits;
+
+class IonDOMMethodExitFrameLayout
+{
+ protected: // only to silence a clang warning about unused private fields
+ ExitFooterFrame footer_;
+ ExitFrameLayout exit_;
+ // This must be the last thing pushed, so as to stay common with
+ // IonDOMExitFrameLayout.
+ JSObject* thisObj_;
+ Value* argv_;
+ uintptr_t argc_;
+
+ // We need to split the Value into 2 fields of 32 bits, otherwise the C++
+ // compiler may add some padding between the fields.
+ uint32_t loCalleeResult_;
+ uint32_t hiCalleeResult_;
+
+ friend struct IonDOMMethodExitFrameLayoutTraits;
+
+ public:
+ static JitCode* Token() { return (JitCode*)IonDOMMethodExitFrameLayoutToken; }
+
+ static inline size_t Size() {
+ return sizeof(IonDOMMethodExitFrameLayout);
+ }
+
+ static size_t offsetOfResult() {
+ return offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_);
+ }
+
+ inline Value* vp() {
+ // The code in visitCallDOMNative depends on this static assert holding
+ JS_STATIC_ASSERT(offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_) ==
+ (offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t)));
+ return reinterpret_cast<Value*>(&loCalleeResult_);
+ }
+ inline JSObject** thisObjAddress() {
+ return &thisObj_;
+ }
+ inline uintptr_t argc() {
+ return argc_;
+ }
+};
+
+inline bool
+IonDOMExitFrameLayout::isMethodFrame()
+{
+ return footer_.jitCode() == IonDOMMethodExitFrameLayout::Token();
+}
+
+template <>
+inline bool
+ExitFrameLayout::is<IonDOMExitFrameLayout>()
+{
+ JitCode* code = footer()->jitCode();
+ return
+ code == IonDOMExitFrameLayout::GetterToken() ||
+ code == IonDOMExitFrameLayout::SetterToken() ||
+ code == IonDOMMethodExitFrameLayout::Token();
+}
+
+template <>
+inline IonDOMExitFrameLayout*
+ExitFrameLayout::as<IonDOMExitFrameLayout>()
+{
+ MOZ_ASSERT(is<IonDOMExitFrameLayout>());
+ return reinterpret_cast<IonDOMExitFrameLayout*>(footer());
+}
+
+struct IonDOMMethodExitFrameLayoutTraits {
+ static const size_t offsetOfArgcFromArgv =
+ offsetof(IonDOMMethodExitFrameLayout, argc_) -
+ offsetof(IonDOMMethodExitFrameLayout, argv_);
+};
+
+// Cannot inherit implementation since we need to extend the top of
+// ExitFrameLayout.
+class LazyLinkExitFrameLayout
+{
+ protected: // silence clang warning about unused private fields
+ JitCode* stubCode_;
+ ExitFooterFrame footer_;
+ JitFrameLayout exit_;
+
+ public:
+ static JitCode* Token() { return (JitCode*) LazyLinkExitFrameLayoutToken; }
+
+ static inline size_t Size() {
+ return sizeof(LazyLinkExitFrameLayout);
+ }
+
+ inline JitCode** stubCode() {
+ return &stubCode_;
+ }
+ inline JitFrameLayout* jsFrame() {
+ return &exit_;
+ }
+ static size_t offsetOfExitFrame() {
+ return offsetof(LazyLinkExitFrameLayout, exit_);
+ }
+};
+
+template <>
+inline LazyLinkExitFrameLayout*
+ExitFrameLayout::as<LazyLinkExitFrameLayout>()
+{
+ MOZ_ASSERT(is<LazyLinkExitFrameLayout>());
+ uint8_t* sp = reinterpret_cast<uint8_t*>(this);
+ sp -= LazyLinkExitFrameLayout::offsetOfExitFrame();
+ return reinterpret_cast<LazyLinkExitFrameLayout*>(sp);
+}
+
+class ICStub;
+
+class JitStubFrameLayout : public CommonFrameLayout
+{
+ // Info on the stack
+ //
+ // --------------------
+ // |JitStubFrameLayout|
+ // +------------------+
+ // | - Descriptor | => Marks end of JitFrame_IonJS
+ // | - returnaddres |
+ // +------------------+
+ // | - StubPtr | => First thing pushed in a stub only when the stub will do
+ // -------------------- a vmcall. Else we cannot have JitStubFrame. But technically
+ // not a member of the layout.
+
+ public:
+ static size_t Size() {
+ return sizeof(JitStubFrameLayout);
+ }
+
+ static inline int reverseOffsetOfStubPtr() {
+ return -int(sizeof(void*));
+ }
+
+ inline ICStub* maybeStubPtr() {
+ uint8_t* fp = reinterpret_cast<uint8_t*>(this);
+ return *reinterpret_cast<ICStub**>(fp + reverseOffsetOfStubPtr());
+ }
+};
+
+class BaselineStubFrameLayout : public JitStubFrameLayout
+{
+ // Info on the stack
+ //
+ // -------------------------
+ // |BaselineStubFrameLayout|
+ // +-----------------------+
+ // | - Descriptor | => Marks end of JitFrame_BaselineJS
+ // | - returnaddres |
+ // +-----------------------+
+ // | - StubPtr | => First thing pushed in a stub only when the stub will do
+ // +-----------------------+ a vmcall. Else we cannot have BaselineStubFrame.
+ // | - FramePtr | => Baseline stubs also need to push the frame ptr when doing
+ // ------------------------- a vmcall.
+ // Technically these last two variables are not part of the
+ // layout.
+
+ public:
+ static inline size_t Size() {
+ return sizeof(BaselineStubFrameLayout);
+ }
+
+ static inline int reverseOffsetOfSavedFramePtr() {
+ return -int(2 * sizeof(void*));
+ }
+
+ void* reverseSavedFramePtr() {
+ uint8_t* addr = ((uint8_t*) this) + reverseOffsetOfSavedFramePtr();
+ return *(void**)addr;
+ }
+
+ inline void setStubPtr(ICStub* stub) {
+ uint8_t* fp = reinterpret_cast<uint8_t*>(this);
+ *reinterpret_cast<ICStub**>(fp + reverseOffsetOfStubPtr()) = stub;
+ }
+};
+
+// An invalidation bailout stack is at the stack pointer for the callee frame.
+class InvalidationBailoutStack
+{
+ RegisterDump::FPUArray fpregs_;
+ RegisterDump::GPRArray regs_;
+ IonScript* ionScript_;
+ uint8_t* osiPointReturnAddress_;
+
+ public:
+ uint8_t* sp() const {
+ return (uint8_t*) this + sizeof(InvalidationBailoutStack);
+ }
+ JitFrameLayout* fp() const;
+ MachineState machine() {
+ return MachineState::FromBailout(regs_, fpregs_);
+ }
+
+ IonScript* ionScript() const {
+ return ionScript_;
+ }
+ uint8_t* osiPointReturnAddress() const {
+ return osiPointReturnAddress_;
+ }
+ static size_t offsetOfFpRegs() {
+ return offsetof(InvalidationBailoutStack, fpregs_);
+ }
+ static size_t offsetOfRegs() {
+ return offsetof(InvalidationBailoutStack, regs_);
+ }
+
+ void checkInvariants() const;
+};
+
+void
+GetPcScript(JSContext* cx, JSScript** scriptRes, jsbytecode** pcRes);
+
+CalleeToken
+MarkCalleeToken(JSTracer* trc, CalleeToken token);
+
+// Baseline requires one slot for this/argument type checks.
+static const uint32_t MinJITStackSize = 1;
+
+} /* namespace jit */
+} /* namespace js */
+
+#endif /* jit_JitFrames_h */