js/src/jit/IonFrames.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/IonFrames.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,849 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef jit_IonFrames_h
    1.11 +#define jit_IonFrames_h
    1.12 +
    1.13 +#ifdef JS_ION
    1.14 +
    1.15 +#include <stdint.h>
    1.16 +
    1.17 +#include "jscntxt.h"
    1.18 +#include "jsfun.h"
    1.19 +
    1.20 +#include "jit/JitFrameIterator.h"
    1.21 +
    1.22 +namespace js {
    1.23 +namespace jit {
    1.24 +
    1.25 +typedef void * CalleeToken;
    1.26 +
    1.27 +enum CalleeTokenTag
    1.28 +{
    1.29 +    CalleeToken_Function = 0x0, // untagged
    1.30 +    CalleeToken_Script = 0x1
    1.31 +};
    1.32 +
    1.33 +static inline CalleeTokenTag
    1.34 +GetCalleeTokenTag(CalleeToken token)
    1.35 +{
    1.36 +    CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3);
    1.37 +    JS_ASSERT(tag <= CalleeToken_Script);
    1.38 +    return tag;
    1.39 +}
    1.40 +static inline CalleeToken
    1.41 +CalleeToToken(JSFunction *fun)
    1.42 +{
    1.43 +    return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_Function));
    1.44 +}
    1.45 +static inline CalleeToken
    1.46 +CalleeToToken(JSScript *script)
    1.47 +{
    1.48 +    return CalleeToken(uintptr_t(script) | uintptr_t(CalleeToken_Script));
    1.49 +}
    1.50 +static inline bool
    1.51 +CalleeTokenIsFunction(CalleeToken token)
    1.52 +{
    1.53 +    return GetCalleeTokenTag(token) == CalleeToken_Function;
    1.54 +}
    1.55 +static inline JSFunction *
    1.56 +CalleeTokenToFunction(CalleeToken token)
    1.57 +{
    1.58 +    JS_ASSERT(CalleeTokenIsFunction(token));
    1.59 +    return (JSFunction *)token;
    1.60 +}
    1.61 +static inline JSScript *
    1.62 +CalleeTokenToScript(CalleeToken token)
    1.63 +{
    1.64 +    JS_ASSERT(GetCalleeTokenTag(token) == CalleeToken_Script);
    1.65 +    return (JSScript *)(uintptr_t(token) & ~uintptr_t(0x3));
    1.66 +}
    1.67 +
    1.68 +static inline JSScript *
    1.69 +ScriptFromCalleeToken(CalleeToken token)
    1.70 +{
    1.71 +    switch (GetCalleeTokenTag(token)) {
    1.72 +      case CalleeToken_Script:
    1.73 +        return CalleeTokenToScript(token);
    1.74 +      case CalleeToken_Function:
    1.75 +        return CalleeTokenToFunction(token)->nonLazyScript();
    1.76 +    }
    1.77 +    MOZ_ASSUME_UNREACHABLE("invalid callee token tag");
    1.78 +}
    1.79 +
    1.80 +// In between every two frames lies a small header describing both frames. This
    1.81 +// header, minimally, contains a returnAddress word and a descriptor word. The
    1.82 +// descriptor describes the size and type of the previous frame, whereas the
    1.83 +// returnAddress describes the address the newer frame (the callee) will return
    1.84 +// to. The exact mechanism in which frames are laid out is architecture
    1.85 +// dependent.
    1.86 +//
    1.87 +// Two special frame types exist. Entry frames begin an ion activation, and
    1.88 +// therefore there is exactly one per activation of jit::Cannon. Exit frames
    1.89 +// are necessary to leave JIT code and enter C++, and thus, C++ code will
    1.90 +// always begin iterating from the topmost exit frame.
    1.91 +
    1.92 +class LSafepoint;
    1.93 +
    1.94 +// Two-tuple that lets you look up the safepoint entry given the
    1.95 +// displacement of a call instruction within the JIT code.
    1.96 +class SafepointIndex
    1.97 +{
    1.98 +    // The displacement is the distance from the first byte of the JIT'd code
    1.99 +    // to the return address (of the call that the safepoint was generated for).
   1.100 +    uint32_t displacement_;
   1.101 +
   1.102 +    union {
   1.103 +        LSafepoint *safepoint_;
   1.104 +
   1.105 +        // Offset to the start of the encoded safepoint in the safepoint stream.
   1.106 +        uint32_t safepointOffset_;
   1.107 +    };
   1.108 +
   1.109 +#ifdef DEBUG
   1.110 +    bool resolved;
   1.111 +#endif
   1.112 +
   1.113 +  public:
   1.114 +    SafepointIndex(uint32_t displacement, LSafepoint *safepoint)
   1.115 +      : displacement_(displacement),
   1.116 +        safepoint_(safepoint)
   1.117 +#ifdef DEBUG
   1.118 +      , resolved(false)
   1.119 +#endif
   1.120 +    { }
   1.121 +
   1.122 +    void resolve();
   1.123 +
   1.124 +    LSafepoint *safepoint() {
   1.125 +        JS_ASSERT(!resolved);
   1.126 +        return safepoint_;
   1.127 +    }
   1.128 +    uint32_t displacement() const {
   1.129 +        return displacement_;
   1.130 +    }
   1.131 +    uint32_t safepointOffset() const {
   1.132 +        return safepointOffset_;
   1.133 +    }
   1.134 +    void adjustDisplacement(uint32_t offset) {
   1.135 +        JS_ASSERT(offset >= displacement_);
   1.136 +        displacement_ = offset;
   1.137 +    }
   1.138 +    inline SnapshotOffset snapshotOffset() const;
   1.139 +    inline bool hasSnapshotOffset() const;
   1.140 +};
   1.141 +
   1.142 +class MacroAssembler;
   1.143 +// The OSI point is patched to a call instruction. Therefore, the
   1.144 +// returnPoint for an OSI call is the address immediately following that
   1.145 +// call instruction. The displacement of that point within the assembly
   1.146 +// buffer is the |returnPointDisplacement|.
   1.147 +class OsiIndex
   1.148 +{
   1.149 +    uint32_t callPointDisplacement_;
   1.150 +    uint32_t snapshotOffset_;
   1.151 +
   1.152 +  public:
   1.153 +    OsiIndex(uint32_t callPointDisplacement, uint32_t snapshotOffset)
   1.154 +      : callPointDisplacement_(callPointDisplacement),
   1.155 +        snapshotOffset_(snapshotOffset)
   1.156 +    { }
   1.157 +
   1.158 +    uint32_t returnPointDisplacement() const;
   1.159 +    uint32_t callPointDisplacement() const {
   1.160 +        return callPointDisplacement_;
   1.161 +    }
   1.162 +    uint32_t snapshotOffset() const {
   1.163 +        return snapshotOffset_;
   1.164 +    }
   1.165 +    void fixUpOffset(MacroAssembler &masm);
   1.166 +};
   1.167 +
   1.168 +// The layout of an Ion frame on the C stack is roughly:
   1.169 +//      argN     _
   1.170 +//      ...       \ - These are jsvals
   1.171 +//      arg0      /
   1.172 +//   -3 this    _/
   1.173 +//   -2 callee
   1.174 +//   -1 descriptor
   1.175 +//    0 returnAddress
   1.176 +//   .. locals ..
   1.177 +
   1.178 +// The descriptor is organized into three sections:
   1.179 +// [ frame size | constructing bit | frame type ]
   1.180 +// < highest - - - - - - - - - - - - - - lowest >
   1.181 +static const uintptr_t FRAMESIZE_SHIFT = 4;
   1.182 +static const uintptr_t FRAMETYPE_BITS = 4;
   1.183 +static const uintptr_t FRAMETYPE_MASK = (1 << FRAMETYPE_BITS) - 1;
   1.184 +
   1.185 +// Ion frames have a few important numbers associated with them:
   1.186 +//      Local depth:    The number of bytes required to spill local variables.
   1.187 +//      Argument depth: The number of bytes required to push arguments and make
   1.188 +//                      a function call.
   1.189 +//      Slack:          A frame may temporarily use extra stack to resolve cycles.
   1.190 +//
   1.191 +// The (local + argument) depth determines the "fixed frame size". The fixed
   1.192 +// frame size is the distance between the stack pointer and the frame header.
   1.193 +// Thus, fixed >= (local + argument).
   1.194 +//
   1.195 +// In order to compress guards, we create shared jump tables that recover the
   1.196 +// script from the stack and recover a snapshot pointer based on which jump was
   1.197 +// taken. Thus, we create a jump table for each fixed frame size.
   1.198 +//
   1.199 +// Jump tables are big. To control the amount of jump tables we generate, each
   1.200 +// platform chooses how to segregate stack size classes based on its
   1.201 +// architecture.
   1.202 +//
   1.203 +// On some architectures, these jump tables are not used at all, or frame
   1.204 +// size segregation is not needed. Thus, there is an option for a frame to not
   1.205 +// have any frame size class, and to be totally dynamic.
   1.206 +static const uint32_t NO_FRAME_SIZE_CLASS_ID = uint32_t(-1);
   1.207 +
   1.208 +class FrameSizeClass
   1.209 +{
   1.210 +    uint32_t class_;
   1.211 +
   1.212 +    explicit FrameSizeClass(uint32_t class_) : class_(class_)
   1.213 +    { }
   1.214 +
   1.215 +  public:
   1.216 +    FrameSizeClass()
   1.217 +    { }
   1.218 +
   1.219 +    static FrameSizeClass None() {
   1.220 +        return FrameSizeClass(NO_FRAME_SIZE_CLASS_ID);
   1.221 +    }
   1.222 +    static FrameSizeClass FromClass(uint32_t class_) {
   1.223 +        return FrameSizeClass(class_);
   1.224 +    }
   1.225 +
   1.226 +    // These functions are implemented in specific CodeGenerator-* files.
   1.227 +    static FrameSizeClass FromDepth(uint32_t frameDepth);
   1.228 +    static FrameSizeClass ClassLimit();
   1.229 +    uint32_t frameSize() const;
   1.230 +
   1.231 +    uint32_t classId() const {
   1.232 +        JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
   1.233 +        return class_;
   1.234 +    }
   1.235 +
   1.236 +    bool operator ==(const FrameSizeClass &other) const {
   1.237 +        return class_ == other.class_;
   1.238 +    }
   1.239 +    bool operator !=(const FrameSizeClass &other) const {
   1.240 +        return class_ != other.class_;
   1.241 +    }
   1.242 +};
   1.243 +
   1.244 +struct BaselineBailoutInfo;
   1.245 +
   1.246 +// Data needed to recover from an exception.
   1.247 +struct ResumeFromException
   1.248 +{
   1.249 +    static const uint32_t RESUME_ENTRY_FRAME = 0;
   1.250 +    static const uint32_t RESUME_CATCH = 1;
   1.251 +    static const uint32_t RESUME_FINALLY = 2;
   1.252 +    static const uint32_t RESUME_FORCED_RETURN = 3;
   1.253 +    static const uint32_t RESUME_BAILOUT = 4;
   1.254 +
   1.255 +    uint8_t *framePointer;
   1.256 +    uint8_t *stackPointer;
   1.257 +    uint8_t *target;
   1.258 +    uint32_t kind;
   1.259 +
   1.260 +    // Value to push when resuming into a |finally| block.
   1.261 +    Value exception;
   1.262 +
   1.263 +    BaselineBailoutInfo *bailoutInfo;
   1.264 +};
   1.265 +
   1.266 +void HandleException(ResumeFromException *rfe);
   1.267 +void HandleParallelFailure(ResumeFromException *rfe);
   1.268 +
   1.269 +void EnsureExitFrame(IonCommonFrameLayout *frame);
   1.270 +
   1.271 +void MarkJitActivations(JSRuntime *rt, JSTracer *trc);
   1.272 +void MarkIonCompilerRoots(JSTracer *trc);
   1.273 +
   1.274 +#ifdef JSGC_GENERATIONAL
   1.275 +void UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc);
   1.276 +#endif
   1.277 +
   1.278 +static inline uint32_t
   1.279 +MakeFrameDescriptor(uint32_t frameSize, FrameType type)
   1.280 +{
   1.281 +    return (frameSize << FRAMESIZE_SHIFT) | type;
   1.282 +}
   1.283 +
   1.284 +// Returns the JSScript associated with the topmost Ion frame.
   1.285 +inline JSScript *
   1.286 +GetTopIonJSScript(uint8_t *ionTop, void **returnAddrOut, ExecutionMode mode)
   1.287 +{
   1.288 +    JitFrameIterator iter(ionTop, mode);
   1.289 +    JS_ASSERT(iter.type() == JitFrame_Exit);
   1.290 +    ++iter;
   1.291 +
   1.292 +    JS_ASSERT(iter.returnAddressToFp() != nullptr);
   1.293 +    if (returnAddrOut)
   1.294 +        *returnAddrOut = (void *) iter.returnAddressToFp();
   1.295 +
   1.296 +    if (iter.isBaselineStub()) {
   1.297 +        ++iter;
   1.298 +        JS_ASSERT(iter.isBaselineJS());
   1.299 +    }
   1.300 +
   1.301 +    JS_ASSERT(iter.isScripted());
   1.302 +    return iter.script();
   1.303 +}
   1.304 +
   1.305 +static JitCode *const ION_FRAME_DOMGETTER       = (JitCode *)0x1;
   1.306 +static JitCode *const ION_FRAME_DOMSETTER       = (JitCode *)0x2;
   1.307 +static JitCode *const ION_FRAME_DOMMETHOD       = (JitCode *)0x3;
   1.308 +static JitCode *const ION_FRAME_OOL_NATIVE      = (JitCode *)0x4;
   1.309 +static JitCode *const ION_FRAME_OOL_PROPERTY_OP = (JitCode *)0x5;
   1.310 +static JitCode *const ION_FRAME_OOL_PROXY       = (JitCode *)0x6;
   1.311 +
   1.312 +// Layout of the frame prefix. This assumes the stack architecture grows down.
   1.313 +// If this is ever not the case, we'll have to refactor.
   1.314 +class IonCommonFrameLayout
   1.315 +{
   1.316 +    uint8_t *returnAddress_;
   1.317 +    uintptr_t descriptor_;
   1.318 +
   1.319 +    static const uintptr_t FrameTypeMask = (1 << FRAMETYPE_BITS) - 1;
   1.320 +
   1.321 +  public:
   1.322 +    static size_t offsetOfDescriptor() {
   1.323 +        return offsetof(IonCommonFrameLayout, descriptor_);
   1.324 +    }
   1.325 +    static size_t offsetOfReturnAddress() {
   1.326 +        return offsetof(IonCommonFrameLayout, returnAddress_);
   1.327 +    }
   1.328 +    FrameType prevType() const {
   1.329 +        return FrameType(descriptor_ & FrameTypeMask);
   1.330 +    }
   1.331 +    void changePrevType(FrameType type) {
   1.332 +        descriptor_ &= ~FrameTypeMask;
   1.333 +        descriptor_ |= type;
   1.334 +    }
   1.335 +    size_t prevFrameLocalSize() const {
   1.336 +        return descriptor_ >> FRAMESIZE_SHIFT;
   1.337 +    }
   1.338 +    void setFrameDescriptor(size_t size, FrameType type) {
   1.339 +        descriptor_ = (size << FRAMESIZE_SHIFT) | type;
   1.340 +    }
   1.341 +    uint8_t *returnAddress() const {
   1.342 +        return returnAddress_;
   1.343 +    }
   1.344 +    void setReturnAddress(uint8_t *addr) {
   1.345 +        returnAddress_ = addr;
   1.346 +    }
   1.347 +};
   1.348 +
   1.349 +class IonJSFrameLayout : public IonCommonFrameLayout
   1.350 +{
   1.351 +    CalleeToken calleeToken_;
   1.352 +    uintptr_t numActualArgs_;
   1.353 +
   1.354 +  public:
   1.355 +    CalleeToken calleeToken() const {
   1.356 +        return calleeToken_;
   1.357 +    }
   1.358 +    void replaceCalleeToken(CalleeToken calleeToken) {
   1.359 +        calleeToken_ = calleeToken;
   1.360 +    }
   1.361 +
   1.362 +    static size_t offsetOfCalleeToken() {
   1.363 +        return offsetof(IonJSFrameLayout, calleeToken_);
   1.364 +    }
   1.365 +    static size_t offsetOfNumActualArgs() {
   1.366 +        return offsetof(IonJSFrameLayout, numActualArgs_);
   1.367 +    }
   1.368 +    static size_t offsetOfThis() {
   1.369 +        IonJSFrameLayout *base = nullptr;
   1.370 +        return reinterpret_cast<size_t>(&base->argv()[0]);
   1.371 +    }
   1.372 +    static size_t offsetOfActualArgs() {
   1.373 +        IonJSFrameLayout *base = nullptr;
   1.374 +        // +1 to skip |this|.
   1.375 +        return reinterpret_cast<size_t>(&base->argv()[1]);
   1.376 +    }
   1.377 +    static size_t offsetOfActualArg(size_t arg) {
   1.378 +        return offsetOfActualArgs() + arg * sizeof(Value);
   1.379 +    }
   1.380 +
   1.381 +    Value thisv() {
   1.382 +        return argv()[0];
   1.383 +    }
   1.384 +    Value *argv() {
   1.385 +        return (Value *)(this + 1);
   1.386 +    }
   1.387 +    uintptr_t numActualArgs() const {
   1.388 +        return numActualArgs_;
   1.389 +    }
   1.390 +
   1.391 +    // Computes a reference to a slot, where a slot is a distance from the base
   1.392 +    // frame pointer (as would be used for LStackSlot).
   1.393 +    uintptr_t *slotRef(uint32_t slot) {
   1.394 +        return (uintptr_t *)((uint8_t *)this - slot);
   1.395 +    }
   1.396 +
   1.397 +    static inline size_t Size() {
   1.398 +        return sizeof(IonJSFrameLayout);
   1.399 +    }
   1.400 +};
   1.401 +
   1.402 +// this is the layout of the frame that is used when we enter Ion code from platform ABI code
   1.403 +class IonEntryFrameLayout : public IonJSFrameLayout
   1.404 +{
   1.405 +  public:
   1.406 +    static inline size_t Size() {
   1.407 +        return sizeof(IonEntryFrameLayout);
   1.408 +    }
   1.409 +};
   1.410 +
   1.411 +class IonRectifierFrameLayout : public IonJSFrameLayout
   1.412 +{
   1.413 +  public:
   1.414 +    static inline size_t Size() {
   1.415 +        return sizeof(IonRectifierFrameLayout);
   1.416 +    }
   1.417 +};
   1.418 +
   1.419 +// The callee token is now dead.
   1.420 +class IonUnwoundRectifierFrameLayout : public IonRectifierFrameLayout
   1.421 +{
   1.422 +  public:
   1.423 +    static inline size_t Size() {
   1.424 +        // It is not necessary to accout for an extra callee token here because
   1.425 +        // sizeof(IonExitFrameLayout) == sizeof(IonRectifierFrameLayout) due to
   1.426 +        // extra padding.
   1.427 +        return sizeof(IonUnwoundRectifierFrameLayout);
   1.428 +    }
   1.429 +};
   1.430 +
   1.431 +// GC related data used to keep alive data surrounding the Exit frame.
   1.432 +class IonExitFooterFrame
   1.433 +{
   1.434 +    const VMFunction *function_;
   1.435 +    JitCode *jitCode_;
   1.436 +
   1.437 +  public:
   1.438 +    static inline size_t Size() {
   1.439 +        return sizeof(IonExitFooterFrame);
   1.440 +    }
   1.441 +    inline JitCode *jitCode() const {
   1.442 +        return jitCode_;
   1.443 +    }
   1.444 +    inline JitCode **addressOfJitCode() {
   1.445 +        return &jitCode_;
   1.446 +    }
   1.447 +    inline const VMFunction *function() const {
   1.448 +        return function_;
   1.449 +    }
   1.450 +
   1.451 +    // This should only be called for function()->outParam == Type_Handle
   1.452 +    template <typename T>
   1.453 +    T *outParam() {
   1.454 +        return reinterpret_cast<T *>(reinterpret_cast<char *>(this) - sizeof(T));
   1.455 +    }
   1.456 +};
   1.457 +
   1.458 +class IonNativeExitFrameLayout;
   1.459 +class IonOOLNativeExitFrameLayout;
   1.460 +class IonOOLPropertyOpExitFrameLayout;
   1.461 +class IonOOLProxyExitFrameLayout;
   1.462 +class IonDOMExitFrameLayout;
   1.463 +
   1.464 +// this is the frame layout when we are exiting ion code, and about to enter platform ABI code
   1.465 +class IonExitFrameLayout : public IonCommonFrameLayout
   1.466 +{
   1.467 +    inline uint8_t *top() {
   1.468 +        return reinterpret_cast<uint8_t *>(this + 1);
   1.469 +    }
   1.470 +
   1.471 +  public:
   1.472 +    static inline size_t Size() {
   1.473 +        return sizeof(IonExitFrameLayout);
   1.474 +    }
   1.475 +    static inline size_t SizeWithFooter() {
   1.476 +        return Size() + IonExitFooterFrame::Size();
   1.477 +    }
   1.478 +
   1.479 +    inline IonExitFooterFrame *footer() {
   1.480 +        uint8_t *sp = reinterpret_cast<uint8_t *>(this);
   1.481 +        return reinterpret_cast<IonExitFooterFrame *>(sp - IonExitFooterFrame::Size());
   1.482 +    }
   1.483 +
   1.484 +    // argBase targets the point which precedes the exit frame. Arguments of VM
   1.485 +    // each wrapper are pushed before the exit frame.  This correspond exactly
   1.486 +    // to the value of the argBase register of the generateVMWrapper function.
   1.487 +    inline uint8_t *argBase() {
   1.488 +        JS_ASSERT(footer()->jitCode() != nullptr);
   1.489 +        return top();
   1.490 +    }
   1.491 +
   1.492 +    inline bool isWrapperExit() {
   1.493 +        return footer()->function() != nullptr;
   1.494 +    }
   1.495 +    inline bool isNativeExit() {
   1.496 +        return footer()->jitCode() == nullptr;
   1.497 +    }
   1.498 +    inline bool isOOLNativeExit() {
   1.499 +        return footer()->jitCode() == ION_FRAME_OOL_NATIVE;
   1.500 +    }
   1.501 +    inline bool isOOLPropertyOpExit() {
   1.502 +        return footer()->jitCode() == ION_FRAME_OOL_PROPERTY_OP;
   1.503 +    }
   1.504 +    inline bool isOOLProxyExit() {
   1.505 +        return footer()->jitCode() == ION_FRAME_OOL_PROXY;
   1.506 +    }
   1.507 +    inline bool isDomExit() {
   1.508 +        JitCode *code = footer()->jitCode();
   1.509 +        return
   1.510 +            code == ION_FRAME_DOMGETTER ||
   1.511 +            code == ION_FRAME_DOMSETTER ||
   1.512 +            code == ION_FRAME_DOMMETHOD;
   1.513 +    }
   1.514 +
   1.515 +    inline IonNativeExitFrameLayout *nativeExit() {
   1.516 +        // see CodeGenerator::visitCallNative
   1.517 +        JS_ASSERT(isNativeExit());
   1.518 +        return reinterpret_cast<IonNativeExitFrameLayout *>(footer());
   1.519 +    }
   1.520 +    inline IonOOLNativeExitFrameLayout *oolNativeExit() {
   1.521 +        JS_ASSERT(isOOLNativeExit());
   1.522 +        return reinterpret_cast<IonOOLNativeExitFrameLayout *>(footer());
   1.523 +    }
   1.524 +    inline IonOOLPropertyOpExitFrameLayout *oolPropertyOpExit() {
   1.525 +        JS_ASSERT(isOOLPropertyOpExit());
   1.526 +        return reinterpret_cast<IonOOLPropertyOpExitFrameLayout *>(footer());
   1.527 +    }
   1.528 +    inline IonOOLProxyExitFrameLayout *oolProxyExit() {
   1.529 +        JS_ASSERT(isOOLProxyExit());
   1.530 +        return reinterpret_cast<IonOOLProxyExitFrameLayout *>(footer());
   1.531 +    }
   1.532 +    inline IonDOMExitFrameLayout *DOMExit() {
   1.533 +        JS_ASSERT(isDomExit());
   1.534 +        return reinterpret_cast<IonDOMExitFrameLayout *>(footer());
   1.535 +    }
   1.536 +};
   1.537 +
   1.538 +// Cannot inherit implementa<tion since we need to extend the top of
   1.539 +// IonExitFrameLayout.
   1.540 +class IonNativeExitFrameLayout
   1.541 +{
   1.542 +  protected: // only to silence a clang warning about unused private fields
   1.543 +    IonExitFooterFrame footer_;
   1.544 +    IonExitFrameLayout exit_;
   1.545 +    uintptr_t argc_;
   1.546 +
   1.547 +    // We need to split the Value into 2 fields of 32 bits, otherwise the C++
   1.548 +    // compiler may add some padding between the fields.
   1.549 +    uint32_t loCalleeResult_;
   1.550 +    uint32_t hiCalleeResult_;
   1.551 +
   1.552 +  public:
   1.553 +    static inline size_t Size() {
   1.554 +        return sizeof(IonNativeExitFrameLayout);
   1.555 +    }
   1.556 +
   1.557 +    static size_t offsetOfResult() {
   1.558 +        return offsetof(IonNativeExitFrameLayout, loCalleeResult_);
   1.559 +    }
   1.560 +    inline Value *vp() {
   1.561 +        return reinterpret_cast<Value*>(&loCalleeResult_);
   1.562 +    }
   1.563 +    inline uintptr_t argc() const {
   1.564 +        return argc_;
   1.565 +    }
   1.566 +};
   1.567 +
   1.568 +class IonOOLNativeExitFrameLayout
   1.569 +{
   1.570 +  protected: // only to silence a clang warning about unused private fields
   1.571 +    IonExitFooterFrame footer_;
   1.572 +    IonExitFrameLayout exit_;
   1.573 +
   1.574 +    // pointer to root the stub's JitCode
   1.575 +    JitCode *stubCode_;
   1.576 +
   1.577 +    uintptr_t argc_;
   1.578 +
   1.579 +    // We need to split the Value into 2 fields of 32 bits, otherwise the C++
   1.580 +    // compiler may add some padding between the fields.
   1.581 +    uint32_t loCalleeResult_;
   1.582 +    uint32_t hiCalleeResult_;
   1.583 +
   1.584 +    // Split Value for |this| and args above.
   1.585 +    uint32_t loThis_;
   1.586 +    uint32_t hiThis_;
   1.587 +
   1.588 +  public:
   1.589 +    static inline size_t Size(size_t argc) {
   1.590 +        // The frame accounts for the callee/result and |this|, so we only need args.
   1.591 +        return sizeof(IonOOLNativeExitFrameLayout) + (argc * sizeof(Value));
   1.592 +    }
   1.593 +
   1.594 +    static size_t offsetOfResult() {
   1.595 +        return offsetof(IonOOLNativeExitFrameLayout, loCalleeResult_);
   1.596 +    }
   1.597 +
   1.598 +    inline JitCode **stubCode() {
   1.599 +        return &stubCode_;
   1.600 +    }
   1.601 +    inline Value *vp() {
   1.602 +        return reinterpret_cast<Value*>(&loCalleeResult_);
   1.603 +    }
   1.604 +    inline Value *thisp() {
   1.605 +        return reinterpret_cast<Value*>(&loThis_);
   1.606 +    }
   1.607 +    inline uintptr_t argc() const {
   1.608 +        return argc_;
   1.609 +    }
   1.610 +};
   1.611 +
   1.612 +class IonOOLPropertyOpExitFrameLayout
   1.613 +{
   1.614 +  protected: // only to silence a clang warning about unused private fields
   1.615 +    IonExitFooterFrame footer_;
   1.616 +    IonExitFrameLayout exit_;
   1.617 +
   1.618 +    // Object for HandleObject
   1.619 +    JSObject *obj_;
   1.620 +
   1.621 +    // id for HandleId
   1.622 +    jsid id_;
   1.623 +
   1.624 +    // space for MutableHandleValue result
   1.625 +    // use two uint32_t so compiler doesn't align.
   1.626 +    uint32_t vp0_;
   1.627 +    uint32_t vp1_;
   1.628 +
   1.629 +    // pointer to root the stub's JitCode
   1.630 +    JitCode *stubCode_;
   1.631 +
   1.632 +  public:
   1.633 +    static inline size_t Size() {
   1.634 +        return sizeof(IonOOLPropertyOpExitFrameLayout);
   1.635 +    }
   1.636 +
   1.637 +    static size_t offsetOfResult() {
   1.638 +        return offsetof(IonOOLPropertyOpExitFrameLayout, vp0_);
   1.639 +    }
   1.640 +
   1.641 +    inline JitCode **stubCode() {
   1.642 +        return &stubCode_;
   1.643 +    }
   1.644 +    inline Value *vp() {
   1.645 +        return reinterpret_cast<Value*>(&vp0_);
   1.646 +    }
   1.647 +    inline jsid *id() {
   1.648 +        return &id_;
   1.649 +    }
   1.650 +    inline JSObject **obj() {
   1.651 +        return &obj_;
   1.652 +    }
   1.653 +};
   1.654 +
   1.655 +// Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
   1.656 +//            MutableHandleValue vp)
   1.657 +// Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
   1.658 +//            bool strict, MutableHandleValue vp)
   1.659 +class IonOOLProxyExitFrameLayout
   1.660 +{
   1.661 +  protected: // only to silence a clang warning about unused private fields
   1.662 +    IonExitFooterFrame footer_;
   1.663 +    IonExitFrameLayout exit_;
   1.664 +
   1.665 +    // The proxy object.
   1.666 +    JSObject *proxy_;
   1.667 +
   1.668 +    // Object for HandleObject
   1.669 +    JSObject *receiver_;
   1.670 +
   1.671 +    // id for HandleId
   1.672 +    jsid id_;
   1.673 +
   1.674 +    // space for MutableHandleValue result
   1.675 +    // use two uint32_t so compiler doesn't align.
   1.676 +    uint32_t vp0_;
   1.677 +    uint32_t vp1_;
   1.678 +
   1.679 +    // pointer to root the stub's JitCode
   1.680 +    JitCode *stubCode_;
   1.681 +
   1.682 +  public:
   1.683 +    static inline size_t Size() {
   1.684 +        return sizeof(IonOOLProxyExitFrameLayout);
   1.685 +    }
   1.686 +
   1.687 +    static size_t offsetOfResult() {
   1.688 +        return offsetof(IonOOLProxyExitFrameLayout, vp0_);
   1.689 +    }
   1.690 +
   1.691 +    inline JitCode **stubCode() {
   1.692 +        return &stubCode_;
   1.693 +    }
   1.694 +    inline Value *vp() {
   1.695 +        return reinterpret_cast<Value*>(&vp0_);
   1.696 +    }
   1.697 +    inline jsid *id() {
   1.698 +        return &id_;
   1.699 +    }
   1.700 +    inline JSObject **receiver() {
   1.701 +        return &receiver_;
   1.702 +    }
   1.703 +    inline JSObject **proxy() {
   1.704 +        return &proxy_;
   1.705 +    }
   1.706 +};
   1.707 +
   1.708 +class IonDOMExitFrameLayout
   1.709 +{
   1.710 +  protected: // only to silence a clang warning about unused private fields
   1.711 +    IonExitFooterFrame footer_;
   1.712 +    IonExitFrameLayout exit_;
   1.713 +    JSObject *thisObj;
   1.714 +
   1.715 +    // We need to split the Value into 2 fields of 32 bits, otherwise the C++
   1.716 +    // compiler may add some padding between the fields.
   1.717 +    uint32_t loCalleeResult_;
   1.718 +    uint32_t hiCalleeResult_;
   1.719 +
   1.720 +  public:
   1.721 +    static inline size_t Size() {
   1.722 +        return sizeof(IonDOMExitFrameLayout);
   1.723 +    }
   1.724 +
   1.725 +    static size_t offsetOfResult() {
   1.726 +        return offsetof(IonDOMExitFrameLayout, loCalleeResult_);
   1.727 +    }
   1.728 +    inline Value *vp() {
   1.729 +        return reinterpret_cast<Value*>(&loCalleeResult_);
   1.730 +    }
   1.731 +    inline JSObject **thisObjAddress() {
   1.732 +        return &thisObj;
   1.733 +    }
   1.734 +    inline bool isMethodFrame() {
   1.735 +        return footer_.jitCode() == ION_FRAME_DOMMETHOD;
   1.736 +    }
   1.737 +};
   1.738 +
   1.739 +struct IonDOMMethodExitFrameLayoutTraits;
   1.740 +
   1.741 +class IonDOMMethodExitFrameLayout
   1.742 +{
   1.743 +  protected: // only to silence a clang warning about unused private fields
   1.744 +    IonExitFooterFrame footer_;
   1.745 +    IonExitFrameLayout exit_;
   1.746 +    // This must be the last thing pushed, so as to stay common with
   1.747 +    // IonDOMExitFrameLayout.
   1.748 +    JSObject *thisObj_;
   1.749 +    Value *argv_;
   1.750 +    uintptr_t argc_;
   1.751 +
   1.752 +    // We need to split the Value into 2 fields of 32 bits, otherwise the C++
   1.753 +    // compiler may add some padding between the fields.
   1.754 +    uint32_t loCalleeResult_;
   1.755 +    uint32_t hiCalleeResult_;
   1.756 +
   1.757 +    friend struct IonDOMMethodExitFrameLayoutTraits;
   1.758 +
   1.759 +  public:
   1.760 +    static inline size_t Size() {
   1.761 +        return sizeof(IonDOMMethodExitFrameLayout);
   1.762 +    }
   1.763 +
   1.764 +    static size_t offsetOfResult() {
   1.765 +        return offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_);
   1.766 +    }
   1.767 +
   1.768 +    inline Value *vp() {
   1.769 +        // The code in visitCallDOMNative depends on this static assert holding
   1.770 +        JS_STATIC_ASSERT(offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_) ==
   1.771 +                         (offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t)));
   1.772 +        return reinterpret_cast<Value*>(&loCalleeResult_);
   1.773 +    }
   1.774 +    inline JSObject **thisObjAddress() {
   1.775 +        return &thisObj_;
   1.776 +    }
   1.777 +    inline uintptr_t argc() {
   1.778 +        return argc_;
   1.779 +    }
   1.780 +};
   1.781 +
   1.782 +struct IonDOMMethodExitFrameLayoutTraits {
   1.783 +    static const size_t offsetOfArgcFromArgv =
   1.784 +        offsetof(IonDOMMethodExitFrameLayout, argc_) -
   1.785 +        offsetof(IonDOMMethodExitFrameLayout, argv_);
   1.786 +};
   1.787 +
   1.788 +class ICStub;
   1.789 +
   1.790 +class IonBaselineStubFrameLayout : public IonCommonFrameLayout
   1.791 +{
   1.792 +  public:
   1.793 +    static inline size_t Size() {
   1.794 +        return sizeof(IonBaselineStubFrameLayout);
   1.795 +    }
   1.796 +
   1.797 +    static inline int reverseOffsetOfStubPtr() {
   1.798 +        return -int(sizeof(void *));
   1.799 +    }
   1.800 +    static inline int reverseOffsetOfSavedFramePtr() {
   1.801 +        return -int(2 * sizeof(void *));
   1.802 +    }
   1.803 +
   1.804 +    inline ICStub *maybeStubPtr() {
   1.805 +        uint8_t *fp = reinterpret_cast<uint8_t *>(this);
   1.806 +        return *reinterpret_cast<ICStub **>(fp + reverseOffsetOfStubPtr());
   1.807 +    }
   1.808 +    inline void setStubPtr(ICStub *stub) {
   1.809 +        uint8_t *fp = reinterpret_cast<uint8_t *>(this);
   1.810 +        *reinterpret_cast<ICStub **>(fp + reverseOffsetOfStubPtr()) = stub;
   1.811 +    }
   1.812 +};
   1.813 +
   1.814 +// An invalidation bailout stack is at the stack pointer for the callee frame.
   1.815 +class InvalidationBailoutStack
   1.816 +{
   1.817 +    mozilla::Array<double, FloatRegisters::Total> fpregs_;
   1.818 +    mozilla::Array<uintptr_t, Registers::Total> regs_;
   1.819 +    IonScript   *ionScript_;
   1.820 +    uint8_t       *osiPointReturnAddress_;
   1.821 +
   1.822 +  public:
   1.823 +    uint8_t *sp() const {
   1.824 +        return (uint8_t *) this + sizeof(InvalidationBailoutStack);
   1.825 +    }
   1.826 +    IonJSFrameLayout *fp() const;
   1.827 +    MachineState machine() {
   1.828 +        return MachineState::FromBailout(regs_, fpregs_);
   1.829 +    }
   1.830 +
   1.831 +    IonScript *ionScript() const {
   1.832 +        return ionScript_;
   1.833 +    }
   1.834 +    uint8_t *osiPointReturnAddress() const {
   1.835 +        return osiPointReturnAddress_;
   1.836 +    }
   1.837 +
   1.838 +    void checkInvariants() const;
   1.839 +};
   1.840 +
   1.841 +void
   1.842 +GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes);
   1.843 +
   1.844 +CalleeToken
   1.845 +MarkCalleeToken(JSTracer *trc, CalleeToken token);
   1.846 +
   1.847 +} /* namespace jit */
   1.848 +} /* namespace js */
   1.849 +
   1.850 +#endif // JS_ION
   1.851 +
   1.852 +#endif /* jit_IonFrames_h */

mercurial