js/src/jit/LIR.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/LIR.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1678 @@
     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_LIR_h
    1.11 +#define jit_LIR_h
    1.12 +
    1.13 +// This file declares the core data structures for LIR: storage allocations for
    1.14 +// inputs and outputs, as well as the interface instructions must conform to.
    1.15 +
    1.16 +#include "mozilla/Array.h"
    1.17 +
    1.18 +#include "jit/Bailouts.h"
    1.19 +#include "jit/InlineList.h"
    1.20 +#include "jit/IonAllocPolicy.h"
    1.21 +#include "jit/LOpcodes.h"
    1.22 +#include "jit/MIR.h"
    1.23 +#include "jit/MIRGraph.h"
    1.24 +#include "jit/Registers.h"
    1.25 +#include "jit/Safepoints.h"
    1.26 +
    1.27 +namespace js {
    1.28 +namespace jit {
    1.29 +
    1.30 +class LUse;
    1.31 +class LGeneralReg;
    1.32 +class LFloatReg;
    1.33 +class LStackSlot;
    1.34 +class LArgument;
    1.35 +class LConstantIndex;
    1.36 +class MBasicBlock;
    1.37 +class MTableSwitch;
    1.38 +class MIRGenerator;
    1.39 +class MSnapshot;
    1.40 +
    1.41 +static const uint32_t VREG_INCREMENT = 1;
    1.42 +
    1.43 +static const uint32_t THIS_FRAME_ARGSLOT = 0;
    1.44 +
    1.45 +#if defined(JS_NUNBOX32)
    1.46 +# define BOX_PIECES         2
    1.47 +static const uint32_t VREG_TYPE_OFFSET = 0;
    1.48 +static const uint32_t VREG_DATA_OFFSET = 1;
    1.49 +static const uint32_t TYPE_INDEX = 0;
    1.50 +static const uint32_t PAYLOAD_INDEX = 1;
    1.51 +#elif defined(JS_PUNBOX64)
    1.52 +# define BOX_PIECES         1
    1.53 +#else
    1.54 +# error "Unknown!"
    1.55 +#endif
    1.56 +
    1.57 +// Represents storage for an operand. For constants, the pointer is tagged
    1.58 +// with a single bit, and the untagged pointer is a pointer to a Value.
    1.59 +class LAllocation : public TempObject
    1.60 +{
    1.61 +    uintptr_t bits_;
    1.62 +
    1.63 +    static const uintptr_t TAG_BIT = 1;
    1.64 +    static const uintptr_t TAG_SHIFT = 0;
    1.65 +    static const uintptr_t TAG_MASK = 1 << TAG_SHIFT;
    1.66 +    static const uintptr_t KIND_BITS = 3;
    1.67 +    static const uintptr_t KIND_SHIFT = TAG_SHIFT + TAG_BIT;
    1.68 +    static const uintptr_t KIND_MASK = (1 << KIND_BITS) - 1;
    1.69 +
    1.70 +  protected:
    1.71 +    static const uintptr_t DATA_BITS = (sizeof(uint32_t) * 8) - KIND_BITS - TAG_BIT;
    1.72 +    static const uintptr_t DATA_SHIFT = KIND_SHIFT + KIND_BITS;
    1.73 +    static const uintptr_t DATA_MASK = (1 << DATA_BITS) - 1;
    1.74 +
    1.75 +  public:
    1.76 +    enum Kind {
    1.77 +        USE,            // Use of a virtual register, with physical allocation policy.
    1.78 +        CONSTANT_VALUE, // Constant js::Value.
    1.79 +        CONSTANT_INDEX, // Constant arbitrary index.
    1.80 +        GPR,            // General purpose register.
    1.81 +        FPU,            // Floating-point register.
    1.82 +        STACK_SLOT,     // Stack slot.
    1.83 +        ARGUMENT_SLOT   // Argument slot.
    1.84 +    };
    1.85 +
    1.86 +  protected:
    1.87 +    bool isTagged() const {
    1.88 +        return !!(bits_ & TAG_MASK);
    1.89 +    }
    1.90 +
    1.91 +    int32_t data() const {
    1.92 +        return int32_t(bits_) >> DATA_SHIFT;
    1.93 +    }
    1.94 +    void setData(int32_t data) {
    1.95 +        JS_ASSERT(int32_t(data) <= int32_t(DATA_MASK));
    1.96 +        bits_ &= ~(DATA_MASK << DATA_SHIFT);
    1.97 +        bits_ |= (data << DATA_SHIFT);
    1.98 +    }
    1.99 +    void setKindAndData(Kind kind, uint32_t data) {
   1.100 +        JS_ASSERT(int32_t(data) <= int32_t(DATA_MASK));
   1.101 +        bits_ = (uint32_t(kind) << KIND_SHIFT) | data << DATA_SHIFT;
   1.102 +    }
   1.103 +
   1.104 +    LAllocation(Kind kind, uint32_t data) {
   1.105 +        setKindAndData(kind, data);
   1.106 +    }
   1.107 +    explicit LAllocation(Kind kind) {
   1.108 +        setKindAndData(kind, 0);
   1.109 +    }
   1.110 +
   1.111 +  public:
   1.112 +    LAllocation() : bits_(0)
   1.113 +    { }
   1.114 +
   1.115 +    static LAllocation *New(TempAllocator &alloc) {
   1.116 +        return new(alloc) LAllocation();
   1.117 +    }
   1.118 +    template <typename T>
   1.119 +    static LAllocation *New(TempAllocator &alloc, const T &other) {
   1.120 +        return new(alloc) LAllocation(other);
   1.121 +    }
   1.122 +
   1.123 +    // The value pointer must be rooted in MIR and have its low bit cleared.
   1.124 +    explicit LAllocation(const Value *vp) {
   1.125 +        bits_ = uintptr_t(vp);
   1.126 +        JS_ASSERT(!isTagged());
   1.127 +        bits_ |= TAG_MASK;
   1.128 +    }
   1.129 +    inline explicit LAllocation(const AnyRegister &reg);
   1.130 +
   1.131 +    Kind kind() const {
   1.132 +        if (isTagged())
   1.133 +            return CONSTANT_VALUE;
   1.134 +        return (Kind)((bits_ >> KIND_SHIFT) & KIND_MASK);
   1.135 +    }
   1.136 +
   1.137 +    bool isUse() const {
   1.138 +        return kind() == USE;
   1.139 +    }
   1.140 +    bool isConstant() const {
   1.141 +        return isConstantValue() || isConstantIndex();
   1.142 +    }
   1.143 +    bool isConstantValue() const {
   1.144 +        return kind() == CONSTANT_VALUE;
   1.145 +    }
   1.146 +    bool isConstantIndex() const {
   1.147 +        return kind() == CONSTANT_INDEX;
   1.148 +    }
   1.149 +    bool isValue() const {
   1.150 +        return kind() == CONSTANT_VALUE;
   1.151 +    }
   1.152 +    bool isGeneralReg() const {
   1.153 +        return kind() == GPR;
   1.154 +    }
   1.155 +    bool isFloatReg() const {
   1.156 +        return kind() == FPU;
   1.157 +    }
   1.158 +    bool isStackSlot() const {
   1.159 +        return kind() == STACK_SLOT;
   1.160 +    }
   1.161 +    bool isArgument() const {
   1.162 +        return kind() == ARGUMENT_SLOT;
   1.163 +    }
   1.164 +    bool isRegister() const {
   1.165 +        return isGeneralReg() || isFloatReg();
   1.166 +    }
   1.167 +    bool isRegister(bool needFloat) const {
   1.168 +        return needFloat ? isFloatReg() : isGeneralReg();
   1.169 +    }
   1.170 +    bool isMemory() const {
   1.171 +        return isStackSlot() || isArgument();
   1.172 +    }
   1.173 +    inline LUse *toUse();
   1.174 +    inline const LUse *toUse() const;
   1.175 +    inline const LGeneralReg *toGeneralReg() const;
   1.176 +    inline const LFloatReg *toFloatReg() const;
   1.177 +    inline const LStackSlot *toStackSlot() const;
   1.178 +    inline const LArgument *toArgument() const;
   1.179 +    inline const LConstantIndex *toConstantIndex() const;
   1.180 +    inline AnyRegister toRegister() const;
   1.181 +
   1.182 +    const Value *toConstant() const {
   1.183 +        JS_ASSERT(isConstantValue());
   1.184 +        return reinterpret_cast<const Value *>(bits_ & ~TAG_MASK);
   1.185 +    }
   1.186 +
   1.187 +    bool operator ==(const LAllocation &other) const {
   1.188 +        return bits_ == other.bits_;
   1.189 +    }
   1.190 +
   1.191 +    bool operator !=(const LAllocation &other) const {
   1.192 +        return bits_ != other.bits_;
   1.193 +    }
   1.194 +
   1.195 +    HashNumber hash() const {
   1.196 +        return bits_;
   1.197 +    }
   1.198 +
   1.199 +#ifdef DEBUG
   1.200 +    const char *toString() const;
   1.201 +#else
   1.202 +    const char *toString() const { return "???"; }
   1.203 +#endif
   1.204 +
   1.205 +    void dump() const;
   1.206 +};
   1.207 +
   1.208 +class LUse : public LAllocation
   1.209 +{
   1.210 +    static const uint32_t POLICY_BITS = 3;
   1.211 +    static const uint32_t POLICY_SHIFT = 0;
   1.212 +    static const uint32_t POLICY_MASK = (1 << POLICY_BITS) - 1;
   1.213 +    static const uint32_t REG_BITS = 5;
   1.214 +    static const uint32_t REG_SHIFT = POLICY_SHIFT + POLICY_BITS;
   1.215 +    static const uint32_t REG_MASK = (1 << REG_BITS) - 1;
   1.216 +
   1.217 +    // Whether the physical register for this operand may be reused for a def.
   1.218 +    static const uint32_t USED_AT_START_BITS = 1;
   1.219 +    static const uint32_t USED_AT_START_SHIFT = REG_SHIFT + REG_BITS;
   1.220 +    static const uint32_t USED_AT_START_MASK = (1 << USED_AT_START_BITS) - 1;
   1.221 +
   1.222 +  public:
   1.223 +    // Virtual registers get the remaining 20 bits.
   1.224 +    static const uint32_t VREG_BITS = DATA_BITS - (USED_AT_START_SHIFT + USED_AT_START_BITS);
   1.225 +    static const uint32_t VREG_SHIFT = USED_AT_START_SHIFT + USED_AT_START_BITS;
   1.226 +    static const uint32_t VREG_MASK = (1 << VREG_BITS) - 1;
   1.227 +
   1.228 +    enum Policy {
   1.229 +        // Input should be in a read-only register or stack slot.
   1.230 +        ANY,
   1.231 +
   1.232 +        // Input must be in a read-only register.
   1.233 +        REGISTER,
   1.234 +
   1.235 +        // Input must be in a specific, read-only register.
   1.236 +        FIXED,
   1.237 +
   1.238 +        // Keep the used virtual register alive, and use whatever allocation is
   1.239 +        // available. This is similar to ANY but hints to the register allocator
   1.240 +        // that it is never useful to optimize this site.
   1.241 +        KEEPALIVE,
   1.242 +
   1.243 +        // For snapshot inputs, indicates that the associated instruction will
   1.244 +        // write this input to its output register before bailing out.
   1.245 +        // The register allocator may thus allocate that output register, and
   1.246 +        // does not need to keep the virtual register alive (alternatively,
   1.247 +        // this may be treated as KEEPALIVE).
   1.248 +        RECOVERED_INPUT
   1.249 +    };
   1.250 +
   1.251 +    void set(Policy policy, uint32_t reg, bool usedAtStart) {
   1.252 +        setKindAndData(USE, (policy << POLICY_SHIFT) |
   1.253 +                            (reg << REG_SHIFT) |
   1.254 +                            ((usedAtStart ? 1 : 0) << USED_AT_START_SHIFT));
   1.255 +    }
   1.256 +
   1.257 +  public:
   1.258 +    LUse(uint32_t vreg, Policy policy, bool usedAtStart = false) {
   1.259 +        set(policy, 0, usedAtStart);
   1.260 +        setVirtualRegister(vreg);
   1.261 +    }
   1.262 +    LUse(Policy policy, bool usedAtStart = false) {
   1.263 +        set(policy, 0, usedAtStart);
   1.264 +    }
   1.265 +    LUse(Register reg, bool usedAtStart = false) {
   1.266 +        set(FIXED, reg.code(), usedAtStart);
   1.267 +    }
   1.268 +    LUse(FloatRegister reg, bool usedAtStart = false) {
   1.269 +        set(FIXED, reg.code(), usedAtStart);
   1.270 +    }
   1.271 +    LUse(Register reg, uint32_t virtualRegister) {
   1.272 +        set(FIXED, reg.code(), false);
   1.273 +        setVirtualRegister(virtualRegister);
   1.274 +    }
   1.275 +    LUse(FloatRegister reg, uint32_t virtualRegister) {
   1.276 +        set(FIXED, reg.code(), false);
   1.277 +        setVirtualRegister(virtualRegister);
   1.278 +    }
   1.279 +
   1.280 +    void setVirtualRegister(uint32_t index) {
   1.281 +        JS_ASSERT(index < VREG_MASK);
   1.282 +
   1.283 +        uint32_t old = data() & ~(VREG_MASK << VREG_SHIFT);
   1.284 +        setData(old | (index << VREG_SHIFT));
   1.285 +    }
   1.286 +
   1.287 +    Policy policy() const {
   1.288 +        Policy policy = (Policy)((data() >> POLICY_SHIFT) & POLICY_MASK);
   1.289 +        return policy;
   1.290 +    }
   1.291 +    uint32_t virtualRegister() const {
   1.292 +        uint32_t index = (data() >> VREG_SHIFT) & VREG_MASK;
   1.293 +        return index;
   1.294 +    }
   1.295 +    uint32_t registerCode() const {
   1.296 +        JS_ASSERT(policy() == FIXED);
   1.297 +        return (data() >> REG_SHIFT) & REG_MASK;
   1.298 +    }
   1.299 +    bool isFixedRegister() const {
   1.300 +        return policy() == FIXED;
   1.301 +    }
   1.302 +    bool usedAtStart() const {
   1.303 +        return !!((data() >> USED_AT_START_SHIFT) & USED_AT_START_MASK);
   1.304 +    }
   1.305 +};
   1.306 +
   1.307 +static const uint32_t MAX_VIRTUAL_REGISTERS = LUse::VREG_MASK;
   1.308 +
   1.309 +class LGeneralReg : public LAllocation
   1.310 +{
   1.311 +  public:
   1.312 +    explicit LGeneralReg(Register reg)
   1.313 +      : LAllocation(GPR, reg.code())
   1.314 +    { }
   1.315 +
   1.316 +    Register reg() const {
   1.317 +        return Register::FromCode(data());
   1.318 +    }
   1.319 +};
   1.320 +
   1.321 +class LFloatReg : public LAllocation
   1.322 +{
   1.323 +  public:
   1.324 +    explicit LFloatReg(FloatRegister reg)
   1.325 +      : LAllocation(FPU, reg.code())
   1.326 +    { }
   1.327 +
   1.328 +    FloatRegister reg() const {
   1.329 +        return FloatRegister::FromCode(data());
   1.330 +    }
   1.331 +};
   1.332 +
   1.333 +// Arbitrary constant index.
   1.334 +class LConstantIndex : public LAllocation
   1.335 +{
   1.336 +    explicit LConstantIndex(uint32_t index)
   1.337 +      : LAllocation(CONSTANT_INDEX, index)
   1.338 +    { }
   1.339 +
   1.340 +  public:
   1.341 +    // Used as a placeholder for inputs that can be ignored.
   1.342 +    static LConstantIndex Bogus() {
   1.343 +        return LConstantIndex(0);
   1.344 +    }
   1.345 +
   1.346 +    static LConstantIndex FromIndex(uint32_t index) {
   1.347 +        return LConstantIndex(index);
   1.348 +    }
   1.349 +
   1.350 +    uint32_t index() const {
   1.351 +        return data();
   1.352 +    }
   1.353 +};
   1.354 +
   1.355 +// Stack slots are indices into the stack. The indices are byte indices.
   1.356 +class LStackSlot : public LAllocation
   1.357 +{
   1.358 +  public:
   1.359 +    explicit LStackSlot(uint32_t slot)
   1.360 +      : LAllocation(STACK_SLOT, slot)
   1.361 +    { }
   1.362 +
   1.363 +    uint32_t slot() const {
   1.364 +        return data();
   1.365 +    }
   1.366 +};
   1.367 +
   1.368 +// Arguments are reverse indices into the stack. The indices are byte indices.
   1.369 +class LArgument : public LAllocation
   1.370 +{
   1.371 +  public:
   1.372 +    explicit LArgument(int32_t index)
   1.373 +      : LAllocation(ARGUMENT_SLOT, index)
   1.374 +    { }
   1.375 +
   1.376 +    int32_t index() const {
   1.377 +        return data();
   1.378 +    }
   1.379 +};
   1.380 +
   1.381 +// Represents storage for a definition.
   1.382 +class LDefinition
   1.383 +{
   1.384 +    // Bits containing policy, type, and virtual register.
   1.385 +    uint32_t bits_;
   1.386 +
   1.387 +    // Before register allocation, this optionally contains a fixed policy.
   1.388 +    // Register allocation assigns this field to a physical policy if none is
   1.389 +    // preset.
   1.390 +    //
   1.391 +    // Right now, pre-allocated outputs are limited to the following:
   1.392 +    //   * Physical argument stack slots.
   1.393 +    //   * Physical registers.
   1.394 +    LAllocation output_;
   1.395 +
   1.396 +    static const uint32_t TYPE_BITS = 3;
   1.397 +    static const uint32_t TYPE_SHIFT = 0;
   1.398 +    static const uint32_t TYPE_MASK = (1 << TYPE_BITS) - 1;
   1.399 +    static const uint32_t POLICY_BITS = 2;
   1.400 +    static const uint32_t POLICY_SHIFT = TYPE_SHIFT + TYPE_BITS;
   1.401 +    static const uint32_t POLICY_MASK = (1 << POLICY_BITS) - 1;
   1.402 +
   1.403 +    static const uint32_t VREG_BITS = (sizeof(uint32_t) * 8) - (POLICY_BITS + TYPE_BITS);
   1.404 +    static const uint32_t VREG_SHIFT = POLICY_SHIFT + POLICY_BITS;
   1.405 +    static const uint32_t VREG_MASK = (1 << VREG_BITS) - 1;
   1.406 +
   1.407 +  public:
   1.408 +    // Note that definitions, by default, are always allocated a register,
   1.409 +    // unless the policy specifies that an input can be re-used and that input
   1.410 +    // is a stack slot.
   1.411 +    enum Policy {
   1.412 +        // A random register of an appropriate class will be assigned.
   1.413 +        DEFAULT,
   1.414 +
   1.415 +        // The policy is predetermined by the LAllocation attached to this
   1.416 +        // definition. The allocation may be:
   1.417 +        //   * A register, which may not appear as any fixed temporary.
   1.418 +        //   * A stack slot or argument.
   1.419 +        //
   1.420 +        // Register allocation will not modify a preset allocation.
   1.421 +        PRESET,
   1.422 +
   1.423 +        // One definition per instruction must re-use the first input
   1.424 +        // allocation, which (for now) must be a register.
   1.425 +        MUST_REUSE_INPUT,
   1.426 +
   1.427 +        // This definition's virtual register is the same as another; this is
   1.428 +        // for instructions which consume a register and silently define it as
   1.429 +        // the same register. It is not legal to use this if doing so would
   1.430 +        // change the type of the virtual register.
   1.431 +        PASSTHROUGH
   1.432 +    };
   1.433 +
   1.434 +    enum Type {
   1.435 +        GENERAL,    // Generic, integer or pointer-width data (GPR).
   1.436 +        INT32,      // int32 data (GPR).
   1.437 +        OBJECT,     // Pointer that may be collected as garbage (GPR).
   1.438 +        SLOTS,      // Slots/elements pointer that may be moved by minor GCs (GPR).
   1.439 +        FLOAT32,    // 32-bit floating-point value (FPU).
   1.440 +        DOUBLE,     // 64-bit floating-point value (FPU).
   1.441 +#ifdef JS_NUNBOX32
   1.442 +        // A type virtual register must be followed by a payload virtual
   1.443 +        // register, as both will be tracked as a single gcthing.
   1.444 +        TYPE,
   1.445 +        PAYLOAD
   1.446 +#else
   1.447 +        BOX         // Joined box, for punbox systems. (GPR, gcthing)
   1.448 +#endif
   1.449 +    };
   1.450 +
   1.451 +    void set(uint32_t index, Type type, Policy policy) {
   1.452 +        JS_STATIC_ASSERT(MAX_VIRTUAL_REGISTERS <= VREG_MASK);
   1.453 +        bits_ = (index << VREG_SHIFT) | (policy << POLICY_SHIFT) | (type << TYPE_SHIFT);
   1.454 +    }
   1.455 +
   1.456 +  public:
   1.457 +    LDefinition(uint32_t index, Type type, Policy policy = DEFAULT) {
   1.458 +        set(index, type, policy);
   1.459 +    }
   1.460 +
   1.461 +    LDefinition(Type type, Policy policy = DEFAULT) {
   1.462 +        set(0, type, policy);
   1.463 +    }
   1.464 +
   1.465 +    LDefinition(Type type, const LAllocation &a)
   1.466 +      : output_(a)
   1.467 +    {
   1.468 +        set(0, type, PRESET);
   1.469 +    }
   1.470 +
   1.471 +    LDefinition(uint32_t index, Type type, const LAllocation &a)
   1.472 +      : output_(a)
   1.473 +    {
   1.474 +        set(index, type, PRESET);
   1.475 +    }
   1.476 +
   1.477 +    LDefinition() : bits_(0)
   1.478 +    { }
   1.479 +
   1.480 +    static LDefinition BogusTemp() {
   1.481 +        return LDefinition(GENERAL, LConstantIndex::Bogus());
   1.482 +    }
   1.483 +
   1.484 +    Policy policy() const {
   1.485 +        return (Policy)((bits_ >> POLICY_SHIFT) & POLICY_MASK);
   1.486 +    }
   1.487 +    Type type() const {
   1.488 +        return (Type)((bits_ >> TYPE_SHIFT) & TYPE_MASK);
   1.489 +    }
   1.490 +    bool isFloatReg() const {
   1.491 +        return type() == FLOAT32 || type() == DOUBLE;
   1.492 +    }
   1.493 +    uint32_t virtualRegister() const {
   1.494 +        return (bits_ >> VREG_SHIFT) & VREG_MASK;
   1.495 +    }
   1.496 +    LAllocation *output() {
   1.497 +        return &output_;
   1.498 +    }
   1.499 +    const LAllocation *output() const {
   1.500 +        return &output_;
   1.501 +    }
   1.502 +    bool isPreset() const {
   1.503 +        return policy() == PRESET;
   1.504 +    }
   1.505 +    bool isBogusTemp() const {
   1.506 +        return isPreset() && output()->isConstantIndex();
   1.507 +    }
   1.508 +    void setVirtualRegister(uint32_t index) {
   1.509 +        JS_ASSERT(index < VREG_MASK);
   1.510 +        bits_ &= ~(VREG_MASK << VREG_SHIFT);
   1.511 +        bits_ |= index << VREG_SHIFT;
   1.512 +    }
   1.513 +    void setOutput(const LAllocation &a) {
   1.514 +        output_ = a;
   1.515 +        if (!a.isUse()) {
   1.516 +            bits_ &= ~(POLICY_MASK << POLICY_SHIFT);
   1.517 +            bits_ |= PRESET << POLICY_SHIFT;
   1.518 +        }
   1.519 +    }
   1.520 +    void setReusedInput(uint32_t operand) {
   1.521 +        output_ = LConstantIndex::FromIndex(operand);
   1.522 +    }
   1.523 +    uint32_t getReusedInput() const {
   1.524 +        JS_ASSERT(policy() == LDefinition::MUST_REUSE_INPUT);
   1.525 +        return output_.toConstantIndex()->index();
   1.526 +    }
   1.527 +
   1.528 +    static inline Type TypeFrom(MIRType type) {
   1.529 +        switch (type) {
   1.530 +          case MIRType_Boolean:
   1.531 +          case MIRType_Int32:
   1.532 +            // The stack slot allocator doesn't currently support allocating
   1.533 +            // 1-byte slots, so for now we lower MIRType_Boolean into INT32.
   1.534 +            static_assert(sizeof(bool) <= sizeof(int32_t), "bool doesn't fit in an int32 slot");
   1.535 +            return LDefinition::INT32;
   1.536 +          case MIRType_String:
   1.537 +          case MIRType_Object:
   1.538 +            return LDefinition::OBJECT;
   1.539 +          case MIRType_Double:
   1.540 +            return LDefinition::DOUBLE;
   1.541 +          case MIRType_Float32:
   1.542 +            return LDefinition::FLOAT32;
   1.543 +#if defined(JS_PUNBOX64)
   1.544 +          case MIRType_Value:
   1.545 +            return LDefinition::BOX;
   1.546 +#endif
   1.547 +          case MIRType_Slots:
   1.548 +          case MIRType_Elements:
   1.549 +            return LDefinition::SLOTS;
   1.550 +          case MIRType_Pointer:
   1.551 +            return LDefinition::GENERAL;
   1.552 +          case MIRType_ForkJoinContext:
   1.553 +            return LDefinition::GENERAL;
   1.554 +          default:
   1.555 +            MOZ_ASSUME_UNREACHABLE("unexpected type");
   1.556 +        }
   1.557 +    }
   1.558 +};
   1.559 +
   1.560 +// Forward declarations of LIR types.
   1.561 +#define LIROP(op) class L##op;
   1.562 +    LIR_OPCODE_LIST(LIROP)
   1.563 +#undef LIROP
   1.564 +
   1.565 +class LSnapshot;
   1.566 +class LSafepoint;
   1.567 +class LInstructionVisitor;
   1.568 +
   1.569 +class LInstruction
   1.570 +  : public TempObject,
   1.571 +    public InlineListNode<LInstruction>
   1.572 +{
   1.573 +    uint32_t id_;
   1.574 +
   1.575 +    // This snapshot could be set after a ResumePoint.  It is used to restart
   1.576 +    // from the resume point pc.
   1.577 +    LSnapshot *snapshot_;
   1.578 +
   1.579 +    // Structure capturing the set of stack slots and registers which are known
   1.580 +    // to hold either gcthings or Values.
   1.581 +    LSafepoint *safepoint_;
   1.582 +
   1.583 +  protected:
   1.584 +    MDefinition *mir_;
   1.585 +
   1.586 +    LInstruction()
   1.587 +      : id_(0),
   1.588 +        snapshot_(nullptr),
   1.589 +        safepoint_(nullptr),
   1.590 +        mir_(nullptr)
   1.591 +    { }
   1.592 +
   1.593 +  public:
   1.594 +    class InputIterator;
   1.595 +    enum Opcode {
   1.596 +#   define LIROP(name) LOp_##name,
   1.597 +        LIR_OPCODE_LIST(LIROP)
   1.598 +#   undef LIROP
   1.599 +        LOp_Invalid
   1.600 +    };
   1.601 +
   1.602 +    const char *opName() {
   1.603 +        switch (op()) {
   1.604 +#   define LIR_NAME_INS(name)                   \
   1.605 +            case LOp_##name: return #name;
   1.606 +            LIR_OPCODE_LIST(LIR_NAME_INS)
   1.607 +#   undef LIR_NAME_INS
   1.608 +          default:
   1.609 +            return "Invalid";
   1.610 +        }
   1.611 +    }
   1.612 +
   1.613 +    // Hook for opcodes to add extra high level detail about what code will be
   1.614 +    // emitted for the op.
   1.615 +    virtual const char *extraName() const {
   1.616 +        return nullptr;
   1.617 +    }
   1.618 +
   1.619 +  public:
   1.620 +    virtual Opcode op() const = 0;
   1.621 +
   1.622 +    // Returns the number of outputs of this instruction. If an output is
   1.623 +    // unallocated, it is an LDefinition, defining a virtual register.
   1.624 +    virtual size_t numDefs() const = 0;
   1.625 +    virtual LDefinition *getDef(size_t index) = 0;
   1.626 +    virtual void setDef(size_t index, const LDefinition &def) = 0;
   1.627 +
   1.628 +    // Returns information about operands.
   1.629 +    virtual size_t numOperands() const = 0;
   1.630 +    virtual LAllocation *getOperand(size_t index) = 0;
   1.631 +    virtual void setOperand(size_t index, const LAllocation &a) = 0;
   1.632 +
   1.633 +    // Returns information about temporary registers needed. Each temporary
   1.634 +    // register is an LUse with a TEMPORARY policy, or a fixed register.
   1.635 +    virtual size_t numTemps() const = 0;
   1.636 +    virtual LDefinition *getTemp(size_t index) = 0;
   1.637 +    virtual void setTemp(size_t index, const LDefinition &a) = 0;
   1.638 +
   1.639 +    // Returns the number of successors of this instruction, if it is a control
   1.640 +    // transfer instruction, or zero otherwise.
   1.641 +    virtual size_t numSuccessors() const = 0;
   1.642 +    virtual MBasicBlock *getSuccessor(size_t i) const = 0;
   1.643 +    virtual void setSuccessor(size_t i, MBasicBlock *successor) = 0;
   1.644 +
   1.645 +    virtual bool isCall() const {
   1.646 +        return false;
   1.647 +    }
   1.648 +    uint32_t id() const {
   1.649 +        return id_;
   1.650 +    }
   1.651 +    void setId(uint32_t id) {
   1.652 +        JS_ASSERT(!id_);
   1.653 +        JS_ASSERT(id);
   1.654 +        id_ = id;
   1.655 +    }
   1.656 +    LSnapshot *snapshot() const {
   1.657 +        return snapshot_;
   1.658 +    }
   1.659 +    LSafepoint *safepoint() const {
   1.660 +        return safepoint_;
   1.661 +    }
   1.662 +    void setMir(MDefinition *mir) {
   1.663 +        mir_ = mir;
   1.664 +    }
   1.665 +    MDefinition *mirRaw() const {
   1.666 +        /* Untyped MIR for this op. Prefer mir() methods in subclasses. */
   1.667 +        return mir_;
   1.668 +    }
   1.669 +    void assignSnapshot(LSnapshot *snapshot);
   1.670 +    void initSafepoint(TempAllocator &alloc);
   1.671 +
   1.672 +    // For an instruction which has a MUST_REUSE_INPUT output, whether that
   1.673 +    // output register will be restored to its original value when bailing out.
   1.674 +    virtual bool recoversInput() const {
   1.675 +        return false;
   1.676 +    }
   1.677 +
   1.678 +    virtual void dump(FILE *fp);
   1.679 +    void dump();
   1.680 +    static void printName(FILE *fp, Opcode op);
   1.681 +    virtual void printName(FILE *fp);
   1.682 +    virtual void printOperands(FILE *fp);
   1.683 +    virtual void printInfo(FILE *fp) { }
   1.684 +
   1.685 +  public:
   1.686 +    // Opcode testing and casts.
   1.687 +#   define LIROP(name)                                                      \
   1.688 +    bool is##name() const {                                                 \
   1.689 +        return op() == LOp_##name;                                          \
   1.690 +    }                                                                       \
   1.691 +    inline L##name *to##name();
   1.692 +    LIR_OPCODE_LIST(LIROP)
   1.693 +#   undef LIROP
   1.694 +
   1.695 +    virtual bool accept(LInstructionVisitor *visitor) = 0;
   1.696 +};
   1.697 +
   1.698 +class LInstructionVisitor
   1.699 +{
   1.700 +    LInstruction *ins_;
   1.701 +
   1.702 +  protected:
   1.703 +    jsbytecode *lastPC_;
   1.704 +
   1.705 +    LInstruction *instruction() {
   1.706 +        return ins_;
   1.707 +    }
   1.708 +
   1.709 +  public:
   1.710 +    void setInstruction(LInstruction *ins) {
   1.711 +        ins_ = ins;
   1.712 +        if (ins->mirRaw())
   1.713 +            lastPC_ = ins->mirRaw()->trackedPc();
   1.714 +    }
   1.715 +
   1.716 +    LInstructionVisitor()
   1.717 +      : ins_(nullptr),
   1.718 +        lastPC_(nullptr)
   1.719 +    {}
   1.720 +
   1.721 +  public:
   1.722 +#define VISIT_INS(op) virtual bool visit##op(L##op *) { MOZ_ASSUME_UNREACHABLE("NYI: " #op); }
   1.723 +    LIR_OPCODE_LIST(VISIT_INS)
   1.724 +#undef VISIT_INS
   1.725 +};
   1.726 +
   1.727 +typedef InlineList<LInstruction>::iterator LInstructionIterator;
   1.728 +typedef InlineList<LInstruction>::reverse_iterator LInstructionReverseIterator;
   1.729 +
   1.730 +class LPhi;
   1.731 +class LMoveGroup;
   1.732 +class LBlock : public TempObject
   1.733 +{
   1.734 +    MBasicBlock *block_;
   1.735 +    Vector<LPhi *, 4, IonAllocPolicy> phis_;
   1.736 +    InlineList<LInstruction> instructions_;
   1.737 +    LMoveGroup *entryMoveGroup_;
   1.738 +    LMoveGroup *exitMoveGroup_;
   1.739 +    Label label_;
   1.740 +
   1.741 +    LBlock(TempAllocator &alloc, MBasicBlock *block)
   1.742 +      : block_(block),
   1.743 +        phis_(alloc),
   1.744 +        entryMoveGroup_(nullptr),
   1.745 +        exitMoveGroup_(nullptr)
   1.746 +    { }
   1.747 +
   1.748 +  public:
   1.749 +    static LBlock *New(TempAllocator &alloc, MBasicBlock *from) {
   1.750 +        return new(alloc) LBlock(alloc, from);
   1.751 +    }
   1.752 +    void add(LInstruction *ins) {
   1.753 +        instructions_.pushBack(ins);
   1.754 +    }
   1.755 +    bool addPhi(LPhi *phi) {
   1.756 +        return phis_.append(phi);
   1.757 +    }
   1.758 +    size_t numPhis() const {
   1.759 +        return phis_.length();
   1.760 +    }
   1.761 +    LPhi *getPhi(size_t index) const {
   1.762 +        return phis_[index];
   1.763 +    }
   1.764 +    void removePhi(size_t index) {
   1.765 +        phis_.erase(&phis_[index]);
   1.766 +    }
   1.767 +    void clearPhis() {
   1.768 +        phis_.clear();
   1.769 +    }
   1.770 +    MBasicBlock *mir() const {
   1.771 +        return block_;
   1.772 +    }
   1.773 +    LInstructionIterator begin() {
   1.774 +        return instructions_.begin();
   1.775 +    }
   1.776 +    LInstructionIterator begin(LInstruction *at) {
   1.777 +        return instructions_.begin(at);
   1.778 +    }
   1.779 +    LInstructionIterator end() {
   1.780 +        return instructions_.end();
   1.781 +    }
   1.782 +    LInstructionReverseIterator rbegin() {
   1.783 +        return instructions_.rbegin();
   1.784 +    }
   1.785 +    LInstructionReverseIterator rbegin(LInstruction *at) {
   1.786 +        return instructions_.rbegin(at);
   1.787 +    }
   1.788 +    LInstructionReverseIterator rend() {
   1.789 +        return instructions_.rend();
   1.790 +    }
   1.791 +    InlineList<LInstruction> &instructions() {
   1.792 +        return instructions_;
   1.793 +    }
   1.794 +    void insertAfter(LInstruction *at, LInstruction *ins) {
   1.795 +        instructions_.insertAfter(at, ins);
   1.796 +    }
   1.797 +    void insertBefore(LInstruction *at, LInstruction *ins) {
   1.798 +        JS_ASSERT(!at->isLabel());
   1.799 +        instructions_.insertBefore(at, ins);
   1.800 +    }
   1.801 +    uint32_t firstId();
   1.802 +    uint32_t lastId();
   1.803 +    Label *label() {
   1.804 +        return &label_;
   1.805 +    }
   1.806 +    LMoveGroup *getEntryMoveGroup(TempAllocator &alloc);
   1.807 +    LMoveGroup *getExitMoveGroup(TempAllocator &alloc);
   1.808 +};
   1.809 +
   1.810 +template <size_t Defs, size_t Operands, size_t Temps>
   1.811 +class LInstructionHelper : public LInstruction
   1.812 +{
   1.813 +    mozilla::Array<LDefinition, Defs> defs_;
   1.814 +    mozilla::Array<LAllocation, Operands> operands_;
   1.815 +    mozilla::Array<LDefinition, Temps> temps_;
   1.816 +
   1.817 +  public:
   1.818 +    size_t numDefs() const MOZ_FINAL MOZ_OVERRIDE {
   1.819 +        return Defs;
   1.820 +    }
   1.821 +    LDefinition *getDef(size_t index) MOZ_FINAL MOZ_OVERRIDE {
   1.822 +        return &defs_[index];
   1.823 +    }
   1.824 +    size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE {
   1.825 +        return Operands;
   1.826 +    }
   1.827 +    LAllocation *getOperand(size_t index) MOZ_FINAL MOZ_OVERRIDE {
   1.828 +        return &operands_[index];
   1.829 +    }
   1.830 +    size_t numTemps() const MOZ_FINAL MOZ_OVERRIDE {
   1.831 +        return Temps;
   1.832 +    }
   1.833 +    LDefinition *getTemp(size_t index) MOZ_FINAL MOZ_OVERRIDE {
   1.834 +        return &temps_[index];
   1.835 +    }
   1.836 +
   1.837 +    void setDef(size_t index, const LDefinition &def) MOZ_FINAL MOZ_OVERRIDE {
   1.838 +        defs_[index] = def;
   1.839 +    }
   1.840 +    void setOperand(size_t index, const LAllocation &a) MOZ_FINAL MOZ_OVERRIDE {
   1.841 +        operands_[index] = a;
   1.842 +    }
   1.843 +    void setTemp(size_t index, const LDefinition &a) MOZ_FINAL MOZ_OVERRIDE {
   1.844 +        temps_[index] = a;
   1.845 +    }
   1.846 +
   1.847 +    size_t numSuccessors() const {
   1.848 +        return 0;
   1.849 +    }
   1.850 +    MBasicBlock *getSuccessor(size_t i) const {
   1.851 +        JS_ASSERT(false);
   1.852 +        return nullptr;
   1.853 +    }
   1.854 +    void setSuccessor(size_t i, MBasicBlock *successor) {
   1.855 +        JS_ASSERT(false);
   1.856 +    }
   1.857 +
   1.858 +    // Default accessors, assuming a single input and output, respectively.
   1.859 +    const LAllocation *input() {
   1.860 +        JS_ASSERT(numOperands() == 1);
   1.861 +        return getOperand(0);
   1.862 +    }
   1.863 +    const LDefinition *output() {
   1.864 +        JS_ASSERT(numDefs() == 1);
   1.865 +        return getDef(0);
   1.866 +    }
   1.867 +
   1.868 +    virtual void printInfo(FILE *fp) {
   1.869 +        printOperands(fp);
   1.870 +    }
   1.871 +};
   1.872 +
   1.873 +template <size_t Defs, size_t Operands, size_t Temps>
   1.874 +class LCallInstructionHelper : public LInstructionHelper<Defs, Operands, Temps>
   1.875 +{
   1.876 +  public:
   1.877 +    virtual bool isCall() const {
   1.878 +        return true;
   1.879 +    }
   1.880 +};
   1.881 +
   1.882 +class LRecoverInfo : public TempObject
   1.883 +{
   1.884 +  public:
   1.885 +    typedef Vector<MResumePoint *, 2, IonAllocPolicy> Instructions;
   1.886 +
   1.887 +  private:
   1.888 +    // List of instructions needed to recover the stack frames.
   1.889 +    // Outer frames are stored before inner frames.
   1.890 +    Instructions instructions_;
   1.891 +
   1.892 +    // Cached offset where this resume point is encoded.
   1.893 +    RecoverOffset recoverOffset_;
   1.894 +
   1.895 +    LRecoverInfo(TempAllocator &alloc);
   1.896 +    bool init(MResumePoint *mir);
   1.897 +
   1.898 +  public:
   1.899 +    static LRecoverInfo *New(MIRGenerator *gen, MResumePoint *mir);
   1.900 +
   1.901 +    // Resume point of the inner most function.
   1.902 +    MResumePoint *mir() const {
   1.903 +        return instructions_.back();
   1.904 +    }
   1.905 +    RecoverOffset recoverOffset() const {
   1.906 +        return recoverOffset_;
   1.907 +    }
   1.908 +    void setRecoverOffset(RecoverOffset offset) {
   1.909 +        JS_ASSERT(recoverOffset_ == INVALID_RECOVER_OFFSET);
   1.910 +        recoverOffset_ = offset;
   1.911 +    }
   1.912 +
   1.913 +    MResumePoint **begin() {
   1.914 +        return instructions_.begin();
   1.915 +    }
   1.916 +    MResumePoint **end() {
   1.917 +        return instructions_.end();
   1.918 +    }
   1.919 +};
   1.920 +
   1.921 +// An LSnapshot is the reflection of an MResumePoint in LIR. Unlike MResumePoints,
   1.922 +// they cannot be shared, as they are filled in by the register allocator in
   1.923 +// order to capture the precise low-level stack state in between an
   1.924 +// instruction's input and output. During code generation, LSnapshots are
   1.925 +// compressed and saved in the compiled script.
   1.926 +class LSnapshot : public TempObject
   1.927 +{
   1.928 +  private:
   1.929 +    uint32_t numSlots_;
   1.930 +    LAllocation *slots_;
   1.931 +    LRecoverInfo *recoverInfo_;
   1.932 +    SnapshotOffset snapshotOffset_;
   1.933 +    BailoutId bailoutId_;
   1.934 +    BailoutKind bailoutKind_;
   1.935 +
   1.936 +    LSnapshot(LRecoverInfo *recover, BailoutKind kind);
   1.937 +    bool init(MIRGenerator *gen);
   1.938 +
   1.939 +  public:
   1.940 +    static LSnapshot *New(MIRGenerator *gen, LRecoverInfo *recover, BailoutKind kind);
   1.941 +
   1.942 +    size_t numEntries() const {
   1.943 +        return numSlots_;
   1.944 +    }
   1.945 +    size_t numSlots() const {
   1.946 +        return numSlots_ / BOX_PIECES;
   1.947 +    }
   1.948 +    LAllocation *payloadOfSlot(size_t i) {
   1.949 +        JS_ASSERT(i < numSlots());
   1.950 +        size_t entryIndex = (i * BOX_PIECES) + (BOX_PIECES - 1);
   1.951 +        return getEntry(entryIndex);
   1.952 +    }
   1.953 +#ifdef JS_NUNBOX32
   1.954 +    LAllocation *typeOfSlot(size_t i) {
   1.955 +        JS_ASSERT(i < numSlots());
   1.956 +        size_t entryIndex = (i * BOX_PIECES) + (BOX_PIECES - 2);
   1.957 +        return getEntry(entryIndex);
   1.958 +    }
   1.959 +#endif
   1.960 +    LAllocation *getEntry(size_t i) {
   1.961 +        JS_ASSERT(i < numSlots_);
   1.962 +        return &slots_[i];
   1.963 +    }
   1.964 +    void setEntry(size_t i, const LAllocation &alloc) {
   1.965 +        JS_ASSERT(i < numSlots_);
   1.966 +        slots_[i] = alloc;
   1.967 +    }
   1.968 +    LRecoverInfo *recoverInfo() const {
   1.969 +        return recoverInfo_;
   1.970 +    }
   1.971 +    MResumePoint *mir() const {
   1.972 +        return recoverInfo()->mir();
   1.973 +    }
   1.974 +    SnapshotOffset snapshotOffset() const {
   1.975 +        return snapshotOffset_;
   1.976 +    }
   1.977 +    BailoutId bailoutId() const {
   1.978 +        return bailoutId_;
   1.979 +    }
   1.980 +    void setSnapshotOffset(SnapshotOffset offset) {
   1.981 +        JS_ASSERT(snapshotOffset_ == INVALID_SNAPSHOT_OFFSET);
   1.982 +        snapshotOffset_ = offset;
   1.983 +    }
   1.984 +    void setBailoutId(BailoutId id) {
   1.985 +        JS_ASSERT(bailoutId_ == INVALID_BAILOUT_ID);
   1.986 +        bailoutId_ = id;
   1.987 +    }
   1.988 +    BailoutKind bailoutKind() const {
   1.989 +        return bailoutKind_;
   1.990 +    }
   1.991 +    void setBailoutKind(BailoutKind kind) {
   1.992 +        bailoutKind_ = kind;
   1.993 +    }
   1.994 +    void rewriteRecoveredInput(LUse input);
   1.995 +};
   1.996 +
   1.997 +struct SafepointNunboxEntry {
   1.998 +    LAllocation type;
   1.999 +    LAllocation payload;
  1.1000 +
  1.1001 +    SafepointNunboxEntry() { }
  1.1002 +    SafepointNunboxEntry(LAllocation type, LAllocation payload)
  1.1003 +      : type(type), payload(payload)
  1.1004 +    { }
  1.1005 +};
  1.1006 +
  1.1007 +class LSafepoint : public TempObject
  1.1008 +{
  1.1009 +    typedef SafepointNunboxEntry NunboxEntry;
  1.1010 +
  1.1011 +  public:
  1.1012 +    typedef Vector<uint32_t, 0, IonAllocPolicy> SlotList;
  1.1013 +    typedef Vector<NunboxEntry, 0, IonAllocPolicy> NunboxList;
  1.1014 +
  1.1015 +  private:
  1.1016 +    // The information in a safepoint describes the registers and gc related
  1.1017 +    // values that are live at the start of the associated instruction.
  1.1018 +
  1.1019 +    // The set of registers which are live at an OOL call made within the
  1.1020 +    // instruction. This includes any registers for inputs which are not
  1.1021 +    // use-at-start, any registers for temps, and any registers live after the
  1.1022 +    // call except outputs of the instruction.
  1.1023 +    //
  1.1024 +    // For call instructions, the live regs are empty. Call instructions may
  1.1025 +    // have register inputs or temporaries, which will *not* be in the live
  1.1026 +    // registers: if passed to the call, the values passed will be marked via
  1.1027 +    // MarkJitExitFrame, and no registers can be live after the instruction
  1.1028 +    // except its outputs.
  1.1029 +    RegisterSet liveRegs_;
  1.1030 +
  1.1031 +    // The subset of liveRegs which contains gcthing pointers.
  1.1032 +    GeneralRegisterSet gcRegs_;
  1.1033 +
  1.1034 +#ifdef CHECK_OSIPOINT_REGISTERS
  1.1035 +    // Clobbered regs of the current instruction. This set is never written to
  1.1036 +    // the safepoint; it's only used by assertions during compilation.
  1.1037 +    RegisterSet clobberedRegs_;
  1.1038 +#endif
  1.1039 +
  1.1040 +    // Offset to a position in the safepoint stream, or
  1.1041 +    // INVALID_SAFEPOINT_OFFSET.
  1.1042 +    uint32_t safepointOffset_;
  1.1043 +
  1.1044 +    // Assembler buffer displacement to OSI point's call location.
  1.1045 +    uint32_t osiCallPointOffset_;
  1.1046 +
  1.1047 +    // List of stack slots which have gcthing pointers.
  1.1048 +    SlotList gcSlots_;
  1.1049 +
  1.1050 +    // List of stack slots which have Values.
  1.1051 +    SlotList valueSlots_;
  1.1052 +
  1.1053 +#ifdef JS_NUNBOX32
  1.1054 +    // List of registers (in liveRegs) and stack slots which contain pieces of Values.
  1.1055 +    NunboxList nunboxParts_;
  1.1056 +
  1.1057 +    // Number of nunboxParts which are not completely filled in.
  1.1058 +    uint32_t partialNunboxes_;
  1.1059 +#elif JS_PUNBOX64
  1.1060 +    // The subset of liveRegs which have Values.
  1.1061 +    GeneralRegisterSet valueRegs_;
  1.1062 +#endif
  1.1063 +
  1.1064 +    // The subset of liveRegs which contains pointers to slots/elements.
  1.1065 +    GeneralRegisterSet slotsOrElementsRegs_;
  1.1066 +
  1.1067 +    // List of stack slots which have slots/elements pointers.
  1.1068 +    SlotList slotsOrElementsSlots_;
  1.1069 +
  1.1070 +  public:
  1.1071 +    void assertInvariants() {
  1.1072 +        // Every register in valueRegs and gcRegs should also be in liveRegs.
  1.1073 +#ifndef JS_NUNBOX32
  1.1074 +        JS_ASSERT((valueRegs().bits() & ~liveRegs().gprs().bits()) == 0);
  1.1075 +#endif
  1.1076 +        JS_ASSERT((gcRegs().bits() & ~liveRegs().gprs().bits()) == 0);
  1.1077 +    }
  1.1078 +
  1.1079 +    LSafepoint(TempAllocator &alloc)
  1.1080 +      : safepointOffset_(INVALID_SAFEPOINT_OFFSET)
  1.1081 +      , osiCallPointOffset_(0)
  1.1082 +      , gcSlots_(alloc)
  1.1083 +      , valueSlots_(alloc)
  1.1084 +#ifdef JS_NUNBOX32
  1.1085 +      , nunboxParts_(alloc)
  1.1086 +      , partialNunboxes_(0)
  1.1087 +#endif
  1.1088 +      , slotsOrElementsSlots_(alloc)
  1.1089 +    {
  1.1090 +      assertInvariants();
  1.1091 +    }
  1.1092 +    void addLiveRegister(AnyRegister reg) {
  1.1093 +        liveRegs_.addUnchecked(reg);
  1.1094 +        assertInvariants();
  1.1095 +    }
  1.1096 +    const RegisterSet &liveRegs() const {
  1.1097 +        return liveRegs_;
  1.1098 +    }
  1.1099 +#ifdef CHECK_OSIPOINT_REGISTERS
  1.1100 +    void addClobberedRegister(AnyRegister reg) {
  1.1101 +        clobberedRegs_.addUnchecked(reg);
  1.1102 +        assertInvariants();
  1.1103 +    }
  1.1104 +    const RegisterSet &clobberedRegs() const {
  1.1105 +        return clobberedRegs_;
  1.1106 +    }
  1.1107 +#endif
  1.1108 +    void addGcRegister(Register reg) {
  1.1109 +        gcRegs_.addUnchecked(reg);
  1.1110 +        assertInvariants();
  1.1111 +    }
  1.1112 +    GeneralRegisterSet gcRegs() const {
  1.1113 +        return gcRegs_;
  1.1114 +    }
  1.1115 +    bool addGcSlot(uint32_t slot) {
  1.1116 +        bool result = gcSlots_.append(slot);
  1.1117 +        if (result)
  1.1118 +            assertInvariants();
  1.1119 +        return result;
  1.1120 +    }
  1.1121 +    SlotList &gcSlots() {
  1.1122 +        return gcSlots_;
  1.1123 +    }
  1.1124 +
  1.1125 +    SlotList &slotsOrElementsSlots() {
  1.1126 +        return slotsOrElementsSlots_;
  1.1127 +    }
  1.1128 +    GeneralRegisterSet slotsOrElementsRegs() const {
  1.1129 +        return slotsOrElementsRegs_;
  1.1130 +    }
  1.1131 +    void addSlotsOrElementsRegister(Register reg) {
  1.1132 +        slotsOrElementsRegs_.addUnchecked(reg);
  1.1133 +        assertInvariants();
  1.1134 +    }
  1.1135 +    bool addSlotsOrElementsSlot(uint32_t slot) {
  1.1136 +        bool result = slotsOrElementsSlots_.append(slot);
  1.1137 +        if (result)
  1.1138 +            assertInvariants();
  1.1139 +        return result;
  1.1140 +    }
  1.1141 +    bool addSlotsOrElementsPointer(LAllocation alloc) {
  1.1142 +        if (alloc.isStackSlot())
  1.1143 +            return addSlotsOrElementsSlot(alloc.toStackSlot()->slot());
  1.1144 +        JS_ASSERT(alloc.isRegister());
  1.1145 +        addSlotsOrElementsRegister(alloc.toRegister().gpr());
  1.1146 +        assertInvariants();
  1.1147 +        return true;
  1.1148 +    }
  1.1149 +    bool hasSlotsOrElementsPointer(LAllocation alloc) const {
  1.1150 +        if (alloc.isRegister())
  1.1151 +            return slotsOrElementsRegs().has(alloc.toRegister().gpr());
  1.1152 +        if (alloc.isStackSlot()) {
  1.1153 +            for (size_t i = 0; i < slotsOrElementsSlots_.length(); i++) {
  1.1154 +                if (slotsOrElementsSlots_[i] == alloc.toStackSlot()->slot())
  1.1155 +                    return true;
  1.1156 +            }
  1.1157 +            return false;
  1.1158 +        }
  1.1159 +        return false;
  1.1160 +    }
  1.1161 +
  1.1162 +    bool addGcPointer(LAllocation alloc) {
  1.1163 +        if (alloc.isStackSlot())
  1.1164 +            return addGcSlot(alloc.toStackSlot()->slot());
  1.1165 +        if (alloc.isRegister())
  1.1166 +            addGcRegister(alloc.toRegister().gpr());
  1.1167 +        assertInvariants();
  1.1168 +        return true;
  1.1169 +    }
  1.1170 +
  1.1171 +    bool hasGcPointer(LAllocation alloc) const {
  1.1172 +        if (alloc.isRegister())
  1.1173 +            return gcRegs().has(alloc.toRegister().gpr());
  1.1174 +        if (alloc.isStackSlot()) {
  1.1175 +            for (size_t i = 0; i < gcSlots_.length(); i++) {
  1.1176 +                if (gcSlots_[i] == alloc.toStackSlot()->slot())
  1.1177 +                    return true;
  1.1178 +            }
  1.1179 +            return false;
  1.1180 +        }
  1.1181 +        JS_ASSERT(alloc.isArgument());
  1.1182 +        return true;
  1.1183 +    }
  1.1184 +
  1.1185 +    bool addValueSlot(uint32_t slot) {
  1.1186 +        bool result = valueSlots_.append(slot);
  1.1187 +        if (result)
  1.1188 +            assertInvariants();
  1.1189 +        return result;
  1.1190 +    }
  1.1191 +    SlotList &valueSlots() {
  1.1192 +        return valueSlots_;
  1.1193 +    }
  1.1194 +
  1.1195 +    bool hasValueSlot(uint32_t slot) const {
  1.1196 +        for (size_t i = 0; i < valueSlots_.length(); i++) {
  1.1197 +            if (valueSlots_[i] == slot)
  1.1198 +                return true;
  1.1199 +        }
  1.1200 +        return false;
  1.1201 +    }
  1.1202 +
  1.1203 +#ifdef JS_NUNBOX32
  1.1204 +
  1.1205 +    bool addNunboxParts(LAllocation type, LAllocation payload) {
  1.1206 +        bool result = nunboxParts_.append(NunboxEntry(type, payload));
  1.1207 +        if (result)
  1.1208 +            assertInvariants();
  1.1209 +        return result;
  1.1210 +    }
  1.1211 +
  1.1212 +    bool addNunboxType(uint32_t typeVreg, LAllocation type) {
  1.1213 +        for (size_t i = 0; i < nunboxParts_.length(); i++) {
  1.1214 +            if (nunboxParts_[i].type == type)
  1.1215 +                return true;
  1.1216 +            if (nunboxParts_[i].type == LUse(typeVreg, LUse::ANY)) {
  1.1217 +                nunboxParts_[i].type = type;
  1.1218 +                partialNunboxes_--;
  1.1219 +                return true;
  1.1220 +            }
  1.1221 +        }
  1.1222 +        partialNunboxes_++;
  1.1223 +
  1.1224 +        // vregs for nunbox pairs are adjacent, with the type coming first.
  1.1225 +        uint32_t payloadVreg = typeVreg + 1;
  1.1226 +        bool result = nunboxParts_.append(NunboxEntry(type, LUse(payloadVreg, LUse::ANY)));
  1.1227 +        if (result)
  1.1228 +            assertInvariants();
  1.1229 +        return result;
  1.1230 +    }
  1.1231 +
  1.1232 +    bool hasNunboxType(LAllocation type) const {
  1.1233 +        if (type.isArgument())
  1.1234 +            return true;
  1.1235 +        if (type.isStackSlot() && hasValueSlot(type.toStackSlot()->slot() + 1))
  1.1236 +            return true;
  1.1237 +        for (size_t i = 0; i < nunboxParts_.length(); i++) {
  1.1238 +            if (nunboxParts_[i].type == type)
  1.1239 +                return true;
  1.1240 +        }
  1.1241 +        return false;
  1.1242 +    }
  1.1243 +
  1.1244 +    bool addNunboxPayload(uint32_t payloadVreg, LAllocation payload) {
  1.1245 +        for (size_t i = 0; i < nunboxParts_.length(); i++) {
  1.1246 +            if (nunboxParts_[i].payload == payload)
  1.1247 +                return true;
  1.1248 +            if (nunboxParts_[i].payload == LUse(payloadVreg, LUse::ANY)) {
  1.1249 +                partialNunboxes_--;
  1.1250 +                nunboxParts_[i].payload = payload;
  1.1251 +                return true;
  1.1252 +            }
  1.1253 +        }
  1.1254 +        partialNunboxes_++;
  1.1255 +
  1.1256 +        // vregs for nunbox pairs are adjacent, with the type coming first.
  1.1257 +        uint32_t typeVreg = payloadVreg - 1;
  1.1258 +        bool result = nunboxParts_.append(NunboxEntry(LUse(typeVreg, LUse::ANY), payload));
  1.1259 +        if (result)
  1.1260 +            assertInvariants();
  1.1261 +        return result;
  1.1262 +    }
  1.1263 +
  1.1264 +    bool hasNunboxPayload(LAllocation payload) const {
  1.1265 +        if (payload.isArgument())
  1.1266 +            return true;
  1.1267 +        if (payload.isStackSlot() && hasValueSlot(payload.toStackSlot()->slot()))
  1.1268 +            return true;
  1.1269 +        for (size_t i = 0; i < nunboxParts_.length(); i++) {
  1.1270 +            if (nunboxParts_[i].payload == payload)
  1.1271 +                return true;
  1.1272 +        }
  1.1273 +        return false;
  1.1274 +    }
  1.1275 +
  1.1276 +    NunboxList &nunboxParts() {
  1.1277 +        return nunboxParts_;
  1.1278 +    }
  1.1279 +
  1.1280 +    uint32_t partialNunboxes() {
  1.1281 +        return partialNunboxes_;
  1.1282 +    }
  1.1283 +
  1.1284 +#elif JS_PUNBOX64
  1.1285 +
  1.1286 +    void addValueRegister(Register reg) {
  1.1287 +        valueRegs_.add(reg);
  1.1288 +        assertInvariants();
  1.1289 +    }
  1.1290 +    GeneralRegisterSet valueRegs() const {
  1.1291 +        return valueRegs_;
  1.1292 +    }
  1.1293 +
  1.1294 +    bool addBoxedValue(LAllocation alloc) {
  1.1295 +        if (alloc.isRegister()) {
  1.1296 +            Register reg = alloc.toRegister().gpr();
  1.1297 +            if (!valueRegs().has(reg))
  1.1298 +                addValueRegister(reg);
  1.1299 +            return true;
  1.1300 +        }
  1.1301 +        if (alloc.isStackSlot()) {
  1.1302 +            uint32_t slot = alloc.toStackSlot()->slot();
  1.1303 +            for (size_t i = 0; i < valueSlots().length(); i++) {
  1.1304 +                if (valueSlots()[i] == slot)
  1.1305 +                    return true;
  1.1306 +            }
  1.1307 +            return addValueSlot(slot);
  1.1308 +        }
  1.1309 +        JS_ASSERT(alloc.isArgument());
  1.1310 +        return true;
  1.1311 +    }
  1.1312 +
  1.1313 +    bool hasBoxedValue(LAllocation alloc) const {
  1.1314 +        if (alloc.isRegister())
  1.1315 +            return valueRegs().has(alloc.toRegister().gpr());
  1.1316 +        if (alloc.isStackSlot())
  1.1317 +            return hasValueSlot(alloc.toStackSlot()->slot());
  1.1318 +        JS_ASSERT(alloc.isArgument());
  1.1319 +        return true;
  1.1320 +    }
  1.1321 +
  1.1322 +#endif // JS_PUNBOX64
  1.1323 +
  1.1324 +    bool encoded() const {
  1.1325 +        return safepointOffset_ != INVALID_SAFEPOINT_OFFSET;
  1.1326 +    }
  1.1327 +    uint32_t offset() const {
  1.1328 +        JS_ASSERT(encoded());
  1.1329 +        return safepointOffset_;
  1.1330 +    }
  1.1331 +    void setOffset(uint32_t offset) {
  1.1332 +        safepointOffset_ = offset;
  1.1333 +    }
  1.1334 +    uint32_t osiReturnPointOffset() const {
  1.1335 +        // In general, pointer arithmetic on code is bad, but in this case,
  1.1336 +        // getting the return address from a call instruction, stepping over pools
  1.1337 +        // would be wrong.
  1.1338 +        return osiCallPointOffset_ + Assembler::patchWrite_NearCallSize();
  1.1339 +    }
  1.1340 +    uint32_t osiCallPointOffset() const {
  1.1341 +        return osiCallPointOffset_;
  1.1342 +    }
  1.1343 +    void setOsiCallPointOffset(uint32_t osiCallPointOffset) {
  1.1344 +        JS_ASSERT(!osiCallPointOffset_);
  1.1345 +        osiCallPointOffset_ = osiCallPointOffset;
  1.1346 +    }
  1.1347 +    void fixupOffset(MacroAssembler *masm) {
  1.1348 +        osiCallPointOffset_ = masm->actualOffset(osiCallPointOffset_);
  1.1349 +    }
  1.1350 +};
  1.1351 +
  1.1352 +class LInstruction::InputIterator
  1.1353 +{
  1.1354 +  private:
  1.1355 +    LInstruction &ins_;
  1.1356 +    size_t idx_;
  1.1357 +    bool snapshot_;
  1.1358 +
  1.1359 +    void handleOperandsEnd() {
  1.1360 +        // Iterate on the snapshot when iteration over all operands is done.
  1.1361 +        if (!snapshot_ && idx_ == ins_.numOperands() && ins_.snapshot()) {
  1.1362 +            idx_ = 0;
  1.1363 +            snapshot_ = true;
  1.1364 +        }
  1.1365 +    }
  1.1366 +
  1.1367 +public:
  1.1368 +    InputIterator(LInstruction &ins) :
  1.1369 +      ins_(ins),
  1.1370 +      idx_(0),
  1.1371 +      snapshot_(false)
  1.1372 +    {
  1.1373 +        handleOperandsEnd();
  1.1374 +    }
  1.1375 +
  1.1376 +    bool more() const {
  1.1377 +        if (snapshot_)
  1.1378 +            return idx_ < ins_.snapshot()->numEntries();
  1.1379 +        if (idx_ < ins_.numOperands())
  1.1380 +            return true;
  1.1381 +        if (ins_.snapshot() && ins_.snapshot()->numEntries())
  1.1382 +            return true;
  1.1383 +        return false;
  1.1384 +    }
  1.1385 +
  1.1386 +    bool isSnapshotInput() const {
  1.1387 +        return snapshot_;
  1.1388 +    }
  1.1389 +
  1.1390 +    void next() {
  1.1391 +        JS_ASSERT(more());
  1.1392 +        idx_++;
  1.1393 +        handleOperandsEnd();
  1.1394 +    }
  1.1395 +
  1.1396 +    void replace(const LAllocation &alloc) {
  1.1397 +        if (snapshot_)
  1.1398 +            ins_.snapshot()->setEntry(idx_, alloc);
  1.1399 +        else
  1.1400 +            ins_.setOperand(idx_, alloc);
  1.1401 +    }
  1.1402 +
  1.1403 +    LAllocation *operator *() const {
  1.1404 +        if (snapshot_)
  1.1405 +            return ins_.snapshot()->getEntry(idx_);
  1.1406 +        return ins_.getOperand(idx_);
  1.1407 +    }
  1.1408 +
  1.1409 +    LAllocation *operator ->() const {
  1.1410 +        return **this;
  1.1411 +    }
  1.1412 +};
  1.1413 +
  1.1414 +class LIRGraph
  1.1415 +{
  1.1416 +    struct ValueHasher
  1.1417 +    {
  1.1418 +        typedef Value Lookup;
  1.1419 +        static HashNumber hash(const Value &v) {
  1.1420 +            return HashNumber(v.asRawBits());
  1.1421 +        }
  1.1422 +        static bool match(const Value &lhs, const Value &rhs) {
  1.1423 +            return lhs == rhs;
  1.1424 +        }
  1.1425 +
  1.1426 +#ifdef DEBUG
  1.1427 +        bool canOptimizeOutIfUnused();
  1.1428 +#endif
  1.1429 +    };
  1.1430 +
  1.1431 +
  1.1432 +    Vector<LBlock *, 16, IonAllocPolicy> blocks_;
  1.1433 +    Vector<Value, 0, IonAllocPolicy> constantPool_;
  1.1434 +    typedef HashMap<Value, uint32_t, ValueHasher, IonAllocPolicy> ConstantPoolMap;
  1.1435 +    ConstantPoolMap constantPoolMap_;
  1.1436 +    Vector<LInstruction *, 0, IonAllocPolicy> safepoints_;
  1.1437 +    Vector<LInstruction *, 0, IonAllocPolicy> nonCallSafepoints_;
  1.1438 +    uint32_t numVirtualRegisters_;
  1.1439 +    uint32_t numInstructions_;
  1.1440 +
  1.1441 +    // Number of stack slots needed for local spills.
  1.1442 +    uint32_t localSlotCount_;
  1.1443 +    // Number of stack slots needed for argument construction for calls.
  1.1444 +    uint32_t argumentSlotCount_;
  1.1445 +
  1.1446 +    // Snapshot taken before any LIR has been lowered.
  1.1447 +    LSnapshot *entrySnapshot_;
  1.1448 +
  1.1449 +    // LBlock containing LOsrEntry, or nullptr.
  1.1450 +    LBlock *osrBlock_;
  1.1451 +
  1.1452 +    MIRGraph &mir_;
  1.1453 +
  1.1454 +  public:
  1.1455 +    LIRGraph(MIRGraph *mir);
  1.1456 +
  1.1457 +    bool init() {
  1.1458 +        return constantPoolMap_.init();
  1.1459 +    }
  1.1460 +    MIRGraph &mir() const {
  1.1461 +        return mir_;
  1.1462 +    }
  1.1463 +    size_t numBlocks() const {
  1.1464 +        return blocks_.length();
  1.1465 +    }
  1.1466 +    LBlock *getBlock(size_t i) const {
  1.1467 +        return blocks_[i];
  1.1468 +    }
  1.1469 +    uint32_t numBlockIds() const {
  1.1470 +        return mir_.numBlockIds();
  1.1471 +    }
  1.1472 +    bool addBlock(LBlock *block) {
  1.1473 +        return blocks_.append(block);
  1.1474 +    }
  1.1475 +    uint32_t getVirtualRegister() {
  1.1476 +        numVirtualRegisters_ += VREG_INCREMENT;
  1.1477 +        return numVirtualRegisters_;
  1.1478 +    }
  1.1479 +    uint32_t numVirtualRegisters() const {
  1.1480 +        // Virtual registers are 1-based, not 0-based, so add one as a
  1.1481 +        // convenience for 0-based arrays.
  1.1482 +        return numVirtualRegisters_ + 1;
  1.1483 +    }
  1.1484 +    uint32_t getInstructionId() {
  1.1485 +        return numInstructions_++;
  1.1486 +    }
  1.1487 +    uint32_t numInstructions() const {
  1.1488 +        return numInstructions_;
  1.1489 +    }
  1.1490 +    void setLocalSlotCount(uint32_t localSlotCount) {
  1.1491 +        localSlotCount_ = localSlotCount;
  1.1492 +    }
  1.1493 +    uint32_t localSlotCount() const {
  1.1494 +        return localSlotCount_;
  1.1495 +    }
  1.1496 +    // Return the localSlotCount() value rounded up so that it satisfies the
  1.1497 +    // platform stack alignment requirement, and so that it's a multiple of
  1.1498 +    // the number of slots per Value.
  1.1499 +    uint32_t paddedLocalSlotCount() const {
  1.1500 +        // Round to StackAlignment, but also round to at least sizeof(Value) in
  1.1501 +        // case that's greater, because StackOffsetOfPassedArg rounds argument
  1.1502 +        // slots to 8-byte boundaries.
  1.1503 +        size_t Alignment = Max(sizeof(StackAlignment), sizeof(Value));
  1.1504 +        return AlignBytes(localSlotCount(), Alignment);
  1.1505 +    }
  1.1506 +    size_t paddedLocalSlotsSize() const {
  1.1507 +        return paddedLocalSlotCount();
  1.1508 +    }
  1.1509 +    void setArgumentSlotCount(uint32_t argumentSlotCount) {
  1.1510 +        argumentSlotCount_ = argumentSlotCount;
  1.1511 +    }
  1.1512 +    uint32_t argumentSlotCount() const {
  1.1513 +        return argumentSlotCount_;
  1.1514 +    }
  1.1515 +    size_t argumentsSize() const {
  1.1516 +        return argumentSlotCount() * sizeof(Value);
  1.1517 +    }
  1.1518 +    uint32_t totalSlotCount() const {
  1.1519 +        return paddedLocalSlotCount() + argumentsSize();
  1.1520 +    }
  1.1521 +    bool addConstantToPool(const Value &v, uint32_t *index);
  1.1522 +    size_t numConstants() const {
  1.1523 +        return constantPool_.length();
  1.1524 +    }
  1.1525 +    Value *constantPool() {
  1.1526 +        return &constantPool_[0];
  1.1527 +    }
  1.1528 +    void setEntrySnapshot(LSnapshot *snapshot) {
  1.1529 +        JS_ASSERT(!entrySnapshot_);
  1.1530 +        JS_ASSERT(snapshot->bailoutKind() == Bailout_Normal);
  1.1531 +        snapshot->setBailoutKind(Bailout_ArgumentCheck);
  1.1532 +        entrySnapshot_ = snapshot;
  1.1533 +    }
  1.1534 +    LSnapshot *entrySnapshot() const {
  1.1535 +        JS_ASSERT(entrySnapshot_);
  1.1536 +        return entrySnapshot_;
  1.1537 +    }
  1.1538 +    void setOsrBlock(LBlock *block) {
  1.1539 +        JS_ASSERT(!osrBlock_);
  1.1540 +        osrBlock_ = block;
  1.1541 +    }
  1.1542 +    LBlock *osrBlock() const {
  1.1543 +        return osrBlock_;
  1.1544 +    }
  1.1545 +    bool noteNeedsSafepoint(LInstruction *ins);
  1.1546 +    size_t numNonCallSafepoints() const {
  1.1547 +        return nonCallSafepoints_.length();
  1.1548 +    }
  1.1549 +    LInstruction *getNonCallSafepoint(size_t i) const {
  1.1550 +        return nonCallSafepoints_[i];
  1.1551 +    }
  1.1552 +    size_t numSafepoints() const {
  1.1553 +        return safepoints_.length();
  1.1554 +    }
  1.1555 +    LInstruction *getSafepoint(size_t i) const {
  1.1556 +        return safepoints_[i];
  1.1557 +    }
  1.1558 +    void removeBlock(size_t i);
  1.1559 +};
  1.1560 +
  1.1561 +LAllocation::LAllocation(const AnyRegister &reg)
  1.1562 +{
  1.1563 +    if (reg.isFloat())
  1.1564 +        *this = LFloatReg(reg.fpu());
  1.1565 +    else
  1.1566 +        *this = LGeneralReg(reg.gpr());
  1.1567 +}
  1.1568 +
  1.1569 +AnyRegister
  1.1570 +LAllocation::toRegister() const
  1.1571 +{
  1.1572 +    JS_ASSERT(isRegister());
  1.1573 +    if (isFloatReg())
  1.1574 +        return AnyRegister(toFloatReg()->reg());
  1.1575 +    return AnyRegister(toGeneralReg()->reg());
  1.1576 +}
  1.1577 +
  1.1578 +} // namespace jit
  1.1579 +} // namespace js
  1.1580 +
  1.1581 +#define LIR_HEADER(opcode)                                                  \
  1.1582 +    Opcode op() const {                                                     \
  1.1583 +        return LInstruction::LOp_##opcode;                                  \
  1.1584 +    }                                                                       \
  1.1585 +    bool accept(LInstructionVisitor *visitor) {                             \
  1.1586 +        visitor->setInstruction(this);                                      \
  1.1587 +        return visitor->visit##opcode(this);                                \
  1.1588 +    }
  1.1589 +
  1.1590 +#include "jit/LIR-Common.h"
  1.1591 +#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
  1.1592 +# if defined(JS_CODEGEN_X86)
  1.1593 +#  include "jit/x86/LIR-x86.h"
  1.1594 +# elif defined(JS_CODEGEN_X64)
  1.1595 +#  include "jit/x64/LIR-x64.h"
  1.1596 +# endif
  1.1597 +# include "jit/shared/LIR-x86-shared.h"
  1.1598 +#elif defined(JS_CODEGEN_ARM)
  1.1599 +# include "jit/arm/LIR-arm.h"
  1.1600 +#elif defined(JS_CODEGEN_MIPS)
  1.1601 +# include "jit/mips/LIR-mips.h"
  1.1602 +#else
  1.1603 +# error "Unknown architecture!"
  1.1604 +#endif
  1.1605 +
  1.1606 +#undef LIR_HEADER
  1.1607 +
  1.1608 +namespace js {
  1.1609 +namespace jit {
  1.1610 +
  1.1611 +#define LIROP(name)                                                         \
  1.1612 +    L##name *LInstruction::to##name()                                       \
  1.1613 +    {                                                                       \
  1.1614 +        JS_ASSERT(is##name());                                              \
  1.1615 +        return static_cast<L##name *>(this);                                \
  1.1616 +    }
  1.1617 +    LIR_OPCODE_LIST(LIROP)
  1.1618 +#undef LIROP
  1.1619 +
  1.1620 +#define LALLOC_CAST(type)                                                   \
  1.1621 +    L##type *LAllocation::to##type() {                                      \
  1.1622 +        JS_ASSERT(is##type());                                              \
  1.1623 +        return static_cast<L##type *>(this);                                \
  1.1624 +    }
  1.1625 +#define LALLOC_CONST_CAST(type)                                             \
  1.1626 +    const L##type *LAllocation::to##type() const {                          \
  1.1627 +        JS_ASSERT(is##type());                                              \
  1.1628 +        return static_cast<const L##type *>(this);                          \
  1.1629 +    }
  1.1630 +
  1.1631 +LALLOC_CAST(Use)
  1.1632 +LALLOC_CONST_CAST(Use)
  1.1633 +LALLOC_CONST_CAST(GeneralReg)
  1.1634 +LALLOC_CONST_CAST(FloatReg)
  1.1635 +LALLOC_CONST_CAST(StackSlot)
  1.1636 +LALLOC_CONST_CAST(Argument)
  1.1637 +LALLOC_CONST_CAST(ConstantIndex)
  1.1638 +
  1.1639 +#undef LALLOC_CAST
  1.1640 +
  1.1641 +#ifdef JS_NUNBOX32
  1.1642 +static inline signed
  1.1643 +OffsetToOtherHalfOfNunbox(LDefinition::Type type)
  1.1644 +{
  1.1645 +    JS_ASSERT(type == LDefinition::TYPE || type == LDefinition::PAYLOAD);
  1.1646 +    signed offset = (type == LDefinition::TYPE)
  1.1647 +                    ? PAYLOAD_INDEX - TYPE_INDEX
  1.1648 +                    : TYPE_INDEX - PAYLOAD_INDEX;
  1.1649 +    return offset;
  1.1650 +}
  1.1651 +
  1.1652 +static inline void
  1.1653 +AssertTypesFormANunbox(LDefinition::Type type1, LDefinition::Type type2)
  1.1654 +{
  1.1655 +    JS_ASSERT((type1 == LDefinition::TYPE && type2 == LDefinition::PAYLOAD) ||
  1.1656 +              (type2 == LDefinition::TYPE && type1 == LDefinition::PAYLOAD));
  1.1657 +}
  1.1658 +
  1.1659 +static inline unsigned
  1.1660 +OffsetOfNunboxSlot(LDefinition::Type type)
  1.1661 +{
  1.1662 +    if (type == LDefinition::PAYLOAD)
  1.1663 +        return NUNBOX32_PAYLOAD_OFFSET;
  1.1664 +    return NUNBOX32_TYPE_OFFSET;
  1.1665 +}
  1.1666 +
  1.1667 +// Note that stack indexes for LStackSlot are modelled backwards, so a
  1.1668 +// double-sized slot starting at 2 has its next word at 1, *not* 3.
  1.1669 +static inline unsigned
  1.1670 +BaseOfNunboxSlot(LDefinition::Type type, unsigned slot)
  1.1671 +{
  1.1672 +    if (type == LDefinition::PAYLOAD)
  1.1673 +        return slot + NUNBOX32_PAYLOAD_OFFSET;
  1.1674 +    return slot + NUNBOX32_TYPE_OFFSET;
  1.1675 +}
  1.1676 +#endif
  1.1677 +
  1.1678 +} // namespace jit
  1.1679 +} // namespace js
  1.1680 +
  1.1681 +#endif /* jit_LIR_h */

mercurial