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 ®); 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 ®) 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 */