Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
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
#include "jit/TypePolicy.h"
8
9
#include "jit/Lowering.h"
10
#include "jit/MIR.h"
11
#include "jit/MIRGraph.h"
12
13
#include "jit/shared/Lowering-shared-inl.h"
14
15
using namespace js;
16
using namespace js::jit;
17
18
static void EnsureOperandNotFloat32(TempAllocator& alloc, MInstruction* def,
19
unsigned op) {
20
MDefinition* in = def->getOperand(op);
21
if (in->type() == MIRType::Float32) {
22
MToDouble* replace = MToDouble::New(alloc, in);
23
def->block()->insertBefore(def, replace);
24
if (def->isRecoveredOnBailout()) {
25
replace->setRecoveredOnBailout();
26
}
27
def->replaceOperand(op, replace);
28
}
29
}
30
31
MDefinition* js::jit::AlwaysBoxAt(TempAllocator& alloc, MInstruction* at,
32
MDefinition* operand) {
33
MDefinition* boxedOperand = operand;
34
// Replace Float32 by double
35
if (operand->type() == MIRType::Float32) {
36
MInstruction* replace = MToDouble::New(alloc, operand);
37
at->block()->insertBefore(at, replace);
38
boxedOperand = replace;
39
}
40
MBox* box = MBox::New(alloc, boxedOperand);
41
at->block()->insertBefore(at, box);
42
return box;
43
}
44
45
static MDefinition* BoxAt(TempAllocator& alloc, MInstruction* at,
46
MDefinition* operand) {
47
if (operand->isUnbox()) {
48
return operand->toUnbox()->input();
49
}
50
return AlwaysBoxAt(alloc, at, operand);
51
}
52
53
bool BoxInputsPolicy::staticAdjustInputs(TempAllocator& alloc,
54
MInstruction* ins) {
55
for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
56
MDefinition* in = ins->getOperand(i);
57
if (in->type() == MIRType::Value) {
58
continue;
59
}
60
ins->replaceOperand(i, BoxAt(alloc, ins, in));
61
}
62
return true;
63
}
64
65
bool ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
66
MIRType specialization = ins->typePolicySpecialization();
67
if (specialization == MIRType::None) {
68
return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
69
}
70
71
MOZ_ASSERT(ins->type() == MIRType::Double || ins->type() == MIRType::Int32 ||
72
ins->type() == MIRType::Float32);
73
74
for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
75
MDefinition* in = ins->getOperand(i);
76
if (in->type() == ins->type()) {
77
continue;
78
}
79
80
MInstruction* replace;
81
82
if (ins->type() == MIRType::Double) {
83
replace = MToDouble::New(alloc, in);
84
} else if (ins->type() == MIRType::Float32) {
85
replace = MToFloat32::New(alloc, in);
86
} else {
87
replace = MToNumberInt32::New(alloc, in);
88
}
89
90
ins->block()->insertBefore(ins, replace);
91
ins->replaceOperand(i, replace);
92
93
if (!replace->typePolicy()->adjustInputs(alloc, replace)) {
94
return false;
95
}
96
}
97
98
return true;
99
}
100
101
bool AllDoublePolicy::staticAdjustInputs(TempAllocator& alloc,
102
MInstruction* ins) {
103
for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
104
MDefinition* in = ins->getOperand(i);
105
if (in->type() == MIRType::Double) {
106
continue;
107
}
108
109
if (!alloc.ensureBallast()) {
110
return false;
111
}
112
MInstruction* replace = MToDouble::New(alloc, in);
113
114
ins->block()->insertBefore(ins, replace);
115
ins->replaceOperand(i, replace);
116
117
if (!replace->typePolicy()->adjustInputs(alloc, replace)) {
118
return false;
119
}
120
}
121
122
return true;
123
}
124
125
bool ComparePolicy::adjustInputs(TempAllocator& alloc,
126
MInstruction* def) const {
127
MOZ_ASSERT(def->isCompare());
128
MCompare* compare = def->toCompare();
129
130
// Convert Float32 operands to doubles
131
for (size_t i = 0; i < 2; i++) {
132
MDefinition* in = def->getOperand(i);
133
if (in->type() == MIRType::Float32) {
134
MInstruction* replace = MToDouble::New(alloc, in);
135
def->block()->insertBefore(def, replace);
136
def->replaceOperand(i, replace);
137
}
138
}
139
140
// Box inputs to get value
141
if (compare->compareType() == MCompare::Compare_Unknown ||
142
compare->compareType() == MCompare::Compare_Bitwise) {
143
return BoxInputsPolicy::staticAdjustInputs(alloc, def);
144
}
145
146
// Compare_Boolean specialization is done for "Anything === Bool"
147
// If the LHS is boolean, we set the specialization to Compare_Int32.
148
// This matches other comparisons of the form bool === bool and
149
// generated code of Compare_Int32 is more efficient.
150
if (compare->compareType() == MCompare::Compare_Boolean &&
151
def->getOperand(0)->type() == MIRType::Boolean) {
152
compare->setCompareType(MCompare::Compare_Int32MaybeCoerceBoth);
153
}
154
155
// Compare_Boolean specialization is done for "Anything === Bool"
156
// As of previous line Anything can't be Boolean
157
if (compare->compareType() == MCompare::Compare_Boolean) {
158
// Unbox rhs that is definitely Boolean
159
MDefinition* rhs = def->getOperand(1);
160
if (rhs->type() != MIRType::Boolean) {
161
MInstruction* unbox =
162
MUnbox::New(alloc, rhs, MIRType::Boolean, MUnbox::Infallible);
163
def->block()->insertBefore(def, unbox);
164
def->replaceOperand(1, unbox);
165
if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) {
166
return false;
167
}
168
}
169
170
MOZ_ASSERT(def->getOperand(0)->type() != MIRType::Boolean);
171
MOZ_ASSERT(def->getOperand(1)->type() == MIRType::Boolean);
172
return true;
173
}
174
175
// Compare_StrictString specialization is done for "Anything === String"
176
// If the LHS is string, we set the specialization to Compare_String.
177
if (compare->compareType() == MCompare::Compare_StrictString &&
178
def->getOperand(0)->type() == MIRType::String) {
179
compare->setCompareType(MCompare::Compare_String);
180
}
181
182
// Compare_StrictString specialization is done for "Anything === String"
183
// As of previous line Anything can't be String
184
if (compare->compareType() == MCompare::Compare_StrictString) {
185
// Unbox rhs that is definitely String
186
MDefinition* rhs = def->getOperand(1);
187
if (rhs->type() != MIRType::String) {
188
MInstruction* unbox =
189
MUnbox::New(alloc, rhs, MIRType::String, MUnbox::Infallible);
190
def->block()->insertBefore(def, unbox);
191
def->replaceOperand(1, unbox);
192
if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) {
193
return false;
194
}
195
}
196
197
MOZ_ASSERT(def->getOperand(0)->type() != MIRType::String);
198
MOZ_ASSERT(def->getOperand(1)->type() == MIRType::String);
199
return true;
200
}
201
202
if (compare->compareType() == MCompare::Compare_Undefined ||
203
compare->compareType() == MCompare::Compare_Null) {
204
// Nothing to do for undefined and null, lowering handles all types.
205
return true;
206
}
207
208
// Convert all inputs to the right input type
209
MIRType type = compare->inputType();
210
MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Double ||
211
type == MIRType::Float32 || type == MIRType::Object ||
212
type == MIRType::String || type == MIRType::Symbol);
213
for (size_t i = 0; i < 2; i++) {
214
MDefinition* in = def->getOperand(i);
215
if (in->type() == type) {
216
continue;
217
}
218
219
MInstruction* replace;
220
221
switch (type) {
222
case MIRType::Double: {
223
MToFPInstruction::ConversionKind convert =
224
MToFPInstruction::NumbersOnly;
225
if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS &&
226
i == 0) {
227
convert = MToFPInstruction::NonNullNonStringPrimitives;
228
} else if (compare->compareType() ==
229
MCompare::Compare_DoubleMaybeCoerceRHS &&
230
i == 1) {
231
convert = MToFPInstruction::NonNullNonStringPrimitives;
232
}
233
replace = MToDouble::New(alloc, in, convert);
234
break;
235
}
236
case MIRType::Float32: {
237
MToFPInstruction::ConversionKind convert =
238
MToFPInstruction::NumbersOnly;
239
if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS &&
240
i == 0) {
241
convert = MToFPInstruction::NonNullNonStringPrimitives;
242
} else if (compare->compareType() ==
243
MCompare::Compare_DoubleMaybeCoerceRHS &&
244
i == 1) {
245
convert = MToFPInstruction::NonNullNonStringPrimitives;
246
}
247
replace = MToFloat32::New(alloc, in, convert);
248
break;
249
}
250
case MIRType::Int32: {
251
IntConversionInputKind convert = IntConversionInputKind::NumbersOnly;
252
if (compare->compareType() == MCompare::Compare_Int32MaybeCoerceBoth ||
253
(compare->compareType() == MCompare::Compare_Int32MaybeCoerceLHS &&
254
i == 0) ||
255
(compare->compareType() == MCompare::Compare_Int32MaybeCoerceRHS &&
256
i == 1)) {
257
convert = IntConversionInputKind::NumbersOrBoolsOnly;
258
}
259
replace = MToNumberInt32::New(alloc, in, convert);
260
break;
261
}
262
case MIRType::Object:
263
replace = MUnbox::New(alloc, in, MIRType::Object, MUnbox::Infallible);
264
break;
265
case MIRType::String:
266
replace = MUnbox::New(alloc, in, MIRType::String, MUnbox::Infallible);
267
break;
268
case MIRType::Symbol:
269
replace = MUnbox::New(alloc, in, MIRType::Symbol, MUnbox::Infallible);
270
break;
271
default:
272
MOZ_CRASH("Unknown compare specialization");
273
}
274
275
def->block()->insertBefore(def, replace);
276
def->replaceOperand(i, replace);
277
278
if (!replace->typePolicy()->adjustInputs(alloc, replace)) {
279
return false;
280
}
281
}
282
283
return true;
284
}
285
286
bool SameValuePolicy::adjustInputs(TempAllocator& alloc,
287
MInstruction* def) const {
288
MOZ_ASSERT(def->isSameValue());
289
MSameValue* sameValue = def->toSameValue();
290
MIRType lhsType = sameValue->lhs()->type();
291
MIRType rhsType = sameValue->rhs()->type();
292
293
// If both operands are numbers, convert them to doubles.
294
if (IsNumberType(lhsType) && IsNumberType(rhsType)) {
295
return AllDoublePolicy::staticAdjustInputs(alloc, def);
296
}
297
298
// SameValue(Anything, Double) is specialized, so convert the rhs if it's
299
// not already a double.
300
if (lhsType == MIRType::Value && IsNumberType(rhsType)) {
301
if (rhsType != MIRType::Double) {
302
MInstruction* replace = MToDouble::New(alloc, sameValue->rhs());
303
def->block()->insertBefore(def, replace);
304
def->replaceOperand(1, replace);
305
306
if (!replace->typePolicy()->adjustInputs(alloc, replace)) {
307
return false;
308
}
309
}
310
311
return true;
312
}
313
314
// Otherwise box both operands.
315
return BoxInputsPolicy::staticAdjustInputs(alloc, def);
316
}
317
318
bool TypeBarrierPolicy::adjustInputs(TempAllocator& alloc,
319
MInstruction* def) const {
320
MTypeBarrier* ins = def->toTypeBarrier();
321
MIRType inputType = ins->getOperand(0)->type();
322
MIRType outputType = ins->type();
323
324
// Input and output type are already in accordance.
325
if (inputType == outputType) {
326
return true;
327
}
328
329
// Output is a value, currently box the input.
330
if (outputType == MIRType::Value) {
331
// XXX: Possible optimization: decrease resultTypeSet to only include
332
// the inputType. This will remove the need for boxing.
333
MOZ_ASSERT(inputType != MIRType::Value);
334
ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
335
return true;
336
}
337
338
// Box input if needed.
339
if (inputType != MIRType::Value) {
340
MOZ_ASSERT(ins->alwaysBails());
341
ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
342
}
343
344
// We can't unbox a value to null/undefined/lazyargs. So keep output
345
// also a value.
346
// Note: Using setResultType shouldn't be done in TypePolicies,
347
// Here it is fine, since the type barrier has no uses.
348
if (IsNullOrUndefined(outputType) ||
349
outputType == MIRType::MagicOptimizedArguments) {
350
MOZ_ASSERT(!ins->hasDefUses());
351
ins->setResultType(MIRType::Value);
352
return true;
353
}
354
355
// Unbox / propagate the right type.
356
MUnbox::Mode mode = MUnbox::TypeBarrier;
357
MInstruction* replace =
358
MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode);
359
if (!ins->isMovable()) {
360
replace->setNotMovable();
361
}
362
363
ins->block()->insertBefore(ins, replace);
364
ins->replaceOperand(0, replace);
365
if (!replace->typePolicy()->adjustInputs(alloc, replace)) {
366
return false;
367
}
368
369
// The TypeBarrier is equivalent to removing branches with unexpected
370
// types. The unexpected types would have changed Range Analysis
371
// predictions. As such, we need to prevent destructive optimizations.
372
ins->block()->flagOperandsOfPrunedBranches(replace);
373
374
return true;
375
}
376
377
bool TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
378
MDefinition* op = ins->getOperand(0);
379
switch (op->type()) {
380
case MIRType::Value:
381
case MIRType::Null:
382
case MIRType::Undefined:
383
case MIRType::Boolean:
384
case MIRType::Int32:
385
case MIRType::Double:
386
case MIRType::Float32:
387
case MIRType::Symbol:
388
case MIRType::Object:
389
break;
390
391
case MIRType::String: {
392
MStringLength* length = MStringLength::New(alloc, op);
393
ins->block()->insertBefore(ins, length);
394
ins->replaceOperand(0, length);
395
break;
396
}
397
398
default:
399
ins->replaceOperand(0, BoxAt(alloc, ins, op));
400
break;
401
}
402
return true;
403
}
404
405
bool BitwisePolicy::adjustInputs(TempAllocator& alloc,
406
MInstruction* ins) const {
407
MIRType specialization = ins->typePolicySpecialization();
408
if (specialization == MIRType::None) {
409
return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
410
}
411
412
MOZ_ASSERT(ins->type() == MIRType::Value || ins->type() == specialization);
413
MOZ_ASSERT(specialization == MIRType::Int32 ||
414
specialization == MIRType::Double);
415
416
// This policy works for both unary and binary bitwise operations.
417
for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
418
MDefinition* in = ins->getOperand(i);
419
if (in->type() == MIRType::Int32) {
420
continue;
421
}
422
423
MInstruction* replace = MTruncateToInt32::New(alloc, in);
424
ins->block()->insertBefore(ins, replace);
425
ins->replaceOperand(i, replace);
426
427
if (!replace->typePolicy()->adjustInputs(alloc, replace)) {
428
return false;
429
}
430
}
431
432
return true;
433
}
434
435
bool PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
436
MIRType specialization = ins->typePolicySpecialization();
437
MOZ_ASSERT(specialization == MIRType::Int32 ||
438
specialization == MIRType::Double ||
439
specialization == MIRType::None);
440
441
// Inputs will be boxed if either is non-numeric.
442
if (specialization == MIRType::None) {
443
return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
444
}
445
446
// Otherwise, input must be a double.
447
if (!DoublePolicy<0>::staticAdjustInputs(alloc, ins)) {
448
return false;
449
}
450
451
// Power may be an int32 or a double. Integers receive a faster path.
452
if (specialization == MIRType::Double) {
453
return DoublePolicy<1>::staticAdjustInputs(alloc, ins);
454
}
455
return UnboxedInt32Policy<1>::staticAdjustInputs(alloc, ins);
456
}
457
458
bool SignPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
459
MOZ_ASSERT(ins->isSign());
460
MIRType specialization = ins->typePolicySpecialization();
461
462
// MSign is specialized for int32 input types.
463
if (specialization == MIRType::Int32) {
464
return UnboxedInt32Policy<0>::staticAdjustInputs(alloc, ins);
465
}
466
467
// Otherwise convert input to double.
468
MOZ_ASSERT(IsFloatingPointType(specialization));
469
return DoublePolicy<0>::staticAdjustInputs(alloc, ins);
470
}
471
472
template <unsigned Op>
473
bool StringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
474
MInstruction* ins) {
475
MDefinition* in = ins->getOperand(Op);
476
if (in->type() == MIRType::String) {
477
return true;
478
}
479
480
MUnbox* replace = MUnbox::New(alloc, in, MIRType::String, MUnbox::Fallible);
481
ins->block()->insertBefore(ins, replace);
482
ins->replaceOperand(Op, replace);
483
484
return replace->typePolicy()->adjustInputs(alloc, replace);
485
}
486
487
template bool StringPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
488
MInstruction* ins);
489
template bool StringPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
490
MInstruction* ins);
491
template bool StringPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
492
MInstruction* ins);
493
494
template <unsigned Op>
495
bool ConvertToStringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
496
MInstruction* ins) {
497
MDefinition* in = ins->getOperand(Op);
498
if (in->type() == MIRType::String) {
499
return true;
500
}
501
502
MToString* replace = MToString::New(alloc, in);
503
ins->block()->insertBefore(ins, replace);
504
ins->replaceOperand(Op, replace);
505
506
if (!ToStringPolicy::staticAdjustInputs(alloc, replace)) {
507
return false;
508
}
509
510
return true;
511
}
512
513
template bool ConvertToStringPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
514
MInstruction* ins);
515
template bool ConvertToStringPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
516
MInstruction* ins);
517
template bool ConvertToStringPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
518
MInstruction* ins);
519
520
template <unsigned Op>
521
bool BooleanPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
522
MInstruction* def) {
523
MDefinition* in = def->getOperand(Op);
524
if (in->type() == MIRType::Boolean) {
525
return true;
526
}
527
528
MUnbox* replace = MUnbox::New(alloc, in, MIRType::Boolean, MUnbox::Fallible);
529
def->block()->insertBefore(def, replace);
530
def->replaceOperand(Op, replace);
531
532
return replace->typePolicy()->adjustInputs(alloc, replace);
533
}
534
535
template bool BooleanPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
536
MInstruction* def);
537
538
template <unsigned Op>
539
bool UnboxedInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
540
MInstruction* def) {
541
MDefinition* in = def->getOperand(Op);
542
if (in->type() == MIRType::Int32) {
543
return true;
544
}
545
546
MUnbox* replace = MUnbox::New(alloc, in, MIRType::Int32, MUnbox::Fallible);
547
def->block()->insertBefore(def, replace);
548
def->replaceOperand(Op, replace);
549
550
return replace->typePolicy()->adjustInputs(alloc, replace);
551
}
552
553
template bool UnboxedInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
554
MInstruction* def);
555
template bool UnboxedInt32Policy<1>::staticAdjustInputs(TempAllocator& alloc,
556
MInstruction* def);
557
template bool UnboxedInt32Policy<2>::staticAdjustInputs(TempAllocator& alloc,
558
MInstruction* def);
559
template bool UnboxedInt32Policy<3>::staticAdjustInputs(TempAllocator& alloc,
560
MInstruction* def);
561
562
template <unsigned Op>
563
bool ConvertToInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
564
MInstruction* def) {
565
MDefinition* in = def->getOperand(Op);
566
if (in->type() == MIRType::Int32) {
567
return true;
568
}
569
570
auto* replace = MToNumberInt32::New(alloc, in);
571
def->block()->insertBefore(def, replace);
572
def->replaceOperand(Op, replace);
573
574
return replace->typePolicy()->adjustInputs(alloc, replace);
575
}
576
577
template bool ConvertToInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
578
MInstruction* def);
579
580
template <unsigned Op>
581
bool TruncateToInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
582
MInstruction* def) {
583
MDefinition* in = def->getOperand(Op);
584
if (in->type() == MIRType::Int32) {
585
return true;
586
}
587
588
MTruncateToInt32* replace = MTruncateToInt32::New(alloc, in);
589
def->block()->insertBefore(def, replace);
590
def->replaceOperand(Op, replace);
591
592
return replace->typePolicy()->adjustInputs(alloc, replace);
593
}
594
595
template bool TruncateToInt32Policy<2>::staticAdjustInputs(TempAllocator& alloc,
596
MInstruction* def);
597
template bool TruncateToInt32Policy<3>::staticAdjustInputs(TempAllocator& alloc,
598
MInstruction* def);
599
600
template <unsigned Op>
601
bool DoublePolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
602
MInstruction* def) {
603
MDefinition* in = def->getOperand(Op);
604
if (in->type() == MIRType::Double) {
605
return true;
606
}
607
608
MToDouble* replace = MToDouble::New(alloc, in);
609
def->block()->insertBefore(def, replace);
610
def->replaceOperand(Op, replace);
611
612
return replace->typePolicy()->adjustInputs(alloc, replace);
613
}
614
615
template bool DoublePolicy<0>::staticAdjustInputs(TempAllocator& alloc,
616
MInstruction* def);
617
template bool DoublePolicy<1>::staticAdjustInputs(TempAllocator& alloc,
618
MInstruction* def);
619
620
template <unsigned Op>
621
bool Float32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
622
MInstruction* def) {
623
MDefinition* in = def->getOperand(Op);
624
if (in->type() == MIRType::Float32) {
625
return true;
626
}
627
628
MToFloat32* replace = MToFloat32::New(alloc, in);
629
def->block()->insertBefore(def, replace);
630
def->replaceOperand(Op, replace);
631
632
return replace->typePolicy()->adjustInputs(alloc, replace);
633
}
634
635
template bool Float32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
636
MInstruction* def);
637
template bool Float32Policy<1>::staticAdjustInputs(TempAllocator& alloc,
638
MInstruction* def);
639
template bool Float32Policy<2>::staticAdjustInputs(TempAllocator& alloc,
640
MInstruction* def);
641
642
template <unsigned Op>
643
bool FloatingPointPolicy<Op>::adjustInputs(TempAllocator& alloc,
644
MInstruction* def) const {
645
MIRType policyType = def->typePolicySpecialization();
646
if (policyType == MIRType::Double) {
647
return DoublePolicy<Op>::staticAdjustInputs(alloc, def);
648
}
649
return Float32Policy<Op>::staticAdjustInputs(alloc, def);
650
}
651
652
template bool FloatingPointPolicy<0>::adjustInputs(TempAllocator& alloc,
653
MInstruction* def) const;
654
655
template <unsigned Op>
656
bool NoFloatPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
657
MInstruction* def) {
658
EnsureOperandNotFloat32(alloc, def, Op);
659
return true;
660
}
661
662
template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
663
MInstruction* def);
664
template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
665
MInstruction* def);
666
template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
667
MInstruction* def);
668
template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
669
MInstruction* def);
670
671
template <unsigned FirstOp>
672
bool NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator& alloc,
673
MInstruction* def) const {
674
for (size_t op = FirstOp, e = def->numOperands(); op < e; op++) {
675
EnsureOperandNotFloat32(alloc, def, op);
676
}
677
return true;
678
}
679
680
template bool NoFloatPolicyAfter<0>::adjustInputs(TempAllocator& alloc,
681
MInstruction* def) const;
682
template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator& alloc,
683
MInstruction* def) const;
684
template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator& alloc,
685
MInstruction* def) const;
686
687
template <unsigned Op>
688
bool BoxPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
689
MInstruction* ins) {
690
MDefinition* in = ins->getOperand(Op);
691
if (in->type() == MIRType::Value) {
692
return true;
693
}
694
695
ins->replaceOperand(Op, BoxAt(alloc, ins, in));
696
return true;
697
}
698
699
template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
700
MInstruction* ins);
701
template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
702
MInstruction* ins);
703
template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
704
MInstruction* ins);
705
706
template <unsigned Op, MIRType Type>
707
bool BoxExceptPolicy<Op, Type>::staticAdjustInputs(TempAllocator& alloc,
708
MInstruction* ins) {
709
MDefinition* in = ins->getOperand(Op);
710
if (in->type() == Type) {
711
return true;
712
}
713
return BoxPolicy<Op>::staticAdjustInputs(alloc, ins);
714
}
715
716
template bool BoxExceptPolicy<0, MIRType::Object>::staticAdjustInputs(
717
TempAllocator& alloc, MInstruction* ins);
718
719
template <unsigned Op>
720
bool CacheIdPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
721
MInstruction* ins) {
722
MDefinition* in = ins->getOperand(Op);
723
switch (in->type()) {
724
case MIRType::Int32:
725
case MIRType::String:
726
case MIRType::Symbol:
727
return true;
728
default:
729
return BoxPolicy<Op>::staticAdjustInputs(alloc, ins);
730
}
731
}
732
733
template bool CacheIdPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
734
MInstruction* ins);
735
template bool CacheIdPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
736
MInstruction* ins);
737
738
bool ToDoublePolicy::staticAdjustInputs(TempAllocator& alloc,
739
MInstruction* ins) {
740
MOZ_ASSERT(ins->isToDouble() || ins->isToFloat32());
741
742
MDefinition* in = ins->getOperand(0);
743
MToFPInstruction::ConversionKind conversion;
744
if (ins->isToDouble()) {
745
conversion = ins->toToDouble()->conversion();
746
} else {
747
conversion = ins->toToFloat32()->conversion();
748
}
749
750
switch (in->type()) {
751
case MIRType::Int32:
752
case MIRType::Float32:
753
case MIRType::Double:
754
case MIRType::Value:
755
// No need for boxing for these types.
756
return true;
757
case MIRType::Null:
758
// No need for boxing, when we will convert.
759
if (conversion == MToFPInstruction::NonStringPrimitives) {
760
return true;
761
}
762
break;
763
case MIRType::Undefined:
764
case MIRType::Boolean:
765
// No need for boxing, when we will convert.
766
if (conversion == MToFPInstruction::NonStringPrimitives) {
767
return true;
768
}
769
if (conversion == MToFPInstruction::NonNullNonStringPrimitives) {
770
return true;
771
}
772
break;
773
case MIRType::Object:
774
case MIRType::String:
775
case MIRType::Symbol:
776
case MIRType::BigInt:
777
// Objects might be effectful. Symbols and BigInts give TypeError.
778
break;
779
default:
780
break;
781
}
782
783
in = BoxAt(alloc, ins, in);
784
ins->replaceOperand(0, in);
785
return true;
786
}
787
788
bool ToInt32Policy::staticAdjustInputs(TempAllocator& alloc,
789
MInstruction* ins) {
790
MOZ_ASSERT(ins->isToNumberInt32() || ins->isTruncateToInt32());
791
792
IntConversionInputKind conversion = IntConversionInputKind::Any;
793
if (ins->isToNumberInt32()) {
794
conversion = ins->toToNumberInt32()->conversion();
795
}
796
797
MDefinition* in = ins->getOperand(0);
798
switch (in->type()) {
799
case MIRType::Int32:
800
case MIRType::Float32:
801
case MIRType::Double:
802
case MIRType::Value:
803
// No need for boxing for these types.
804
return true;
805
case MIRType::Undefined:
806
// No need for boxing when truncating.
807
if (ins->isTruncateToInt32()) {
808
return true;
809
}
810
break;
811
case MIRType::Null:
812
// No need for boxing, when we will convert.
813
if (conversion == IntConversionInputKind::Any) {
814
return true;
815
}
816
break;
817
case MIRType::Boolean:
818
// No need for boxing, when we will convert.
819
if (conversion == IntConversionInputKind::Any) {
820
return true;
821
}
822
if (conversion == IntConversionInputKind::NumbersOrBoolsOnly) {
823
return true;
824
}
825
break;
826
case MIRType::Object:
827
case MIRType::String:
828
case MIRType::Symbol:
829
case MIRType::BigInt:
830
// Objects might be effectful. Symbols and BigInts give TypeError.
831
break;
832
default:
833
break;
834
}
835
836
in = BoxAt(alloc, ins, in);
837
ins->replaceOperand(0, in);
838
return true;
839
}
840
841
bool ToStringPolicy::staticAdjustInputs(TempAllocator& alloc,
842
MInstruction* ins) {
843
MOZ_ASSERT(ins->isToString());
844
845
MIRType type = ins->getOperand(0)->type();
846
if (type == MIRType::Object || type == MIRType::Symbol ||
847
type == MIRType::BigInt) {
848
ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
849
return true;
850
}
851
852
// TODO remove the following line once 966957 has landed
853
EnsureOperandNotFloat32(alloc, ins, 0);
854
855
return true;
856
}
857
858
template <unsigned Op>
859
bool ObjectPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
860
MInstruction* ins) {
861
MDefinition* in = ins->getOperand(Op);
862
if (in->type() == MIRType::Object || in->type() == MIRType::Slots ||
863
in->type() == MIRType::Elements) {
864
return true;
865
}
866
867
MUnbox* replace = MUnbox::New(alloc, in, MIRType::Object, MUnbox::Fallible);
868
ins->block()->insertBefore(ins, replace);
869
ins->replaceOperand(Op, replace);
870
871
return replace->typePolicy()->adjustInputs(alloc, replace);
872
}
873
874
template bool ObjectPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
875
MInstruction* ins);
876
template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
877
MInstruction* ins);
878
template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
879
MInstruction* ins);
880
template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
881
MInstruction* ins);
882
883
bool CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
884
MCall* call = ins->toCall();
885
886
MDefinition* func = call->getFunction();
887
if (func->type() != MIRType::Object) {
888
MInstruction* unbox =
889
MUnbox::New(alloc, func, MIRType::Object, MUnbox::Fallible);
890
call->block()->insertBefore(call, unbox);
891
call->replaceFunction(unbox);
892
893
if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) {
894
return false;
895
}
896
}
897
898
for (uint32_t i = 0; i < call->numStackArgs(); i++) {
899
if (!alloc.ensureBallast()) {
900
return false;
901
}
902
EnsureOperandNotFloat32(alloc, call, MCall::IndexOfStackArg(i));
903
}
904
905
return true;
906
}
907
908
bool CallSetElementPolicy::adjustInputs(TempAllocator& alloc,
909
MInstruction* ins) const {
910
// The first operand should be an object.
911
if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins)) {
912
return false;
913
}
914
915
// Box the index and value operands.
916
for (size_t i = 1, e = ins->numOperands(); i < e; i++) {
917
MDefinition* in = ins->getOperand(i);
918
if (in->type() == MIRType::Value) {
919
continue;
920
}
921
ins->replaceOperand(i, BoxAt(alloc, ins, in));
922
}
923
return true;
924
}
925
926
bool InstanceOfPolicy::adjustInputs(TempAllocator& alloc,
927
MInstruction* def) const {
928
// Box first operand if it isn't object
929
if (def->getOperand(0)->type() != MIRType::Object) {
930
if (!BoxPolicy<0>::staticAdjustInputs(alloc, def)) {
931
return false;
932
}
933
}
934
935
return true;
936
}
937
938
bool StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc,
939
MInstruction* ins,
940
Scalar::Type writeType,
941
MDefinition* value,
942
int valueOperand) {
943
MDefinition* curValue = value;
944
// First, ensure the value is int32, boolean, double or Value.
945
// The conversion is based on TypedArrayObjectTemplate::setElementTail.
946
switch (value->type()) {
947
case MIRType::Int32:
948
case MIRType::Double:
949
case MIRType::Float32:
950
case MIRType::Boolean:
951
case MIRType::Value:
952
break;
953
case MIRType::Null:
954
value->setImplicitlyUsedUnchecked();
955
value = MConstant::New(alloc, Int32Value(0));
956
ins->block()->insertBefore(ins, value->toInstruction());
957
break;
958
case MIRType::Undefined:
959
value->setImplicitlyUsedUnchecked();
960
value = MConstant::New(alloc, JS::NaNValue());
961
ins->block()->insertBefore(ins, value->toInstruction());
962
break;
963
case MIRType::Object:
964
case MIRType::String:
965
case MIRType::Symbol:
966
case MIRType::BigInt:
967
value = BoxAt(alloc, ins, value);
968
break;
969
default:
970
MOZ_CRASH("Unexpected type");
971
}
972
973
if (value != curValue) {
974
ins->replaceOperand(valueOperand, value);
975
curValue = value;
976
}
977
978
MOZ_ASSERT(
979
value->type() == MIRType::Int32 || value->type() == MIRType::Boolean ||
980
value->type() == MIRType::Double || value->type() == MIRType::Float32 ||
981
value->type() == MIRType::Value);
982
983
switch (writeType) {
984
case Scalar::Int8:
985
case Scalar::Uint8:
986
case Scalar::Int16:
987
case Scalar::Uint16:
988
case Scalar::Int32:
989
case Scalar::Uint32:
990
if (value->type() != MIRType::Int32) {
991
value = MTruncateToInt32::New(alloc, value);
992
ins->block()->insertBefore(ins, value->toInstruction());
993
}
994
break;
995
case Scalar::Uint8Clamped:
996
// IonBuilder should have inserted ClampToUint8.
997
MOZ_ASSERT(value->type() == MIRType::Int32);
998
break;
999
case Scalar::Float32:
1000
if (value->type() != MIRType::Float32) {
1001
value = MToFloat32::New(alloc, value);
1002
ins->block()->insertBefore(ins, value->toInstruction());
1003
}
1004
break;
1005
case Scalar::Float64:
1006
if (value->type() != MIRType::Double) {
1007
value = MToDouble::New(alloc, value);
1008
ins->block()->insertBefore(ins, value->toInstruction());
1009
}
1010
break;
1011
default:
1012
MOZ_CRASH("Invalid array type");
1013
}
1014
1015
if (value != curValue) {
1016
ins->replaceOperand(valueOperand, value);
1017
}
1018
1019
return true;
1020
}
1021
1022
bool StoreUnboxedScalarPolicy::adjustInputs(TempAllocator& alloc,
1023
MInstruction* ins) const {
1024
if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins)) {
1025
return false;
1026
}
1027
1028
MStoreUnboxedScalar* store = ins->toStoreUnboxedScalar();
1029
MOZ_ASSERT(IsValidElementsType(store->elements(), store->offsetAdjustment()));
1030
MOZ_ASSERT(store->index()->type() == MIRType::Int32);
1031
1032
return adjustValueInput(alloc, store, store->writeType(), store->value(), 2);
1033
}
1034
1035
bool StoreTypedArrayHolePolicy::adjustInputs(TempAllocator& alloc,
1036
MInstruction* ins) const {
1037
MStoreTypedArrayElementHole* store = ins->toStoreTypedArrayElementHole();
1038
MOZ_ASSERT(store->elements()->type() == MIRType::Elements);
1039
MOZ_ASSERT(store->index()->type() == MIRType::Int32);
1040
MOZ_ASSERT(store->length()->type() == MIRType::Int32);
1041
1042
return StoreUnboxedScalarPolicy::adjustValueInput(
1043
alloc, ins, store->arrayType(), store->value(), 3);
1044
}
1045
1046
bool StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator& alloc,
1047
MInstruction* ins) const {
1048
if (!ObjectPolicy<0>::staticAdjustInputs(alloc, ins)) {
1049
return false;
1050
}
1051
1052
if (!ObjectPolicy<3>::staticAdjustInputs(alloc, ins)) {
1053
return false;
1054
}
1055
1056
// Change the value input to a ToObjectOrNull instruction if it might be
1057
// a non-null primitive. Insert a post barrier for the instruction's object
1058
// and whatever its new value is, unless the value is definitely null.
1059
MStoreUnboxedObjectOrNull* store = ins->toStoreUnboxedObjectOrNull();
1060
1061
MOZ_ASSERT(store->typedObj()->type() == MIRType::Object);
1062
1063
MDefinition* value = store->value();
1064
if (value->type() == MIRType::Object || value->type() == MIRType::Null ||
1065
value->type() == MIRType::ObjectOrNull) {
1066
if (value->type() != MIRType::Null) {
1067
MInstruction* barrier =
1068
MPostWriteBarrier::New(alloc, store->typedObj(), value);
1069
store->block()->insertBefore(store, barrier);
1070
}
1071
return true;
1072
}
1073
1074
MToObjectOrNull* replace = MToObjectOrNull::New(alloc, value);
1075
store->block()->insertBefore(store, replace);
1076
store->setValue(replace);
1077
1078
if (!BoxPolicy<0>::staticAdjustInputs(alloc, replace)) {
1079
return false;
1080
}
1081
1082
MInstruction* barrier =
1083
MPostWriteBarrier::New(alloc, store->typedObj(), replace);
1084
store->block()->insertBefore(store, barrier);
1085
1086
return true;
1087
}
1088
1089
bool StoreUnboxedStringPolicy::adjustInputs(TempAllocator& alloc,
1090
MInstruction* ins) const {
1091
if (!ObjectPolicy<0>::staticAdjustInputs(alloc, ins)) {
1092
return false;
1093
}
1094
1095
// Change the value input to a ToString instruction if it might be
1096
// a non-null primitive.
1097
if (!ConvertToStringPolicy<2>::staticAdjustInputs(alloc, ins)) {
1098
return false;
1099
}
1100
1101
if (!ObjectPolicy<3>::staticAdjustInputs(alloc, ins)) {
1102
return false;
1103
}
1104
1105
// Insert a post barrier for the instruction's object and whatever its new
1106
// value is.
1107
MStoreUnboxedString* store = ins->toStoreUnboxedString();
1108
1109
MOZ_ASSERT(store->typedObj()->type() == MIRType::Object);
1110
1111
MDefinition* value = store->value();
1112
MOZ_ASSERT(value->type() == MIRType::String);
1113
MInstruction* barrier =
1114
MPostWriteBarrier::New(alloc, store->typedObj(), value);
1115
store->block()->insertBefore(store, barrier);
1116
return true;
1117
}
1118
1119
bool ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
1120
MDefinition* in = ins->toClampToUint8()->input();
1121
1122
switch (in->type()) {
1123
case MIRType::Int32:
1124
case MIRType::Double:
1125
case MIRType::Value:
1126
break;
1127
default:
1128
ins->replaceOperand(0, BoxAt(alloc, ins, in));
1129
break;
1130
}
1131
1132
return true;
1133
}
1134
1135
bool FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc,
1136
MInstruction* ins) const {
1137
MOZ_ASSERT(ins->numOperands() == 1);
1138
MIRType inputType = ins->getOperand(0)->type();
1139
MIRType outputType = ins->type();
1140
1141
// Special case when output is a Float32, but input isn't.
1142
if (outputType == MIRType::Float32 && inputType != MIRType::Float32) {
1143
// Create a MToFloat32 to add between the MFilterTypeSet and
1144
// its uses.
1145
MInstruction* replace = MToFloat32::New(alloc, ins);
1146
ins->justReplaceAllUsesWithExcept(replace);
1147
ins->block()->insertAfter(ins, replace);
1148
1149
// Reset the type to not MIRType::Float32
1150
// Note: setResultType shouldn't happen in TypePolicies,
1151
// Here it is fine, since there is just one use we just
1152
// added ourself. And the resulting type after MToFloat32
1153
// equals the original type.
1154
ins->setResultType(ins->resultTypeSet()->getKnownMIRType());
1155
outputType = ins->type();
1156
1157
// Do the type analysis
1158
if (!replace->typePolicy()->adjustInputs(alloc, replace)) {
1159
return false;
1160
}
1161
1162
// Fall through to let the MFilterTypeSet adjust its input based
1163
// on its new type.
1164
}
1165
1166
// Input and output type are already in accordance.
1167
if (inputType == outputType) {
1168
return true;
1169
}
1170
1171
// Output is a value, box the input.
1172
if (outputType == MIRType::Value) {
1173
MOZ_ASSERT(inputType != MIRType::Value);
1174
ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
1175
return true;
1176
}
1177
1178
// The outputType should be a subset of the inputType else we are in code
1179
// that has never executed yet. Bail to see the new type (if that hasn't
1180
// happened yet).
1181
if (inputType != MIRType::Value) {
1182
MBail* bail = MBail::New(alloc);
1183
ins->block()->insertBefore(ins, bail);
1184
bail->setDependency(ins->dependency());
1185
ins->setDependency(bail);
1186
ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
1187
}
1188
1189
// We can't unbox a value to null/undefined/lazyargs. So keep output
1190
// also a value.
1191
// Note: Using setResultType shouldn't be done in TypePolicies,
1192
// Here it is fine, since the type barrier has no uses.
1193
if (IsNullOrUndefined(outputType) ||
1194
outputType == MIRType::MagicOptimizedArguments) {
1195
MOZ_ASSERT(!ins->hasDefUses());
1196
ins->setResultType(MIRType::Value);
1197
return true;
1198
}
1199
1200
// Unbox / propagate the right type.
1201
MUnbox::Mode mode = MUnbox::Infallible;
1202
MInstruction* replace =
1203
MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode);
1204
1205
ins->block()->insertBefore(ins, replace);
1206
ins->replaceOperand(0, replace);
1207
if (!replace->typePolicy()->adjustInputs(alloc, replace)) {
1208
return false;
1209
}
1210
1211
// Carry over the dependency the MFilterTypeSet had.
1212
replace->setDependency(ins->dependency());
1213
1214
return true;
1215
}
1216
1217
// Lists of all TypePolicy specializations which are used by MIR Instructions.
1218
#define TYPE_POLICY_LIST(_) \
1219
_(AllDoublePolicy) \
1220
_(ArithPolicy) \
1221
_(BitwisePolicy) \
1222
_(BoxInputsPolicy) \
1223
_(CallPolicy) \
1224
_(CallSetElementPolicy) \
1225
_(ClampPolicy) \
1226
_(ComparePolicy) \
1227
_(FilterTypeSetPolicy) \
1228
_(InstanceOfPolicy) \
1229
_(PowPolicy) \
1230
_(SameValuePolicy) \
1231
_(SignPolicy) \
1232
_(StoreTypedArrayHolePolicy) \
1233
_(StoreUnboxedScalarPolicy) \
1234
_(StoreUnboxedObjectOrNullPolicy) \
1235
_(StoreUnboxedStringPolicy) \
1236
_(TestPolicy) \
1237
_(ToDoublePolicy) \
1238
_(ToInt32Policy) \
1239
_(ToStringPolicy) \
1240
_(TypeBarrierPolicy)
1241
1242
#define TEMPLATE_TYPE_POLICY_LIST(_) \
1243
_(BoxExceptPolicy<0, MIRType::Object>) \
1244
_(BoxPolicy<0>) \
1245
_(ConvertToInt32Policy<0>) \
1246
_(ConvertToStringPolicy<0>) \
1247
_(ConvertToStringPolicy<2>) \
1248
_(DoublePolicy<0>) \
1249
_(FloatingPointPolicy<0>) \
1250
_(UnboxedInt32Policy<0>) \
1251
_(UnboxedInt32Policy<1>) \
1252
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, BoxPolicy<2>>) \
1253
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>) \
1254
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>) \
1255
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2>>) \
1256
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
1257
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, \
1258
TruncateToInt32Policy<2>>) \
1259
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2>>) \
1260
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, UnboxedInt32Policy<2>>) \
1261
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2>>) \
1262
_(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
1263
_(MixPolicy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2>>) \
1264
_(MixPolicy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2>>) \
1265
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, UnboxedInt32Policy<2>>) \
1266
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>, \
1267
UnboxedInt32Policy<3>>) \
1268
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, \
1269
TruncateToInt32Policy<2>, TruncateToInt32Policy<3>>) \
1270
_(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>) \
1271
_(MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>, \
1272
CacheIdPolicy<2>>) \
1273
_(MixPolicy<BoxPolicy<0>, ObjectPolicy<1>>) \
1274
_(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1>>) \
1275
_(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1>>) \
1276
_(MixPolicy<DoublePolicy<0>, DoublePolicy<1>>) \
1277
_(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>>) \
1278
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>>) \
1279
_(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>) \
1280
_(MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1>>) \
1281
_(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1>>) \
1282
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>>) \
1283
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<2>>) \
1284
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1>>) \
1285
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2>>) \
1286
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3>>) \
1287
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>>) \
1288
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1>>) \
1289
_(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2>>) \
1290
_(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0>>) \
1291
_(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>>) \
1292
_(MixPolicy<StringPolicy<0>, StringPolicy<1>>) \
1293
_(MixPolicy<BoxPolicy<0>, BoxPolicy<1>>) \
1294
_(NoFloatPolicy<0>) \
1295
_(NoFloatPolicyAfter<0>) \
1296
_(NoFloatPolicyAfter<1>) \
1297
_(NoFloatPolicyAfter<2>) \
1298
_(ObjectPolicy<0>) \
1299
_(ObjectPolicy<1>) \
1300
_(ObjectPolicy<3>) \
1301
_(StringPolicy<0>)
1302
1303
namespace js {
1304
namespace jit {
1305
1306
// Define for all used TypePolicy specialization, the definition for
1307
// |TypePolicy::Data::thisTypePolicy|. This function returns one constant
1308
// instance of the TypePolicy which is shared among all MIR Instructions of the
1309
// same type.
1310
//
1311
// This Macro use __VA_ARGS__ to account for commas of template parameters.
1312
#define DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_(...) \
1313
const TypePolicy* __VA_ARGS__::Data::thisTypePolicy() { \
1314
static constexpr __VA_ARGS__ singletonType; \
1315
return &singletonType; \
1316
}
1317
1318
TYPE_POLICY_LIST(DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_)
1319
TEMPLATE_TYPE_POLICY_LIST(template <> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_)
1320
#undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
1321
1322
} // namespace jit
1323
} // namespace js
1324
1325
namespace {
1326
1327
// For extra-good measure in case an unqualified use is ever introduced. (The
1328
// main use in the macro below is explicitly qualified so as not to consult
1329
// this scope and find this function.)
1330
inline TypePolicy* thisTypePolicy() = delete;
1331
1332
static MIRType thisTypeSpecialization() {
1333
MOZ_CRASH("TypeSpecialization lacks definition of thisTypeSpecialization.");
1334
}
1335
1336
} // namespace
1337
1338
// For each MIR Instruction, this macro define the |typePolicy| method which is
1339
// using the |thisTypePolicy| method. The |thisTypePolicy| method is either a
1340
// member of the MIR Instruction, such as with MGetElementCache, a member
1341
// inherited from the TypePolicy::Data structure, or a member inherited from
1342
// NoTypePolicy if the MIR instruction has no type policy.
1343
#define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op) \
1344
const TypePolicy* js::jit::M##op::typePolicy() { \
1345
return M##op::thisTypePolicy(); \
1346
} \
1347
\
1348
MIRType js::jit::M##op::typePolicySpecialization() { \
1349
return thisTypeSpecialization(); \
1350
}
1351
1352
MIR_OPCODE_LIST(DEFINE_MIR_TYPEPOLICY_MEMBERS_)
1353
#undef DEFINE_MIR_TYPEPOLICY_MEMBERS_