Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef jit_LIR_h
8 : #define jit_LIR_h
9 :
10 : // This file declares the core data structures for LIR: storage allocations for
11 : // inputs and outputs, as well as the interface instructions must conform to.
12 :
13 : #include "mozilla/Array.h"
14 :
15 : #include "jit/Bailouts.h"
16 : #include "jit/FixedList.h"
17 : #include "jit/InlineList.h"
18 : #include "jit/JitAllocPolicy.h"
19 : #include "jit/LOpcodes.h"
20 : #include "jit/MIR.h"
21 : #include "jit/MIRGraph.h"
22 : #include "jit/Registers.h"
23 : #include "jit/Safepoints.h"
24 :
25 : namespace js {
26 : namespace jit {
27 :
28 : class LUse;
29 : class LGeneralReg;
30 : class LFloatReg;
31 : class LStackSlot;
32 : class LArgument;
33 : class LConstantIndex;
34 : class MBasicBlock;
35 : class MIRGenerator;
36 :
37 : static const uint32_t VREG_INCREMENT = 1;
38 :
39 : static const uint32_t THIS_FRAME_ARGSLOT = 0;
40 :
41 : #if defined(JS_NUNBOX32)
42 : # define BOX_PIECES 2
43 : static const uint32_t VREG_TYPE_OFFSET = 0;
44 : static const uint32_t VREG_DATA_OFFSET = 1;
45 : static const uint32_t TYPE_INDEX = 0;
46 : static const uint32_t PAYLOAD_INDEX = 1;
47 : static const uint32_t INT64LOW_INDEX = 0;
48 : static const uint32_t INT64HIGH_INDEX = 1;
49 : #elif defined(JS_PUNBOX64)
50 : # define BOX_PIECES 1
51 : #else
52 : # error "Unknown!"
53 : #endif
54 :
55 : static const uint32_t INT64_PIECES = sizeof(int64_t) / sizeof(uintptr_t);
56 :
57 : // Represents storage for an operand. For constants, the pointer is tagged
58 : // with a single bit, and the untagged pointer is a pointer to a Value.
59 : class LAllocation : public TempObject
60 : {
61 : uintptr_t bits_;
62 :
63 : // 3 bits gives us enough for an interesting set of Kinds and also fits
64 : // within the alignment bits of pointers to Value, which are always
65 : // 8-byte aligned.
66 : static const uintptr_t KIND_BITS = 3;
67 : static const uintptr_t KIND_SHIFT = 0;
68 : static const uintptr_t KIND_MASK = (1 << KIND_BITS) - 1;
69 :
70 : protected:
71 : static const uintptr_t DATA_BITS = (sizeof(uint32_t) * 8) - KIND_BITS;
72 : static const uintptr_t DATA_SHIFT = KIND_SHIFT + KIND_BITS;
73 :
74 : public:
75 : enum Kind {
76 : CONSTANT_VALUE, // MConstant*.
77 : CONSTANT_INDEX, // Constant arbitrary index.
78 : USE, // Use of a virtual register, with physical allocation policy.
79 : GPR, // General purpose register.
80 : FPU, // Floating-point register.
81 : STACK_SLOT, // Stack slot.
82 : ARGUMENT_SLOT // Argument slot.
83 : };
84 :
85 : static const uintptr_t DATA_MASK = (1 << DATA_BITS) - 1;
86 :
87 : protected:
88 224924 : uint32_t data() const {
89 224924 : return uint32_t(bits_) >> DATA_SHIFT;
90 : }
91 6415 : void setData(uint32_t data) {
92 6415 : MOZ_ASSERT(data <= DATA_MASK);
93 6415 : bits_ &= ~(DATA_MASK << DATA_SHIFT);
94 6415 : bits_ |= (data << DATA_SHIFT);
95 6415 : }
96 10060 : void setKindAndData(Kind kind, uint32_t data) {
97 10060 : MOZ_ASSERT(data <= DATA_MASK);
98 10060 : bits_ = (uint32_t(kind) << KIND_SHIFT) | data << DATA_SHIFT;
99 10060 : }
100 :
101 3645 : LAllocation(Kind kind, uint32_t data) {
102 3645 : setKindAndData(kind, data);
103 3645 : }
104 : explicit LAllocation(Kind kind) {
105 : setKindAndData(kind, 0);
106 : }
107 :
108 : public:
109 30114 : LAllocation() : bits_(0)
110 : {
111 30114 : MOZ_ASSERT(isBogus());
112 30114 : }
113 :
114 : // The MConstant pointer must have its low bits cleared.
115 1929 : explicit LAllocation(const MConstant* c) {
116 1929 : MOZ_ASSERT(c);
117 1929 : bits_ = uintptr_t(c);
118 1929 : MOZ_ASSERT((bits_ & (KIND_MASK << KIND_SHIFT)) == 0);
119 1929 : bits_ |= CONSTANT_VALUE << KIND_SHIFT;
120 1929 : }
121 : inline explicit LAllocation(AnyRegister reg);
122 :
123 266742 : Kind kind() const {
124 266742 : return (Kind)((bits_ >> KIND_SHIFT) & KIND_MASK);
125 : }
126 :
127 101153 : bool isBogus() const {
128 101153 : return bits_ == 0;
129 : }
130 67374 : bool isUse() const {
131 67374 : return kind() == USE;
132 : }
133 3960 : bool isConstant() const {
134 3960 : return isConstantValue() || isConstantIndex();
135 : }
136 4148 : bool isConstantValue() const {
137 4148 : return kind() == CONSTANT_VALUE;
138 : }
139 3477 : bool isConstantIndex() const {
140 3477 : return kind() == CONSTANT_INDEX;
141 : }
142 51442 : bool isGeneralReg() const {
143 51442 : return kind() == GPR;
144 : }
145 30603 : bool isFloatReg() const {
146 30603 : return kind() == FPU;
147 : }
148 100542 : bool isStackSlot() const {
149 100542 : return kind() == STACK_SLOT;
150 : }
151 8909 : bool isArgument() const {
152 8909 : return kind() == ARGUMENT_SLOT;
153 : }
154 32385 : bool isRegister() const {
155 32385 : return isGeneralReg() || isFloatReg();
156 : }
157 : bool isRegister(bool needFloat) const {
158 : return needFloat ? isFloatReg() : isGeneralReg();
159 : }
160 29352 : bool isMemory() const {
161 29352 : return isStackSlot() || isArgument();
162 : }
163 : inline uint32_t memorySlot() const;
164 : inline LUse* toUse();
165 : inline const LUse* toUse() const;
166 : inline const LGeneralReg* toGeneralReg() const;
167 : inline const LFloatReg* toFloatReg() const;
168 : inline const LStackSlot* toStackSlot() const;
169 : inline const LArgument* toArgument() const;
170 : inline const LConstantIndex* toConstantIndex() const;
171 : inline AnyRegister toRegister() const;
172 :
173 124 : const MConstant* toConstant() const {
174 124 : MOZ_ASSERT(isConstantValue());
175 124 : return reinterpret_cast<const MConstant*>(bits_ & ~(KIND_MASK << KIND_SHIFT));
176 : }
177 :
178 48238 : bool operator ==(const LAllocation& other) const {
179 48238 : return bits_ == other.bits_;
180 : }
181 :
182 61927 : bool operator !=(const LAllocation& other) const {
183 61927 : return bits_ != other.bits_;
184 : }
185 :
186 12510 : HashNumber hash() const {
187 12510 : return bits_;
188 : }
189 :
190 : UniqueChars toString() const;
191 : bool aliases(const LAllocation& other) const;
192 : void dump() const;
193 : };
194 :
195 : class LUse : public LAllocation
196 : {
197 : static const uint32_t POLICY_BITS = 3;
198 : static const uint32_t POLICY_SHIFT = 0;
199 : static const uint32_t POLICY_MASK = (1 << POLICY_BITS) - 1;
200 : static const uint32_t REG_BITS = 6;
201 : static const uint32_t REG_SHIFT = POLICY_SHIFT + POLICY_BITS;
202 : static const uint32_t REG_MASK = (1 << REG_BITS) - 1;
203 :
204 : // Whether the physical register for this operand may be reused for a def.
205 : static const uint32_t USED_AT_START_BITS = 1;
206 : static const uint32_t USED_AT_START_SHIFT = REG_SHIFT + REG_BITS;
207 : static const uint32_t USED_AT_START_MASK = (1 << USED_AT_START_BITS) - 1;
208 :
209 : public:
210 : // Virtual registers get the remaining 19 bits.
211 : static const uint32_t VREG_BITS = DATA_BITS - (USED_AT_START_SHIFT + USED_AT_START_BITS);
212 : static const uint32_t VREG_SHIFT = USED_AT_START_SHIFT + USED_AT_START_BITS;
213 : static const uint32_t VREG_MASK = (1 << VREG_BITS) - 1;
214 :
215 : enum Policy {
216 : // Input should be in a read-only register or stack slot.
217 : ANY,
218 :
219 : // Input must be in a read-only register.
220 : REGISTER,
221 :
222 : // Input must be in a specific, read-only register.
223 : FIXED,
224 :
225 : // Keep the used virtual register alive, and use whatever allocation is
226 : // available. This is similar to ANY but hints to the register allocator
227 : // that it is never useful to optimize this site.
228 : KEEPALIVE,
229 :
230 : // For snapshot inputs, indicates that the associated instruction will
231 : // write this input to its output register before bailing out.
232 : // The register allocator may thus allocate that output register, and
233 : // does not need to keep the virtual register alive (alternatively,
234 : // this may be treated as KEEPALIVE).
235 : RECOVERED_INPUT
236 : };
237 :
238 6415 : void set(Policy policy, uint32_t reg, bool usedAtStart) {
239 12830 : setKindAndData(USE, (policy << POLICY_SHIFT) |
240 6415 : (reg << REG_SHIFT) |
241 12830 : ((usedAtStart ? 1 : 0) << USED_AT_START_SHIFT));
242 6415 : }
243 :
244 : public:
245 549 : LUse(uint32_t vreg, Policy policy, bool usedAtStart = false) {
246 549 : set(policy, 0, usedAtStart);
247 549 : setVirtualRegister(vreg);
248 549 : }
249 5806 : explicit LUse(Policy policy, bool usedAtStart = false) {
250 5806 : set(policy, 0, usedAtStart);
251 5806 : }
252 60 : explicit LUse(Register reg, bool usedAtStart = false) {
253 60 : set(FIXED, reg.code(), usedAtStart);
254 60 : }
255 0 : explicit LUse(FloatRegister reg, bool usedAtStart = false) {
256 0 : set(FIXED, reg.code(), usedAtStart);
257 0 : }
258 0 : LUse(Register reg, uint32_t virtualRegister, bool usedAtStart = false) {
259 0 : set(FIXED, reg.code(), usedAtStart);
260 0 : setVirtualRegister(virtualRegister);
261 0 : }
262 : LUse(FloatRegister reg, uint32_t virtualRegister, bool usedAtStart = false) {
263 : set(FIXED, reg.code(), usedAtStart);
264 : setVirtualRegister(virtualRegister);
265 : }
266 :
267 6415 : void setVirtualRegister(uint32_t index) {
268 6415 : MOZ_ASSERT(index < VREG_MASK);
269 :
270 6415 : uint32_t old = data() & ~(VREG_MASK << VREG_SHIFT);
271 6415 : setData(old | (index << VREG_SHIFT));
272 6415 : }
273 :
274 136849 : Policy policy() const {
275 136849 : Policy policy = (Policy)((data() >> POLICY_SHIFT) & POLICY_MASK);
276 136849 : return policy;
277 : }
278 26450 : uint32_t virtualRegister() const {
279 26450 : uint32_t index = (data() >> VREG_SHIFT) & VREG_MASK;
280 26450 : MOZ_ASSERT(index != 0);
281 26450 : return index;
282 : }
283 325 : uint32_t registerCode() const {
284 325 : MOZ_ASSERT(policy() == FIXED);
285 325 : return (data() >> REG_SHIFT) & REG_MASK;
286 : }
287 12090 : bool isFixedRegister() const {
288 12090 : return policy() == FIXED;
289 : }
290 13355 : bool usedAtStart() const {
291 13355 : return !!((data() >> USED_AT_START_SHIFT) & USED_AT_START_MASK);
292 : }
293 : };
294 :
295 : static const uint32_t MAX_VIRTUAL_REGISTERS = LUse::VREG_MASK;
296 :
297 : class LBoxAllocation
298 : {
299 : #ifdef JS_NUNBOX32
300 : LAllocation type_;
301 : LAllocation payload_;
302 : #else
303 : LAllocation value_;
304 : #endif
305 :
306 : public:
307 : #ifdef JS_NUNBOX32
308 : LBoxAllocation(LAllocation type, LAllocation payload) : type_(type), payload_(payload) {}
309 :
310 : LAllocation type() const { return type_; }
311 : LAllocation payload() const { return payload_; }
312 : #else
313 160 : explicit LBoxAllocation(LAllocation value) : value_(value) {}
314 :
315 160 : LAllocation value() const { return value_; }
316 : #endif
317 : };
318 :
319 : template<class ValT>
320 : class LInt64Value
321 : {
322 : #if JS_BITS_PER_WORD == 32
323 : ValT high_;
324 : ValT low_;
325 : #else
326 : ValT value_;
327 : #endif
328 :
329 : public:
330 : #if JS_BITS_PER_WORD == 32
331 : LInt64Value(ValT high, ValT low) : high_(high), low_(low) {}
332 :
333 : ValT high() const { return high_; }
334 : ValT low() const { return low_; }
335 : #else
336 0 : explicit LInt64Value(ValT value) : value_(value) {}
337 :
338 0 : ValT value() const { return value_; }
339 : #endif
340 : };
341 :
342 : using LInt64Allocation = LInt64Value<LAllocation>;
343 :
344 : class LGeneralReg : public LAllocation
345 : {
346 : public:
347 1806 : explicit LGeneralReg(Register reg)
348 1806 : : LAllocation(GPR, reg.code())
349 1806 : { }
350 :
351 12753 : Register reg() const {
352 12753 : return Register::FromCode(data());
353 : }
354 : };
355 :
356 : class LFloatReg : public LAllocation
357 : {
358 : public:
359 1706 : explicit LFloatReg(FloatRegister reg)
360 1706 : : LAllocation(FPU, reg.code())
361 1706 : { }
362 :
363 74 : FloatRegister reg() const {
364 74 : return FloatRegister::FromCode(data());
365 : }
366 : };
367 :
368 : // Arbitrary constant index.
369 : class LConstantIndex : public LAllocation
370 : {
371 13 : explicit LConstantIndex(uint32_t index)
372 13 : : LAllocation(CONSTANT_INDEX, index)
373 13 : { }
374 :
375 : public:
376 13 : static LConstantIndex FromIndex(uint32_t index) {
377 13 : return LConstantIndex(index);
378 : }
379 :
380 69 : uint32_t index() const {
381 69 : return data();
382 : }
383 : };
384 :
385 : // Stack slots are indices into the stack. The indices are byte indices.
386 : class LStackSlot : public LAllocation
387 : {
388 : public:
389 84 : explicit LStackSlot(uint32_t slot)
390 84 : : LAllocation(STACK_SLOT, slot)
391 84 : { }
392 :
393 27896 : uint32_t slot() const {
394 27896 : return data();
395 : }
396 : };
397 :
398 : // Arguments are reverse indices into the stack. The indices are byte indices.
399 : class LArgument : public LAllocation
400 : {
401 : public:
402 36 : explicit LArgument(uint32_t index)
403 36 : : LAllocation(ARGUMENT_SLOT, index)
404 36 : { }
405 :
406 738 : uint32_t index() const {
407 738 : return data();
408 : }
409 : };
410 :
411 : inline uint32_t
412 19463 : LAllocation::memorySlot() const
413 : {
414 19463 : MOZ_ASSERT(isMemory());
415 19463 : return isStackSlot() ? toStackSlot()->slot() : toArgument()->index();
416 : }
417 :
418 : // Represents storage for a definition.
419 : class LDefinition
420 : {
421 : // Bits containing policy, type, and virtual register.
422 : uint32_t bits_;
423 :
424 : // Before register allocation, this optionally contains a fixed policy.
425 : // Register allocation assigns this field to a physical policy if none is
426 : // fixed.
427 : //
428 : // Right now, pre-allocated outputs are limited to the following:
429 : // * Physical argument stack slots.
430 : // * Physical registers.
431 : LAllocation output_;
432 :
433 : static const uint32_t TYPE_BITS = 4;
434 : static const uint32_t TYPE_SHIFT = 0;
435 : static const uint32_t TYPE_MASK = (1 << TYPE_BITS) - 1;
436 : static const uint32_t POLICY_BITS = 2;
437 : static const uint32_t POLICY_SHIFT = TYPE_SHIFT + TYPE_BITS;
438 : static const uint32_t POLICY_MASK = (1 << POLICY_BITS) - 1;
439 :
440 : static const uint32_t VREG_BITS = (sizeof(uint32_t) * 8) - (POLICY_BITS + TYPE_BITS);
441 : static const uint32_t VREG_SHIFT = POLICY_SHIFT + POLICY_BITS;
442 : static const uint32_t VREG_MASK = (1 << VREG_BITS) - 1;
443 :
444 : public:
445 : // Note that definitions, by default, are always allocated a register,
446 : // unless the policy specifies that an input can be re-used and that input
447 : // is a stack slot.
448 : enum Policy {
449 : // The policy is predetermined by the LAllocation attached to this
450 : // definition. The allocation may be:
451 : // * A register, which may not appear as any fixed temporary.
452 : // * A stack slot or argument.
453 : //
454 : // Register allocation will not modify a fixed allocation.
455 : FIXED,
456 :
457 : // A random register of an appropriate class will be assigned.
458 : REGISTER,
459 :
460 : // One definition per instruction must re-use the first input
461 : // allocation, which (for now) must be a register.
462 : MUST_REUSE_INPUT
463 : };
464 :
465 : // This should be kept in sync with LIR.cpp's TypeChars.
466 : enum Type {
467 : GENERAL, // Generic, integer or pointer-width data (GPR).
468 : INT32, // int32 data (GPR).
469 : OBJECT, // Pointer that may be collected as garbage (GPR).
470 : SLOTS, // Slots/elements pointer that may be moved by minor GCs (GPR).
471 : FLOAT32, // 32-bit floating-point value (FPU).
472 : DOUBLE, // 64-bit floating-point value (FPU).
473 : SIMD128INT, // 128-bit SIMD integer vector (FPU).
474 : SIMD128FLOAT, // 128-bit SIMD floating point vector (FPU).
475 : SINCOS,
476 : #ifdef JS_NUNBOX32
477 : // A type virtual register must be followed by a payload virtual
478 : // register, as both will be tracked as a single gcthing.
479 : TYPE,
480 : PAYLOAD
481 : #else
482 : BOX // Joined box, for punbox systems. (GPR, gcthing)
483 : #endif
484 : };
485 :
486 1616 : void set(uint32_t index, Type type, Policy policy) {
487 : JS_STATIC_ASSERT(MAX_VIRTUAL_REGISTERS <= VREG_MASK);
488 1616 : bits_ = (index << VREG_SHIFT) | (policy << POLICY_SHIFT) | (type << TYPE_SHIFT);
489 : MOZ_ASSERT_IF(!SupportsSimd, !isSimdType());
490 1616 : }
491 :
492 : public:
493 621 : LDefinition(uint32_t index, Type type, Policy policy = REGISTER) {
494 621 : set(index, type, policy);
495 621 : }
496 :
497 958 : explicit LDefinition(Type type, Policy policy = REGISTER) {
498 958 : set(0, type, policy);
499 958 : }
500 :
501 : LDefinition(Type type, const LAllocation& a)
502 : : output_(a)
503 : {
504 : set(0, type, FIXED);
505 : }
506 :
507 37 : LDefinition(uint32_t index, Type type, const LAllocation& a)
508 37 : : output_(a)
509 : {
510 37 : set(index, type, FIXED);
511 37 : }
512 :
513 1285 : LDefinition() : bits_(0)
514 : {
515 1285 : MOZ_ASSERT(isBogusTemp());
516 1285 : }
517 :
518 86 : static LDefinition BogusTemp() {
519 86 : return LDefinition();
520 : }
521 :
522 92633 : Policy policy() const {
523 92633 : return (Policy)((bits_ >> POLICY_SHIFT) & POLICY_MASK);
524 : }
525 357709 : Type type() const {
526 357709 : return (Type)((bits_ >> TYPE_SHIFT) & TYPE_MASK);
527 : }
528 85279 : bool isSimdType() const {
529 85279 : return type() == SIMD128INT || type() == SIMD128FLOAT;
530 : }
531 43113 : bool isCompatibleReg(const AnyRegister& r) const {
532 43113 : if (isFloatReg() && r.isFloat()) {
533 656 : if (type() == FLOAT32)
534 0 : return r.fpu().isSingle();
535 656 : if (type() == DOUBLE)
536 656 : return r.fpu().isDouble();
537 0 : if (isSimdType())
538 0 : return r.fpu().isSimd128();
539 0 : MOZ_CRASH("Unexpected MDefinition type");
540 : }
541 42457 : return !isFloatReg() && !r.isFloat();
542 : }
543 347 : bool isCompatibleDef(const LDefinition& other) const {
544 : #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
545 : if (isFloatReg() && other.isFloatReg())
546 : return type() == other.type();
547 : return !isFloatReg() && !other.isFloatReg();
548 : #else
549 347 : return isFloatReg() == other.isFloatReg();
550 : #endif
551 : }
552 :
553 86529 : bool isFloatReg() const {
554 86529 : return type() == FLOAT32 || type() == DOUBLE || isSimdType();
555 : }
556 52378 : uint32_t virtualRegister() const {
557 52378 : uint32_t index = (bits_ >> VREG_SHIFT) & VREG_MASK;
558 : //MOZ_ASSERT(index != 0);
559 52378 : return index;
560 : }
561 67552 : LAllocation* output() {
562 67552 : return &output_;
563 : }
564 68338 : const LAllocation* output() const {
565 68338 : return &output_;
566 : }
567 71385 : bool isFixed() const {
568 71385 : return policy() == FIXED;
569 : }
570 69201 : bool isBogusTemp() const {
571 69201 : return isFixed() && output()->isBogus();
572 : }
573 404 : void setVirtualRegister(uint32_t index) {
574 404 : MOZ_ASSERT(index < VREG_MASK);
575 404 : bits_ &= ~(VREG_MASK << VREG_SHIFT);
576 404 : bits_ |= index << VREG_SHIFT;
577 404 : }
578 1064 : void setOutput(const LAllocation& a) {
579 1064 : output_ = a;
580 1064 : if (!a.isUse()) {
581 1064 : bits_ &= ~(POLICY_MASK << POLICY_SHIFT);
582 1064 : bits_ |= FIXED << POLICY_SHIFT;
583 : }
584 1064 : }
585 13 : void setReusedInput(uint32_t operand) {
586 13 : output_ = LConstantIndex::FromIndex(operand);
587 13 : }
588 69 : uint32_t getReusedInput() const {
589 69 : MOZ_ASSERT(policy() == LDefinition::MUST_REUSE_INPUT);
590 69 : return output_.toConstantIndex()->index();
591 : }
592 :
593 494 : static inline Type TypeFrom(MIRType type) {
594 494 : switch (type) {
595 : case MIRType::Boolean:
596 : case MIRType::Int32:
597 : // The stack slot allocator doesn't currently support allocating
598 : // 1-byte slots, so for now we lower MIRType::Boolean into INT32.
599 : static_assert(sizeof(bool) <= sizeof(int32_t), "bool doesn't fit in an int32 slot");
600 216 : return LDefinition::INT32;
601 : case MIRType::String:
602 : case MIRType::Symbol:
603 : case MIRType::Object:
604 : case MIRType::ObjectOrNull:
605 174 : return LDefinition::OBJECT;
606 : case MIRType::Double:
607 1 : return LDefinition::DOUBLE;
608 : case MIRType::Float32:
609 0 : return LDefinition::FLOAT32;
610 : #if defined(JS_PUNBOX64)
611 : case MIRType::Value:
612 86 : return LDefinition::BOX;
613 : #endif
614 : case MIRType::SinCosDouble:
615 0 : return LDefinition::SINCOS;
616 : case MIRType::Slots:
617 : case MIRType::Elements:
618 14 : return LDefinition::SLOTS;
619 : case MIRType::Pointer:
620 3 : return LDefinition::GENERAL;
621 : #if defined(JS_PUNBOX64)
622 : case MIRType::Int64:
623 0 : return LDefinition::GENERAL;
624 : #endif
625 : case MIRType::Int8x16:
626 : case MIRType::Int16x8:
627 : case MIRType::Int32x4:
628 : case MIRType::Bool8x16:
629 : case MIRType::Bool16x8:
630 : case MIRType::Bool32x4:
631 0 : return LDefinition::SIMD128INT;
632 : case MIRType::Float32x4:
633 0 : return LDefinition::SIMD128FLOAT;
634 : default:
635 0 : MOZ_CRASH("unexpected type");
636 : }
637 : }
638 :
639 : UniqueChars toString() const;
640 :
641 : void dump() const;
642 : };
643 :
644 : using LInt64Definition = LInt64Value<LDefinition>;
645 :
646 : // Forward declarations of LIR types.
647 : #define LIROP(op) class L##op;
648 : LIR_OPCODE_LIST(LIROP)
649 : #undef LIROP
650 :
651 : class LSnapshot;
652 : class LSafepoint;
653 : class LInstruction;
654 : class LElementVisitor;
655 :
656 : // The common base class for LPhi and LInstruction.
657 : class LNode
658 : {
659 : uint32_t id_;
660 : LBlock* block_;
661 :
662 : protected:
663 : MDefinition* mir_;
664 :
665 : public:
666 1963 : LNode()
667 1963 : : id_(0),
668 : block_(nullptr),
669 1963 : mir_(nullptr)
670 1963 : { }
671 :
672 : enum Opcode {
673 : # define LIROP(name) LOp_##name,
674 : LIR_OPCODE_LIST(LIROP)
675 : # undef LIROP
676 : LOp_Invalid
677 : };
678 :
679 1681 : const char* opName() {
680 1681 : switch (op()) {
681 : # define LIR_NAME_INS(name) \
682 : case LOp_##name: return #name;
683 109 : LIR_OPCODE_LIST(LIR_NAME_INS)
684 : # undef LIR_NAME_INS
685 : default:
686 0 : return "Invalid";
687 : }
688 : }
689 :
690 : // Hook for opcodes to add extra high level detail about what code will be
691 : // emitted for the op.
692 1420 : virtual const char* extraName() const {
693 1420 : return nullptr;
694 : }
695 :
696 : virtual Opcode op() const = 0;
697 :
698 10465 : bool isInstruction() const {
699 10465 : return op() != LOp_Phi;
700 : }
701 : inline LInstruction* toInstruction();
702 : inline const LInstruction* toInstruction() const;
703 :
704 : // Returns the number of outputs of this instruction. If an output is
705 : // unallocated, it is an LDefinition, defining a virtual register.
706 : virtual size_t numDefs() const = 0;
707 : virtual LDefinition* getDef(size_t index) = 0;
708 : virtual void setDef(size_t index, const LDefinition& def) = 0;
709 :
710 : // Returns information about operands.
711 : virtual size_t numOperands() const = 0;
712 : virtual LAllocation* getOperand(size_t index) = 0;
713 : virtual void setOperand(size_t index, const LAllocation& a) = 0;
714 :
715 : // Returns information about temporary registers needed. Each temporary
716 : // register is an LDefinition with a fixed or virtual register and
717 : // either GENERAL, FLOAT32, or DOUBLE type.
718 : virtual size_t numTemps() const = 0;
719 : virtual LDefinition* getTemp(size_t index) = 0;
720 : virtual void setTemp(size_t index, const LDefinition& a) = 0;
721 :
722 : // Returns the number of successors of this instruction, if it is a control
723 : // transfer instruction, or zero otherwise.
724 : virtual size_t numSuccessors() const = 0;
725 : virtual MBasicBlock* getSuccessor(size_t i) const = 0;
726 : virtual void setSuccessor(size_t i, MBasicBlock* successor) = 0;
727 :
728 19946 : virtual bool isCall() const {
729 19946 : return false;
730 : }
731 :
732 : // Does this call preserve the given register?
733 : // By default, it is assumed that all registers are clobbered by a call.
734 2205 : virtual bool isCallPreserved(AnyRegister reg) const {
735 2205 : return false;
736 : }
737 :
738 163689 : uint32_t id() const {
739 163689 : return id_;
740 : }
741 1534 : void setId(uint32_t id) {
742 1534 : MOZ_ASSERT(!id_);
743 1534 : MOZ_ASSERT(id);
744 1534 : id_ = id;
745 1534 : }
746 990 : void setMir(MDefinition* mir) {
747 990 : mir_ = mir;
748 990 : }
749 18130 : MDefinition* mirRaw() const {
750 : /* Untyped MIR for this op. Prefer mir() methods in subclasses. */
751 18130 : return mir_;
752 : }
753 4042 : LBlock* block() const {
754 4042 : return block_;
755 : }
756 1534 : void setBlock(LBlock* block) {
757 1534 : block_ = block;
758 1534 : }
759 :
760 : // For an instruction which has a MUST_REUSE_INPUT output, whether that
761 : // output register will be restored to its original value when bailing out.
762 879 : virtual bool recoversInput() const {
763 879 : return false;
764 : }
765 :
766 : virtual void dump(GenericPrinter& out);
767 : void dump();
768 : static void printName(GenericPrinter& out, Opcode op);
769 : virtual void printName(GenericPrinter& out);
770 : virtual void printOperands(GenericPrinter& out);
771 :
772 : public:
773 : // Opcode testing and casts.
774 : # define LIROP(name) \
775 : bool is##name() const { \
776 : return op() == LOp_##name; \
777 : } \
778 : inline L##name* to##name(); \
779 : inline const L##name* to##name() const;
780 156212 : LIR_OPCODE_LIST(LIROP)
781 : # undef LIROP
782 :
783 : virtual void accept(LElementVisitor* visitor) = 0;
784 :
785 : #define LIR_HEADER(opcode) \
786 : Opcode op() const { \
787 : return LInstruction::LOp_##opcode; \
788 : } \
789 : void accept(LElementVisitor* visitor) { \
790 : visitor->setElement(this); \
791 : visitor->visit##opcode(this); \
792 : }
793 : };
794 :
795 : class LInstruction
796 : : public LNode
797 : , public TempObject
798 : , public InlineListNode<LInstruction>
799 : {
800 : // This snapshot could be set after a ResumePoint. It is used to restart
801 : // from the resume point pc.
802 : LSnapshot* snapshot_;
803 :
804 : // Structure capturing the set of stack slots and registers which are known
805 : // to hold either gcthings or Values.
806 : LSafepoint* safepoint_;
807 :
808 : LMoveGroup* inputMoves_;
809 : LMoveGroup* fixReuseMoves_;
810 : LMoveGroup* movesAfter_;
811 :
812 : protected:
813 1788 : LInstruction()
814 1788 : : snapshot_(nullptr),
815 : safepoint_(nullptr),
816 : inputMoves_(nullptr),
817 : fixReuseMoves_(nullptr),
818 1788 : movesAfter_(nullptr)
819 1788 : { }
820 :
821 : public:
822 102750 : LSnapshot* snapshot() const {
823 102750 : return snapshot_;
824 : }
825 108860 : LSafepoint* safepoint() const {
826 108860 : return safepoint_;
827 : }
828 305 : LMoveGroup* inputMoves() const {
829 305 : return inputMoves_;
830 : }
831 283 : void setInputMoves(LMoveGroup* moves) {
832 283 : inputMoves_ = moves;
833 283 : }
834 294 : LMoveGroup* fixReuseMoves() const {
835 294 : return fixReuseMoves_;
836 : }
837 0 : void setFixReuseMoves(LMoveGroup* moves) {
838 0 : fixReuseMoves_ = moves;
839 0 : }
840 0 : LMoveGroup* movesAfter() const {
841 0 : return movesAfter_;
842 : }
843 0 : void setMovesAfter(LMoveGroup* moves) {
844 0 : movesAfter_ = moves;
845 0 : }
846 : void assignSnapshot(LSnapshot* snapshot);
847 : void initSafepoint(TempAllocator& alloc);
848 :
849 : class InputIterator;
850 : };
851 :
852 : LInstruction*
853 835 : LNode::toInstruction()
854 : {
855 835 : MOZ_ASSERT(isInstruction());
856 835 : return static_cast<LInstruction*>(this);
857 : }
858 :
859 : const LInstruction*
860 9093 : LNode::toInstruction() const
861 : {
862 9093 : MOZ_ASSERT(isInstruction());
863 9093 : return static_cast<const LInstruction*>(this);
864 : }
865 :
866 : class LElementVisitor
867 : {
868 : LNode* ins_;
869 :
870 : protected:
871 : jsbytecode* lastPC_;
872 : jsbytecode* lastNotInlinedPC_;
873 :
874 323 : LNode* instruction() {
875 323 : return ins_;
876 : }
877 :
878 : public:
879 3362 : void setElement(LNode* ins) {
880 3362 : ins_ = ins;
881 3362 : if (ins->mirRaw()) {
882 1630 : lastPC_ = ins->mirRaw()->trackedPc();
883 1630 : if (ins->mirRaw()->trackedTree())
884 1630 : lastNotInlinedPC_ = ins->mirRaw()->profilerLeavePc();
885 : }
886 3362 : }
887 :
888 8 : LElementVisitor()
889 8 : : ins_(nullptr),
890 : lastPC_(nullptr),
891 8 : lastNotInlinedPC_(nullptr)
892 8 : {}
893 :
894 : public:
895 : #define VISIT_INS(op) virtual void visit##op(L##op*) { MOZ_CRASH("NYI: " #op); }
896 0 : LIR_OPCODE_LIST(VISIT_INS)
897 : #undef VISIT_INS
898 : };
899 :
900 : typedef InlineList<LInstruction>::iterator LInstructionIterator;
901 : typedef InlineList<LInstruction>::reverse_iterator LInstructionReverseIterator;
902 :
903 : class MPhi;
904 :
905 : // Phi is a pseudo-instruction that emits no code, and is an annotation for the
906 : // register allocator. Like its equivalent in MIR, phis are collected at the
907 : // top of blocks and are meant to be executed in parallel, choosing the input
908 : // corresponding to the predecessor taken in the control flow graph.
909 : class LPhi final : public LNode
910 : {
911 : LAllocation* const inputs_;
912 : LDefinition def_;
913 :
914 : public:
915 216 : LIR_HEADER(Phi)
916 :
917 175 : LPhi(MPhi* ins, LAllocation* inputs)
918 175 : : inputs_(inputs)
919 : {
920 175 : setMir(ins);
921 175 : }
922 :
923 350 : size_t numDefs() const {
924 350 : return 1;
925 : }
926 1225 : LDefinition* getDef(size_t index) {
927 1225 : MOZ_ASSERT(index == 0);
928 1225 : return &def_;
929 : }
930 175 : void setDef(size_t index, const LDefinition& def) {
931 175 : MOZ_ASSERT(index == 0);
932 175 : def_ = def;
933 175 : }
934 2772 : size_t numOperands() const {
935 2772 : return mir_->toPhi()->numOperands();
936 : }
937 1720 : LAllocation* getOperand(size_t index) {
938 1720 : MOZ_ASSERT(index < numOperands());
939 1720 : return &inputs_[index];
940 : }
941 430 : void setOperand(size_t index, const LAllocation& a) {
942 430 : MOZ_ASSERT(index < numOperands());
943 430 : inputs_[index] = a;
944 430 : }
945 0 : size_t numTemps() const {
946 0 : return 0;
947 : }
948 0 : LDefinition* getTemp(size_t index) {
949 0 : MOZ_CRASH("no temps");
950 : }
951 0 : void setTemp(size_t index, const LDefinition& temp) {
952 0 : MOZ_CRASH("no temps");
953 : }
954 0 : size_t numSuccessors() const {
955 0 : return 0;
956 : }
957 0 : MBasicBlock* getSuccessor(size_t i) const {
958 0 : MOZ_CRASH("no successors");
959 : }
960 0 : void setSuccessor(size_t i, MBasicBlock*) {
961 0 : MOZ_CRASH("no successors");
962 : }
963 : };
964 :
965 : class LMoveGroup;
966 : class LBlock
967 : {
968 : MBasicBlock* block_;
969 : FixedList<LPhi> phis_;
970 : InlineList<LInstruction> instructions_;
971 : LMoveGroup* entryMoveGroup_;
972 : LMoveGroup* exitMoveGroup_;
973 : Label label_;
974 :
975 : public:
976 : explicit LBlock(MBasicBlock* block);
977 : MOZ_MUST_USE bool init(TempAllocator& alloc);
978 :
979 1359 : void add(LInstruction* ins) {
980 1359 : ins->setBlock(this);
981 1359 : instructions_.pushBack(ins);
982 1359 : }
983 18940 : size_t numPhis() const {
984 18940 : return phis_.length();
985 : }
986 6109 : LPhi* getPhi(size_t index) {
987 6109 : return &phis_[index];
988 : }
989 0 : const LPhi* getPhi(size_t index) const {
990 0 : return &phis_[index];
991 : }
992 114204 : MBasicBlock* mir() const {
993 114204 : return block_;
994 : }
995 4366 : LInstructionIterator begin() {
996 4366 : return instructions_.begin();
997 : }
998 : LInstructionIterator begin(LInstruction* at) {
999 : return instructions_.begin(at);
1000 : }
1001 11837 : LInstructionIterator end() {
1002 11837 : return instructions_.end();
1003 : }
1004 7666 : LInstructionReverseIterator rbegin() {
1005 7666 : return instructions_.rbegin();
1006 : }
1007 18956 : LInstructionReverseIterator rbegin(LInstruction* at) {
1008 18956 : return instructions_.rbegin(at);
1009 : }
1010 109733 : LInstructionReverseIterator rend() {
1011 109733 : return instructions_.rend();
1012 : }
1013 : InlineList<LInstruction>& instructions() {
1014 : return instructions_;
1015 : }
1016 0 : void insertAfter(LInstruction* at, LInstruction* ins) {
1017 0 : instructions_.insertAfter(at, ins);
1018 0 : }
1019 429 : void insertBefore(LInstruction* at, LInstruction* ins) {
1020 429 : instructions_.insertBefore(at, ins);
1021 429 : }
1022 0 : const LNode* firstElementWithId() const {
1023 0 : return !phis_.empty()
1024 0 : ? static_cast<const LNode*>(getPhi(0))
1025 0 : : firstInstructionWithId();
1026 : }
1027 0 : uint32_t firstId() const {
1028 0 : return firstElementWithId()->id();
1029 : }
1030 0 : uint32_t lastId() const {
1031 0 : return lastInstructionWithId()->id();
1032 : }
1033 : const LInstruction* firstInstructionWithId() const;
1034 403 : const LInstruction* lastInstructionWithId() const {
1035 403 : const LInstruction* last = *instructions_.rbegin();
1036 403 : MOZ_ASSERT(last->id());
1037 : // The last instruction is a control flow instruction which does not have
1038 : // any output.
1039 403 : MOZ_ASSERT(last->numDefs() == 0);
1040 403 : return last;
1041 : }
1042 :
1043 : // Return the label to branch to when branching to this block.
1044 506 : Label* label() {
1045 506 : MOZ_ASSERT(!isTrivial());
1046 506 : return &label_;
1047 : }
1048 :
1049 : LMoveGroup* getEntryMoveGroup(TempAllocator& alloc);
1050 : LMoveGroup* getExitMoveGroup(TempAllocator& alloc);
1051 :
1052 : // Test whether this basic block is empty except for a simple goto, and
1053 : // which is not forming a loop. No code will be emitted for such blocks.
1054 1911 : bool isTrivial() {
1055 1911 : return begin()->isGoto() && !mir()->isLoopHeader();
1056 : }
1057 :
1058 : void dump(GenericPrinter& out);
1059 : void dump();
1060 : };
1061 :
1062 : namespace details {
1063 : template <size_t Defs, size_t Temps>
1064 1788 : class LInstructionFixedDefsTempsHelper : public LInstruction
1065 : {
1066 : mozilla::Array<LDefinition, Defs> defs_;
1067 : mozilla::Array<LDefinition, Temps> temps_;
1068 :
1069 : public:
1070 158338 : size_t numDefs() const final override {
1071 158338 : return Defs;
1072 : }
1073 53089 : LDefinition* getDef(size_t index) final override {
1074 53089 : return &defs_[index];
1075 : }
1076 133866 : size_t numTemps() const final override {
1077 133866 : return Temps;
1078 : }
1079 28441 : LDefinition* getTemp(size_t index) final override {
1080 28441 : return &temps_[index];
1081 : }
1082 :
1083 573 : void setDef(size_t index, const LDefinition& def) final override {
1084 573 : defs_[index] = def;
1085 573 : }
1086 387 : void setTemp(size_t index, const LDefinition& a) final override {
1087 387 : temps_[index] = a;
1088 387 : }
1089 : void setInt64Temp(size_t index, const LInt64Definition& a) {
1090 : #if JS_BITS_PER_WORD == 32
1091 : temps_[index] = a.low();
1092 : temps_[index + 1] = a.high();
1093 : #else
1094 : temps_[index] = a.value();
1095 : #endif
1096 : }
1097 :
1098 0 : size_t numSuccessors() const override {
1099 0 : return 0;
1100 : }
1101 0 : MBasicBlock* getSuccessor(size_t i) const override {
1102 0 : MOZ_ASSERT(false);
1103 : return nullptr;
1104 : }
1105 0 : void setSuccessor(size_t i, MBasicBlock* successor) override {
1106 0 : MOZ_ASSERT(false);
1107 : }
1108 :
1109 : // Default accessors, assuming a single input and output, respectively.
1110 66 : const LAllocation* input() {
1111 66 : MOZ_ASSERT(numOperands() == 1);
1112 66 : return getOperand(0);
1113 : }
1114 288 : const LDefinition* output() {
1115 288 : MOZ_ASSERT(numDefs() == 1);
1116 288 : return getDef(0);
1117 : }
1118 : };
1119 : } // namespace details
1120 :
1121 : template <size_t Defs, size_t Operands, size_t Temps>
1122 1788 : class LInstructionHelper : public details::LInstructionFixedDefsTempsHelper<Defs, Temps>
1123 : {
1124 : mozilla::Array<LAllocation, Operands> operands_;
1125 :
1126 : public:
1127 22696 : size_t numOperands() const final override {
1128 22696 : return Operands;
1129 : }
1130 5666 : LAllocation* getOperand(size_t index) final override {
1131 5666 : return &operands_[index];
1132 : }
1133 727 : void setOperand(size_t index, const LAllocation& a) final override {
1134 727 : operands_[index] = a;
1135 727 : }
1136 160 : void setBoxOperand(size_t index, const LBoxAllocation& alloc) {
1137 : #ifdef JS_NUNBOX32
1138 : operands_[index + TYPE_INDEX] = alloc.type();
1139 : operands_[index + PAYLOAD_INDEX] = alloc.payload();
1140 : #else
1141 160 : operands_[index] = alloc.value();
1142 : #endif
1143 160 : }
1144 0 : void setInt64Operand(size_t index, const LInt64Allocation& alloc) {
1145 : #if JS_BITS_PER_WORD == 32
1146 : operands_[index + INT64LOW_INDEX] = alloc.low();
1147 : operands_[index + INT64HIGH_INDEX] = alloc.high();
1148 : #else
1149 0 : operands_[index] = alloc.value();
1150 : #endif
1151 0 : }
1152 0 : const LInt64Allocation getInt64Operand(size_t offset) {
1153 : #if JS_BITS_PER_WORD == 32
1154 : return LInt64Allocation(operands_[offset + INT64HIGH_INDEX],
1155 : operands_[offset + INT64LOW_INDEX]);
1156 : #else
1157 0 : return LInt64Allocation(operands_[offset]);
1158 : #endif
1159 : }
1160 : };
1161 :
1162 : template<size_t Defs, size_t Temps>
1163 0 : class LVariadicInstruction : public details::LInstructionFixedDefsTempsHelper<Defs, Temps>
1164 : {
1165 : FixedList<LAllocation> operands_;
1166 :
1167 : public:
1168 0 : MOZ_MUST_USE bool init(TempAllocator& alloc, size_t length) {
1169 0 : return operands_.init(alloc, length);
1170 : }
1171 0 : size_t numOperands() const final override {
1172 0 : return operands_.length();
1173 : }
1174 0 : LAllocation* getOperand(size_t index) final override {
1175 0 : return &operands_[index];
1176 : }
1177 0 : void setOperand(size_t index, const LAllocation& a) final override {
1178 0 : operands_[index] = a;
1179 0 : }
1180 : };
1181 :
1182 : template <size_t Defs, size_t Operands, size_t Temps>
1183 38 : class LCallInstructionHelper : public LInstructionHelper<Defs, Operands, Temps>
1184 : {
1185 : public:
1186 1920 : virtual bool isCall() const {
1187 1920 : return true;
1188 : }
1189 : };
1190 :
1191 : template <size_t Defs, size_t Temps>
1192 : class LBinaryCallInstructionHelper : public LCallInstructionHelper<Defs, 2, Temps>
1193 : {
1194 : public:
1195 : const LAllocation* lhs() {
1196 : return this->getOperand(0);
1197 : }
1198 : const LAllocation* rhs() {
1199 : return this->getOperand(1);
1200 : }
1201 : };
1202 :
1203 : class LRecoverInfo : public TempObject
1204 : {
1205 : public:
1206 : typedef Vector<MNode*, 2, JitAllocPolicy> Instructions;
1207 :
1208 : private:
1209 : // List of instructions needed to recover the stack frames.
1210 : // Outer frames are stored before inner frames.
1211 : Instructions instructions_;
1212 :
1213 : // Cached offset where this resume point is encoded.
1214 : RecoverOffset recoverOffset_;
1215 :
1216 : explicit LRecoverInfo(TempAllocator& alloc);
1217 : MOZ_MUST_USE bool init(MResumePoint* mir);
1218 :
1219 : // Fill the instruction vector such as all instructions needed for the
1220 : // recovery are pushed before the current instruction.
1221 : MOZ_MUST_USE bool appendOperands(MNode* ins);
1222 : MOZ_MUST_USE bool appendDefinition(MDefinition* def);
1223 : MOZ_MUST_USE bool appendResumePoint(MResumePoint* rp);
1224 : public:
1225 : static LRecoverInfo* New(MIRGenerator* gen, MResumePoint* mir);
1226 :
1227 : // Resume point of the inner most function.
1228 1213 : MResumePoint* mir() const {
1229 1213 : return instructions_.back()->toResumePoint();
1230 : }
1231 646 : RecoverOffset recoverOffset() const {
1232 646 : return recoverOffset_;
1233 : }
1234 174 : void setRecoverOffset(RecoverOffset offset) {
1235 174 : MOZ_ASSERT(recoverOffset_ == INVALID_RECOVER_OFFSET);
1236 174 : recoverOffset_ = offset;
1237 174 : }
1238 :
1239 1634 : MNode** begin() {
1240 1634 : return instructions_.begin();
1241 : }
1242 2043 : MNode** end() {
1243 2043 : return instructions_.end();
1244 : }
1245 174 : size_t numInstructions() const {
1246 174 : return instructions_.length();
1247 : }
1248 :
1249 : class OperandIter
1250 : {
1251 : private:
1252 : MNode** it_;
1253 : MNode** end_;
1254 : size_t op_;
1255 :
1256 : public:
1257 975 : explicit OperandIter(LRecoverInfo* recoverInfo)
1258 975 : : it_(recoverInfo->begin()), end_(recoverInfo->end()), op_(0)
1259 : {
1260 975 : settle();
1261 975 : }
1262 :
1263 21902 : void settle() {
1264 21902 : while ((*it_)->numOperands() == 0) {
1265 0 : ++it_;
1266 0 : op_ = 0;
1267 : }
1268 21902 : }
1269 :
1270 21902 : MDefinition* operator*() {
1271 21902 : return (*it_)->getOperand(op_);
1272 : }
1273 7321 : MDefinition* operator ->() {
1274 7321 : return (*it_)->getOperand(op_);
1275 : }
1276 :
1277 21902 : OperandIter& operator ++() {
1278 21902 : ++op_;
1279 21902 : if (op_ == (*it_)->numOperands()) {
1280 2043 : op_ = 0;
1281 2043 : ++it_;
1282 : }
1283 21902 : if (!*this)
1284 20927 : settle();
1285 :
1286 21902 : return *this;
1287 : }
1288 :
1289 44779 : explicit operator bool() const {
1290 44779 : return it_ == end_;
1291 : }
1292 :
1293 : #ifdef DEBUG
1294 : bool canOptimizeOutIfUnused();
1295 : #endif
1296 : };
1297 : };
1298 :
1299 : // An LSnapshot is the reflection of an MResumePoint in LIR. Unlike MResumePoints,
1300 : // they cannot be shared, as they are filled in by the register allocator in
1301 : // order to capture the precise low-level stack state in between an
1302 : // instruction's input and output. During code generation, LSnapshots are
1303 : // compressed and saved in the compiled script.
1304 : class LSnapshot : public TempObject
1305 : {
1306 : private:
1307 : uint32_t numSlots_;
1308 : LAllocation* slots_;
1309 : LRecoverInfo* recoverInfo_;
1310 : SnapshotOffset snapshotOffset_;
1311 : BailoutId bailoutId_;
1312 : BailoutKind bailoutKind_;
1313 :
1314 : LSnapshot(LRecoverInfo* recover, BailoutKind kind);
1315 : MOZ_MUST_USE bool init(MIRGenerator* gen);
1316 :
1317 : public:
1318 : static LSnapshot* New(MIRGenerator* gen, LRecoverInfo* recover, BailoutKind kind);
1319 :
1320 57440 : size_t numEntries() const {
1321 57440 : return numSlots_;
1322 : }
1323 5919 : size_t numSlots() const {
1324 5919 : return numSlots_ / BOX_PIECES;
1325 : }
1326 5596 : LAllocation* payloadOfSlot(size_t i) {
1327 5596 : MOZ_ASSERT(i < numSlots());
1328 5596 : size_t entryIndex = (i * BOX_PIECES) + (BOX_PIECES - 1);
1329 5596 : return getEntry(entryIndex);
1330 : }
1331 : #ifdef JS_NUNBOX32
1332 : LAllocation* typeOfSlot(size_t i) {
1333 : MOZ_ASSERT(i < numSlots());
1334 : size_t entryIndex = (i * BOX_PIECES) + (BOX_PIECES - 2);
1335 : return getEntry(entryIndex);
1336 : }
1337 : #endif
1338 44116 : LAllocation* getEntry(size_t i) {
1339 44116 : MOZ_ASSERT(i < numSlots_);
1340 44116 : return &slots_[i];
1341 : }
1342 1 : void setEntry(size_t i, const LAllocation& alloc) {
1343 1 : MOZ_ASSERT(i < numSlots_);
1344 1 : slots_[i] = alloc;
1345 1 : }
1346 1001 : LRecoverInfo* recoverInfo() const {
1347 1001 : return recoverInfo_;
1348 : }
1349 370 : MResumePoint* mir() const {
1350 370 : return recoverInfo()->mir();
1351 : }
1352 1008 : SnapshotOffset snapshotOffset() const {
1353 1008 : return snapshotOffset_;
1354 : }
1355 0 : BailoutId bailoutId() const {
1356 0 : return bailoutId_;
1357 : }
1358 323 : void setSnapshotOffset(SnapshotOffset offset) {
1359 323 : MOZ_ASSERT(snapshotOffset_ == INVALID_SNAPSHOT_OFFSET);
1360 323 : snapshotOffset_ = offset;
1361 323 : }
1362 0 : void setBailoutId(BailoutId id) {
1363 0 : MOZ_ASSERT(bailoutId_ == INVALID_BAILOUT_ID);
1364 0 : bailoutId_ = id;
1365 0 : }
1366 323 : BailoutKind bailoutKind() const {
1367 323 : return bailoutKind_;
1368 : }
1369 : void rewriteRecoveredInput(LUse input);
1370 : };
1371 :
1372 : struct SafepointSlotEntry {
1373 : // Flag indicating whether this is a slot in the stack or argument space.
1374 : uint32_t stack:1;
1375 :
1376 : // Byte offset of the slot, as in LStackSlot or LArgument.
1377 : uint32_t slot:31;
1378 :
1379 0 : SafepointSlotEntry() { }
1380 1397 : SafepointSlotEntry(bool stack, uint32_t slot)
1381 1397 : : stack(stack), slot(slot)
1382 1397 : { }
1383 : explicit SafepointSlotEntry(const LAllocation* a)
1384 : : stack(a->isStackSlot()), slot(a->memorySlot())
1385 : { }
1386 : };
1387 :
1388 : struct SafepointNunboxEntry {
1389 : uint32_t typeVreg;
1390 : LAllocation type;
1391 : LAllocation payload;
1392 :
1393 : SafepointNunboxEntry() { }
1394 : SafepointNunboxEntry(uint32_t typeVreg, LAllocation type, LAllocation payload)
1395 : : typeVreg(typeVreg), type(type), payload(payload)
1396 : { }
1397 : };
1398 :
1399 : class LSafepoint : public TempObject
1400 : {
1401 : typedef SafepointSlotEntry SlotEntry;
1402 : typedef SafepointNunboxEntry NunboxEntry;
1403 :
1404 : public:
1405 : typedef Vector<SlotEntry, 0, JitAllocPolicy> SlotList;
1406 : typedef Vector<NunboxEntry, 0, JitAllocPolicy> NunboxList;
1407 :
1408 : private:
1409 : // The information in a safepoint describes the registers and gc related
1410 : // values that are live at the start of the associated instruction.
1411 :
1412 : // The set of registers which are live at an OOL call made within the
1413 : // instruction. This includes any registers for inputs which are not
1414 : // use-at-start, any registers for temps, and any registers live after the
1415 : // call except outputs of the instruction.
1416 : //
1417 : // For call instructions, the live regs are empty. Call instructions may
1418 : // have register inputs or temporaries, which will *not* be in the live
1419 : // registers: if passed to the call, the values passed will be marked via
1420 : // MarkJitExitFrame, and no registers can be live after the instruction
1421 : // except its outputs.
1422 : LiveRegisterSet liveRegs_;
1423 :
1424 : // The subset of liveRegs which contains gcthing pointers.
1425 : LiveGeneralRegisterSet gcRegs_;
1426 :
1427 : #ifdef CHECK_OSIPOINT_REGISTERS
1428 : // Clobbered regs of the current instruction. This set is never written to
1429 : // the safepoint; it's only used by assertions during compilation.
1430 : LiveRegisterSet clobberedRegs_;
1431 : #endif
1432 :
1433 : // Offset to a position in the safepoint stream, or
1434 : // INVALID_SAFEPOINT_OFFSET.
1435 : uint32_t safepointOffset_;
1436 :
1437 : // Assembler buffer displacement to OSI point's call location.
1438 : uint32_t osiCallPointOffset_;
1439 :
1440 : // List of slots which have gcthing pointers.
1441 : SlotList gcSlots_;
1442 :
1443 : // List of slots which have Values.
1444 : SlotList valueSlots_;
1445 :
1446 : #ifdef JS_NUNBOX32
1447 : // List of registers (in liveRegs) and slots which contain pieces of Values.
1448 : NunboxList nunboxParts_;
1449 : #elif JS_PUNBOX64
1450 : // The subset of liveRegs which have Values.
1451 : LiveGeneralRegisterSet valueRegs_;
1452 : #endif
1453 :
1454 : // The subset of liveRegs which contains pointers to slots/elements.
1455 : LiveGeneralRegisterSet slotsOrElementsRegs_;
1456 :
1457 : // List of slots which have slots/elements pointers.
1458 : SlotList slotsOrElementsSlots_;
1459 :
1460 : public:
1461 2384 : void assertInvariants() {
1462 : // Every register in valueRegs and gcRegs should also be in liveRegs.
1463 : #ifndef JS_NUNBOX32
1464 2384 : MOZ_ASSERT((valueRegs().bits() & ~liveRegs().gprs().bits()) == 0);
1465 : #endif
1466 2384 : MOZ_ASSERT((gcRegs().bits() & ~liveRegs().gprs().bits()) == 0);
1467 2384 : }
1468 :
1469 134 : explicit LSafepoint(TempAllocator& alloc)
1470 134 : : safepointOffset_(INVALID_SAFEPOINT_OFFSET)
1471 : , osiCallPointOffset_(0)
1472 : , gcSlots_(alloc)
1473 : , valueSlots_(alloc)
1474 : #ifdef JS_NUNBOX32
1475 : , nunboxParts_(alloc)
1476 : #endif
1477 134 : , slotsOrElementsSlots_(alloc)
1478 : {
1479 134 : assertInvariants();
1480 134 : }
1481 321 : void addLiveRegister(AnyRegister reg) {
1482 321 : liveRegs_.addUnchecked(reg);
1483 321 : assertInvariants();
1484 321 : }
1485 5544 : const LiveRegisterSet& liveRegs() const {
1486 5544 : return liveRegs_;
1487 : }
1488 : #ifdef CHECK_OSIPOINT_REGISTERS
1489 206 : void addClobberedRegister(AnyRegister reg) {
1490 206 : clobberedRegs_.addUnchecked(reg);
1491 206 : assertInvariants();
1492 206 : }
1493 0 : const LiveRegisterSet& clobberedRegs() const {
1494 0 : return clobberedRegs_;
1495 : }
1496 : #endif
1497 149 : void addGcRegister(Register reg) {
1498 149 : gcRegs_.addUnchecked(reg);
1499 149 : assertInvariants();
1500 149 : }
1501 2604 : LiveGeneralRegisterSet gcRegs() const {
1502 2604 : return gcRegs_;
1503 : }
1504 857 : MOZ_MUST_USE bool addGcSlot(bool stack, uint32_t slot) {
1505 857 : bool result = gcSlots_.append(SlotEntry(stack, slot));
1506 857 : if (result)
1507 857 : assertInvariants();
1508 857 : return result;
1509 : }
1510 39 : SlotList& gcSlots() {
1511 39 : return gcSlots_;
1512 : }
1513 :
1514 39 : SlotList& slotsOrElementsSlots() {
1515 39 : return slotsOrElementsSlots_;
1516 : }
1517 40 : LiveGeneralRegisterSet slotsOrElementsRegs() const {
1518 40 : return slotsOrElementsRegs_;
1519 : }
1520 1 : void addSlotsOrElementsRegister(Register reg) {
1521 1 : slotsOrElementsRegs_.addUnchecked(reg);
1522 1 : assertInvariants();
1523 1 : }
1524 0 : MOZ_MUST_USE bool addSlotsOrElementsSlot(bool stack, uint32_t slot) {
1525 0 : bool result = slotsOrElementsSlots_.append(SlotEntry(stack, slot));
1526 0 : if (result)
1527 0 : assertInvariants();
1528 0 : return result;
1529 : }
1530 1 : MOZ_MUST_USE bool addSlotsOrElementsPointer(LAllocation alloc) {
1531 1 : if (alloc.isMemory())
1532 0 : return addSlotsOrElementsSlot(alloc.isStackSlot(), alloc.memorySlot());
1533 1 : MOZ_ASSERT(alloc.isRegister());
1534 1 : addSlotsOrElementsRegister(alloc.toRegister().gpr());
1535 1 : assertInvariants();
1536 1 : return true;
1537 : }
1538 1 : bool hasSlotsOrElementsPointer(LAllocation alloc) const {
1539 1 : if (alloc.isRegister())
1540 1 : return slotsOrElementsRegs().has(alloc.toRegister().gpr());
1541 0 : for (size_t i = 0; i < slotsOrElementsSlots_.length(); i++) {
1542 0 : const SlotEntry& entry = slotsOrElementsSlots_[i];
1543 0 : if (entry.stack == alloc.isStackSlot() && entry.slot == alloc.memorySlot())
1544 0 : return true;
1545 : }
1546 0 : return false;
1547 : }
1548 :
1549 1006 : MOZ_MUST_USE bool addGcPointer(LAllocation alloc) {
1550 1006 : if (alloc.isMemory())
1551 857 : return addGcSlot(alloc.isStackSlot(), alloc.memorySlot());
1552 149 : if (alloc.isRegister())
1553 149 : addGcRegister(alloc.toRegister().gpr());
1554 149 : assertInvariants();
1555 149 : return true;
1556 : }
1557 :
1558 3527 : bool hasGcPointer(LAllocation alloc) const {
1559 3527 : if (alloc.isRegister())
1560 181 : return gcRegs().has(alloc.toRegister().gpr());
1561 3346 : MOZ_ASSERT(alloc.isMemory());
1562 15650 : for (size_t i = 0; i < gcSlots_.length(); i++) {
1563 15650 : if (gcSlots_[i].stack == alloc.isStackSlot() && gcSlots_[i].slot == alloc.memorySlot())
1564 3346 : return true;
1565 : }
1566 0 : return false;
1567 : }
1568 :
1569 540 : MOZ_MUST_USE bool addValueSlot(bool stack, uint32_t slot) {
1570 540 : bool result = valueSlots_.append(SlotEntry(stack, slot));
1571 540 : if (result)
1572 540 : assertInvariants();
1573 540 : return result;
1574 : }
1575 39 : SlotList& valueSlots() {
1576 39 : return valueSlots_;
1577 : }
1578 :
1579 2416 : bool hasValueSlot(bool stack, uint32_t slot) const {
1580 9214 : for (size_t i = 0; i < valueSlots_.length(); i++) {
1581 8674 : if (valueSlots_[i].stack == stack && valueSlots_[i].slot == slot)
1582 1876 : return true;
1583 : }
1584 540 : return false;
1585 : }
1586 :
1587 : #ifdef JS_NUNBOX32
1588 :
1589 : MOZ_MUST_USE bool addNunboxParts(uint32_t typeVreg, LAllocation type, LAllocation payload) {
1590 : bool result = nunboxParts_.append(NunboxEntry(typeVreg, type, payload));
1591 : if (result)
1592 : assertInvariants();
1593 : return result;
1594 : }
1595 :
1596 : MOZ_MUST_USE bool addNunboxType(uint32_t typeVreg, LAllocation type) {
1597 : for (size_t i = 0; i < nunboxParts_.length(); i++) {
1598 : if (nunboxParts_[i].type == type)
1599 : return true;
1600 : if (nunboxParts_[i].type == LUse(typeVreg, LUse::ANY)) {
1601 : nunboxParts_[i].type = type;
1602 : return true;
1603 : }
1604 : }
1605 :
1606 : // vregs for nunbox pairs are adjacent, with the type coming first.
1607 : uint32_t payloadVreg = typeVreg + 1;
1608 : bool result = nunboxParts_.append(NunboxEntry(typeVreg, type, LUse(payloadVreg, LUse::ANY)));
1609 : if (result)
1610 : assertInvariants();
1611 : return result;
1612 : }
1613 :
1614 : MOZ_MUST_USE bool addNunboxPayload(uint32_t payloadVreg, LAllocation payload) {
1615 : for (size_t i = 0; i < nunboxParts_.length(); i++) {
1616 : if (nunboxParts_[i].payload == payload)
1617 : return true;
1618 : if (nunboxParts_[i].payload == LUse(payloadVreg, LUse::ANY)) {
1619 : nunboxParts_[i].payload = payload;
1620 : return true;
1621 : }
1622 : }
1623 :
1624 : // vregs for nunbox pairs are adjacent, with the type coming first.
1625 : uint32_t typeVreg = payloadVreg - 1;
1626 : bool result = nunboxParts_.append(NunboxEntry(typeVreg, LUse(typeVreg, LUse::ANY), payload));
1627 : if (result)
1628 : assertInvariants();
1629 : return result;
1630 : }
1631 :
1632 : LAllocation findTypeAllocation(uint32_t typeVreg) {
1633 : // Look for some allocation for the specified type vreg, to go with a
1634 : // partial nunbox entry for the payload. Note that we don't need to
1635 : // look at the value slots in the safepoint, as these aren't used by
1636 : // register allocators which add partial nunbox entries.
1637 : for (size_t i = 0; i < nunboxParts_.length(); i++) {
1638 : if (nunboxParts_[i].typeVreg == typeVreg && !nunboxParts_[i].type.isUse())
1639 : return nunboxParts_[i].type;
1640 : }
1641 : return LUse(typeVreg, LUse::ANY);
1642 : }
1643 :
1644 : #ifdef DEBUG
1645 : bool hasNunboxPayload(LAllocation payload) const {
1646 : if (payload.isMemory() && hasValueSlot(payload.isStackSlot(), payload.memorySlot()))
1647 : return true;
1648 : for (size_t i = 0; i < nunboxParts_.length(); i++) {
1649 : if (nunboxParts_[i].payload == payload)
1650 : return true;
1651 : }
1652 : return false;
1653 : }
1654 : #endif
1655 :
1656 : NunboxList& nunboxParts() {
1657 : return nunboxParts_;
1658 : }
1659 :
1660 : #elif JS_PUNBOX64
1661 :
1662 26 : void addValueRegister(Register reg) {
1663 26 : valueRegs_.add(reg);
1664 26 : assertInvariants();
1665 26 : }
1666 2471 : LiveGeneralRegisterSet valueRegs() const {
1667 2471 : return valueRegs_;
1668 : }
1669 :
1670 566 : MOZ_MUST_USE bool addBoxedValue(LAllocation alloc) {
1671 566 : if (alloc.isRegister()) {
1672 26 : Register reg = alloc.toRegister().gpr();
1673 26 : if (!valueRegs().has(reg))
1674 26 : addValueRegister(reg);
1675 26 : return true;
1676 : }
1677 540 : if (hasValueSlot(alloc.isStackSlot(), alloc.memorySlot()))
1678 0 : return true;
1679 540 : return addValueSlot(alloc.isStackSlot(), alloc.memorySlot());
1680 : }
1681 :
1682 1911 : bool hasBoxedValue(LAllocation alloc) const {
1683 1911 : if (alloc.isRegister())
1684 35 : return valueRegs().has(alloc.toRegister().gpr());
1685 1876 : return hasValueSlot(alloc.isStackSlot(), alloc.memorySlot());
1686 : }
1687 :
1688 : #endif // JS_PUNBOX64
1689 :
1690 86 : bool encoded() const {
1691 86 : return safepointOffset_ != INVALID_SAFEPOINT_OFFSET;
1692 : }
1693 43 : uint32_t offset() const {
1694 43 : MOZ_ASSERT(encoded());
1695 43 : return safepointOffset_;
1696 : }
1697 39 : void setOffset(uint32_t offset) {
1698 39 : safepointOffset_ = offset;
1699 39 : }
1700 : uint32_t osiReturnPointOffset() const {
1701 : // In general, pointer arithmetic on code is bad, but in this case,
1702 : // getting the return address from a call instruction, stepping over pools
1703 : // would be wrong.
1704 : return osiCallPointOffset_ + Assembler::PatchWrite_NearCallSize();
1705 : }
1706 212 : uint32_t osiCallPointOffset() const {
1707 212 : return osiCallPointOffset_;
1708 : }
1709 134 : void setOsiCallPointOffset(uint32_t osiCallPointOffset) {
1710 134 : MOZ_ASSERT(!osiCallPointOffset_);
1711 134 : osiCallPointOffset_ = osiCallPointOffset;
1712 134 : }
1713 : };
1714 :
1715 : class LInstruction::InputIterator
1716 : {
1717 : private:
1718 : LInstruction& ins_;
1719 : size_t idx_;
1720 : bool snapshot_;
1721 :
1722 38170 : void handleOperandsEnd() {
1723 : // Iterate on the snapshot when iteration over all operands is done.
1724 38170 : if (!snapshot_ && idx_ == ins_.numOperands() && ins_.snapshot()) {
1725 1304 : idx_ = 0;
1726 1304 : snapshot_ = true;
1727 : }
1728 38170 : }
1729 :
1730 : public:
1731 6420 : explicit InputIterator(LInstruction& ins) :
1732 : ins_(ins),
1733 : idx_(0),
1734 6420 : snapshot_(false)
1735 : {
1736 6420 : handleOperandsEnd();
1737 6420 : }
1738 :
1739 69920 : bool more() const {
1740 69920 : if (snapshot_)
1741 57408 : return idx_ < ins_.snapshot()->numEntries();
1742 12512 : if (idx_ < ins_.numOperands())
1743 7396 : return true;
1744 5116 : if (ins_.snapshot() && ins_.snapshot()->numEntries())
1745 0 : return true;
1746 5116 : return false;
1747 : }
1748 :
1749 33 : bool isSnapshotInput() const {
1750 33 : return snapshot_;
1751 : }
1752 :
1753 31750 : void next() {
1754 31750 : MOZ_ASSERT(more());
1755 31750 : idx_++;
1756 31750 : handleOperandsEnd();
1757 31750 : }
1758 :
1759 0 : void replace(const LAllocation& alloc) {
1760 0 : if (snapshot_)
1761 0 : ins_.snapshot()->setEntry(idx_, alloc);
1762 : else
1763 0 : ins_.setOperand(idx_, alloc);
1764 0 : }
1765 :
1766 36052 : LAllocation* operator*() const {
1767 36052 : if (snapshot_)
1768 31468 : return ins_.snapshot()->getEntry(idx_);
1769 4584 : return ins_.getOperand(idx_);
1770 : }
1771 :
1772 22071 : LAllocation* operator ->() const {
1773 22071 : return **this;
1774 : }
1775 : };
1776 :
1777 : class LIRGraph
1778 : {
1779 : struct ValueHasher
1780 : {
1781 : typedef Value Lookup;
1782 766 : static HashNumber hash(const Value& v) {
1783 766 : return HashNumber(v.asRawBits());
1784 : }
1785 755 : static bool match(const Value& lhs, const Value& rhs) {
1786 755 : return lhs == rhs;
1787 : }
1788 : };
1789 :
1790 : FixedList<LBlock> blocks_;
1791 : Vector<Value, 0, JitAllocPolicy> constantPool_;
1792 : typedef HashMap<Value, uint32_t, ValueHasher, JitAllocPolicy> ConstantPoolMap;
1793 : ConstantPoolMap constantPoolMap_;
1794 : Vector<LInstruction*, 0, JitAllocPolicy> safepoints_;
1795 : Vector<LInstruction*, 0, JitAllocPolicy> nonCallSafepoints_;
1796 : uint32_t numVirtualRegisters_;
1797 : uint32_t numInstructions_;
1798 :
1799 : // Number of stack slots needed for local spills.
1800 : uint32_t localSlotCount_;
1801 : // Number of stack slots needed for argument construction for calls.
1802 : uint32_t argumentSlotCount_;
1803 :
1804 : // Snapshot taken before any LIR has been lowered.
1805 : LSnapshot* entrySnapshot_;
1806 :
1807 : MIRGraph& mir_;
1808 :
1809 : public:
1810 : explicit LIRGraph(MIRGraph* mir);
1811 :
1812 8 : MOZ_MUST_USE bool init() {
1813 8 : return constantPoolMap_.init() && blocks_.init(mir_.alloc(), mir_.numBlocks());
1814 : }
1815 2825 : MIRGraph& mir() const {
1816 2825 : return mir_;
1817 : }
1818 13311 : size_t numBlocks() const {
1819 13311 : return blocks_.length();
1820 : }
1821 15857 : LBlock* getBlock(size_t i) {
1822 15857 : return &blocks_[i];
1823 : }
1824 16 : uint32_t numBlockIds() const {
1825 16 : return mir_.numBlockIds();
1826 : }
1827 403 : MOZ_MUST_USE bool initBlock(MBasicBlock* mir) {
1828 403 : auto* block = &blocks_[mir->id()];
1829 403 : auto* lir = new (block) LBlock(mir);
1830 403 : return lir->init(mir_.alloc());
1831 : }
1832 1062 : uint32_t getVirtualRegister() {
1833 1062 : numVirtualRegisters_ += VREG_INCREMENT;
1834 1062 : return numVirtualRegisters_;
1835 : }
1836 8980 : uint32_t numVirtualRegisters() const {
1837 : // Virtual registers are 1-based, not 0-based, so add one as a
1838 : // convenience for 0-based arrays.
1839 8980 : return numVirtualRegisters_ + 1;
1840 : }
1841 1534 : uint32_t getInstructionId() {
1842 1534 : return numInstructions_++;
1843 : }
1844 16 : uint32_t numInstructions() const {
1845 16 : return numInstructions_;
1846 : }
1847 8 : void setLocalSlotCount(uint32_t localSlotCount) {
1848 8 : localSlotCount_ = localSlotCount;
1849 8 : }
1850 658 : uint32_t localSlotCount() const {
1851 658 : return localSlotCount_;
1852 : }
1853 : // Return the localSlotCount() value rounded up so that it satisfies the
1854 : // platform stack alignment requirement, and so that it's a multiple of
1855 : // the number of slots per Value.
1856 119 : uint32_t paddedLocalSlotCount() const {
1857 : // Round to JitStackAlignment, and implicitly to sizeof(Value) as
1858 : // JitStackAlignment is a multiple of sizeof(Value). These alignments
1859 : // are needed for spilling SIMD registers properly, and for
1860 : // StackOffsetOfPassedArg which rounds argument slots to 8-byte
1861 : // boundaries.
1862 119 : return AlignBytes(localSlotCount(), JitStackAlignment);
1863 : }
1864 106 : size_t paddedLocalSlotsSize() const {
1865 106 : return paddedLocalSlotCount();
1866 : }
1867 8 : void setArgumentSlotCount(uint32_t argumentSlotCount) {
1868 8 : argumentSlotCount_ = argumentSlotCount;
1869 8 : }
1870 190 : uint32_t argumentSlotCount() const {
1871 190 : return argumentSlotCount_;
1872 : }
1873 21 : size_t argumentsSize() const {
1874 21 : return argumentSlotCount() * sizeof(Value);
1875 : }
1876 13 : uint32_t totalSlotCount() const {
1877 13 : return paddedLocalSlotCount() + argumentsSize();
1878 : }
1879 : MOZ_MUST_USE bool addConstantToPool(const Value& v, uint32_t* index);
1880 28 : size_t numConstants() const {
1881 28 : return constantPool_.length();
1882 : }
1883 3 : Value* constantPool() {
1884 3 : return &constantPool_[0];
1885 : }
1886 8 : void setEntrySnapshot(LSnapshot* snapshot) {
1887 8 : MOZ_ASSERT(!entrySnapshot_);
1888 8 : entrySnapshot_ = snapshot;
1889 8 : }
1890 8 : LSnapshot* entrySnapshot() const {
1891 8 : MOZ_ASSERT(entrySnapshot_);
1892 8 : return entrySnapshot_;
1893 : }
1894 : bool noteNeedsSafepoint(LInstruction* ins);
1895 14939 : size_t numNonCallSafepoints() const {
1896 14939 : return nonCallSafepoints_.length();
1897 : }
1898 14783 : LInstruction* getNonCallSafepoint(size_t i) const {
1899 14783 : return nonCallSafepoints_[i];
1900 : }
1901 10789 : size_t numSafepoints() const {
1902 10789 : return safepoints_.length();
1903 : }
1904 10182 : LInstruction* getSafepoint(size_t i) const {
1905 10182 : return safepoints_[i];
1906 : }
1907 :
1908 : void dump(GenericPrinter& out);
1909 : void dump();
1910 : };
1911 :
1912 3349 : LAllocation::LAllocation(AnyRegister reg)
1913 : {
1914 3349 : if (reg.isFloat())
1915 1706 : *this = LFloatReg(reg.fpu());
1916 : else
1917 1643 : *this = LGeneralReg(reg.gpr());
1918 3349 : }
1919 :
1920 : AnyRegister
1921 9310 : LAllocation::toRegister() const
1922 : {
1923 9310 : MOZ_ASSERT(isRegister());
1924 9310 : if (isFloatReg())
1925 25 : return AnyRegister(toFloatReg()->reg());
1926 9285 : return AnyRegister(toGeneralReg()->reg());
1927 : }
1928 :
1929 : } // namespace jit
1930 : } // namespace js
1931 :
1932 : #include "jit/shared/LIR-shared.h"
1933 : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
1934 : # if defined(JS_CODEGEN_X86)
1935 : # include "jit/x86/LIR-x86.h"
1936 : # elif defined(JS_CODEGEN_X64)
1937 : # include "jit/x64/LIR-x64.h"
1938 : # endif
1939 : # include "jit/x86-shared/LIR-x86-shared.h"
1940 : #elif defined(JS_CODEGEN_ARM)
1941 : # include "jit/arm/LIR-arm.h"
1942 : #elif defined(JS_CODEGEN_ARM64)
1943 : # include "jit/arm64/LIR-arm64.h"
1944 : #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
1945 : # if defined(JS_CODEGEN_MIPS32)
1946 : # include "jit/mips32/LIR-mips32.h"
1947 : # elif defined(JS_CODEGEN_MIPS64)
1948 : # include "jit/mips64/LIR-mips64.h"
1949 : # endif
1950 : # include "jit/mips-shared/LIR-mips-shared.h"
1951 : #elif defined(JS_CODEGEN_NONE)
1952 : # include "jit/none/LIR-none.h"
1953 : #else
1954 : # error "Unknown architecture!"
1955 : #endif
1956 :
1957 : #undef LIR_HEADER
1958 :
1959 : namespace js {
1960 : namespace jit {
1961 :
1962 : #define LIROP(name) \
1963 : L##name* LNode::to##name() \
1964 : { \
1965 : MOZ_ASSERT(is##name()); \
1966 : return static_cast<L##name*>(this); \
1967 : } \
1968 : const L##name* LNode::to##name() const \
1969 : { \
1970 : MOZ_ASSERT(is##name()); \
1971 : return static_cast<const L##name*>(this); \
1972 : }
1973 29851 : LIR_OPCODE_LIST(LIROP)
1974 : #undef LIROP
1975 :
1976 : #define LALLOC_CAST(type) \
1977 : L##type* LAllocation::to##type() { \
1978 : MOZ_ASSERT(is##type()); \
1979 : return static_cast<L##type*>(this); \
1980 : }
1981 : #define LALLOC_CONST_CAST(type) \
1982 : const L##type* LAllocation::to##type() const { \
1983 : MOZ_ASSERT(is##type()); \
1984 : return static_cast<const L##type*>(this); \
1985 : }
1986 :
1987 13169 : LALLOC_CAST(Use)
1988 14047 : LALLOC_CONST_CAST(Use)
1989 12753 : LALLOC_CONST_CAST(GeneralReg)
1990 74 : LALLOC_CONST_CAST(FloatReg)
1991 27896 : LALLOC_CONST_CAST(StackSlot)
1992 738 : LALLOC_CONST_CAST(Argument)
1993 69 : LALLOC_CONST_CAST(ConstantIndex)
1994 :
1995 : #undef LALLOC_CAST
1996 :
1997 : #ifdef JS_NUNBOX32
1998 : static inline signed
1999 : OffsetToOtherHalfOfNunbox(LDefinition::Type type)
2000 : {
2001 : MOZ_ASSERT(type == LDefinition::TYPE || type == LDefinition::PAYLOAD);
2002 : signed offset = (type == LDefinition::TYPE)
2003 : ? PAYLOAD_INDEX - TYPE_INDEX
2004 : : TYPE_INDEX - PAYLOAD_INDEX;
2005 : return offset;
2006 : }
2007 :
2008 : static inline void
2009 : AssertTypesFormANunbox(LDefinition::Type type1, LDefinition::Type type2)
2010 : {
2011 : MOZ_ASSERT((type1 == LDefinition::TYPE && type2 == LDefinition::PAYLOAD) ||
2012 : (type2 == LDefinition::TYPE && type1 == LDefinition::PAYLOAD));
2013 : }
2014 :
2015 : static inline unsigned
2016 : OffsetOfNunboxSlot(LDefinition::Type type)
2017 : {
2018 : if (type == LDefinition::PAYLOAD)
2019 : return NUNBOX32_PAYLOAD_OFFSET;
2020 : return NUNBOX32_TYPE_OFFSET;
2021 : }
2022 :
2023 : // Note that stack indexes for LStackSlot are modelled backwards, so a
2024 : // double-sized slot starting at 2 has its next word at 1, *not* 3.
2025 : static inline unsigned
2026 : BaseOfNunboxSlot(LDefinition::Type type, unsigned slot)
2027 : {
2028 : if (type == LDefinition::PAYLOAD)
2029 : return slot + NUNBOX32_PAYLOAD_OFFSET;
2030 : return slot + NUNBOX32_TYPE_OFFSET;
2031 : }
2032 : #endif
2033 :
2034 : } // namespace jit
2035 : } // namespace js
2036 :
2037 : #endif /* jit_LIR_h */
|