js/src/jit/BaselineFrameInfo.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/BaselineFrameInfo.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,323 @@
     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_BaselineFrameInfo_h
    1.11 +#define jit_BaselineFrameInfo_h
    1.12 +
    1.13 +#ifdef JS_ION
    1.14 +
    1.15 +#include "mozilla/Alignment.h"
    1.16 +
    1.17 +#include "jit/BaselineFrame.h"
    1.18 +#include "jit/BaselineRegisters.h"
    1.19 +#include "jit/FixedList.h"
    1.20 +#include "jit/IonMacroAssembler.h"
    1.21 +
    1.22 +namespace js {
    1.23 +namespace jit {
    1.24 +
    1.25 +struct BytecodeInfo;
    1.26 +
    1.27 +// FrameInfo overview.
    1.28 +//
    1.29 +// FrameInfo is used by the compiler to track values stored in the frame. This
    1.30 +// includes locals, arguments and stack values. Locals and arguments are always
    1.31 +// fully synced. Stack values can either be synced, stored as constant, stored in
    1.32 +// a Value register or refer to a local slot. Syncing a StackValue ensures it's
    1.33 +// stored on the stack, e.g. kind == Stack.
    1.34 +//
    1.35 +// To see how this works, consider the following statement:
    1.36 +//
    1.37 +//    var y = x + 9;
    1.38 +//
    1.39 +// Here two values are pushed: StackValue(LocalSlot(0)) and StackValue(Int32Value(9)).
    1.40 +// Only when we reach the ADD op, code is generated to load the operands directly
    1.41 +// into the right operand registers and sync all other stack values.
    1.42 +//
    1.43 +// For stack values, the following invariants hold (and are checked between ops):
    1.44 +//
    1.45 +// (1) If a value is synced (kind == Stack), all values below it must also be synced.
    1.46 +//     In other words, values with kind other than Stack can only appear on top of the
    1.47 +//     abstract stack.
    1.48 +//
    1.49 +// (2) When we call a stub or IC, all values still on the stack must be synced.
    1.50 +
    1.51 +// Represents a value pushed on the stack. Note that StackValue is not used for
    1.52 +// locals or arguments since these are always fully synced.
    1.53 +class StackValue
    1.54 +{
    1.55 +  public:
    1.56 +    enum Kind {
    1.57 +        Constant,
    1.58 +        Register,
    1.59 +        Stack,
    1.60 +        LocalSlot,
    1.61 +        ArgSlot,
    1.62 +        ThisSlot
    1.63 +#ifdef DEBUG
    1.64 +        // In debug builds, assert Kind is initialized.
    1.65 +        , Uninitialized
    1.66 +#endif
    1.67 +    };
    1.68 +
    1.69 +  private:
    1.70 +    Kind kind_;
    1.71 +
    1.72 +    union {
    1.73 +        struct {
    1.74 +            Value v;
    1.75 +        } constant;
    1.76 +        struct {
    1.77 +            mozilla::AlignedStorage2<ValueOperand> reg;
    1.78 +        } reg;
    1.79 +        struct {
    1.80 +            uint32_t slot;
    1.81 +        } local;
    1.82 +        struct {
    1.83 +            uint32_t slot;
    1.84 +        } arg;
    1.85 +    } data;
    1.86 +
    1.87 +    JSValueType knownType_;
    1.88 +
    1.89 +  public:
    1.90 +    StackValue() {
    1.91 +        reset();
    1.92 +    }
    1.93 +
    1.94 +    Kind kind() const {
    1.95 +        return kind_;
    1.96 +    }
    1.97 +    bool hasKnownType() const {
    1.98 +        return knownType_ != JSVAL_TYPE_UNKNOWN;
    1.99 +    }
   1.100 +    bool hasKnownType(JSValueType type) const {
   1.101 +        JS_ASSERT(type != JSVAL_TYPE_UNKNOWN);
   1.102 +        return knownType_ == type;
   1.103 +    }
   1.104 +    bool isKnownBoolean() const {
   1.105 +        return hasKnownType(JSVAL_TYPE_BOOLEAN);
   1.106 +    }
   1.107 +    JSValueType knownType() const {
   1.108 +        JS_ASSERT(hasKnownType());
   1.109 +        return knownType_;
   1.110 +    }
   1.111 +    void reset() {
   1.112 +#ifdef DEBUG
   1.113 +        kind_ = Uninitialized;
   1.114 +        knownType_ = JSVAL_TYPE_UNKNOWN;
   1.115 +#endif
   1.116 +    }
   1.117 +    Value constant() const {
   1.118 +        JS_ASSERT(kind_ == Constant);
   1.119 +        return data.constant.v;
   1.120 +    }
   1.121 +    ValueOperand reg() const {
   1.122 +        JS_ASSERT(kind_ == Register);
   1.123 +        return *data.reg.reg.addr();
   1.124 +    }
   1.125 +    uint32_t localSlot() const {
   1.126 +        JS_ASSERT(kind_ == LocalSlot);
   1.127 +        return data.local.slot;
   1.128 +    }
   1.129 +    uint32_t argSlot() const {
   1.130 +        JS_ASSERT(kind_ == ArgSlot);
   1.131 +        return data.arg.slot;
   1.132 +    }
   1.133 +
   1.134 +    void setConstant(const Value &v) {
   1.135 +        kind_ = Constant;
   1.136 +        data.constant.v = v;
   1.137 +        knownType_ = v.isDouble() ? JSVAL_TYPE_DOUBLE : v.extractNonDoubleType();
   1.138 +    }
   1.139 +    void setRegister(const ValueOperand &val, JSValueType knownType = JSVAL_TYPE_UNKNOWN) {
   1.140 +        kind_ = Register;
   1.141 +        *data.reg.reg.addr() = val;
   1.142 +        knownType_ = knownType;
   1.143 +    }
   1.144 +    void setLocalSlot(uint32_t slot) {
   1.145 +        kind_ = LocalSlot;
   1.146 +        data.local.slot = slot;
   1.147 +        knownType_ = JSVAL_TYPE_UNKNOWN;
   1.148 +    }
   1.149 +    void setArgSlot(uint32_t slot) {
   1.150 +        kind_ = ArgSlot;
   1.151 +        data.arg.slot = slot;
   1.152 +        knownType_ = JSVAL_TYPE_UNKNOWN;
   1.153 +    }
   1.154 +    void setThis() {
   1.155 +        kind_ = ThisSlot;
   1.156 +        knownType_ = JSVAL_TYPE_UNKNOWN;
   1.157 +    }
   1.158 +    void setStack() {
   1.159 +        kind_ = Stack;
   1.160 +        knownType_ = JSVAL_TYPE_UNKNOWN;
   1.161 +    }
   1.162 +};
   1.163 +
   1.164 +enum StackAdjustment { AdjustStack, DontAdjustStack };
   1.165 +
   1.166 +class FrameInfo
   1.167 +{
   1.168 +    JSScript *script;
   1.169 +    MacroAssembler &masm;
   1.170 +
   1.171 +    FixedList<StackValue> stack;
   1.172 +    size_t spIndex;
   1.173 +
   1.174 +  public:
   1.175 +    FrameInfo(JSScript *script, MacroAssembler &masm)
   1.176 +      : script(script),
   1.177 +        masm(masm),
   1.178 +        stack(),
   1.179 +        spIndex(0)
   1.180 +    { }
   1.181 +
   1.182 +    bool init(TempAllocator &alloc);
   1.183 +
   1.184 +    uint32_t nlocals() const {
   1.185 +        return script->nfixed();
   1.186 +    }
   1.187 +    uint32_t nargs() const {
   1.188 +        return script->functionNonDelazifying()->nargs();
   1.189 +    }
   1.190 +
   1.191 +  private:
   1.192 +    inline StackValue *rawPush() {
   1.193 +        StackValue *val = &stack[spIndex++];
   1.194 +        val->reset();
   1.195 +        return val;
   1.196 +    }
   1.197 +
   1.198 +  public:
   1.199 +    inline size_t stackDepth() const {
   1.200 +        return spIndex;
   1.201 +    }
   1.202 +    inline void setStackDepth(uint32_t newDepth) {
   1.203 +        if (newDepth <= stackDepth()) {
   1.204 +            spIndex = newDepth;
   1.205 +        } else {
   1.206 +            uint32_t diff = newDepth - stackDepth();
   1.207 +            for (uint32_t i = 0; i < diff; i++) {
   1.208 +                StackValue *val = rawPush();
   1.209 +                val->setStack();
   1.210 +            }
   1.211 +
   1.212 +            JS_ASSERT(spIndex == newDepth);
   1.213 +        }
   1.214 +    }
   1.215 +    inline StackValue *peek(int32_t index) const {
   1.216 +        JS_ASSERT(index < 0);
   1.217 +        return const_cast<StackValue *>(&stack[spIndex + index]);
   1.218 +    }
   1.219 +
   1.220 +    inline void pop(StackAdjustment adjust = AdjustStack) {
   1.221 +        spIndex--;
   1.222 +        StackValue *popped = &stack[spIndex];
   1.223 +
   1.224 +        if (adjust == AdjustStack && popped->kind() == StackValue::Stack)
   1.225 +            masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
   1.226 +
   1.227 +        // Assert when anything uses this value.
   1.228 +        popped->reset();
   1.229 +    }
   1.230 +    inline void popn(uint32_t n, StackAdjustment adjust = AdjustStack) {
   1.231 +        uint32_t poppedStack = 0;
   1.232 +        for (uint32_t i = 0; i < n; i++) {
   1.233 +            if (peek(-1)->kind() == StackValue::Stack)
   1.234 +                poppedStack++;
   1.235 +            pop(DontAdjustStack);
   1.236 +        }
   1.237 +        if (adjust == AdjustStack && poppedStack > 0)
   1.238 +            masm.addPtr(Imm32(sizeof(Value) * poppedStack), BaselineStackReg);
   1.239 +    }
   1.240 +    inline void push(const Value &val) {
   1.241 +        StackValue *sv = rawPush();
   1.242 +        sv->setConstant(val);
   1.243 +    }
   1.244 +    inline void push(const ValueOperand &val, JSValueType knownType=JSVAL_TYPE_UNKNOWN) {
   1.245 +        StackValue *sv = rawPush();
   1.246 +        sv->setRegister(val, knownType);
   1.247 +    }
   1.248 +    inline void pushLocal(uint32_t local) {
   1.249 +        JS_ASSERT(local < nlocals());
   1.250 +        StackValue *sv = rawPush();
   1.251 +        sv->setLocalSlot(local);
   1.252 +    }
   1.253 +    inline void pushArg(uint32_t arg) {
   1.254 +        StackValue *sv = rawPush();
   1.255 +        sv->setArgSlot(arg);
   1.256 +    }
   1.257 +    inline void pushThis() {
   1.258 +        StackValue *sv = rawPush();
   1.259 +        sv->setThis();
   1.260 +    }
   1.261 +    inline void pushScratchValue() {
   1.262 +        masm.pushValue(addressOfScratchValue());
   1.263 +        StackValue *sv = rawPush();
   1.264 +        sv->setStack();
   1.265 +    }
   1.266 +    inline Address addressOfLocal(size_t local) const {
   1.267 +        JS_ASSERT(local < nlocals());
   1.268 +        return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(local));
   1.269 +    }
   1.270 +    Address addressOfArg(size_t arg) const {
   1.271 +        JS_ASSERT(arg < nargs());
   1.272 +        return Address(BaselineFrameReg, BaselineFrame::offsetOfArg(arg));
   1.273 +    }
   1.274 +    Address addressOfThis() const {
   1.275 +        return Address(BaselineFrameReg, BaselineFrame::offsetOfThis());
   1.276 +    }
   1.277 +    Address addressOfCallee() const {
   1.278 +        return Address(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken());
   1.279 +    }
   1.280 +    Address addressOfScopeChain() const {
   1.281 +        return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScopeChain());
   1.282 +    }
   1.283 +    Address addressOfFlags() const {
   1.284 +        return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags());
   1.285 +    }
   1.286 +    Address addressOfEvalScript() const {
   1.287 +        return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfEvalScript());
   1.288 +    }
   1.289 +    Address addressOfReturnValue() const {
   1.290 +        return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfReturnValue());
   1.291 +    }
   1.292 +    Address addressOfStackValue(const StackValue *value) const {
   1.293 +        JS_ASSERT(value->kind() == StackValue::Stack);
   1.294 +        size_t slot = value - &stack[0];
   1.295 +        JS_ASSERT(slot < stackDepth());
   1.296 +        return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(nlocals() + slot));
   1.297 +    }
   1.298 +    Address addressOfScratchValue() const {
   1.299 +        return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScratchValue());
   1.300 +    }
   1.301 +
   1.302 +    void popValue(ValueOperand dest);
   1.303 +
   1.304 +    void sync(StackValue *val);
   1.305 +    void syncStack(uint32_t uses);
   1.306 +    uint32_t numUnsyncedSlots();
   1.307 +    void popRegsAndSync(uint32_t uses);
   1.308 +
   1.309 +    inline void assertSyncedStack() const {
   1.310 +        JS_ASSERT_IF(stackDepth() > 0, peek(-1)->kind() == StackValue::Stack);
   1.311 +    }
   1.312 +
   1.313 +#ifdef DEBUG
   1.314 +    // Assert the state is valid before excuting "pc".
   1.315 +    void assertValidState(const BytecodeInfo &info);
   1.316 +#else
   1.317 +    inline void assertValidState(const BytecodeInfo &info) {}
   1.318 +#endif
   1.319 +};
   1.320 +
   1.321 +} // namespace jit
   1.322 +} // namespace js
   1.323 +
   1.324 +#endif // JS_ION
   1.325 +
   1.326 +#endif /* jit_BaselineFrameInfo_h */

mercurial