Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/js/src/jit/x64/MacroAssembler-x64.h
Line
Count
Source (jump to first uncovered line)
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_x64_MacroAssembler_x64_h
8
#define jit_x64_MacroAssembler_x64_h
9
10
#include "jit/JitFrames.h"
11
#include "jit/MoveResolver.h"
12
#include "jit/x86-shared/MacroAssembler-x86-shared.h"
13
#include "js/HeapAPI.h"
14
15
namespace js {
16
namespace jit {
17
18
struct ImmShiftedTag : public ImmWord
19
{
20
    explicit ImmShiftedTag(JSValueShiftedTag shtag)
21
      : ImmWord((uintptr_t)shtag)
22
165
    { }
23
24
    explicit ImmShiftedTag(JSValueType type)
25
      : ImmWord(uintptr_t(JSValueShiftedTag(JSVAL_TYPE_TO_SHIFTED_TAG(type))))
26
46
    { }
27
};
28
29
struct ImmTag : public Imm32
30
{
31
    explicit ImmTag(JSValueTag tag)
32
      : Imm32(tag)
33
288
    { }
34
};
35
36
// ScratchTagScope and ScratchTagScopeRelease are used to manage the tag
37
// register for splitTagForTest(), which has different register management on
38
// different platforms.  On 64-bit platforms it requires a scratch register that
39
// does not interfere with other operations; on 32-bit platforms it uses a
40
// register that is already part of the Value.
41
//
42
// The ScratchTagScope RAII type acquires the appropriate register; a reference
43
// to a variable of this type is then passed to splitTagForTest().
44
//
45
// On 64-bit platforms ScratchTagScopeRelease makes the owned scratch register
46
// available in a dynamic scope during compilation.  However it is important to
47
// remember that that does not preserve the register value in any way, so this
48
// RAII type should only be used along paths that eventually branch past further
49
// uses of the extracted tag value.
50
//
51
// On 32-bit platforms ScratchTagScopeRelease has no effect, since it does not
52
// manage a register, it only aliases a register in the ValueOperand.
53
54
class ScratchTagScope : public ScratchRegisterScope
55
{
56
  public:
57
    ScratchTagScope(MacroAssembler& masm, const ValueOperand&)
58
      : ScratchRegisterScope(masm)
59
1
    {}
60
};
61
62
class ScratchTagScopeRelease
63
{
64
    ScratchTagScope* ts_;
65
  public:
66
0
    explicit ScratchTagScopeRelease(ScratchTagScope* ts) : ts_(ts) {
67
0
        ts_->release();
68
0
    }
69
0
    ~ScratchTagScopeRelease() {
70
0
        ts_->reacquire();
71
0
    }
72
};
73
74
class MacroAssemblerX64 : public MacroAssemblerX86Shared
75
{
76
  private:
77
    // Perform a downcast. Should be removed by Bug 996602.
78
    MacroAssembler& asMasm();
79
    const MacroAssembler& asMasm() const;
80
81
    void bindOffsets(const MacroAssemblerX86Shared::UsesVector&);
82
83
  public:
84
    using MacroAssemblerX86Shared::load32;
85
    using MacroAssemblerX86Shared::store32;
86
    using MacroAssemblerX86Shared::store16;
87
88
    MacroAssemblerX64()
89
141
    {
90
141
    }
91
92
    // The buffer is about to be linked, make sure any constant pools or excess
93
    // bookkeeping has been flushed to the instruction stream.
94
    void finish();
95
96
    /////////////////////////////////////////////////////////////////
97
    // X64 helpers.
98
    /////////////////////////////////////////////////////////////////
99
160
    void writeDataRelocation(const Value& val) {
100
160
        if (val.isGCThing()) {
101
79
            gc::Cell* cell = val.toGCThing();
102
79
            if (cell && gc::IsInsideNursery(cell)) {
103
0
                embedsNurseryPointers_ = true;
104
0
            }
105
79
            dataRelocations_.writeUnsigned(masm.currentOffset());
106
79
        }
107
160
    }
108
109
    // Refers to the upper 32 bits of a 64-bit Value operand.
110
    // On x86_64, the upper 32 bits do not necessarily only contain the type.
111
0
    Operand ToUpper32(Operand base) {
112
0
        switch (base.kind()) {
113
0
          case Operand::MEM_REG_DISP:
114
0
            return Operand(Register::FromCode(base.base()), base.disp() + 4);
115
0
116
0
          case Operand::MEM_SCALE:
117
0
            return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()),
118
0
                           base.scale(), base.disp() + 4);
119
0
120
0
          default:
121
0
            MOZ_CRASH("unexpected operand kind");
122
0
        }
123
0
    }
124
0
    static inline Operand ToUpper32(const Address& address) {
125
0
        return Operand(address.base, address.offset + 4);
126
0
    }
127
0
    static inline Operand ToUpper32(const BaseIndex& address) {
128
0
        return Operand(address.base, address.index, address.scale, address.offset + 4);
129
0
    }
130
131
0
    uint32_t Upper32Of(JSValueShiftedTag tag) {
132
0
        union { // Implemented in this way to appease MSVC++.
133
0
            uint64_t tag;
134
0
            struct {
135
0
                uint32_t lo32;
136
0
                uint32_t hi32;
137
0
            } s;
138
0
        } e;
139
0
        e.tag = tag;
140
0
        return e.s.hi32;
141
0
    }
142
143
0
    JSValueShiftedTag GetShiftedTag(JSValueType type) {
144
0
        return (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type);
145
0
    }
146
147
    /////////////////////////////////////////////////////////////////
148
    // X86/X64-common interface.
149
    /////////////////////////////////////////////////////////////////
150
0
    Address ToPayload(Address value) {
151
0
        return value;
152
0
    }
153
154
61
    void storeValue(ValueOperand val, Operand dest) {
155
61
        movq(val.valueReg(), dest);
156
61
    }
157
54
    void storeValue(ValueOperand val, const Address& dest) {
158
54
        storeValue(val, Operand(dest));
159
54
    }
160
    template <typename T>
161
98
    void storeValue(JSValueType type, Register reg, const T& dest) {
162
98
        // Value types with 32-bit payloads can be emitted as two 32-bit moves.
163
98
        if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
164
0
            movl(reg, Operand(dest));
165
0
            movl(Imm32(Upper32Of(GetShiftedTag(type))), ToUpper32(Operand(dest)));
166
98
        } else {
167
98
            ScratchRegisterScope scratch(asMasm());
168
98
#ifdef NIGHTLY_BUILD
169
98
            // Bug 1485209 - Diagnostic assert for constructing Values with
170
98
            // nullptr or misaligned (eg poisoned) JSObject/JSString pointers.
171
98
            if (type == JSVAL_TYPE_OBJECT || type == JSVAL_TYPE_STRING) {
172
98
                Label crash, ok;
173
98
                testPtr(reg, Imm32(js::gc::CellAlignMask));
174
98
                j(Assembler::NonZero, &crash);
175
98
                testPtr(reg, reg);
176
98
                j(Assembler::NonZero, &ok);
177
98
                bind(&crash);
178
98
                breakpoint();
179
98
                bind(&ok);
180
98
            }
181
98
#endif
182
98
            boxValue(type, reg, scratch);
183
98
            movq(scratch, Operand(dest));
184
98
        }
185
98
    }
Unexecuted instantiation: void js::jit::MacroAssemblerX64::storeValue<js::jit::BaseObjectElementIndex>(JSValueType, js::jit::Register, js::jit::BaseObjectElementIndex const&)
void js::jit::MacroAssemblerX64::storeValue<js::jit::Address>(JSValueType, js::jit::Register, js::jit::Address const&)
Line
Count
Source
161
98
    void storeValue(JSValueType type, Register reg, const T& dest) {
162
98
        // Value types with 32-bit payloads can be emitted as two 32-bit moves.
163
98
        if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
164
0
            movl(reg, Operand(dest));
165
0
            movl(Imm32(Upper32Of(GetShiftedTag(type))), ToUpper32(Operand(dest)));
166
98
        } else {
167
98
            ScratchRegisterScope scratch(asMasm());
168
98
#ifdef NIGHTLY_BUILD
169
98
            // Bug 1485209 - Diagnostic assert for constructing Values with
170
98
            // nullptr or misaligned (eg poisoned) JSObject/JSString pointers.
171
98
            if (type == JSVAL_TYPE_OBJECT || type == JSVAL_TYPE_STRING) {
172
98
                Label crash, ok;
173
98
                testPtr(reg, Imm32(js::gc::CellAlignMask));
174
98
                j(Assembler::NonZero, &crash);
175
98
                testPtr(reg, reg);
176
98
                j(Assembler::NonZero, &ok);
177
98
                bind(&crash);
178
98
                breakpoint();
179
98
                bind(&ok);
180
98
            }
181
98
#endif
182
98
            boxValue(type, reg, scratch);
183
98
            movq(scratch, Operand(dest));
184
98
        }
185
98
    }
186
    template <typename T>
187
14
    void storeValue(const Value& val, const T& dest) {
188
14
        ScratchRegisterScope scratch(asMasm());
189
14
        if (val.isGCThing()) {
190
0
            movWithPatch(ImmWord(val.asRawBits()), scratch);
191
0
            writeDataRelocation(val);
192
14
        } else {
193
14
            mov(ImmWord(val.asRawBits()), scratch);
194
14
        }
195
14
        movq(scratch, Operand(dest));
196
14
    }
void js::jit::MacroAssemblerX64::storeValue<js::jit::Address>(JS::Value const&, js::jit::Address const&)
Line
Count
Source
187
14
    void storeValue(const Value& val, const T& dest) {
188
14
        ScratchRegisterScope scratch(asMasm());
189
14
        if (val.isGCThing()) {
190
0
            movWithPatch(ImmWord(val.asRawBits()), scratch);
191
0
            writeDataRelocation(val);
192
14
        } else {
193
14
            mov(ImmWord(val.asRawBits()), scratch);
194
14
        }
195
14
        movq(scratch, Operand(dest));
196
14
    }
Unexecuted instantiation: void js::jit::MacroAssemblerX64::storeValue<js::jit::BaseObjectElementIndex>(JS::Value const&, js::jit::BaseObjectElementIndex const&)
197
4
    void storeValue(ValueOperand val, BaseIndex dest) {
198
4
        storeValue(val, Operand(dest));
199
4
    }
200
0
    void storeValue(const Address& src, const Address& dest, Register temp) {
201
0
        loadPtr(src, temp);
202
0
        storePtr(temp, dest);
203
0
    }
204
275
    void loadValue(Operand src, ValueOperand val) {
205
275
        movq(src, val.valueReg());
206
275
    }
207
264
    void loadValue(Address src, ValueOperand val) {
208
264
        loadValue(Operand(src), val);
209
264
    }
210
11
    void loadValue(const BaseIndex& src, ValueOperand val) {
211
11
        loadValue(Operand(src), val);
212
11
    }
213
46
    void tagValue(JSValueType type, Register payload, ValueOperand dest) {
214
46
        ScratchRegisterScope scratch(asMasm());
215
46
        MOZ_ASSERT(dest.valueReg() != scratch);
216
46
        if (payload != dest.valueReg()) {
217
13
            movq(payload, dest.valueReg());
218
13
        }
219
46
        mov(ImmShiftedTag(type), scratch);
220
46
        orq(scratch, dest.valueReg());
221
46
    }
222
289
    void pushValue(ValueOperand val) {
223
289
        push(val.valueReg());
224
289
    }
225
325
    void popValue(ValueOperand val) {
226
325
        pop(val.valueReg());
227
325
    }
228
381
    void pushValue(const Value& val) {
229
381
        if (val.isGCThing()) {
230
68
            ScratchRegisterScope scratch(asMasm());
231
68
            movWithPatch(ImmWord(val.asRawBits()), scratch);
232
68
            writeDataRelocation(val);
233
68
            push(scratch);
234
313
        } else {
235
313
            push(ImmWord(val.asRawBits()));
236
313
        }
237
381
    }
238
53
    void pushValue(JSValueType type, Register reg) {
239
53
        ScratchRegisterScope scratch(asMasm());
240
53
        boxValue(type, reg, scratch);
241
53
        push(scratch);
242
53
    }
243
85
    void pushValue(const Address& addr) {
244
85
        push(Operand(addr));
245
85
    }
246
247
    void boxValue(JSValueType type, Register src, Register dest);
248
249
6
    Condition testUndefined(Condition cond, Register tag) {
250
6
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
251
6
        cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED));
252
6
        return cond;
253
6
    }
254
14
    Condition testInt32(Condition cond, Register tag) {
255
14
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
256
14
        cmp32(tag, ImmTag(JSVAL_TAG_INT32));
257
14
        return cond;
258
14
    }
259
40
    Condition testBoolean(Condition cond, Register tag) {
260
40
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
261
40
        cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN));
262
40
        return cond;
263
40
    }
264
3
    Condition testNull(Condition cond, Register tag) {
265
3
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
266
3
        cmp32(tag, ImmTag(JSVAL_TAG_NULL));
267
3
        return cond;
268
3
    }
269
58
    Condition testString(Condition cond, Register tag) {
270
58
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
271
58
        cmp32(tag, ImmTag(JSVAL_TAG_STRING));
272
58
        return cond;
273
58
    }
274
1
    Condition testSymbol(Condition cond, Register tag) {
275
1
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
276
1
        cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
277
1
        return cond;
278
1
    }
279
164
    Condition testObject(Condition cond, Register tag) {
280
164
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
281
164
        cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
282
164
        return cond;
283
164
    }
284
2
    Condition testDouble(Condition cond, Register tag) {
285
2
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
286
2
        cmp32(tag, Imm32(JSVAL_TAG_MAX_DOUBLE));
287
2
        return cond == Equal ? BelowOrEqual : Above;
288
2
    }
289
2
    Condition testNumber(Condition cond, Register tag) {
290
2
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
291
2
        cmp32(tag, Imm32(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET));
292
2
        return cond == Equal ? BelowOrEqual : Above;
293
2
    }
294
2
    Condition testGCThing(Condition cond, Register tag) {
295
2
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
296
2
        cmp32(tag, Imm32(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
297
2
        return cond == Equal ? AboveOrEqual : Below;
298
2
    }
299
300
2
    Condition testMagic(Condition cond, Register tag) {
301
2
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
302
2
        cmp32(tag, ImmTag(JSVAL_TAG_MAGIC));
303
2
        return cond;
304
2
    }
305
0
    Condition testError(Condition cond, Register tag) {
306
0
        return testMagic(cond, tag);
307
0
    }
308
0
    Condition testPrimitive(Condition cond, Register tag) {
309
0
        MOZ_ASSERT(cond == Equal || cond == NotEqual);
310
0
        cmp32(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET));
311
0
        return cond == Equal ? Below : AboveOrEqual;
312
0
    }
313
314
6
    Condition testUndefined(Condition cond, const ValueOperand& src) {
315
6
        ScratchRegisterScope scratch(asMasm());
316
6
        splitTag(src, scratch);
317
6
        return testUndefined(cond, scratch);
318
6
    }
319
14
    Condition testInt32(Condition cond, const ValueOperand& src) {
320
14
        ScratchRegisterScope scratch(asMasm());
321
14
        splitTag(src, scratch);
322
14
        return testInt32(cond, scratch);
323
14
    }
324
40
    Condition testBoolean(Condition cond, const ValueOperand& src) {
325
40
        ScratchRegisterScope scratch(asMasm());
326
40
        splitTag(src, scratch);
327
40
        return testBoolean(cond, scratch);
328
40
    }
329
2
    Condition testDouble(Condition cond, const ValueOperand& src) {
330
2
        ScratchRegisterScope scratch(asMasm());
331
2
        splitTag(src, scratch);
332
2
        return testDouble(cond, scratch);
333
2
    }
334
0
    Condition testNumber(Condition cond, const ValueOperand& src) {
335
0
        ScratchRegisterScope scratch(asMasm());
336
0
        splitTag(src, scratch);
337
0
        return testNumber(cond, scratch);
338
0
    }
339
3
    Condition testNull(Condition cond, const ValueOperand& src) {
340
3
        ScratchRegisterScope scratch(asMasm());
341
3
        splitTag(src, scratch);
342
3
        return testNull(cond, scratch);
343
3
    }
344
27
    Condition testString(Condition cond, const ValueOperand& src) {
345
27
        ScratchRegisterScope scratch(asMasm());
346
27
        splitTag(src, scratch);
347
27
        return testString(cond, scratch);
348
27
    }
349
1
    Condition testSymbol(Condition cond, const ValueOperand& src) {
350
1
        ScratchRegisterScope scratch(asMasm());
351
1
        splitTag(src, scratch);
352
1
        return testSymbol(cond, scratch);
353
1
    }
354
133
    Condition testObject(Condition cond, const ValueOperand& src) {
355
133
        ScratchRegisterScope scratch(asMasm());
356
133
        splitTag(src, scratch);
357
133
        return testObject(cond, scratch);
358
133
    }
359
0
    Condition testGCThing(Condition cond, const ValueOperand& src) {
360
0
        ScratchRegisterScope scratch(asMasm());
361
0
        splitTag(src, scratch);
362
0
        return testGCThing(cond, scratch);
363
0
    }
364
0
    Condition testPrimitive(Condition cond, const ValueOperand& src) {
365
0
        ScratchRegisterScope scratch(asMasm());
366
0
        splitTag(src, scratch);
367
0
        return testPrimitive(cond, scratch);
368
0
    }
369
370
371
0
    Condition testUndefined(Condition cond, const Address& src) {
372
0
        cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED))));
373
0
        return cond;
374
0
    }
375
0
    Condition testInt32(Condition cond, const Address& src) {
376
0
        cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32))));
377
0
        return cond;
378
0
    }
379
0
    Condition testBoolean(Condition cond, const Address& src) {
380
0
        cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_BOOLEAN))));
381
0
        return cond;
382
0
    }
383
0
    Condition testDouble(Condition cond, const Address& src) {
384
0
        ScratchRegisterScope scratch(asMasm());
385
0
        splitTag(src, scratch);
386
0
        return testDouble(cond, scratch);
387
0
    }
388
0
    Condition testNumber(Condition cond, const Address& src) {
389
0
        ScratchRegisterScope scratch(asMasm());
390
0
        splitTag(src, scratch);
391
0
        return testNumber(cond, scratch);
392
0
    }
393
0
    Condition testNull(Condition cond, const Address& src) {
394
0
        cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL))));
395
0
        return cond;
396
0
    }
397
0
    Condition testString(Condition cond, const Address& src) {
398
0
        ScratchRegisterScope scratch(asMasm());
399
0
        splitTag(src, scratch);
400
0
        return testString(cond, scratch);
401
0
    }
402
0
    Condition testSymbol(Condition cond, const Address& src) {
403
0
        ScratchRegisterScope scratch(asMasm());
404
0
        splitTag(src, scratch);
405
0
        return testSymbol(cond, scratch);
406
0
    }
407
0
    Condition testObject(Condition cond, const Address& src) {
408
0
        ScratchRegisterScope scratch(asMasm());
409
0
        splitTag(src, scratch);
410
0
        return testObject(cond, scratch);
411
0
    }
412
0
    Condition testPrimitive(Condition cond, const Address& src) {
413
0
        ScratchRegisterScope scratch(asMasm());
414
0
        splitTag(src, scratch);
415
0
        return testPrimitive(cond, scratch);
416
0
    }
417
1
    Condition testGCThing(Condition cond, const Address& src) {
418
1
        ScratchRegisterScope scratch(asMasm());
419
1
        splitTag(src, scratch);
420
1
        return testGCThing(cond, scratch);
421
1
    }
422
0
    Condition testMagic(Condition cond, const Address& src) {
423
0
        ScratchRegisterScope scratch(asMasm());
424
0
        splitTag(src, scratch);
425
0
        return testMagic(cond, scratch);
426
0
    }
427
428
429
0
    Condition testUndefined(Condition cond, const BaseIndex& src) {
430
0
        ScratchRegisterScope scratch(asMasm());
431
0
        splitTag(src, scratch);
432
0
        return testUndefined(cond, scratch);
433
0
    }
434
0
    Condition testNull(Condition cond, const BaseIndex& src) {
435
0
        ScratchRegisterScope scratch(asMasm());
436
0
        splitTag(src, scratch);
437
0
        return testNull(cond, scratch);
438
0
    }
439
0
    Condition testBoolean(Condition cond, const BaseIndex& src) {
440
0
        ScratchRegisterScope scratch(asMasm());
441
0
        splitTag(src, scratch);
442
0
        return testBoolean(cond, scratch);
443
0
    }
444
0
    Condition testString(Condition cond, const BaseIndex& src) {
445
0
        ScratchRegisterScope scratch(asMasm());
446
0
        splitTag(src, scratch);
447
0
        return testString(cond, scratch);
448
0
    }
449
0
    Condition testSymbol(Condition cond, const BaseIndex& src) {
450
0
        ScratchRegisterScope scratch(asMasm());
451
0
        splitTag(src, scratch);
452
0
        return testSymbol(cond, scratch);
453
0
    }
454
0
    Condition testInt32(Condition cond, const BaseIndex& src) {
455
0
        ScratchRegisterScope scratch(asMasm());
456
0
        splitTag(src, scratch);
457
0
        return testInt32(cond, scratch);
458
0
    }
459
0
    Condition testObject(Condition cond, const BaseIndex& src) {
460
0
        ScratchRegisterScope scratch(asMasm());
461
0
        splitTag(src, scratch);
462
0
        return testObject(cond, scratch);
463
0
    }
464
0
    Condition testDouble(Condition cond, const BaseIndex& src) {
465
0
        ScratchRegisterScope scratch(asMasm());
466
0
        splitTag(src, scratch);
467
0
        return testDouble(cond, scratch);
468
0
    }
469
1
    Condition testMagic(Condition cond, const BaseIndex& src) {
470
1
        ScratchRegisterScope scratch(asMasm());
471
1
        splitTag(src, scratch);
472
1
        return testMagic(cond, scratch);
473
1
    }
474
1
    Condition testGCThing(Condition cond, const BaseIndex& src) {
475
1
        ScratchRegisterScope scratch(asMasm());
476
1
        splitTag(src, scratch);
477
1
        return testGCThing(cond, scratch);
478
1
    }
479
480
0
    Condition isMagic(Condition cond, const ValueOperand& src, JSWhyMagic why) {
481
0
        uint64_t magic = MagicValue(why).asRawBits();
482
0
        cmpPtr(src.valueReg(), ImmWord(magic));
483
0
        return cond;
484
0
    }
485
486
0
    void cmpPtr(Register lhs, const ImmWord rhs) {
487
0
        ScratchRegisterScope scratch(asMasm());
488
0
        MOZ_ASSERT(lhs != scratch);
489
0
        if (intptr_t(rhs.value) <= INT32_MAX && intptr_t(rhs.value) >= INT32_MIN) {
490
0
            cmpPtr(lhs, Imm32(int32_t(rhs.value)));
491
0
        } else {
492
0
            movePtr(rhs, scratch);
493
0
            cmpPtr(lhs, scratch);
494
0
        }
495
0
    }
496
0
    void cmpPtr(Register lhs, const ImmPtr rhs) {
497
0
        cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
498
0
    }
499
0
    void cmpPtr(Register lhs, const ImmGCPtr rhs) {
500
0
        ScratchRegisterScope scratch(asMasm());
501
0
        MOZ_ASSERT(lhs != scratch);
502
0
        movePtr(rhs, scratch);
503
0
        cmpPtr(lhs, scratch);
504
0
    }
505
0
    void cmpPtr(Register lhs, const Imm32 rhs) {
506
0
        cmpq(rhs, lhs);
507
0
    }
508
107
    void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) {
509
107
        ScratchRegisterScope scratch(asMasm());
510
107
        MOZ_ASSERT(!lhs.containsReg(scratch));
511
107
        movePtr(rhs, scratch);
512
107
        cmpPtr(lhs, scratch);
513
107
    }
514
73
    void cmpPtr(const Operand& lhs, const ImmWord rhs) {
515
73
        if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) {
516
24
            cmpPtr(lhs, Imm32((int32_t)rhs.value));
517
49
        } else {
518
49
            ScratchRegisterScope scratch(asMasm());
519
49
            movePtr(rhs, scratch);
520
49
            cmpPtr(lhs, scratch);
521
49
        }
522
73
    }
523
68
    void cmpPtr(const Operand& lhs, const ImmPtr rhs) {
524
68
        cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
525
68
    }
526
0
    void cmpPtr(const Address& lhs, const ImmGCPtr rhs) {
527
0
        cmpPtr(Operand(lhs), rhs);
528
0
    }
529
0
    void cmpPtr(const Address& lhs, const ImmWord rhs) {
530
0
        cmpPtr(Operand(lhs), rhs);
531
0
    }
532
0
    void cmpPtr(const Address& lhs, const ImmPtr rhs) {
533
0
        cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
534
0
    }
535
222
    void cmpPtr(const Operand& lhs, Register rhs) {
536
222
        cmpq(rhs, lhs);
537
222
    }
538
0
    void cmpPtr(Register lhs, const Operand& rhs) {
539
0
        cmpq(rhs, lhs);
540
0
    }
541
24
    void cmpPtr(const Operand& lhs, const Imm32 rhs) {
542
24
        cmpq(rhs, lhs);
543
24
    }
544
0
    void cmpPtr(const Address& lhs, Register rhs) {
545
0
        cmpPtr(Operand(lhs), rhs);
546
0
    }
547
7
    void cmpPtr(Register lhs, Register rhs) {
548
7
        cmpq(rhs, lhs);
549
7
    }
550
278
    void testPtr(Register lhs, Register rhs) {
551
278
        testq(rhs, lhs);
552
278
    }
553
100
    void testPtr(Register lhs, Imm32 rhs) {
554
100
        testq(rhs, lhs);
555
100
    }
556
0
    void testPtr(const Operand& lhs, Imm32 rhs) {
557
0
        testq(rhs, lhs);
558
0
    }
559
560
    /////////////////////////////////////////////////////////////////
561
    // Common interface.
562
    /////////////////////////////////////////////////////////////////
563
564
37
    CodeOffsetJump jumpWithPatch(RepatchLabel* label) {
565
37
        JmpSrc src = jmpSrc(label);
566
37
        return CodeOffsetJump(size(), addPatchableJump(src, RelocationKind::HARDCODED));
567
37
    }
568
569
191
    void movePtr(Register src, Register dest) {
570
191
        movq(src, dest);
571
191
    }
572
0
    void movePtr(Register src, const Operand& dest) {
573
0
        movq(src, dest);
574
0
    }
575
84
    void movePtr(ImmWord imm, Register dest) {
576
84
        mov(imm, dest);
577
84
    }
578
861
    void movePtr(ImmPtr imm, Register dest) {
579
861
        mov(imm, dest);
580
861
    }
581
0
    void movePtr(wasm::SymbolicAddress imm, Register dest) {
582
0
        mov(imm, dest);
583
0
    }
584
127
    void movePtr(ImmGCPtr imm, Register dest) {
585
127
        movq(imm, dest);
586
127
    }
587
75
    void loadPtr(AbsoluteAddress address, Register dest) {
588
75
        if (X86Encoding::IsAddressImmediate(address.addr)) {
589
0
            movq(Operand(address), dest);
590
75
        } else {
591
75
            ScratchRegisterScope scratch(asMasm());
592
75
            mov(ImmPtr(address.addr), scratch);
593
75
            loadPtr(Address(scratch, 0x0), dest);
594
75
        }
595
75
    }
596
2.68k
    void loadPtr(const Address& address, Register dest) {
597
2.68k
        movq(Operand(address), dest);
598
2.68k
    }
599
0
    void load64(const Address& address, Register dest) {
600
0
        movq(Operand(address), dest);
601
0
    }
602
0
    void loadPtr(const Operand& src, Register dest) {
603
0
        movq(src, dest);
604
0
    }
605
28
    void loadPtr(const BaseIndex& src, Register dest) {
606
28
        movq(Operand(src), dest);
607
28
    }
608
0
    void loadPrivate(const Address& src, Register dest) {
609
0
        loadPtr(src, dest);
610
0
        shlq(Imm32(1), dest);
611
0
    }
612
0
    void load32(AbsoluteAddress address, Register dest) {
613
0
        if (X86Encoding::IsAddressImmediate(address.addr)) {
614
0
            movl(Operand(address), dest);
615
0
        } else {
616
0
            ScratchRegisterScope scratch(asMasm());
617
0
            mov(ImmPtr(address.addr), scratch);
618
0
            load32(Address(scratch, 0x0), dest);
619
0
        }
620
0
    }
621
0
    void load64(const Address& address, Register64 dest) {
622
0
        movq(Operand(address), dest.reg);
623
0
    }
624
    template <typename T>
625
35
    void storePtr(ImmWord imm, T address) {
626
35
        if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) {
627
34
            movq(Imm32((int32_t)imm.value), Operand(address));
628
34
        } else {
629
1
            ScratchRegisterScope scratch(asMasm());
630
1
            mov(imm, scratch);
631
1
            movq(scratch, Operand(address));
632
1
        }
633
35
    }
void js::jit::MacroAssemblerX64::storePtr<js::jit::Address>(js::jit::ImmWord, js::jit::Address)
Line
Count
Source
625
35
    void storePtr(ImmWord imm, T address) {
626
35
        if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) {
627
34
            movq(Imm32((int32_t)imm.value), Operand(address));
628
34
        } else {
629
1
            ScratchRegisterScope scratch(asMasm());
630
1
            mov(imm, scratch);
631
1
            movq(scratch, Operand(address));
632
1
        }
633
35
    }
Unexecuted instantiation: void js::jit::MacroAssemblerX64::storePtr<js::jit::BaseIndex>(js::jit::ImmWord, js::jit::BaseIndex)
634
    template <typename T>
635
34
    void storePtr(ImmPtr imm, T address) {
636
34
        storePtr(ImmWord(uintptr_t(imm.value)), address);
637
34
    }
638
    template <typename T>
639
3
    void storePtr(ImmGCPtr imm, T address) {
640
3
        ScratchRegisterScope scratch(asMasm());
641
3
        movq(imm, scratch);
642
3
        movq(scratch, Operand(address));
643
3
    }
void js::jit::MacroAssemblerX64::storePtr<js::jit::Address>(js::jit::ImmGCPtr, js::jit::Address)
Line
Count
Source
639
3
    void storePtr(ImmGCPtr imm, T address) {
640
3
        ScratchRegisterScope scratch(asMasm());
641
3
        movq(imm, scratch);
642
3
        movq(scratch, Operand(address));
643
3
    }
Unexecuted instantiation: void js::jit::MacroAssemblerX64::storePtr<js::jit::BaseIndex>(js::jit::ImmGCPtr, js::jit::BaseIndex)
644
892
    void storePtr(Register src, const Address& address) {
645
892
        movq(src, Operand(address));
646
892
    }
647
0
    void store64(Register src, const Address& address) {
648
0
        movq(src, Operand(address));
649
0
    }
650
1
    void storePtr(Register src, const BaseIndex& address) {
651
1
        movq(src, Operand(address));
652
1
    }
653
0
    void storePtr(Register src, const Operand& dest) {
654
0
        movq(src, dest);
655
0
    }
656
84
    void storePtr(Register src, AbsoluteAddress address) {
657
84
        if (X86Encoding::IsAddressImmediate(address.addr)) {
658
0
            movq(src, Operand(address));
659
84
        } else {
660
84
            ScratchRegisterScope scratch(asMasm());
661
84
            mov(ImmPtr(address.addr), scratch);
662
84
            storePtr(src, Address(scratch, 0x0));
663
84
        }
664
84
    }
665
0
    void store32(Register src, AbsoluteAddress address) {
666
0
        if (X86Encoding::IsAddressImmediate(address.addr)) {
667
0
            movl(src, Operand(address));
668
0
        } else {
669
0
            ScratchRegisterScope scratch(asMasm());
670
0
            mov(ImmPtr(address.addr), scratch);
671
0
            store32(src, Address(scratch, 0x0));
672
0
        }
673
0
    }
674
0
    void store16(Register src, AbsoluteAddress address) {
675
0
        if (X86Encoding::IsAddressImmediate(address.addr)) {
676
0
            movw(src, Operand(address));
677
0
        } else {
678
0
            ScratchRegisterScope scratch(asMasm());
679
0
            mov(ImmPtr(address.addr), scratch);
680
0
            store16(src, Address(scratch, 0x0));
681
0
        }
682
0
    }
683
0
    void store64(Register64 src, Address address) {
684
0
        storePtr(src.reg, address);
685
0
    }
686
0
    void store64(Imm64 imm, Address address) {
687
0
        storePtr(ImmWord(imm.value), address);
688
0
    }
689
690
288
    void splitTag(Register src, Register dest) {
691
288
        if (src != dest) {
692
232
            movq(src, dest);
693
232
        }
694
288
        shrq(Imm32(JSVAL_TAG_SHIFT), dest);
695
288
    }
696
232
    void splitTag(const ValueOperand& operand, Register dest) {
697
232
        splitTag(operand.valueReg(), dest);
698
232
    }
699
3
    void splitTag(const Operand& operand, Register dest) {
700
3
        movq(operand, dest);
701
3
        shrq(Imm32(JSVAL_TAG_SHIFT), dest);
702
3
    }
703
1
    void splitTag(const Address& operand, Register dest) {
704
1
        splitTag(Operand(operand), dest);
705
1
    }
706
2
    void splitTag(const BaseIndex& operand, Register dest) {
707
2
        splitTag(Operand(operand), dest);
708
2
    }
709
710
    // Extracts the tag of a value and places it in tag.
711
1
    void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) {
712
1
        splitTag(value, tag);
713
1
    }
714
0
    void cmpTag(const ValueOperand& operand, ImmTag tag) {
715
0
        ScratchTagScope reg(asMasm(), operand);
716
0
        splitTagForTest(operand, reg);
717
0
        cmp32(reg, tag);
718
0
    }
719
720
1
    Condition testMagic(Condition cond, const ValueOperand& src) {
721
1
        ScratchTagScope scratch(asMasm(), src);
722
1
        splitTagForTest(src, scratch);
723
1
        return testMagic(cond, scratch);
724
1
    }
725
0
    Condition testError(Condition cond, const ValueOperand& src) {
726
0
        return testMagic(cond, src);
727
0
    }
728
729
0
    void testNullSet(Condition cond, const ValueOperand& value, Register dest) {
730
0
        cond = testNull(cond, value);
731
0
        emitSet(cond, dest);
732
0
    }
733
734
0
    void testObjectSet(Condition cond, const ValueOperand& value, Register dest) {
735
0
        cond = testObject(cond, value);
736
0
        emitSet(cond, dest);
737
0
    }
738
739
0
    void testUndefinedSet(Condition cond, const ValueOperand& value, Register dest) {
740
0
        cond = testUndefined(cond, value);
741
0
        emitSet(cond, dest);
742
0
    }
743
744
0
    void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister) {
745
0
        vmovq(src, dest.valueReg());
746
0
    }
747
0
    void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) {
748
0
        MOZ_ASSERT(src != dest.valueReg());
749
0
        boxValue(type, src, dest.valueReg());
750
0
    }
751
752
    // Note that the |dest| register here may be ScratchReg, so we shouldn't
753
    // use it.
754
12
    void unboxInt32(const ValueOperand& src, Register dest) {
755
12
        movl(src.valueReg(), dest);
756
12
    }
757
3
    void unboxInt32(const Operand& src, Register dest) {
758
3
        movl(src, dest);
759
3
    }
760
0
    void unboxInt32(const Address& src, Register dest) {
761
0
        unboxInt32(Operand(src), dest);
762
0
    }
763
0
    void unboxDouble(const Address& src, FloatRegister dest) {
764
0
        loadDouble(Operand(src), dest);
765
0
    }
766
767
0
    void unboxArgObjMagic(const ValueOperand& src, Register dest) {
768
0
        unboxArgObjMagic(Operand(src.valueReg()), dest);
769
0
    }
770
0
    void unboxArgObjMagic(const Operand& src, Register dest) {
771
0
        mov(ImmWord(0), dest);
772
0
    }
773
0
    void unboxArgObjMagic(const Address& src, Register dest) {
774
0
        unboxArgObjMagic(Operand(src), dest);
775
0
    }
776
777
0
    void unboxBoolean(const ValueOperand& src, Register dest) {
778
0
        movl(src.valueReg(), dest);
779
0
    }
780
0
    void unboxBoolean(const Operand& src, Register dest) {
781
0
        movl(src, dest);
782
0
    }
783
0
    void unboxBoolean(const Address& src, Register dest) {
784
0
        unboxBoolean(Operand(src), dest);
785
0
    }
786
787
0
    void unboxMagic(const ValueOperand& src, Register dest) {
788
0
        movl(src.valueReg(), dest);
789
0
    }
790
791
2
    void unboxDouble(const ValueOperand& src, FloatRegister dest) {
792
2
        vmovq(src.valueReg(), dest);
793
2
    }
794
0
    void unboxPrivate(const ValueOperand& src, const Register dest) {
795
0
        movq(src.valueReg(), dest);
796
0
        shlq(Imm32(1), dest);
797
0
    }
798
799
5
    void notBoolean(const ValueOperand& val) {
800
5
        xorq(Imm32(1), val.valueReg());
801
5
    }
802
803
54
    void unboxNonDouble(const ValueOperand& src, Register dest, JSValueType type) {
804
54
        MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
805
54
        if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
806
0
            movl(src.valueReg(), dest);
807
0
            return;
808
0
        }
809
54
        if (src.valueReg() == dest) {
810
27
            ScratchRegisterScope scratch(asMasm());
811
27
            mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), scratch);
812
27
            xorq(scratch, dest);
813
27
        } else {
814
27
            mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), dest);
815
27
            xorq(src.valueReg(), dest);
816
27
        }
817
54
    }
818
212
    void unboxNonDouble(const Operand& src, Register dest, JSValueType type) {
819
212
        MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
820
212
        if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
821
0
            movl(src, dest);
822
0
            return;
823
0
        }
824
212
        // Explicitly permits |dest| to be used in |src|.
825
212
        ScratchRegisterScope scratch(asMasm());
826
212
        MOZ_ASSERT(dest != scratch);
827
212
        if (src.containsReg(dest)) {
828
7
            mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), scratch);
829
7
            // If src is already a register, then src and dest are the same
830
7
            // thing and we don't need to move anything into dest.
831
7
            if (src.kind() != Operand::REG) {
832
2
                movq(src, dest);
833
2
            }
834
7
            xorq(scratch, dest);
835
205
        } else {
836
205
            mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), dest);
837
205
            xorq(src, dest);
838
205
        }
839
212
    }
840
0
    void unboxNonDouble(const Address& src, Register dest, JSValueType type) {
841
0
        unboxNonDouble(Operand(src), dest, type);
842
0
    }
843
0
    void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type) {
844
0
        unboxNonDouble(Operand(src), dest, type);
845
0
    }
846
847
3
    void unboxString(const ValueOperand& src, Register dest) {
848
3
        unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
849
3
    }
850
42
    void unboxString(const Operand& src, Register dest) {
851
42
        unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
852
42
    }
853
0
    void unboxString(const Address& src, Register dest) {
854
0
        unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
855
0
    }
856
857
0
    void unboxSymbol(const ValueOperand& src, Register dest) {
858
0
        unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
859
0
    }
860
0
    void unboxSymbol(const Operand& src, Register dest) {
861
0
        unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
862
0
    }
863
864
9
    void unboxObject(const ValueOperand& src, Register dest) {
865
9
        unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
866
9
    }
867
126
    void unboxObject(const Operand& src, Register dest) {
868
126
        unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
869
126
    }
870
16
    void unboxObject(const Address& src, Register dest) {
871
16
        unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT);
872
16
    }
873
0
    void unboxObject(const BaseIndex& src, Register dest) {
874
0
        unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT);
875
0
    }
876
877
    template <typename T>
878
0
    void unboxObjectOrNull(const T& src, Register dest) {
879
0
        unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
880
0
        ScratchRegisterScope scratch(asMasm());
881
0
        mov(ImmWord(~JSVAL_OBJECT_OR_NULL_BIT), scratch);
882
0
        andq(scratch, dest);
883
0
    }
Unexecuted instantiation: void js::jit::MacroAssemblerX64::unboxObjectOrNull<js::jit::BaseObjectElementIndex>(js::jit::BaseObjectElementIndex const&, js::jit::Register)
Unexecuted instantiation: void js::jit::MacroAssemblerX64::unboxObjectOrNull<js::jit::Address>(js::jit::Address const&, js::jit::Register)
884
885
    // This should only be used for the pre-barrier trampoline, to unbox a
886
    // string/symbol/object Value. It's fine there because we don't depend on
887
    // the actual Value type. In almost all other cases, this would be
888
    // Spectre-unsafe - use unboxNonDouble and friends instead.
889
3
    void unboxGCThingForPreBarrierTrampoline(const Address& src, Register dest) {
890
3
        movq(ImmWord(JSVAL_PAYLOAD_MASK_GCTHING), dest);
891
3
        andq(Operand(src), dest);
892
3
    }
893
894
    // Extended unboxing API. If the payload is already in a register, returns
895
    // that register. Otherwise, provides a move to the given scratch register,
896
    // and returns that.
897
14
    MOZ_MUST_USE Register extractObject(const Address& address, Register scratch) {
898
14
        MOZ_ASSERT(scratch != ScratchReg);
899
14
        unboxObject(address, scratch);
900
14
        return scratch;
901
14
    }
902
5
    MOZ_MUST_USE Register extractObject(const ValueOperand& value, Register scratch) {
903
5
        MOZ_ASSERT(scratch != ScratchReg);
904
5
        unboxObject(value, scratch);
905
5
        return scratch;
906
5
    }
907
0
    MOZ_MUST_USE Register extractSymbol(const ValueOperand& value, Register scratch) {
908
0
        MOZ_ASSERT(scratch != ScratchReg);
909
0
        unboxSymbol(value, scratch);
910
0
        return scratch;
911
0
    }
912
0
    MOZ_MUST_USE Register extractInt32(const ValueOperand& value, Register scratch) {
913
0
        MOZ_ASSERT(scratch != ScratchReg);
914
0
        unboxInt32(value, scratch);
915
0
        return scratch;
916
0
    }
917
0
    MOZ_MUST_USE Register extractBoolean(const ValueOperand& value, Register scratch) {
918
0
        MOZ_ASSERT(scratch != ScratchReg);
919
0
        unboxBoolean(value, scratch);
920
0
        return scratch;
921
0
    }
922
56
    MOZ_MUST_USE Register extractTag(const Address& address, Register scratch) {
923
56
        MOZ_ASSERT(scratch != ScratchReg);
924
56
        loadPtr(address, scratch);
925
56
        splitTag(scratch, scratch);
926
56
        return scratch;
927
56
    }
928
2
    MOZ_MUST_USE Register extractTag(const ValueOperand& value, Register scratch) {
929
2
        MOZ_ASSERT(scratch != ScratchReg);
930
2
        splitTag(value, scratch);
931
2
        return scratch;
932
2
    }
933
934
    inline void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type);
935
936
    // These two functions use the low 32-bits of the full value register.
937
0
    void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) {
938
0
        convertInt32ToDouble(operand.valueReg(), dest);
939
0
    }
940
0
    void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest) {
941
0
        convertInt32ToDouble(operand.valueReg(), dest);
942
0
    }
943
944
0
    void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
945
0
        convertInt32ToFloat32(operand.valueReg(), dest);
946
0
    }
947
0
    void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
948
0
        convertInt32ToFloat32(operand.valueReg(), dest);
949
0
    }
950
951
    void loadConstantDouble(double d, FloatRegister dest);
952
    void loadConstantFloat32(float f, FloatRegister dest);
953
954
    void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest);
955
    void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest);
956
957
0
    void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
958
0
        loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalArea) + globalDataOffset), dest);
959
0
    }
960
0
    void loadWasmPinnedRegsFromTls() {
961
0
        loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg);
962
0
    }
963
964
  public:
965
1
    Condition testInt32Truthy(bool truthy, const ValueOperand& operand) {
966
1
        test32(operand.valueReg(), operand.valueReg());
967
1
        return truthy ? NonZero : Zero;
968
1
    }
969
0
    Condition testStringTruthy(bool truthy, const ValueOperand& value) {
970
0
        ScratchRegisterScope scratch(asMasm());
971
0
        unboxString(value, scratch);
972
0
        cmp32(Operand(scratch, JSString::offsetOfLength()), Imm32(0));
973
0
        return truthy ? Assembler::NotEqual : Assembler::Equal;
974
0
    }
975
976
    template <typename T>
977
    inline void loadInt32OrDouble(const T& src, FloatRegister dest);
978
979
    template <typename T>
980
28
    void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) {
981
28
        if (dest.isFloat()) {
982
0
            loadInt32OrDouble(src, dest.fpu());
983
28
        } else if (type == MIRType::ObjectOrNull) {
984
0
            unboxObjectOrNull(src, dest.gpr());
985
28
        } else {
986
28
            unboxNonDouble(Operand(src), dest.gpr(), ValueTypeFromMIRType(type));
987
28
        }
988
28
    }
Unexecuted instantiation: void js::jit::MacroAssemblerX64::loadUnboxedValue<js::jit::BaseObjectElementIndex>(js::jit::BaseObjectElementIndex const&, js::jit::MIRType, js::jit::AnyRegister)
void js::jit::MacroAssemblerX64::loadUnboxedValue<js::jit::Address>(js::jit::Address const&, js::jit::MIRType, js::jit::AnyRegister)
Line
Count
Source
980
28
    void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) {
981
28
        if (dest.isFloat()) {
982
0
            loadInt32OrDouble(src, dest.fpu());
983
28
        } else if (type == MIRType::ObjectOrNull) {
984
0
            unboxObjectOrNull(src, dest.gpr());
985
28
        } else {
986
28
            unboxNonDouble(Operand(src), dest.gpr(), ValueTypeFromMIRType(type));
987
28
        }
988
28
    }
989
990
    template <typename T>
991
2
    void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes, JSValueType type) {
992
2
        switch (nbytes) {
993
2
          case 8: {
994
1
            ScratchRegisterScope scratch(asMasm());
995
1
            unboxNonDouble(value, scratch, type);
996
1
            storePtr(scratch, address);
997
1
            if (type == JSVAL_TYPE_OBJECT) {
998
1
                // Ideally we would call unboxObjectOrNull, but we need an extra
999
1
                // scratch register for that. So unbox as object, then clear the
1000
1
                // object-or-null bit.
1001
1
                mov(ImmWord(~JSVAL_OBJECT_OR_NULL_BIT), scratch);
1002
1
                andq(scratch, Operand(address));
1003
1
            }
1004
1
            return;
1005
2
          }
1006
2
          case 4:
1007
0
            store32(value.valueReg(), address);
1008
0
            return;
1009
2
          case 1:
1010
1
            store8(value.valueReg(), address);
1011
1
            return;
1012
2
          default: MOZ_CRASH("Bad payload width");
1013
2
        }
1014
2
    }
Unexecuted instantiation: void js::jit::MacroAssemblerX64::storeUnboxedPayload<js::jit::Address>(js::jit::ValueOperand, js::jit::Address, unsigned long, JSValueType)
void js::jit::MacroAssemblerX64::storeUnboxedPayload<js::jit::BaseIndex>(js::jit::ValueOperand, js::jit::BaseIndex, unsigned long, JSValueType)
Line
Count
Source
991
2
    void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes, JSValueType type) {
992
2
        switch (nbytes) {
993
2
          case 8: {
994
1
            ScratchRegisterScope scratch(asMasm());
995
1
            unboxNonDouble(value, scratch, type);
996
1
            storePtr(scratch, address);
997
1
            if (type == JSVAL_TYPE_OBJECT) {
998
1
                // Ideally we would call unboxObjectOrNull, but we need an extra
999
1
                // scratch register for that. So unbox as object, then clear the
1000
1
                // object-or-null bit.
1001
1
                mov(ImmWord(~JSVAL_OBJECT_OR_NULL_BIT), scratch);
1002
1
                andq(scratch, Operand(address));
1003
1
            }
1004
1
            return;
1005
2
          }
1006
2
          case 4:
1007
0
            store32(value.valueReg(), address);
1008
0
            return;
1009
2
          case 1:
1010
1
            store8(value.valueReg(), address);
1011
1
            return;
1012
2
          default: MOZ_CRASH("Bad payload width");
1013
2
        }
1014
2
    }
1015
1016
0
    void loadInstructionPointerAfterCall(Register dest) {
1017
0
        loadPtr(Address(StackPointer, 0x0), dest);
1018
0
    }
1019
1020
0
    void convertUInt32ToDouble(Register src, FloatRegister dest) {
1021
0
        // Zero the output register to break dependencies, see convertInt32ToDouble.
1022
0
        zeroDouble(dest);
1023
0
1024
0
        vcvtsq2sd(src, dest, dest);
1025
0
    }
1026
1027
0
    void convertUInt32ToFloat32(Register src, FloatRegister dest) {
1028
0
        // Zero the output register to break dependencies, see convertInt32ToDouble.
1029
0
        zeroDouble(dest);
1030
0
1031
0
        vcvtsq2ss(src, dest, dest);
1032
0
    }
1033
1034
    inline void incrementInt32Value(const Address& addr);
1035
1036
    inline void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure);
1037
1038
  public:
1039
    void handleFailureWithHandlerTail(void* handler, Label* profilerExitTail);
1040
1041
    // Instrumentation for entering and leaving the profiler.
1042
    void profilerEnterFrame(Register framePtr, Register scratch);
1043
    void profilerExitFrame();
1044
};
1045
1046
typedef MacroAssemblerX64 MacroAssemblerSpecific;
1047
1048
} // namespace jit
1049
} // namespace js
1050
1051
#endif /* jit_x64_MacroAssembler_x64_h */