js/src/jit/LIR.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef jit_LIR_h
michael@0 8 #define jit_LIR_h
michael@0 9
michael@0 10 // This file declares the core data structures for LIR: storage allocations for
michael@0 11 // inputs and outputs, as well as the interface instructions must conform to.
michael@0 12
michael@0 13 #include "mozilla/Array.h"
michael@0 14
michael@0 15 #include "jit/Bailouts.h"
michael@0 16 #include "jit/InlineList.h"
michael@0 17 #include "jit/IonAllocPolicy.h"
michael@0 18 #include "jit/LOpcodes.h"
michael@0 19 #include "jit/MIR.h"
michael@0 20 #include "jit/MIRGraph.h"
michael@0 21 #include "jit/Registers.h"
michael@0 22 #include "jit/Safepoints.h"
michael@0 23
michael@0 24 namespace js {
michael@0 25 namespace jit {
michael@0 26
michael@0 27 class LUse;
michael@0 28 class LGeneralReg;
michael@0 29 class LFloatReg;
michael@0 30 class LStackSlot;
michael@0 31 class LArgument;
michael@0 32 class LConstantIndex;
michael@0 33 class MBasicBlock;
michael@0 34 class MTableSwitch;
michael@0 35 class MIRGenerator;
michael@0 36 class MSnapshot;
michael@0 37
michael@0 38 static const uint32_t VREG_INCREMENT = 1;
michael@0 39
michael@0 40 static const uint32_t THIS_FRAME_ARGSLOT = 0;
michael@0 41
michael@0 42 #if defined(JS_NUNBOX32)
michael@0 43 # define BOX_PIECES 2
michael@0 44 static const uint32_t VREG_TYPE_OFFSET = 0;
michael@0 45 static const uint32_t VREG_DATA_OFFSET = 1;
michael@0 46 static const uint32_t TYPE_INDEX = 0;
michael@0 47 static const uint32_t PAYLOAD_INDEX = 1;
michael@0 48 #elif defined(JS_PUNBOX64)
michael@0 49 # define BOX_PIECES 1
michael@0 50 #else
michael@0 51 # error "Unknown!"
michael@0 52 #endif
michael@0 53
michael@0 54 // Represents storage for an operand. For constants, the pointer is tagged
michael@0 55 // with a single bit, and the untagged pointer is a pointer to a Value.
michael@0 56 class LAllocation : public TempObject
michael@0 57 {
michael@0 58 uintptr_t bits_;
michael@0 59
michael@0 60 static const uintptr_t TAG_BIT = 1;
michael@0 61 static const uintptr_t TAG_SHIFT = 0;
michael@0 62 static const uintptr_t TAG_MASK = 1 << TAG_SHIFT;
michael@0 63 static const uintptr_t KIND_BITS = 3;
michael@0 64 static const uintptr_t KIND_SHIFT = TAG_SHIFT + TAG_BIT;
michael@0 65 static const uintptr_t KIND_MASK = (1 << KIND_BITS) - 1;
michael@0 66
michael@0 67 protected:
michael@0 68 static const uintptr_t DATA_BITS = (sizeof(uint32_t) * 8) - KIND_BITS - TAG_BIT;
michael@0 69 static const uintptr_t DATA_SHIFT = KIND_SHIFT + KIND_BITS;
michael@0 70 static const uintptr_t DATA_MASK = (1 << DATA_BITS) - 1;
michael@0 71
michael@0 72 public:
michael@0 73 enum Kind {
michael@0 74 USE, // Use of a virtual register, with physical allocation policy.
michael@0 75 CONSTANT_VALUE, // Constant js::Value.
michael@0 76 CONSTANT_INDEX, // Constant arbitrary index.
michael@0 77 GPR, // General purpose register.
michael@0 78 FPU, // Floating-point register.
michael@0 79 STACK_SLOT, // Stack slot.
michael@0 80 ARGUMENT_SLOT // Argument slot.
michael@0 81 };
michael@0 82
michael@0 83 protected:
michael@0 84 bool isTagged() const {
michael@0 85 return !!(bits_ & TAG_MASK);
michael@0 86 }
michael@0 87
michael@0 88 int32_t data() const {
michael@0 89 return int32_t(bits_) >> DATA_SHIFT;
michael@0 90 }
michael@0 91 void setData(int32_t data) {
michael@0 92 JS_ASSERT(int32_t(data) <= int32_t(DATA_MASK));
michael@0 93 bits_ &= ~(DATA_MASK << DATA_SHIFT);
michael@0 94 bits_ |= (data << DATA_SHIFT);
michael@0 95 }
michael@0 96 void setKindAndData(Kind kind, uint32_t data) {
michael@0 97 JS_ASSERT(int32_t(data) <= int32_t(DATA_MASK));
michael@0 98 bits_ = (uint32_t(kind) << KIND_SHIFT) | data << DATA_SHIFT;
michael@0 99 }
michael@0 100
michael@0 101 LAllocation(Kind kind, uint32_t data) {
michael@0 102 setKindAndData(kind, data);
michael@0 103 }
michael@0 104 explicit LAllocation(Kind kind) {
michael@0 105 setKindAndData(kind, 0);
michael@0 106 }
michael@0 107
michael@0 108 public:
michael@0 109 LAllocation() : bits_(0)
michael@0 110 { }
michael@0 111
michael@0 112 static LAllocation *New(TempAllocator &alloc) {
michael@0 113 return new(alloc) LAllocation();
michael@0 114 }
michael@0 115 template <typename T>
michael@0 116 static LAllocation *New(TempAllocator &alloc, const T &other) {
michael@0 117 return new(alloc) LAllocation(other);
michael@0 118 }
michael@0 119
michael@0 120 // The value pointer must be rooted in MIR and have its low bit cleared.
michael@0 121 explicit LAllocation(const Value *vp) {
michael@0 122 bits_ = uintptr_t(vp);
michael@0 123 JS_ASSERT(!isTagged());
michael@0 124 bits_ |= TAG_MASK;
michael@0 125 }
michael@0 126 inline explicit LAllocation(const AnyRegister &reg);
michael@0 127
michael@0 128 Kind kind() const {
michael@0 129 if (isTagged())
michael@0 130 return CONSTANT_VALUE;
michael@0 131 return (Kind)((bits_ >> KIND_SHIFT) & KIND_MASK);
michael@0 132 }
michael@0 133
michael@0 134 bool isUse() const {
michael@0 135 return kind() == USE;
michael@0 136 }
michael@0 137 bool isConstant() const {
michael@0 138 return isConstantValue() || isConstantIndex();
michael@0 139 }
michael@0 140 bool isConstantValue() const {
michael@0 141 return kind() == CONSTANT_VALUE;
michael@0 142 }
michael@0 143 bool isConstantIndex() const {
michael@0 144 return kind() == CONSTANT_INDEX;
michael@0 145 }
michael@0 146 bool isValue() const {
michael@0 147 return kind() == CONSTANT_VALUE;
michael@0 148 }
michael@0 149 bool isGeneralReg() const {
michael@0 150 return kind() == GPR;
michael@0 151 }
michael@0 152 bool isFloatReg() const {
michael@0 153 return kind() == FPU;
michael@0 154 }
michael@0 155 bool isStackSlot() const {
michael@0 156 return kind() == STACK_SLOT;
michael@0 157 }
michael@0 158 bool isArgument() const {
michael@0 159 return kind() == ARGUMENT_SLOT;
michael@0 160 }
michael@0 161 bool isRegister() const {
michael@0 162 return isGeneralReg() || isFloatReg();
michael@0 163 }
michael@0 164 bool isRegister(bool needFloat) const {
michael@0 165 return needFloat ? isFloatReg() : isGeneralReg();
michael@0 166 }
michael@0 167 bool isMemory() const {
michael@0 168 return isStackSlot() || isArgument();
michael@0 169 }
michael@0 170 inline LUse *toUse();
michael@0 171 inline const LUse *toUse() const;
michael@0 172 inline const LGeneralReg *toGeneralReg() const;
michael@0 173 inline const LFloatReg *toFloatReg() const;
michael@0 174 inline const LStackSlot *toStackSlot() const;
michael@0 175 inline const LArgument *toArgument() const;
michael@0 176 inline const LConstantIndex *toConstantIndex() const;
michael@0 177 inline AnyRegister toRegister() const;
michael@0 178
michael@0 179 const Value *toConstant() const {
michael@0 180 JS_ASSERT(isConstantValue());
michael@0 181 return reinterpret_cast<const Value *>(bits_ & ~TAG_MASK);
michael@0 182 }
michael@0 183
michael@0 184 bool operator ==(const LAllocation &other) const {
michael@0 185 return bits_ == other.bits_;
michael@0 186 }
michael@0 187
michael@0 188 bool operator !=(const LAllocation &other) const {
michael@0 189 return bits_ != other.bits_;
michael@0 190 }
michael@0 191
michael@0 192 HashNumber hash() const {
michael@0 193 return bits_;
michael@0 194 }
michael@0 195
michael@0 196 #ifdef DEBUG
michael@0 197 const char *toString() const;
michael@0 198 #else
michael@0 199 const char *toString() const { return "???"; }
michael@0 200 #endif
michael@0 201
michael@0 202 void dump() const;
michael@0 203 };
michael@0 204
michael@0 205 class LUse : public LAllocation
michael@0 206 {
michael@0 207 static const uint32_t POLICY_BITS = 3;
michael@0 208 static const uint32_t POLICY_SHIFT = 0;
michael@0 209 static const uint32_t POLICY_MASK = (1 << POLICY_BITS) - 1;
michael@0 210 static const uint32_t REG_BITS = 5;
michael@0 211 static const uint32_t REG_SHIFT = POLICY_SHIFT + POLICY_BITS;
michael@0 212 static const uint32_t REG_MASK = (1 << REG_BITS) - 1;
michael@0 213
michael@0 214 // Whether the physical register for this operand may be reused for a def.
michael@0 215 static const uint32_t USED_AT_START_BITS = 1;
michael@0 216 static const uint32_t USED_AT_START_SHIFT = REG_SHIFT + REG_BITS;
michael@0 217 static const uint32_t USED_AT_START_MASK = (1 << USED_AT_START_BITS) - 1;
michael@0 218
michael@0 219 public:
michael@0 220 // Virtual registers get the remaining 20 bits.
michael@0 221 static const uint32_t VREG_BITS = DATA_BITS - (USED_AT_START_SHIFT + USED_AT_START_BITS);
michael@0 222 static const uint32_t VREG_SHIFT = USED_AT_START_SHIFT + USED_AT_START_BITS;
michael@0 223 static const uint32_t VREG_MASK = (1 << VREG_BITS) - 1;
michael@0 224
michael@0 225 enum Policy {
michael@0 226 // Input should be in a read-only register or stack slot.
michael@0 227 ANY,
michael@0 228
michael@0 229 // Input must be in a read-only register.
michael@0 230 REGISTER,
michael@0 231
michael@0 232 // Input must be in a specific, read-only register.
michael@0 233 FIXED,
michael@0 234
michael@0 235 // Keep the used virtual register alive, and use whatever allocation is
michael@0 236 // available. This is similar to ANY but hints to the register allocator
michael@0 237 // that it is never useful to optimize this site.
michael@0 238 KEEPALIVE,
michael@0 239
michael@0 240 // For snapshot inputs, indicates that the associated instruction will
michael@0 241 // write this input to its output register before bailing out.
michael@0 242 // The register allocator may thus allocate that output register, and
michael@0 243 // does not need to keep the virtual register alive (alternatively,
michael@0 244 // this may be treated as KEEPALIVE).
michael@0 245 RECOVERED_INPUT
michael@0 246 };
michael@0 247
michael@0 248 void set(Policy policy, uint32_t reg, bool usedAtStart) {
michael@0 249 setKindAndData(USE, (policy << POLICY_SHIFT) |
michael@0 250 (reg << REG_SHIFT) |
michael@0 251 ((usedAtStart ? 1 : 0) << USED_AT_START_SHIFT));
michael@0 252 }
michael@0 253
michael@0 254 public:
michael@0 255 LUse(uint32_t vreg, Policy policy, bool usedAtStart = false) {
michael@0 256 set(policy, 0, usedAtStart);
michael@0 257 setVirtualRegister(vreg);
michael@0 258 }
michael@0 259 LUse(Policy policy, bool usedAtStart = false) {
michael@0 260 set(policy, 0, usedAtStart);
michael@0 261 }
michael@0 262 LUse(Register reg, bool usedAtStart = false) {
michael@0 263 set(FIXED, reg.code(), usedAtStart);
michael@0 264 }
michael@0 265 LUse(FloatRegister reg, bool usedAtStart = false) {
michael@0 266 set(FIXED, reg.code(), usedAtStart);
michael@0 267 }
michael@0 268 LUse(Register reg, uint32_t virtualRegister) {
michael@0 269 set(FIXED, reg.code(), false);
michael@0 270 setVirtualRegister(virtualRegister);
michael@0 271 }
michael@0 272 LUse(FloatRegister reg, uint32_t virtualRegister) {
michael@0 273 set(FIXED, reg.code(), false);
michael@0 274 setVirtualRegister(virtualRegister);
michael@0 275 }
michael@0 276
michael@0 277 void setVirtualRegister(uint32_t index) {
michael@0 278 JS_ASSERT(index < VREG_MASK);
michael@0 279
michael@0 280 uint32_t old = data() & ~(VREG_MASK << VREG_SHIFT);
michael@0 281 setData(old | (index << VREG_SHIFT));
michael@0 282 }
michael@0 283
michael@0 284 Policy policy() const {
michael@0 285 Policy policy = (Policy)((data() >> POLICY_SHIFT) & POLICY_MASK);
michael@0 286 return policy;
michael@0 287 }
michael@0 288 uint32_t virtualRegister() const {
michael@0 289 uint32_t index = (data() >> VREG_SHIFT) & VREG_MASK;
michael@0 290 return index;
michael@0 291 }
michael@0 292 uint32_t registerCode() const {
michael@0 293 JS_ASSERT(policy() == FIXED);
michael@0 294 return (data() >> REG_SHIFT) & REG_MASK;
michael@0 295 }
michael@0 296 bool isFixedRegister() const {
michael@0 297 return policy() == FIXED;
michael@0 298 }
michael@0 299 bool usedAtStart() const {
michael@0 300 return !!((data() >> USED_AT_START_SHIFT) & USED_AT_START_MASK);
michael@0 301 }
michael@0 302 };
michael@0 303
michael@0 304 static const uint32_t MAX_VIRTUAL_REGISTERS = LUse::VREG_MASK;
michael@0 305
michael@0 306 class LGeneralReg : public LAllocation
michael@0 307 {
michael@0 308 public:
michael@0 309 explicit LGeneralReg(Register reg)
michael@0 310 : LAllocation(GPR, reg.code())
michael@0 311 { }
michael@0 312
michael@0 313 Register reg() const {
michael@0 314 return Register::FromCode(data());
michael@0 315 }
michael@0 316 };
michael@0 317
michael@0 318 class LFloatReg : public LAllocation
michael@0 319 {
michael@0 320 public:
michael@0 321 explicit LFloatReg(FloatRegister reg)
michael@0 322 : LAllocation(FPU, reg.code())
michael@0 323 { }
michael@0 324
michael@0 325 FloatRegister reg() const {
michael@0 326 return FloatRegister::FromCode(data());
michael@0 327 }
michael@0 328 };
michael@0 329
michael@0 330 // Arbitrary constant index.
michael@0 331 class LConstantIndex : public LAllocation
michael@0 332 {
michael@0 333 explicit LConstantIndex(uint32_t index)
michael@0 334 : LAllocation(CONSTANT_INDEX, index)
michael@0 335 { }
michael@0 336
michael@0 337 public:
michael@0 338 // Used as a placeholder for inputs that can be ignored.
michael@0 339 static LConstantIndex Bogus() {
michael@0 340 return LConstantIndex(0);
michael@0 341 }
michael@0 342
michael@0 343 static LConstantIndex FromIndex(uint32_t index) {
michael@0 344 return LConstantIndex(index);
michael@0 345 }
michael@0 346
michael@0 347 uint32_t index() const {
michael@0 348 return data();
michael@0 349 }
michael@0 350 };
michael@0 351
michael@0 352 // Stack slots are indices into the stack. The indices are byte indices.
michael@0 353 class LStackSlot : public LAllocation
michael@0 354 {
michael@0 355 public:
michael@0 356 explicit LStackSlot(uint32_t slot)
michael@0 357 : LAllocation(STACK_SLOT, slot)
michael@0 358 { }
michael@0 359
michael@0 360 uint32_t slot() const {
michael@0 361 return data();
michael@0 362 }
michael@0 363 };
michael@0 364
michael@0 365 // Arguments are reverse indices into the stack. The indices are byte indices.
michael@0 366 class LArgument : public LAllocation
michael@0 367 {
michael@0 368 public:
michael@0 369 explicit LArgument(int32_t index)
michael@0 370 : LAllocation(ARGUMENT_SLOT, index)
michael@0 371 { }
michael@0 372
michael@0 373 int32_t index() const {
michael@0 374 return data();
michael@0 375 }
michael@0 376 };
michael@0 377
michael@0 378 // Represents storage for a definition.
michael@0 379 class LDefinition
michael@0 380 {
michael@0 381 // Bits containing policy, type, and virtual register.
michael@0 382 uint32_t bits_;
michael@0 383
michael@0 384 // Before register allocation, this optionally contains a fixed policy.
michael@0 385 // Register allocation assigns this field to a physical policy if none is
michael@0 386 // preset.
michael@0 387 //
michael@0 388 // Right now, pre-allocated outputs are limited to the following:
michael@0 389 // * Physical argument stack slots.
michael@0 390 // * Physical registers.
michael@0 391 LAllocation output_;
michael@0 392
michael@0 393 static const uint32_t TYPE_BITS = 3;
michael@0 394 static const uint32_t TYPE_SHIFT = 0;
michael@0 395 static const uint32_t TYPE_MASK = (1 << TYPE_BITS) - 1;
michael@0 396 static const uint32_t POLICY_BITS = 2;
michael@0 397 static const uint32_t POLICY_SHIFT = TYPE_SHIFT + TYPE_BITS;
michael@0 398 static const uint32_t POLICY_MASK = (1 << POLICY_BITS) - 1;
michael@0 399
michael@0 400 static const uint32_t VREG_BITS = (sizeof(uint32_t) * 8) - (POLICY_BITS + TYPE_BITS);
michael@0 401 static const uint32_t VREG_SHIFT = POLICY_SHIFT + POLICY_BITS;
michael@0 402 static const uint32_t VREG_MASK = (1 << VREG_BITS) - 1;
michael@0 403
michael@0 404 public:
michael@0 405 // Note that definitions, by default, are always allocated a register,
michael@0 406 // unless the policy specifies that an input can be re-used and that input
michael@0 407 // is a stack slot.
michael@0 408 enum Policy {
michael@0 409 // A random register of an appropriate class will be assigned.
michael@0 410 DEFAULT,
michael@0 411
michael@0 412 // The policy is predetermined by the LAllocation attached to this
michael@0 413 // definition. The allocation may be:
michael@0 414 // * A register, which may not appear as any fixed temporary.
michael@0 415 // * A stack slot or argument.
michael@0 416 //
michael@0 417 // Register allocation will not modify a preset allocation.
michael@0 418 PRESET,
michael@0 419
michael@0 420 // One definition per instruction must re-use the first input
michael@0 421 // allocation, which (for now) must be a register.
michael@0 422 MUST_REUSE_INPUT,
michael@0 423
michael@0 424 // This definition's virtual register is the same as another; this is
michael@0 425 // for instructions which consume a register and silently define it as
michael@0 426 // the same register. It is not legal to use this if doing so would
michael@0 427 // change the type of the virtual register.
michael@0 428 PASSTHROUGH
michael@0 429 };
michael@0 430
michael@0 431 enum Type {
michael@0 432 GENERAL, // Generic, integer or pointer-width data (GPR).
michael@0 433 INT32, // int32 data (GPR).
michael@0 434 OBJECT, // Pointer that may be collected as garbage (GPR).
michael@0 435 SLOTS, // Slots/elements pointer that may be moved by minor GCs (GPR).
michael@0 436 FLOAT32, // 32-bit floating-point value (FPU).
michael@0 437 DOUBLE, // 64-bit floating-point value (FPU).
michael@0 438 #ifdef JS_NUNBOX32
michael@0 439 // A type virtual register must be followed by a payload virtual
michael@0 440 // register, as both will be tracked as a single gcthing.
michael@0 441 TYPE,
michael@0 442 PAYLOAD
michael@0 443 #else
michael@0 444 BOX // Joined box, for punbox systems. (GPR, gcthing)
michael@0 445 #endif
michael@0 446 };
michael@0 447
michael@0 448 void set(uint32_t index, Type type, Policy policy) {
michael@0 449 JS_STATIC_ASSERT(MAX_VIRTUAL_REGISTERS <= VREG_MASK);
michael@0 450 bits_ = (index << VREG_SHIFT) | (policy << POLICY_SHIFT) | (type << TYPE_SHIFT);
michael@0 451 }
michael@0 452
michael@0 453 public:
michael@0 454 LDefinition(uint32_t index, Type type, Policy policy = DEFAULT) {
michael@0 455 set(index, type, policy);
michael@0 456 }
michael@0 457
michael@0 458 LDefinition(Type type, Policy policy = DEFAULT) {
michael@0 459 set(0, type, policy);
michael@0 460 }
michael@0 461
michael@0 462 LDefinition(Type type, const LAllocation &a)
michael@0 463 : output_(a)
michael@0 464 {
michael@0 465 set(0, type, PRESET);
michael@0 466 }
michael@0 467
michael@0 468 LDefinition(uint32_t index, Type type, const LAllocation &a)
michael@0 469 : output_(a)
michael@0 470 {
michael@0 471 set(index, type, PRESET);
michael@0 472 }
michael@0 473
michael@0 474 LDefinition() : bits_(0)
michael@0 475 { }
michael@0 476
michael@0 477 static LDefinition BogusTemp() {
michael@0 478 return LDefinition(GENERAL, LConstantIndex::Bogus());
michael@0 479 }
michael@0 480
michael@0 481 Policy policy() const {
michael@0 482 return (Policy)((bits_ >> POLICY_SHIFT) & POLICY_MASK);
michael@0 483 }
michael@0 484 Type type() const {
michael@0 485 return (Type)((bits_ >> TYPE_SHIFT) & TYPE_MASK);
michael@0 486 }
michael@0 487 bool isFloatReg() const {
michael@0 488 return type() == FLOAT32 || type() == DOUBLE;
michael@0 489 }
michael@0 490 uint32_t virtualRegister() const {
michael@0 491 return (bits_ >> VREG_SHIFT) & VREG_MASK;
michael@0 492 }
michael@0 493 LAllocation *output() {
michael@0 494 return &output_;
michael@0 495 }
michael@0 496 const LAllocation *output() const {
michael@0 497 return &output_;
michael@0 498 }
michael@0 499 bool isPreset() const {
michael@0 500 return policy() == PRESET;
michael@0 501 }
michael@0 502 bool isBogusTemp() const {
michael@0 503 return isPreset() && output()->isConstantIndex();
michael@0 504 }
michael@0 505 void setVirtualRegister(uint32_t index) {
michael@0 506 JS_ASSERT(index < VREG_MASK);
michael@0 507 bits_ &= ~(VREG_MASK << VREG_SHIFT);
michael@0 508 bits_ |= index << VREG_SHIFT;
michael@0 509 }
michael@0 510 void setOutput(const LAllocation &a) {
michael@0 511 output_ = a;
michael@0 512 if (!a.isUse()) {
michael@0 513 bits_ &= ~(POLICY_MASK << POLICY_SHIFT);
michael@0 514 bits_ |= PRESET << POLICY_SHIFT;
michael@0 515 }
michael@0 516 }
michael@0 517 void setReusedInput(uint32_t operand) {
michael@0 518 output_ = LConstantIndex::FromIndex(operand);
michael@0 519 }
michael@0 520 uint32_t getReusedInput() const {
michael@0 521 JS_ASSERT(policy() == LDefinition::MUST_REUSE_INPUT);
michael@0 522 return output_.toConstantIndex()->index();
michael@0 523 }
michael@0 524
michael@0 525 static inline Type TypeFrom(MIRType type) {
michael@0 526 switch (type) {
michael@0 527 case MIRType_Boolean:
michael@0 528 case MIRType_Int32:
michael@0 529 // The stack slot allocator doesn't currently support allocating
michael@0 530 // 1-byte slots, so for now we lower MIRType_Boolean into INT32.
michael@0 531 static_assert(sizeof(bool) <= sizeof(int32_t), "bool doesn't fit in an int32 slot");
michael@0 532 return LDefinition::INT32;
michael@0 533 case MIRType_String:
michael@0 534 case MIRType_Object:
michael@0 535 return LDefinition::OBJECT;
michael@0 536 case MIRType_Double:
michael@0 537 return LDefinition::DOUBLE;
michael@0 538 case MIRType_Float32:
michael@0 539 return LDefinition::FLOAT32;
michael@0 540 #if defined(JS_PUNBOX64)
michael@0 541 case MIRType_Value:
michael@0 542 return LDefinition::BOX;
michael@0 543 #endif
michael@0 544 case MIRType_Slots:
michael@0 545 case MIRType_Elements:
michael@0 546 return LDefinition::SLOTS;
michael@0 547 case MIRType_Pointer:
michael@0 548 return LDefinition::GENERAL;
michael@0 549 case MIRType_ForkJoinContext:
michael@0 550 return LDefinition::GENERAL;
michael@0 551 default:
michael@0 552 MOZ_ASSUME_UNREACHABLE("unexpected type");
michael@0 553 }
michael@0 554 }
michael@0 555 };
michael@0 556
michael@0 557 // Forward declarations of LIR types.
michael@0 558 #define LIROP(op) class L##op;
michael@0 559 LIR_OPCODE_LIST(LIROP)
michael@0 560 #undef LIROP
michael@0 561
michael@0 562 class LSnapshot;
michael@0 563 class LSafepoint;
michael@0 564 class LInstructionVisitor;
michael@0 565
michael@0 566 class LInstruction
michael@0 567 : public TempObject,
michael@0 568 public InlineListNode<LInstruction>
michael@0 569 {
michael@0 570 uint32_t id_;
michael@0 571
michael@0 572 // This snapshot could be set after a ResumePoint. It is used to restart
michael@0 573 // from the resume point pc.
michael@0 574 LSnapshot *snapshot_;
michael@0 575
michael@0 576 // Structure capturing the set of stack slots and registers which are known
michael@0 577 // to hold either gcthings or Values.
michael@0 578 LSafepoint *safepoint_;
michael@0 579
michael@0 580 protected:
michael@0 581 MDefinition *mir_;
michael@0 582
michael@0 583 LInstruction()
michael@0 584 : id_(0),
michael@0 585 snapshot_(nullptr),
michael@0 586 safepoint_(nullptr),
michael@0 587 mir_(nullptr)
michael@0 588 { }
michael@0 589
michael@0 590 public:
michael@0 591 class InputIterator;
michael@0 592 enum Opcode {
michael@0 593 # define LIROP(name) LOp_##name,
michael@0 594 LIR_OPCODE_LIST(LIROP)
michael@0 595 # undef LIROP
michael@0 596 LOp_Invalid
michael@0 597 };
michael@0 598
michael@0 599 const char *opName() {
michael@0 600 switch (op()) {
michael@0 601 # define LIR_NAME_INS(name) \
michael@0 602 case LOp_##name: return #name;
michael@0 603 LIR_OPCODE_LIST(LIR_NAME_INS)
michael@0 604 # undef LIR_NAME_INS
michael@0 605 default:
michael@0 606 return "Invalid";
michael@0 607 }
michael@0 608 }
michael@0 609
michael@0 610 // Hook for opcodes to add extra high level detail about what code will be
michael@0 611 // emitted for the op.
michael@0 612 virtual const char *extraName() const {
michael@0 613 return nullptr;
michael@0 614 }
michael@0 615
michael@0 616 public:
michael@0 617 virtual Opcode op() const = 0;
michael@0 618
michael@0 619 // Returns the number of outputs of this instruction. If an output is
michael@0 620 // unallocated, it is an LDefinition, defining a virtual register.
michael@0 621 virtual size_t numDefs() const = 0;
michael@0 622 virtual LDefinition *getDef(size_t index) = 0;
michael@0 623 virtual void setDef(size_t index, const LDefinition &def) = 0;
michael@0 624
michael@0 625 // Returns information about operands.
michael@0 626 virtual size_t numOperands() const = 0;
michael@0 627 virtual LAllocation *getOperand(size_t index) = 0;
michael@0 628 virtual void setOperand(size_t index, const LAllocation &a) = 0;
michael@0 629
michael@0 630 // Returns information about temporary registers needed. Each temporary
michael@0 631 // register is an LUse with a TEMPORARY policy, or a fixed register.
michael@0 632 virtual size_t numTemps() const = 0;
michael@0 633 virtual LDefinition *getTemp(size_t index) = 0;
michael@0 634 virtual void setTemp(size_t index, const LDefinition &a) = 0;
michael@0 635
michael@0 636 // Returns the number of successors of this instruction, if it is a control
michael@0 637 // transfer instruction, or zero otherwise.
michael@0 638 virtual size_t numSuccessors() const = 0;
michael@0 639 virtual MBasicBlock *getSuccessor(size_t i) const = 0;
michael@0 640 virtual void setSuccessor(size_t i, MBasicBlock *successor) = 0;
michael@0 641
michael@0 642 virtual bool isCall() const {
michael@0 643 return false;
michael@0 644 }
michael@0 645 uint32_t id() const {
michael@0 646 return id_;
michael@0 647 }
michael@0 648 void setId(uint32_t id) {
michael@0 649 JS_ASSERT(!id_);
michael@0 650 JS_ASSERT(id);
michael@0 651 id_ = id;
michael@0 652 }
michael@0 653 LSnapshot *snapshot() const {
michael@0 654 return snapshot_;
michael@0 655 }
michael@0 656 LSafepoint *safepoint() const {
michael@0 657 return safepoint_;
michael@0 658 }
michael@0 659 void setMir(MDefinition *mir) {
michael@0 660 mir_ = mir;
michael@0 661 }
michael@0 662 MDefinition *mirRaw() const {
michael@0 663 /* Untyped MIR for this op. Prefer mir() methods in subclasses. */
michael@0 664 return mir_;
michael@0 665 }
michael@0 666 void assignSnapshot(LSnapshot *snapshot);
michael@0 667 void initSafepoint(TempAllocator &alloc);
michael@0 668
michael@0 669 // For an instruction which has a MUST_REUSE_INPUT output, whether that
michael@0 670 // output register will be restored to its original value when bailing out.
michael@0 671 virtual bool recoversInput() const {
michael@0 672 return false;
michael@0 673 }
michael@0 674
michael@0 675 virtual void dump(FILE *fp);
michael@0 676 void dump();
michael@0 677 static void printName(FILE *fp, Opcode op);
michael@0 678 virtual void printName(FILE *fp);
michael@0 679 virtual void printOperands(FILE *fp);
michael@0 680 virtual void printInfo(FILE *fp) { }
michael@0 681
michael@0 682 public:
michael@0 683 // Opcode testing and casts.
michael@0 684 # define LIROP(name) \
michael@0 685 bool is##name() const { \
michael@0 686 return op() == LOp_##name; \
michael@0 687 } \
michael@0 688 inline L##name *to##name();
michael@0 689 LIR_OPCODE_LIST(LIROP)
michael@0 690 # undef LIROP
michael@0 691
michael@0 692 virtual bool accept(LInstructionVisitor *visitor) = 0;
michael@0 693 };
michael@0 694
michael@0 695 class LInstructionVisitor
michael@0 696 {
michael@0 697 LInstruction *ins_;
michael@0 698
michael@0 699 protected:
michael@0 700 jsbytecode *lastPC_;
michael@0 701
michael@0 702 LInstruction *instruction() {
michael@0 703 return ins_;
michael@0 704 }
michael@0 705
michael@0 706 public:
michael@0 707 void setInstruction(LInstruction *ins) {
michael@0 708 ins_ = ins;
michael@0 709 if (ins->mirRaw())
michael@0 710 lastPC_ = ins->mirRaw()->trackedPc();
michael@0 711 }
michael@0 712
michael@0 713 LInstructionVisitor()
michael@0 714 : ins_(nullptr),
michael@0 715 lastPC_(nullptr)
michael@0 716 {}
michael@0 717
michael@0 718 public:
michael@0 719 #define VISIT_INS(op) virtual bool visit##op(L##op *) { MOZ_ASSUME_UNREACHABLE("NYI: " #op); }
michael@0 720 LIR_OPCODE_LIST(VISIT_INS)
michael@0 721 #undef VISIT_INS
michael@0 722 };
michael@0 723
michael@0 724 typedef InlineList<LInstruction>::iterator LInstructionIterator;
michael@0 725 typedef InlineList<LInstruction>::reverse_iterator LInstructionReverseIterator;
michael@0 726
michael@0 727 class LPhi;
michael@0 728 class LMoveGroup;
michael@0 729 class LBlock : public TempObject
michael@0 730 {
michael@0 731 MBasicBlock *block_;
michael@0 732 Vector<LPhi *, 4, IonAllocPolicy> phis_;
michael@0 733 InlineList<LInstruction> instructions_;
michael@0 734 LMoveGroup *entryMoveGroup_;
michael@0 735 LMoveGroup *exitMoveGroup_;
michael@0 736 Label label_;
michael@0 737
michael@0 738 LBlock(TempAllocator &alloc, MBasicBlock *block)
michael@0 739 : block_(block),
michael@0 740 phis_(alloc),
michael@0 741 entryMoveGroup_(nullptr),
michael@0 742 exitMoveGroup_(nullptr)
michael@0 743 { }
michael@0 744
michael@0 745 public:
michael@0 746 static LBlock *New(TempAllocator &alloc, MBasicBlock *from) {
michael@0 747 return new(alloc) LBlock(alloc, from);
michael@0 748 }
michael@0 749 void add(LInstruction *ins) {
michael@0 750 instructions_.pushBack(ins);
michael@0 751 }
michael@0 752 bool addPhi(LPhi *phi) {
michael@0 753 return phis_.append(phi);
michael@0 754 }
michael@0 755 size_t numPhis() const {
michael@0 756 return phis_.length();
michael@0 757 }
michael@0 758 LPhi *getPhi(size_t index) const {
michael@0 759 return phis_[index];
michael@0 760 }
michael@0 761 void removePhi(size_t index) {
michael@0 762 phis_.erase(&phis_[index]);
michael@0 763 }
michael@0 764 void clearPhis() {
michael@0 765 phis_.clear();
michael@0 766 }
michael@0 767 MBasicBlock *mir() const {
michael@0 768 return block_;
michael@0 769 }
michael@0 770 LInstructionIterator begin() {
michael@0 771 return instructions_.begin();
michael@0 772 }
michael@0 773 LInstructionIterator begin(LInstruction *at) {
michael@0 774 return instructions_.begin(at);
michael@0 775 }
michael@0 776 LInstructionIterator end() {
michael@0 777 return instructions_.end();
michael@0 778 }
michael@0 779 LInstructionReverseIterator rbegin() {
michael@0 780 return instructions_.rbegin();
michael@0 781 }
michael@0 782 LInstructionReverseIterator rbegin(LInstruction *at) {
michael@0 783 return instructions_.rbegin(at);
michael@0 784 }
michael@0 785 LInstructionReverseIterator rend() {
michael@0 786 return instructions_.rend();
michael@0 787 }
michael@0 788 InlineList<LInstruction> &instructions() {
michael@0 789 return instructions_;
michael@0 790 }
michael@0 791 void insertAfter(LInstruction *at, LInstruction *ins) {
michael@0 792 instructions_.insertAfter(at, ins);
michael@0 793 }
michael@0 794 void insertBefore(LInstruction *at, LInstruction *ins) {
michael@0 795 JS_ASSERT(!at->isLabel());
michael@0 796 instructions_.insertBefore(at, ins);
michael@0 797 }
michael@0 798 uint32_t firstId();
michael@0 799 uint32_t lastId();
michael@0 800 Label *label() {
michael@0 801 return &label_;
michael@0 802 }
michael@0 803 LMoveGroup *getEntryMoveGroup(TempAllocator &alloc);
michael@0 804 LMoveGroup *getExitMoveGroup(TempAllocator &alloc);
michael@0 805 };
michael@0 806
michael@0 807 template <size_t Defs, size_t Operands, size_t Temps>
michael@0 808 class LInstructionHelper : public LInstruction
michael@0 809 {
michael@0 810 mozilla::Array<LDefinition, Defs> defs_;
michael@0 811 mozilla::Array<LAllocation, Operands> operands_;
michael@0 812 mozilla::Array<LDefinition, Temps> temps_;
michael@0 813
michael@0 814 public:
michael@0 815 size_t numDefs() const MOZ_FINAL MOZ_OVERRIDE {
michael@0 816 return Defs;
michael@0 817 }
michael@0 818 LDefinition *getDef(size_t index) MOZ_FINAL MOZ_OVERRIDE {
michael@0 819 return &defs_[index];
michael@0 820 }
michael@0 821 size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE {
michael@0 822 return Operands;
michael@0 823 }
michael@0 824 LAllocation *getOperand(size_t index) MOZ_FINAL MOZ_OVERRIDE {
michael@0 825 return &operands_[index];
michael@0 826 }
michael@0 827 size_t numTemps() const MOZ_FINAL MOZ_OVERRIDE {
michael@0 828 return Temps;
michael@0 829 }
michael@0 830 LDefinition *getTemp(size_t index) MOZ_FINAL MOZ_OVERRIDE {
michael@0 831 return &temps_[index];
michael@0 832 }
michael@0 833
michael@0 834 void setDef(size_t index, const LDefinition &def) MOZ_FINAL MOZ_OVERRIDE {
michael@0 835 defs_[index] = def;
michael@0 836 }
michael@0 837 void setOperand(size_t index, const LAllocation &a) MOZ_FINAL MOZ_OVERRIDE {
michael@0 838 operands_[index] = a;
michael@0 839 }
michael@0 840 void setTemp(size_t index, const LDefinition &a) MOZ_FINAL MOZ_OVERRIDE {
michael@0 841 temps_[index] = a;
michael@0 842 }
michael@0 843
michael@0 844 size_t numSuccessors() const {
michael@0 845 return 0;
michael@0 846 }
michael@0 847 MBasicBlock *getSuccessor(size_t i) const {
michael@0 848 JS_ASSERT(false);
michael@0 849 return nullptr;
michael@0 850 }
michael@0 851 void setSuccessor(size_t i, MBasicBlock *successor) {
michael@0 852 JS_ASSERT(false);
michael@0 853 }
michael@0 854
michael@0 855 // Default accessors, assuming a single input and output, respectively.
michael@0 856 const LAllocation *input() {
michael@0 857 JS_ASSERT(numOperands() == 1);
michael@0 858 return getOperand(0);
michael@0 859 }
michael@0 860 const LDefinition *output() {
michael@0 861 JS_ASSERT(numDefs() == 1);
michael@0 862 return getDef(0);
michael@0 863 }
michael@0 864
michael@0 865 virtual void printInfo(FILE *fp) {
michael@0 866 printOperands(fp);
michael@0 867 }
michael@0 868 };
michael@0 869
michael@0 870 template <size_t Defs, size_t Operands, size_t Temps>
michael@0 871 class LCallInstructionHelper : public LInstructionHelper<Defs, Operands, Temps>
michael@0 872 {
michael@0 873 public:
michael@0 874 virtual bool isCall() const {
michael@0 875 return true;
michael@0 876 }
michael@0 877 };
michael@0 878
michael@0 879 class LRecoverInfo : public TempObject
michael@0 880 {
michael@0 881 public:
michael@0 882 typedef Vector<MResumePoint *, 2, IonAllocPolicy> Instructions;
michael@0 883
michael@0 884 private:
michael@0 885 // List of instructions needed to recover the stack frames.
michael@0 886 // Outer frames are stored before inner frames.
michael@0 887 Instructions instructions_;
michael@0 888
michael@0 889 // Cached offset where this resume point is encoded.
michael@0 890 RecoverOffset recoverOffset_;
michael@0 891
michael@0 892 LRecoverInfo(TempAllocator &alloc);
michael@0 893 bool init(MResumePoint *mir);
michael@0 894
michael@0 895 public:
michael@0 896 static LRecoverInfo *New(MIRGenerator *gen, MResumePoint *mir);
michael@0 897
michael@0 898 // Resume point of the inner most function.
michael@0 899 MResumePoint *mir() const {
michael@0 900 return instructions_.back();
michael@0 901 }
michael@0 902 RecoverOffset recoverOffset() const {
michael@0 903 return recoverOffset_;
michael@0 904 }
michael@0 905 void setRecoverOffset(RecoverOffset offset) {
michael@0 906 JS_ASSERT(recoverOffset_ == INVALID_RECOVER_OFFSET);
michael@0 907 recoverOffset_ = offset;
michael@0 908 }
michael@0 909
michael@0 910 MResumePoint **begin() {
michael@0 911 return instructions_.begin();
michael@0 912 }
michael@0 913 MResumePoint **end() {
michael@0 914 return instructions_.end();
michael@0 915 }
michael@0 916 };
michael@0 917
michael@0 918 // An LSnapshot is the reflection of an MResumePoint in LIR. Unlike MResumePoints,
michael@0 919 // they cannot be shared, as they are filled in by the register allocator in
michael@0 920 // order to capture the precise low-level stack state in between an
michael@0 921 // instruction's input and output. During code generation, LSnapshots are
michael@0 922 // compressed and saved in the compiled script.
michael@0 923 class LSnapshot : public TempObject
michael@0 924 {
michael@0 925 private:
michael@0 926 uint32_t numSlots_;
michael@0 927 LAllocation *slots_;
michael@0 928 LRecoverInfo *recoverInfo_;
michael@0 929 SnapshotOffset snapshotOffset_;
michael@0 930 BailoutId bailoutId_;
michael@0 931 BailoutKind bailoutKind_;
michael@0 932
michael@0 933 LSnapshot(LRecoverInfo *recover, BailoutKind kind);
michael@0 934 bool init(MIRGenerator *gen);
michael@0 935
michael@0 936 public:
michael@0 937 static LSnapshot *New(MIRGenerator *gen, LRecoverInfo *recover, BailoutKind kind);
michael@0 938
michael@0 939 size_t numEntries() const {
michael@0 940 return numSlots_;
michael@0 941 }
michael@0 942 size_t numSlots() const {
michael@0 943 return numSlots_ / BOX_PIECES;
michael@0 944 }
michael@0 945 LAllocation *payloadOfSlot(size_t i) {
michael@0 946 JS_ASSERT(i < numSlots());
michael@0 947 size_t entryIndex = (i * BOX_PIECES) + (BOX_PIECES - 1);
michael@0 948 return getEntry(entryIndex);
michael@0 949 }
michael@0 950 #ifdef JS_NUNBOX32
michael@0 951 LAllocation *typeOfSlot(size_t i) {
michael@0 952 JS_ASSERT(i < numSlots());
michael@0 953 size_t entryIndex = (i * BOX_PIECES) + (BOX_PIECES - 2);
michael@0 954 return getEntry(entryIndex);
michael@0 955 }
michael@0 956 #endif
michael@0 957 LAllocation *getEntry(size_t i) {
michael@0 958 JS_ASSERT(i < numSlots_);
michael@0 959 return &slots_[i];
michael@0 960 }
michael@0 961 void setEntry(size_t i, const LAllocation &alloc) {
michael@0 962 JS_ASSERT(i < numSlots_);
michael@0 963 slots_[i] = alloc;
michael@0 964 }
michael@0 965 LRecoverInfo *recoverInfo() const {
michael@0 966 return recoverInfo_;
michael@0 967 }
michael@0 968 MResumePoint *mir() const {
michael@0 969 return recoverInfo()->mir();
michael@0 970 }
michael@0 971 SnapshotOffset snapshotOffset() const {
michael@0 972 return snapshotOffset_;
michael@0 973 }
michael@0 974 BailoutId bailoutId() const {
michael@0 975 return bailoutId_;
michael@0 976 }
michael@0 977 void setSnapshotOffset(SnapshotOffset offset) {
michael@0 978 JS_ASSERT(snapshotOffset_ == INVALID_SNAPSHOT_OFFSET);
michael@0 979 snapshotOffset_ = offset;
michael@0 980 }
michael@0 981 void setBailoutId(BailoutId id) {
michael@0 982 JS_ASSERT(bailoutId_ == INVALID_BAILOUT_ID);
michael@0 983 bailoutId_ = id;
michael@0 984 }
michael@0 985 BailoutKind bailoutKind() const {
michael@0 986 return bailoutKind_;
michael@0 987 }
michael@0 988 void setBailoutKind(BailoutKind kind) {
michael@0 989 bailoutKind_ = kind;
michael@0 990 }
michael@0 991 void rewriteRecoveredInput(LUse input);
michael@0 992 };
michael@0 993
michael@0 994 struct SafepointNunboxEntry {
michael@0 995 LAllocation type;
michael@0 996 LAllocation payload;
michael@0 997
michael@0 998 SafepointNunboxEntry() { }
michael@0 999 SafepointNunboxEntry(LAllocation type, LAllocation payload)
michael@0 1000 : type(type), payload(payload)
michael@0 1001 { }
michael@0 1002 };
michael@0 1003
michael@0 1004 class LSafepoint : public TempObject
michael@0 1005 {
michael@0 1006 typedef SafepointNunboxEntry NunboxEntry;
michael@0 1007
michael@0 1008 public:
michael@0 1009 typedef Vector<uint32_t, 0, IonAllocPolicy> SlotList;
michael@0 1010 typedef Vector<NunboxEntry, 0, IonAllocPolicy> NunboxList;
michael@0 1011
michael@0 1012 private:
michael@0 1013 // The information in a safepoint describes the registers and gc related
michael@0 1014 // values that are live at the start of the associated instruction.
michael@0 1015
michael@0 1016 // The set of registers which are live at an OOL call made within the
michael@0 1017 // instruction. This includes any registers for inputs which are not
michael@0 1018 // use-at-start, any registers for temps, and any registers live after the
michael@0 1019 // call except outputs of the instruction.
michael@0 1020 //
michael@0 1021 // For call instructions, the live regs are empty. Call instructions may
michael@0 1022 // have register inputs or temporaries, which will *not* be in the live
michael@0 1023 // registers: if passed to the call, the values passed will be marked via
michael@0 1024 // MarkJitExitFrame, and no registers can be live after the instruction
michael@0 1025 // except its outputs.
michael@0 1026 RegisterSet liveRegs_;
michael@0 1027
michael@0 1028 // The subset of liveRegs which contains gcthing pointers.
michael@0 1029 GeneralRegisterSet gcRegs_;
michael@0 1030
michael@0 1031 #ifdef CHECK_OSIPOINT_REGISTERS
michael@0 1032 // Clobbered regs of the current instruction. This set is never written to
michael@0 1033 // the safepoint; it's only used by assertions during compilation.
michael@0 1034 RegisterSet clobberedRegs_;
michael@0 1035 #endif
michael@0 1036
michael@0 1037 // Offset to a position in the safepoint stream, or
michael@0 1038 // INVALID_SAFEPOINT_OFFSET.
michael@0 1039 uint32_t safepointOffset_;
michael@0 1040
michael@0 1041 // Assembler buffer displacement to OSI point's call location.
michael@0 1042 uint32_t osiCallPointOffset_;
michael@0 1043
michael@0 1044 // List of stack slots which have gcthing pointers.
michael@0 1045 SlotList gcSlots_;
michael@0 1046
michael@0 1047 // List of stack slots which have Values.
michael@0 1048 SlotList valueSlots_;
michael@0 1049
michael@0 1050 #ifdef JS_NUNBOX32
michael@0 1051 // List of registers (in liveRegs) and stack slots which contain pieces of Values.
michael@0 1052 NunboxList nunboxParts_;
michael@0 1053
michael@0 1054 // Number of nunboxParts which are not completely filled in.
michael@0 1055 uint32_t partialNunboxes_;
michael@0 1056 #elif JS_PUNBOX64
michael@0 1057 // The subset of liveRegs which have Values.
michael@0 1058 GeneralRegisterSet valueRegs_;
michael@0 1059 #endif
michael@0 1060
michael@0 1061 // The subset of liveRegs which contains pointers to slots/elements.
michael@0 1062 GeneralRegisterSet slotsOrElementsRegs_;
michael@0 1063
michael@0 1064 // List of stack slots which have slots/elements pointers.
michael@0 1065 SlotList slotsOrElementsSlots_;
michael@0 1066
michael@0 1067 public:
michael@0 1068 void assertInvariants() {
michael@0 1069 // Every register in valueRegs and gcRegs should also be in liveRegs.
michael@0 1070 #ifndef JS_NUNBOX32
michael@0 1071 JS_ASSERT((valueRegs().bits() & ~liveRegs().gprs().bits()) == 0);
michael@0 1072 #endif
michael@0 1073 JS_ASSERT((gcRegs().bits() & ~liveRegs().gprs().bits()) == 0);
michael@0 1074 }
michael@0 1075
michael@0 1076 LSafepoint(TempAllocator &alloc)
michael@0 1077 : safepointOffset_(INVALID_SAFEPOINT_OFFSET)
michael@0 1078 , osiCallPointOffset_(0)
michael@0 1079 , gcSlots_(alloc)
michael@0 1080 , valueSlots_(alloc)
michael@0 1081 #ifdef JS_NUNBOX32
michael@0 1082 , nunboxParts_(alloc)
michael@0 1083 , partialNunboxes_(0)
michael@0 1084 #endif
michael@0 1085 , slotsOrElementsSlots_(alloc)
michael@0 1086 {
michael@0 1087 assertInvariants();
michael@0 1088 }
michael@0 1089 void addLiveRegister(AnyRegister reg) {
michael@0 1090 liveRegs_.addUnchecked(reg);
michael@0 1091 assertInvariants();
michael@0 1092 }
michael@0 1093 const RegisterSet &liveRegs() const {
michael@0 1094 return liveRegs_;
michael@0 1095 }
michael@0 1096 #ifdef CHECK_OSIPOINT_REGISTERS
michael@0 1097 void addClobberedRegister(AnyRegister reg) {
michael@0 1098 clobberedRegs_.addUnchecked(reg);
michael@0 1099 assertInvariants();
michael@0 1100 }
michael@0 1101 const RegisterSet &clobberedRegs() const {
michael@0 1102 return clobberedRegs_;
michael@0 1103 }
michael@0 1104 #endif
michael@0 1105 void addGcRegister(Register reg) {
michael@0 1106 gcRegs_.addUnchecked(reg);
michael@0 1107 assertInvariants();
michael@0 1108 }
michael@0 1109 GeneralRegisterSet gcRegs() const {
michael@0 1110 return gcRegs_;
michael@0 1111 }
michael@0 1112 bool addGcSlot(uint32_t slot) {
michael@0 1113 bool result = gcSlots_.append(slot);
michael@0 1114 if (result)
michael@0 1115 assertInvariants();
michael@0 1116 return result;
michael@0 1117 }
michael@0 1118 SlotList &gcSlots() {
michael@0 1119 return gcSlots_;
michael@0 1120 }
michael@0 1121
michael@0 1122 SlotList &slotsOrElementsSlots() {
michael@0 1123 return slotsOrElementsSlots_;
michael@0 1124 }
michael@0 1125 GeneralRegisterSet slotsOrElementsRegs() const {
michael@0 1126 return slotsOrElementsRegs_;
michael@0 1127 }
michael@0 1128 void addSlotsOrElementsRegister(Register reg) {
michael@0 1129 slotsOrElementsRegs_.addUnchecked(reg);
michael@0 1130 assertInvariants();
michael@0 1131 }
michael@0 1132 bool addSlotsOrElementsSlot(uint32_t slot) {
michael@0 1133 bool result = slotsOrElementsSlots_.append(slot);
michael@0 1134 if (result)
michael@0 1135 assertInvariants();
michael@0 1136 return result;
michael@0 1137 }
michael@0 1138 bool addSlotsOrElementsPointer(LAllocation alloc) {
michael@0 1139 if (alloc.isStackSlot())
michael@0 1140 return addSlotsOrElementsSlot(alloc.toStackSlot()->slot());
michael@0 1141 JS_ASSERT(alloc.isRegister());
michael@0 1142 addSlotsOrElementsRegister(alloc.toRegister().gpr());
michael@0 1143 assertInvariants();
michael@0 1144 return true;
michael@0 1145 }
michael@0 1146 bool hasSlotsOrElementsPointer(LAllocation alloc) const {
michael@0 1147 if (alloc.isRegister())
michael@0 1148 return slotsOrElementsRegs().has(alloc.toRegister().gpr());
michael@0 1149 if (alloc.isStackSlot()) {
michael@0 1150 for (size_t i = 0; i < slotsOrElementsSlots_.length(); i++) {
michael@0 1151 if (slotsOrElementsSlots_[i] == alloc.toStackSlot()->slot())
michael@0 1152 return true;
michael@0 1153 }
michael@0 1154 return false;
michael@0 1155 }
michael@0 1156 return false;
michael@0 1157 }
michael@0 1158
michael@0 1159 bool addGcPointer(LAllocation alloc) {
michael@0 1160 if (alloc.isStackSlot())
michael@0 1161 return addGcSlot(alloc.toStackSlot()->slot());
michael@0 1162 if (alloc.isRegister())
michael@0 1163 addGcRegister(alloc.toRegister().gpr());
michael@0 1164 assertInvariants();
michael@0 1165 return true;
michael@0 1166 }
michael@0 1167
michael@0 1168 bool hasGcPointer(LAllocation alloc) const {
michael@0 1169 if (alloc.isRegister())
michael@0 1170 return gcRegs().has(alloc.toRegister().gpr());
michael@0 1171 if (alloc.isStackSlot()) {
michael@0 1172 for (size_t i = 0; i < gcSlots_.length(); i++) {
michael@0 1173 if (gcSlots_[i] == alloc.toStackSlot()->slot())
michael@0 1174 return true;
michael@0 1175 }
michael@0 1176 return false;
michael@0 1177 }
michael@0 1178 JS_ASSERT(alloc.isArgument());
michael@0 1179 return true;
michael@0 1180 }
michael@0 1181
michael@0 1182 bool addValueSlot(uint32_t slot) {
michael@0 1183 bool result = valueSlots_.append(slot);
michael@0 1184 if (result)
michael@0 1185 assertInvariants();
michael@0 1186 return result;
michael@0 1187 }
michael@0 1188 SlotList &valueSlots() {
michael@0 1189 return valueSlots_;
michael@0 1190 }
michael@0 1191
michael@0 1192 bool hasValueSlot(uint32_t slot) const {
michael@0 1193 for (size_t i = 0; i < valueSlots_.length(); i++) {
michael@0 1194 if (valueSlots_[i] == slot)
michael@0 1195 return true;
michael@0 1196 }
michael@0 1197 return false;
michael@0 1198 }
michael@0 1199
michael@0 1200 #ifdef JS_NUNBOX32
michael@0 1201
michael@0 1202 bool addNunboxParts(LAllocation type, LAllocation payload) {
michael@0 1203 bool result = nunboxParts_.append(NunboxEntry(type, payload));
michael@0 1204 if (result)
michael@0 1205 assertInvariants();
michael@0 1206 return result;
michael@0 1207 }
michael@0 1208
michael@0 1209 bool addNunboxType(uint32_t typeVreg, LAllocation type) {
michael@0 1210 for (size_t i = 0; i < nunboxParts_.length(); i++) {
michael@0 1211 if (nunboxParts_[i].type == type)
michael@0 1212 return true;
michael@0 1213 if (nunboxParts_[i].type == LUse(typeVreg, LUse::ANY)) {
michael@0 1214 nunboxParts_[i].type = type;
michael@0 1215 partialNunboxes_--;
michael@0 1216 return true;
michael@0 1217 }
michael@0 1218 }
michael@0 1219 partialNunboxes_++;
michael@0 1220
michael@0 1221 // vregs for nunbox pairs are adjacent, with the type coming first.
michael@0 1222 uint32_t payloadVreg = typeVreg + 1;
michael@0 1223 bool result = nunboxParts_.append(NunboxEntry(type, LUse(payloadVreg, LUse::ANY)));
michael@0 1224 if (result)
michael@0 1225 assertInvariants();
michael@0 1226 return result;
michael@0 1227 }
michael@0 1228
michael@0 1229 bool hasNunboxType(LAllocation type) const {
michael@0 1230 if (type.isArgument())
michael@0 1231 return true;
michael@0 1232 if (type.isStackSlot() && hasValueSlot(type.toStackSlot()->slot() + 1))
michael@0 1233 return true;
michael@0 1234 for (size_t i = 0; i < nunboxParts_.length(); i++) {
michael@0 1235 if (nunboxParts_[i].type == type)
michael@0 1236 return true;
michael@0 1237 }
michael@0 1238 return false;
michael@0 1239 }
michael@0 1240
michael@0 1241 bool addNunboxPayload(uint32_t payloadVreg, LAllocation payload) {
michael@0 1242 for (size_t i = 0; i < nunboxParts_.length(); i++) {
michael@0 1243 if (nunboxParts_[i].payload == payload)
michael@0 1244 return true;
michael@0 1245 if (nunboxParts_[i].payload == LUse(payloadVreg, LUse::ANY)) {
michael@0 1246 partialNunboxes_--;
michael@0 1247 nunboxParts_[i].payload = payload;
michael@0 1248 return true;
michael@0 1249 }
michael@0 1250 }
michael@0 1251 partialNunboxes_++;
michael@0 1252
michael@0 1253 // vregs for nunbox pairs are adjacent, with the type coming first.
michael@0 1254 uint32_t typeVreg = payloadVreg - 1;
michael@0 1255 bool result = nunboxParts_.append(NunboxEntry(LUse(typeVreg, LUse::ANY), payload));
michael@0 1256 if (result)
michael@0 1257 assertInvariants();
michael@0 1258 return result;
michael@0 1259 }
michael@0 1260
michael@0 1261 bool hasNunboxPayload(LAllocation payload) const {
michael@0 1262 if (payload.isArgument())
michael@0 1263 return true;
michael@0 1264 if (payload.isStackSlot() && hasValueSlot(payload.toStackSlot()->slot()))
michael@0 1265 return true;
michael@0 1266 for (size_t i = 0; i < nunboxParts_.length(); i++) {
michael@0 1267 if (nunboxParts_[i].payload == payload)
michael@0 1268 return true;
michael@0 1269 }
michael@0 1270 return false;
michael@0 1271 }
michael@0 1272
michael@0 1273 NunboxList &nunboxParts() {
michael@0 1274 return nunboxParts_;
michael@0 1275 }
michael@0 1276
michael@0 1277 uint32_t partialNunboxes() {
michael@0 1278 return partialNunboxes_;
michael@0 1279 }
michael@0 1280
michael@0 1281 #elif JS_PUNBOX64
michael@0 1282
michael@0 1283 void addValueRegister(Register reg) {
michael@0 1284 valueRegs_.add(reg);
michael@0 1285 assertInvariants();
michael@0 1286 }
michael@0 1287 GeneralRegisterSet valueRegs() const {
michael@0 1288 return valueRegs_;
michael@0 1289 }
michael@0 1290
michael@0 1291 bool addBoxedValue(LAllocation alloc) {
michael@0 1292 if (alloc.isRegister()) {
michael@0 1293 Register reg = alloc.toRegister().gpr();
michael@0 1294 if (!valueRegs().has(reg))
michael@0 1295 addValueRegister(reg);
michael@0 1296 return true;
michael@0 1297 }
michael@0 1298 if (alloc.isStackSlot()) {
michael@0 1299 uint32_t slot = alloc.toStackSlot()->slot();
michael@0 1300 for (size_t i = 0; i < valueSlots().length(); i++) {
michael@0 1301 if (valueSlots()[i] == slot)
michael@0 1302 return true;
michael@0 1303 }
michael@0 1304 return addValueSlot(slot);
michael@0 1305 }
michael@0 1306 JS_ASSERT(alloc.isArgument());
michael@0 1307 return true;
michael@0 1308 }
michael@0 1309
michael@0 1310 bool hasBoxedValue(LAllocation alloc) const {
michael@0 1311 if (alloc.isRegister())
michael@0 1312 return valueRegs().has(alloc.toRegister().gpr());
michael@0 1313 if (alloc.isStackSlot())
michael@0 1314 return hasValueSlot(alloc.toStackSlot()->slot());
michael@0 1315 JS_ASSERT(alloc.isArgument());
michael@0 1316 return true;
michael@0 1317 }
michael@0 1318
michael@0 1319 #endif // JS_PUNBOX64
michael@0 1320
michael@0 1321 bool encoded() const {
michael@0 1322 return safepointOffset_ != INVALID_SAFEPOINT_OFFSET;
michael@0 1323 }
michael@0 1324 uint32_t offset() const {
michael@0 1325 JS_ASSERT(encoded());
michael@0 1326 return safepointOffset_;
michael@0 1327 }
michael@0 1328 void setOffset(uint32_t offset) {
michael@0 1329 safepointOffset_ = offset;
michael@0 1330 }
michael@0 1331 uint32_t osiReturnPointOffset() const {
michael@0 1332 // In general, pointer arithmetic on code is bad, but in this case,
michael@0 1333 // getting the return address from a call instruction, stepping over pools
michael@0 1334 // would be wrong.
michael@0 1335 return osiCallPointOffset_ + Assembler::patchWrite_NearCallSize();
michael@0 1336 }
michael@0 1337 uint32_t osiCallPointOffset() const {
michael@0 1338 return osiCallPointOffset_;
michael@0 1339 }
michael@0 1340 void setOsiCallPointOffset(uint32_t osiCallPointOffset) {
michael@0 1341 JS_ASSERT(!osiCallPointOffset_);
michael@0 1342 osiCallPointOffset_ = osiCallPointOffset;
michael@0 1343 }
michael@0 1344 void fixupOffset(MacroAssembler *masm) {
michael@0 1345 osiCallPointOffset_ = masm->actualOffset(osiCallPointOffset_);
michael@0 1346 }
michael@0 1347 };
michael@0 1348
michael@0 1349 class LInstruction::InputIterator
michael@0 1350 {
michael@0 1351 private:
michael@0 1352 LInstruction &ins_;
michael@0 1353 size_t idx_;
michael@0 1354 bool snapshot_;
michael@0 1355
michael@0 1356 void handleOperandsEnd() {
michael@0 1357 // Iterate on the snapshot when iteration over all operands is done.
michael@0 1358 if (!snapshot_ && idx_ == ins_.numOperands() && ins_.snapshot()) {
michael@0 1359 idx_ = 0;
michael@0 1360 snapshot_ = true;
michael@0 1361 }
michael@0 1362 }
michael@0 1363
michael@0 1364 public:
michael@0 1365 InputIterator(LInstruction &ins) :
michael@0 1366 ins_(ins),
michael@0 1367 idx_(0),
michael@0 1368 snapshot_(false)
michael@0 1369 {
michael@0 1370 handleOperandsEnd();
michael@0 1371 }
michael@0 1372
michael@0 1373 bool more() const {
michael@0 1374 if (snapshot_)
michael@0 1375 return idx_ < ins_.snapshot()->numEntries();
michael@0 1376 if (idx_ < ins_.numOperands())
michael@0 1377 return true;
michael@0 1378 if (ins_.snapshot() && ins_.snapshot()->numEntries())
michael@0 1379 return true;
michael@0 1380 return false;
michael@0 1381 }
michael@0 1382
michael@0 1383 bool isSnapshotInput() const {
michael@0 1384 return snapshot_;
michael@0 1385 }
michael@0 1386
michael@0 1387 void next() {
michael@0 1388 JS_ASSERT(more());
michael@0 1389 idx_++;
michael@0 1390 handleOperandsEnd();
michael@0 1391 }
michael@0 1392
michael@0 1393 void replace(const LAllocation &alloc) {
michael@0 1394 if (snapshot_)
michael@0 1395 ins_.snapshot()->setEntry(idx_, alloc);
michael@0 1396 else
michael@0 1397 ins_.setOperand(idx_, alloc);
michael@0 1398 }
michael@0 1399
michael@0 1400 LAllocation *operator *() const {
michael@0 1401 if (snapshot_)
michael@0 1402 return ins_.snapshot()->getEntry(idx_);
michael@0 1403 return ins_.getOperand(idx_);
michael@0 1404 }
michael@0 1405
michael@0 1406 LAllocation *operator ->() const {
michael@0 1407 return **this;
michael@0 1408 }
michael@0 1409 };
michael@0 1410
michael@0 1411 class LIRGraph
michael@0 1412 {
michael@0 1413 struct ValueHasher
michael@0 1414 {
michael@0 1415 typedef Value Lookup;
michael@0 1416 static HashNumber hash(const Value &v) {
michael@0 1417 return HashNumber(v.asRawBits());
michael@0 1418 }
michael@0 1419 static bool match(const Value &lhs, const Value &rhs) {
michael@0 1420 return lhs == rhs;
michael@0 1421 }
michael@0 1422
michael@0 1423 #ifdef DEBUG
michael@0 1424 bool canOptimizeOutIfUnused();
michael@0 1425 #endif
michael@0 1426 };
michael@0 1427
michael@0 1428
michael@0 1429 Vector<LBlock *, 16, IonAllocPolicy> blocks_;
michael@0 1430 Vector<Value, 0, IonAllocPolicy> constantPool_;
michael@0 1431 typedef HashMap<Value, uint32_t, ValueHasher, IonAllocPolicy> ConstantPoolMap;
michael@0 1432 ConstantPoolMap constantPoolMap_;
michael@0 1433 Vector<LInstruction *, 0, IonAllocPolicy> safepoints_;
michael@0 1434 Vector<LInstruction *, 0, IonAllocPolicy> nonCallSafepoints_;
michael@0 1435 uint32_t numVirtualRegisters_;
michael@0 1436 uint32_t numInstructions_;
michael@0 1437
michael@0 1438 // Number of stack slots needed for local spills.
michael@0 1439 uint32_t localSlotCount_;
michael@0 1440 // Number of stack slots needed for argument construction for calls.
michael@0 1441 uint32_t argumentSlotCount_;
michael@0 1442
michael@0 1443 // Snapshot taken before any LIR has been lowered.
michael@0 1444 LSnapshot *entrySnapshot_;
michael@0 1445
michael@0 1446 // LBlock containing LOsrEntry, or nullptr.
michael@0 1447 LBlock *osrBlock_;
michael@0 1448
michael@0 1449 MIRGraph &mir_;
michael@0 1450
michael@0 1451 public:
michael@0 1452 LIRGraph(MIRGraph *mir);
michael@0 1453
michael@0 1454 bool init() {
michael@0 1455 return constantPoolMap_.init();
michael@0 1456 }
michael@0 1457 MIRGraph &mir() const {
michael@0 1458 return mir_;
michael@0 1459 }
michael@0 1460 size_t numBlocks() const {
michael@0 1461 return blocks_.length();
michael@0 1462 }
michael@0 1463 LBlock *getBlock(size_t i) const {
michael@0 1464 return blocks_[i];
michael@0 1465 }
michael@0 1466 uint32_t numBlockIds() const {
michael@0 1467 return mir_.numBlockIds();
michael@0 1468 }
michael@0 1469 bool addBlock(LBlock *block) {
michael@0 1470 return blocks_.append(block);
michael@0 1471 }
michael@0 1472 uint32_t getVirtualRegister() {
michael@0 1473 numVirtualRegisters_ += VREG_INCREMENT;
michael@0 1474 return numVirtualRegisters_;
michael@0 1475 }
michael@0 1476 uint32_t numVirtualRegisters() const {
michael@0 1477 // Virtual registers are 1-based, not 0-based, so add one as a
michael@0 1478 // convenience for 0-based arrays.
michael@0 1479 return numVirtualRegisters_ + 1;
michael@0 1480 }
michael@0 1481 uint32_t getInstructionId() {
michael@0 1482 return numInstructions_++;
michael@0 1483 }
michael@0 1484 uint32_t numInstructions() const {
michael@0 1485 return numInstructions_;
michael@0 1486 }
michael@0 1487 void setLocalSlotCount(uint32_t localSlotCount) {
michael@0 1488 localSlotCount_ = localSlotCount;
michael@0 1489 }
michael@0 1490 uint32_t localSlotCount() const {
michael@0 1491 return localSlotCount_;
michael@0 1492 }
michael@0 1493 // Return the localSlotCount() value rounded up so that it satisfies the
michael@0 1494 // platform stack alignment requirement, and so that it's a multiple of
michael@0 1495 // the number of slots per Value.
michael@0 1496 uint32_t paddedLocalSlotCount() const {
michael@0 1497 // Round to StackAlignment, but also round to at least sizeof(Value) in
michael@0 1498 // case that's greater, because StackOffsetOfPassedArg rounds argument
michael@0 1499 // slots to 8-byte boundaries.
michael@0 1500 size_t Alignment = Max(sizeof(StackAlignment), sizeof(Value));
michael@0 1501 return AlignBytes(localSlotCount(), Alignment);
michael@0 1502 }
michael@0 1503 size_t paddedLocalSlotsSize() const {
michael@0 1504 return paddedLocalSlotCount();
michael@0 1505 }
michael@0 1506 void setArgumentSlotCount(uint32_t argumentSlotCount) {
michael@0 1507 argumentSlotCount_ = argumentSlotCount;
michael@0 1508 }
michael@0 1509 uint32_t argumentSlotCount() const {
michael@0 1510 return argumentSlotCount_;
michael@0 1511 }
michael@0 1512 size_t argumentsSize() const {
michael@0 1513 return argumentSlotCount() * sizeof(Value);
michael@0 1514 }
michael@0 1515 uint32_t totalSlotCount() const {
michael@0 1516 return paddedLocalSlotCount() + argumentsSize();
michael@0 1517 }
michael@0 1518 bool addConstantToPool(const Value &v, uint32_t *index);
michael@0 1519 size_t numConstants() const {
michael@0 1520 return constantPool_.length();
michael@0 1521 }
michael@0 1522 Value *constantPool() {
michael@0 1523 return &constantPool_[0];
michael@0 1524 }
michael@0 1525 void setEntrySnapshot(LSnapshot *snapshot) {
michael@0 1526 JS_ASSERT(!entrySnapshot_);
michael@0 1527 JS_ASSERT(snapshot->bailoutKind() == Bailout_Normal);
michael@0 1528 snapshot->setBailoutKind(Bailout_ArgumentCheck);
michael@0 1529 entrySnapshot_ = snapshot;
michael@0 1530 }
michael@0 1531 LSnapshot *entrySnapshot() const {
michael@0 1532 JS_ASSERT(entrySnapshot_);
michael@0 1533 return entrySnapshot_;
michael@0 1534 }
michael@0 1535 void setOsrBlock(LBlock *block) {
michael@0 1536 JS_ASSERT(!osrBlock_);
michael@0 1537 osrBlock_ = block;
michael@0 1538 }
michael@0 1539 LBlock *osrBlock() const {
michael@0 1540 return osrBlock_;
michael@0 1541 }
michael@0 1542 bool noteNeedsSafepoint(LInstruction *ins);
michael@0 1543 size_t numNonCallSafepoints() const {
michael@0 1544 return nonCallSafepoints_.length();
michael@0 1545 }
michael@0 1546 LInstruction *getNonCallSafepoint(size_t i) const {
michael@0 1547 return nonCallSafepoints_[i];
michael@0 1548 }
michael@0 1549 size_t numSafepoints() const {
michael@0 1550 return safepoints_.length();
michael@0 1551 }
michael@0 1552 LInstruction *getSafepoint(size_t i) const {
michael@0 1553 return safepoints_[i];
michael@0 1554 }
michael@0 1555 void removeBlock(size_t i);
michael@0 1556 };
michael@0 1557
michael@0 1558 LAllocation::LAllocation(const AnyRegister &reg)
michael@0 1559 {
michael@0 1560 if (reg.isFloat())
michael@0 1561 *this = LFloatReg(reg.fpu());
michael@0 1562 else
michael@0 1563 *this = LGeneralReg(reg.gpr());
michael@0 1564 }
michael@0 1565
michael@0 1566 AnyRegister
michael@0 1567 LAllocation::toRegister() const
michael@0 1568 {
michael@0 1569 JS_ASSERT(isRegister());
michael@0 1570 if (isFloatReg())
michael@0 1571 return AnyRegister(toFloatReg()->reg());
michael@0 1572 return AnyRegister(toGeneralReg()->reg());
michael@0 1573 }
michael@0 1574
michael@0 1575 } // namespace jit
michael@0 1576 } // namespace js
michael@0 1577
michael@0 1578 #define LIR_HEADER(opcode) \
michael@0 1579 Opcode op() const { \
michael@0 1580 return LInstruction::LOp_##opcode; \
michael@0 1581 } \
michael@0 1582 bool accept(LInstructionVisitor *visitor) { \
michael@0 1583 visitor->setInstruction(this); \
michael@0 1584 return visitor->visit##opcode(this); \
michael@0 1585 }
michael@0 1586
michael@0 1587 #include "jit/LIR-Common.h"
michael@0 1588 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
michael@0 1589 # if defined(JS_CODEGEN_X86)
michael@0 1590 # include "jit/x86/LIR-x86.h"
michael@0 1591 # elif defined(JS_CODEGEN_X64)
michael@0 1592 # include "jit/x64/LIR-x64.h"
michael@0 1593 # endif
michael@0 1594 # include "jit/shared/LIR-x86-shared.h"
michael@0 1595 #elif defined(JS_CODEGEN_ARM)
michael@0 1596 # include "jit/arm/LIR-arm.h"
michael@0 1597 #elif defined(JS_CODEGEN_MIPS)
michael@0 1598 # include "jit/mips/LIR-mips.h"
michael@0 1599 #else
michael@0 1600 # error "Unknown architecture!"
michael@0 1601 #endif
michael@0 1602
michael@0 1603 #undef LIR_HEADER
michael@0 1604
michael@0 1605 namespace js {
michael@0 1606 namespace jit {
michael@0 1607
michael@0 1608 #define LIROP(name) \
michael@0 1609 L##name *LInstruction::to##name() \
michael@0 1610 { \
michael@0 1611 JS_ASSERT(is##name()); \
michael@0 1612 return static_cast<L##name *>(this); \
michael@0 1613 }
michael@0 1614 LIR_OPCODE_LIST(LIROP)
michael@0 1615 #undef LIROP
michael@0 1616
michael@0 1617 #define LALLOC_CAST(type) \
michael@0 1618 L##type *LAllocation::to##type() { \
michael@0 1619 JS_ASSERT(is##type()); \
michael@0 1620 return static_cast<L##type *>(this); \
michael@0 1621 }
michael@0 1622 #define LALLOC_CONST_CAST(type) \
michael@0 1623 const L##type *LAllocation::to##type() const { \
michael@0 1624 JS_ASSERT(is##type()); \
michael@0 1625 return static_cast<const L##type *>(this); \
michael@0 1626 }
michael@0 1627
michael@0 1628 LALLOC_CAST(Use)
michael@0 1629 LALLOC_CONST_CAST(Use)
michael@0 1630 LALLOC_CONST_CAST(GeneralReg)
michael@0 1631 LALLOC_CONST_CAST(FloatReg)
michael@0 1632 LALLOC_CONST_CAST(StackSlot)
michael@0 1633 LALLOC_CONST_CAST(Argument)
michael@0 1634 LALLOC_CONST_CAST(ConstantIndex)
michael@0 1635
michael@0 1636 #undef LALLOC_CAST
michael@0 1637
michael@0 1638 #ifdef JS_NUNBOX32
michael@0 1639 static inline signed
michael@0 1640 OffsetToOtherHalfOfNunbox(LDefinition::Type type)
michael@0 1641 {
michael@0 1642 JS_ASSERT(type == LDefinition::TYPE || type == LDefinition::PAYLOAD);
michael@0 1643 signed offset = (type == LDefinition::TYPE)
michael@0 1644 ? PAYLOAD_INDEX - TYPE_INDEX
michael@0 1645 : TYPE_INDEX - PAYLOAD_INDEX;
michael@0 1646 return offset;
michael@0 1647 }
michael@0 1648
michael@0 1649 static inline void
michael@0 1650 AssertTypesFormANunbox(LDefinition::Type type1, LDefinition::Type type2)
michael@0 1651 {
michael@0 1652 JS_ASSERT((type1 == LDefinition::TYPE && type2 == LDefinition::PAYLOAD) ||
michael@0 1653 (type2 == LDefinition::TYPE && type1 == LDefinition::PAYLOAD));
michael@0 1654 }
michael@0 1655
michael@0 1656 static inline unsigned
michael@0 1657 OffsetOfNunboxSlot(LDefinition::Type type)
michael@0 1658 {
michael@0 1659 if (type == LDefinition::PAYLOAD)
michael@0 1660 return NUNBOX32_PAYLOAD_OFFSET;
michael@0 1661 return NUNBOX32_TYPE_OFFSET;
michael@0 1662 }
michael@0 1663
michael@0 1664 // Note that stack indexes for LStackSlot are modelled backwards, so a
michael@0 1665 // double-sized slot starting at 2 has its next word at 1, *not* 3.
michael@0 1666 static inline unsigned
michael@0 1667 BaseOfNunboxSlot(LDefinition::Type type, unsigned slot)
michael@0 1668 {
michael@0 1669 if (type == LDefinition::PAYLOAD)
michael@0 1670 return slot + NUNBOX32_PAYLOAD_OFFSET;
michael@0 1671 return slot + NUNBOX32_TYPE_OFFSET;
michael@0 1672 }
michael@0 1673 #endif
michael@0 1674
michael@0 1675 } // namespace jit
michael@0 1676 } // namespace js
michael@0 1677
michael@0 1678 #endif /* jit_LIR_h */

mercurial