blob: f7149cd6db828f159c20d40e676eedacaa074185 [file] [log] [blame]
/* -*- 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 three sections:
// [ frame size | has cached saved frame bit | frame type ]
// < highest - - - - - - - - - - - - - - lowest >
static const uintptr_t FRAMESIZE_SHIFT = 5;
static const uintptr_t HASCACHEDSAVEDFRAME_BIT = 1 << 4;
static const uintptr_t FRAMETYPE_BITS = 4;
// 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 EnsureExitFrame(CommonFrameLayout* frame);
void MarkJitActivations(JSRuntime* rt, JSTracer* trc);
void MarkIonCompilerRoots(JSTracer* trc);
JSCompartment*
TopmostIonActivationCompartment(JSRuntime* rt);
void UpdateJitActivationsForMinorGC(JSRuntime* rt, JSTracer* trc);
static inline uint32_t
MakeFrameDescriptor(uint32_t frameSize, FrameType type)
{
return 0 | (frameSize << FRAMESIZE_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;
}
void setFrameDescriptor(size_t size, FrameType type) {
descriptor_ = 0 | (size << FRAMESIZE_SHIFT) | type;
}
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);
}
};
// The callee token is now dead.
class IonUnwoundRectifierFrameLayout : public RectifierFrameLayout
{
public:
static inline size_t Size() {
// It is not necessary to accout for an extra callee token here because
// sizeof(ExitFrameLayout) == sizeof(RectifierFrameLayout) due to
// extra padding.
return sizeof(IonUnwoundRectifierFrameLayout);
}
};
// 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);
// The minimum stack size is two. Two slots are needed because INITGLEXICAL
// (stack depth 1) is compiled as a SETPROP (stack depth 2) on the global
// lexical scope. Baseline also requires one slot for this/argument type
// checks.
static const uint32_t MinJITStackSize = 2;
} /* namespace jit */
} /* namespace js */
#endif /* jit_JitFrames_h */