TypePolicy.cpp (46098B)
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/JitAllocPolicy.h" 10 #include "jit/MIR-wasm.h" 11 #include "jit/MIR.h" 12 #include "jit/MIRGraph.h" 13 #include "js/ScalarType.h" // js::Scalar::Type 14 #include "util/DifferentialTesting.h" 15 16 using namespace js; 17 using namespace js::jit; 18 19 static void EnsureOperandNotFloat32(TempAllocator& alloc, MInstruction* def, 20 unsigned op) { 21 MDefinition* in = def->getOperand(op); 22 if (in->type() == MIRType::Float32) { 23 MToDouble* replace = MToDouble::New(alloc, in); 24 def->block()->insertBefore(def, replace); 25 if (def->isRecoveredOnBailout()) { 26 replace->setRecoveredOnBailout(); 27 } 28 def->replaceOperand(op, replace); 29 } 30 } 31 32 template <class T> 33 [[nodiscard]] static bool ConvertOperand(TempAllocator& alloc, 34 MInstruction* def, unsigned op, 35 MIRType expected) { 36 MDefinition* in = def->getOperand(op); 37 if (in->type() == expected) { 38 return true; 39 } 40 41 auto* replace = T::New(alloc, in); 42 def->block()->insertBefore(def, replace); 43 def->replaceOperand(op, replace); 44 45 return replace->typePolicy()->adjustInputs(alloc, replace); 46 } 47 48 static void SetTypePolicyBailoutKind(MInstruction* newIns, 49 MInstruction* forIns) { 50 // Infallible ToFloat32 or ToDouble doesn't bail out. 51 if ((newIns->isToFloat32() || newIns->isToDouble()) && !newIns->isGuard()) { 52 return; 53 } 54 55 // Ensure we're not introducing TypePolicy bailouts for transpiled CacheIR 56 // instructions. Unbox operations and other guards should have been inserted 57 // by the transpiler. 58 // 59 // This avoids a performance cliff because frequent TypePolicy bailouts will 60 // disable Warp compilation instead of invalidating the script. 61 // See bug 1850305. 62 MOZ_ASSERT(forIns->bailoutKind() != BailoutKind::TranspiledCacheIR); 63 64 newIns->setBailoutKind(BailoutKind::TypePolicy); 65 } 66 67 [[nodiscard]] static bool UnboxOperand(TempAllocator& alloc, MInstruction* def, 68 unsigned op, MIRType expected) { 69 MDefinition* in = def->getOperand(op); 70 if (in->type() == expected) { 71 return true; 72 } 73 74 auto* replace = MUnbox::New(alloc, in, expected, MUnbox::Fallible); 75 SetTypePolicyBailoutKind(replace, def); 76 def->block()->insertBefore(def, replace); 77 def->replaceOperand(op, replace); 78 79 return replace->typePolicy()->adjustInputs(alloc, replace); 80 } 81 82 MDefinition* js::jit::BoxAt(TempAllocator& alloc, MInstruction* at, 83 MDefinition* operand) { 84 MDefinition* boxedOperand = operand; 85 // Replace Float32 by double 86 if (operand->type() == MIRType::Float32) { 87 MInstruction* replace = MToDouble::New(alloc, operand); 88 at->block()->insertBefore(at, replace); 89 boxedOperand = replace; 90 } 91 MBox* box = MBox::New(alloc, boxedOperand); 92 at->block()->insertBefore(at, box); 93 return box; 94 } 95 96 bool BoxInputsPolicy::staticAdjustInputs(TempAllocator& alloc, 97 MInstruction* ins) { 98 for (size_t i = 0, e = ins->numOperands(); i < e; i++) { 99 MDefinition* in = ins->getOperand(i); 100 if (in->type() == MIRType::Value) { 101 continue; 102 } 103 ins->replaceOperand(i, BoxAt(alloc, ins, in)); 104 } 105 return true; 106 } 107 108 bool ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const { 109 MOZ_ASSERT(IsNumberType(ins->type())); 110 MOZ_ASSERT(ins->type() == MIRType::Double || ins->type() == MIRType::Int32 || 111 ins->type() == MIRType::Float32 || ins->type() == MIRType::IntPtr); 112 113 for (size_t i = 0, e = ins->numOperands(); i < e; i++) { 114 MDefinition* in = ins->getOperand(i); 115 if (in->type() == ins->type()) { 116 continue; 117 } 118 MOZ_ASSERT(ins->type() != MIRType::IntPtr, 119 "conversion to IntPtr not supported"); 120 121 MInstruction* replace; 122 123 if (ins->type() == MIRType::Double) { 124 replace = MToDouble::New(alloc, in); 125 } else if (ins->type() == MIRType::Float32) { 126 replace = MToFloat32::New(alloc, in); 127 } else { 128 replace = MToNumberInt32::New(alloc, in); 129 } 130 131 SetTypePolicyBailoutKind(replace, ins); 132 ins->block()->insertBefore(ins, replace); 133 ins->replaceOperand(i, replace); 134 135 if (!replace->typePolicy()->adjustInputs(alloc, replace)) { 136 return false; 137 } 138 } 139 140 return true; 141 } 142 143 bool BigIntArithPolicy::adjustInputs(TempAllocator& alloc, 144 MInstruction* ins) const { 145 MOZ_ASSERT(ins->type() == MIRType::BigInt); 146 147 for (size_t i = 0, e = ins->numOperands(); i < e; i++) { 148 if (!ConvertOperand<MToBigInt>(alloc, ins, i, MIRType::BigInt)) { 149 return false; 150 } 151 } 152 153 return true; 154 } 155 156 bool AllDoublePolicy::staticAdjustInputs(TempAllocator& alloc, 157 MInstruction* ins) { 158 for (size_t i = 0, e = ins->numOperands(); i < e; i++) { 159 MDefinition* in = ins->getOperand(i); 160 if (in->type() == MIRType::Double) { 161 continue; 162 } 163 164 if (!alloc.ensureBallast()) { 165 return false; 166 } 167 MInstruction* replace = MToDouble::New(alloc, in); 168 169 ins->block()->insertBefore(ins, replace); 170 ins->replaceOperand(i, replace); 171 172 if (!replace->typePolicy()->adjustInputs(alloc, replace)) { 173 return false; 174 } 175 } 176 177 return true; 178 } 179 180 bool ComparePolicy::adjustInputs(TempAllocator& alloc, 181 MInstruction* def) const { 182 auto convertOperand = [&](size_t index, MIRType expected) { 183 MDefinition* operand = def->getOperand(index); 184 if (operand->type() == expected) { 185 return true; 186 } 187 MInstruction* replace = nullptr; 188 switch (expected) { 189 case MIRType::Double: 190 replace = MToDouble::New(alloc, operand); 191 break; 192 case MIRType::Int32: 193 replace = MToNumberInt32::New(alloc, operand); 194 break; 195 case MIRType::Float32: 196 replace = MToFloat32::New(alloc, operand); 197 break; 198 case MIRType::String: 199 replace = 200 MUnbox::New(alloc, operand, MIRType::String, MUnbox::Fallible); 201 break; 202 case MIRType::Symbol: 203 replace = 204 MUnbox::New(alloc, operand, MIRType::Symbol, MUnbox::Fallible); 205 break; 206 case MIRType::Object: 207 replace = 208 MUnbox::New(alloc, operand, MIRType::Object, MUnbox::Fallible); 209 break; 210 case MIRType::BigInt: 211 replace = 212 MUnbox::New(alloc, operand, MIRType::BigInt, MUnbox::Fallible); 213 break; 214 default: 215 MOZ_CRASH("Unsupported MIRType"); 216 } 217 replace->setBailoutKind(BailoutKind::TypePolicy); 218 def->block()->insertBefore(def, replace); 219 def->replaceOperand(index, replace); 220 return replace->typePolicy()->adjustInputs(alloc, replace); 221 }; 222 223 MOZ_ASSERT(def->isCompare()); 224 MCompare* compare = def->toCompare(); 225 switch (compare->compareType()) { 226 case MCompare::Compare_Undefined: 227 case MCompare::Compare_Null: 228 MOZ_ASSERT(compare->rhs()->type() == MIRType::Undefined || 229 compare->rhs()->type() == MIRType::Null); 230 // IF the operand is float32, we must convert it to a double. 231 if (compare->lhs()->type() == MIRType::Float32) { 232 MInstruction* replace = MToDouble::New(alloc, compare->lhs()); 233 def->block()->insertBefore(def, replace); 234 def->replaceOperand(0, replace); 235 return replace->typePolicy()->adjustInputs(alloc, replace); 236 } 237 // GVN and lowering handle all other types. 238 return true; 239 case MCompare::Compare_Int32: 240 return convertOperand(0, MIRType::Int32) && 241 convertOperand(1, MIRType::Int32); 242 case MCompare::Compare_IntPtr: 243 case MCompare::Compare_UIntPtr: 244 MOZ_ASSERT(compare->lhs()->type() == MIRType::IntPtr); 245 MOZ_ASSERT(compare->rhs()->type() == MIRType::IntPtr); 246 return true; 247 case MCompare::Compare_Double: 248 return convertOperand(0, MIRType::Double) && 249 convertOperand(1, MIRType::Double); 250 case MCompare::Compare_Float32: 251 return convertOperand(0, MIRType::Float32) && 252 convertOperand(1, MIRType::Float32); 253 case MCompare::Compare_String: 254 return convertOperand(0, MIRType::String) && 255 convertOperand(1, MIRType::String); 256 case MCompare::Compare_Symbol: 257 return convertOperand(0, MIRType::Symbol) && 258 convertOperand(1, MIRType::Symbol); 259 case MCompare::Compare_Object: 260 return convertOperand(0, MIRType::Object) && 261 convertOperand(1, MIRType::Object); 262 case MCompare::Compare_BigInt: 263 return convertOperand(0, MIRType::BigInt) && 264 convertOperand(1, MIRType::BigInt); 265 case MCompare::Compare_BigInt_Int32: 266 return convertOperand(0, MIRType::BigInt) && 267 convertOperand(1, MIRType::Int32); 268 case MCompare::Compare_BigInt_Double: 269 return convertOperand(0, MIRType::BigInt) && 270 convertOperand(1, MIRType::Double); 271 case MCompare::Compare_BigInt_String: 272 return convertOperand(0, MIRType::BigInt) && 273 convertOperand(1, MIRType::String); 274 case MCompare::Compare_UInt32: 275 case MCompare::Compare_Int64: 276 case MCompare::Compare_UInt64: 277 case MCompare::Compare_WasmAnyRef: 278 break; 279 } 280 MOZ_CRASH("Unexpected compare type"); 281 } 282 283 bool TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const { 284 MDefinition* op = ins->getOperand(0); 285 switch (op->type()) { 286 case MIRType::Value: 287 case MIRType::Null: 288 case MIRType::Undefined: 289 case MIRType::Boolean: 290 case MIRType::Int32: 291 case MIRType::Double: 292 case MIRType::Float32: 293 case MIRType::Symbol: 294 case MIRType::BigInt: 295 case MIRType::Object: 296 break; 297 298 case MIRType::String: { 299 MStringLength* length = MStringLength::New(alloc, op); 300 ins->block()->insertBefore(ins, length); 301 ins->replaceOperand(0, length); 302 break; 303 } 304 305 case MIRType::Int64: 306 case MIRType::IntPtr: 307 MOZ_CRASH("Int64 and IntPtr are only used as input type after GVN"); 308 309 default: 310 MOZ_ASSERT(IsMagicType(op->type())); 311 ins->replaceOperand(0, BoxAt(alloc, ins, op)); 312 break; 313 } 314 return true; 315 } 316 317 bool BitwisePolicy::adjustInputs(TempAllocator& alloc, 318 MInstruction* ins) const { 319 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::Double || 320 ins->type() == MIRType::IntPtr); 321 322 // No type conversion needed when using IntPtr. 323 if (ins->type() == MIRType::IntPtr) { 324 #ifdef DEBUG 325 for (size_t i = 0, e = ins->numOperands(); i < e; i++) { 326 MOZ_ASSERT(ins->getOperand(i)->type() == MIRType::IntPtr); 327 } 328 #endif 329 return true; 330 } 331 332 // This policy works for both unary and binary bitwise operations. 333 for (size_t i = 0, e = ins->numOperands(); i < e; i++) { 334 if (!ConvertOperand<MTruncateToInt32>(alloc, ins, i, MIRType::Int32)) { 335 return false; 336 } 337 } 338 339 return true; 340 } 341 342 bool PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const { 343 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::Double); 344 345 if (ins->type() == MIRType::Int32) { 346 // Both operands must be int32. 347 return UnboxedInt32Policy<0>::staticAdjustInputs(alloc, ins) && 348 UnboxedInt32Policy<1>::staticAdjustInputs(alloc, ins); 349 } 350 351 // Otherwise, input must be a double. 352 if (!DoublePolicy<0>::staticAdjustInputs(alloc, ins)) { 353 return false; 354 } 355 356 // Power may be an int32 or a double. Integers receive a faster path. 357 MDefinition* power = ins->toPow()->power(); 358 if (power->isToDouble()) { 359 MDefinition* input = power->toToDouble()->input(); 360 if (input->type() == MIRType::Int32) { 361 power->setImplicitlyUsedUnchecked(); 362 ins->replaceOperand(1, input); 363 return true; 364 } 365 } 366 return DoublePolicy<1>::staticAdjustInputs(alloc, ins); 367 } 368 369 bool SignPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const { 370 MOZ_ASSERT(ins->isSign()); 371 MIRType specialization = ins->typePolicySpecialization(); 372 373 // MSign is specialized for int32 input types. 374 if (specialization == MIRType::Int32) { 375 return UnboxedInt32Policy<0>::staticAdjustInputs(alloc, ins); 376 } 377 378 // Otherwise convert input to double. 379 MOZ_ASSERT(IsFloatingPointType(specialization)); 380 return DoublePolicy<0>::staticAdjustInputs(alloc, ins); 381 } 382 383 template <unsigned Op> 384 bool SymbolPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 385 MInstruction* ins) { 386 return UnboxOperand(alloc, ins, Op, MIRType::Symbol); 387 } 388 389 template bool SymbolPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 390 MInstruction* ins); 391 392 template <unsigned Op> 393 bool BooleanPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 394 MInstruction* ins) { 395 return UnboxOperand(alloc, ins, Op, MIRType::Boolean); 396 } 397 398 template bool BooleanPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 399 MInstruction* ins); 400 401 template <unsigned Op> 402 bool StringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 403 MInstruction* ins) { 404 return UnboxOperand(alloc, ins, Op, MIRType::String); 405 } 406 407 template bool StringPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 408 MInstruction* ins); 409 template bool StringPolicy<1>::staticAdjustInputs(TempAllocator& alloc, 410 MInstruction* ins); 411 template bool StringPolicy<2>::staticAdjustInputs(TempAllocator& alloc, 412 MInstruction* ins); 413 414 template <unsigned Op> 415 bool ConvertToStringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 416 MInstruction* ins) { 417 MDefinition* in = ins->getOperand(Op); 418 if (in->type() == MIRType::String) { 419 return true; 420 } 421 422 MToString* replace = 423 MToString::New(alloc, in, MToString::SideEffectHandling::Bailout); 424 ins->block()->insertBefore(ins, replace); 425 ins->replaceOperand(Op, replace); 426 427 return ToStringPolicy::staticAdjustInputs(alloc, replace); 428 } 429 430 template bool ConvertToStringPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 431 MInstruction* ins); 432 template bool ConvertToStringPolicy<1>::staticAdjustInputs(TempAllocator& alloc, 433 MInstruction* ins); 434 template bool ConvertToStringPolicy<2>::staticAdjustInputs(TempAllocator& alloc, 435 MInstruction* ins); 436 437 template <unsigned Op> 438 bool BigIntPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 439 MInstruction* ins) { 440 return UnboxOperand(alloc, ins, Op, MIRType::BigInt); 441 } 442 443 template bool BigIntPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 444 MInstruction* ins); 445 template bool BigIntPolicy<1>::staticAdjustInputs(TempAllocator& alloc, 446 MInstruction* ins); 447 448 template <unsigned Op> 449 bool UnboxedInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc, 450 MInstruction* def) { 451 return UnboxOperand(alloc, def, Op, MIRType::Int32); 452 } 453 454 template bool UnboxedInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc, 455 MInstruction* def); 456 template bool UnboxedInt32Policy<1>::staticAdjustInputs(TempAllocator& alloc, 457 MInstruction* def); 458 template bool UnboxedInt32Policy<2>::staticAdjustInputs(TempAllocator& alloc, 459 MInstruction* def); 460 template bool UnboxedInt32Policy<3>::staticAdjustInputs(TempAllocator& alloc, 461 MInstruction* def); 462 463 template <unsigned Op> 464 bool Int32OrIntPtrPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 465 MInstruction* def) { 466 MDefinition* in = def->getOperand(Op); 467 if (in->type() == MIRType::IntPtr) { 468 return true; 469 } 470 471 return UnboxedInt32Policy<Op>::staticAdjustInputs(alloc, def); 472 } 473 474 template bool Int32OrIntPtrPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 475 MInstruction* def); 476 template bool Int32OrIntPtrPolicy<1>::staticAdjustInputs(TempAllocator& alloc, 477 MInstruction* def); 478 479 template <unsigned Op> 480 bool IntPtrPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 481 MInstruction* def) { 482 // We don't (yet) support converting other types to IntPtr. 483 MOZ_ASSERT(def->getOperand(Op)->type() == MIRType::IntPtr); 484 return true; 485 } 486 487 template bool IntPtrPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 488 MInstruction* def); 489 490 template bool IntPtrPolicy<1>::staticAdjustInputs(TempAllocator& alloc, 491 MInstruction* def); 492 493 template bool IntPtrPolicy<2>::staticAdjustInputs(TempAllocator& alloc, 494 MInstruction* def); 495 496 template <unsigned Op> 497 bool ConvertToInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc, 498 MInstruction* def) { 499 return ConvertOperand<MToNumberInt32>(alloc, def, Op, MIRType::Int32); 500 } 501 502 template bool ConvertToInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc, 503 MInstruction* def); 504 505 template <unsigned Op> 506 bool TruncateToInt32OrToInt64Policy<Op>::staticAdjustInputs( 507 TempAllocator& alloc, MInstruction* def) { 508 MOZ_ASSERT(def->isCompareExchangeTypedArrayElement() || 509 def->isAtomicExchangeTypedArrayElement() || 510 def->isAtomicTypedArrayElementBinop()); 511 512 Scalar::Type type; 513 if (def->isCompareExchangeTypedArrayElement()) { 514 type = def->toCompareExchangeTypedArrayElement()->arrayType(); 515 } else if (def->isAtomicExchangeTypedArrayElement()) { 516 type = def->toAtomicExchangeTypedArrayElement()->arrayType(); 517 } else { 518 type = def->toAtomicTypedArrayElementBinop()->arrayType(); 519 } 520 521 if (Scalar::isBigIntType(type)) { 522 return ConvertOperand<MToInt64>(alloc, def, Op, MIRType::Int64); 523 } 524 return ConvertOperand<MTruncateToInt32>(alloc, def, Op, MIRType::Int32); 525 } 526 527 template bool TruncateToInt32OrToInt64Policy<2>::staticAdjustInputs( 528 TempAllocator& alloc, MInstruction* def); 529 template bool TruncateToInt32OrToInt64Policy<3>::staticAdjustInputs( 530 TempAllocator& alloc, MInstruction* def); 531 532 template <unsigned Op> 533 bool DoublePolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 534 MInstruction* def) { 535 return ConvertOperand<MToDouble>(alloc, def, Op, MIRType::Double); 536 } 537 538 template bool DoublePolicy<0>::staticAdjustInputs(TempAllocator& alloc, 539 MInstruction* def); 540 template bool DoublePolicy<1>::staticAdjustInputs(TempAllocator& alloc, 541 MInstruction* def); 542 543 template <unsigned Op> 544 bool Float32Policy<Op>::staticAdjustInputs(TempAllocator& alloc, 545 MInstruction* def) { 546 return ConvertOperand<MToFloat32>(alloc, def, Op, MIRType::Float32); 547 } 548 549 template bool Float32Policy<0>::staticAdjustInputs(TempAllocator& alloc, 550 MInstruction* def); 551 template bool Float32Policy<1>::staticAdjustInputs(TempAllocator& alloc, 552 MInstruction* def); 553 template bool Float32Policy<2>::staticAdjustInputs(TempAllocator& alloc, 554 MInstruction* def); 555 556 template <unsigned Op> 557 bool FloatingPointPolicy<Op>::adjustInputs(TempAllocator& alloc, 558 MInstruction* def) const { 559 MIRType policyType = def->typePolicySpecialization(); 560 if (policyType == MIRType::Double) { 561 return DoublePolicy<Op>::staticAdjustInputs(alloc, def); 562 } 563 return Float32Policy<Op>::staticAdjustInputs(alloc, def); 564 } 565 566 template bool FloatingPointPolicy<0>::adjustInputs(TempAllocator& alloc, 567 MInstruction* def) const; 568 569 template <unsigned Op> 570 bool NoFloatPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 571 MInstruction* def) { 572 EnsureOperandNotFloat32(alloc, def, Op); 573 return true; 574 } 575 576 template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 577 MInstruction* def); 578 template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator& alloc, 579 MInstruction* def); 580 template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator& alloc, 581 MInstruction* def); 582 template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator& alloc, 583 MInstruction* def); 584 585 template <unsigned FirstOp> 586 bool NoFloatPolicyAfter<FirstOp>::staticAdjustInputs(TempAllocator& alloc, 587 MInstruction* def) { 588 for (size_t op = FirstOp, e = def->numOperands(); op < e; op++) { 589 EnsureOperandNotFloat32(alloc, def, op); 590 } 591 return true; 592 } 593 594 template bool NoFloatPolicyAfter<0>::staticAdjustInputs(TempAllocator& alloc, 595 MInstruction* def); 596 template bool NoFloatPolicyAfter<1>::staticAdjustInputs(TempAllocator& alloc, 597 MInstruction* def); 598 template bool NoFloatPolicyAfter<2>::staticAdjustInputs(TempAllocator& alloc, 599 MInstruction* def); 600 601 template <unsigned Op> 602 bool BoxPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 603 MInstruction* ins) { 604 MDefinition* in = ins->getOperand(Op); 605 if (in->type() == MIRType::Value) { 606 return true; 607 } 608 609 ins->replaceOperand(Op, BoxAt(alloc, ins, in)); 610 return true; 611 } 612 613 template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 614 MInstruction* ins); 615 template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator& alloc, 616 MInstruction* ins); 617 template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator& alloc, 618 MInstruction* ins); 619 620 template <unsigned Op, MIRType Type> 621 bool BoxExceptPolicy<Op, Type>::staticAdjustInputs(TempAllocator& alloc, 622 MInstruction* ins) { 623 MDefinition* in = ins->getOperand(Op); 624 if (in->type() == Type) { 625 return true; 626 } 627 return BoxPolicy<Op>::staticAdjustInputs(alloc, ins); 628 } 629 630 template bool BoxExceptPolicy<0, MIRType::Object>::staticAdjustInputs( 631 TempAllocator& alloc, MInstruction* ins); 632 633 template <unsigned Op> 634 bool CacheIdPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 635 MInstruction* ins) { 636 MDefinition* in = ins->getOperand(Op); 637 switch (in->type()) { 638 case MIRType::Int32: 639 case MIRType::String: 640 case MIRType::Symbol: 641 return true; 642 default: 643 return BoxPolicy<Op>::staticAdjustInputs(alloc, ins); 644 } 645 } 646 647 template bool CacheIdPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 648 MInstruction* ins); 649 template bool CacheIdPolicy<1>::staticAdjustInputs(TempAllocator& alloc, 650 MInstruction* ins); 651 652 bool ToDoublePolicy::staticAdjustInputs(TempAllocator& alloc, 653 MInstruction* ins) { 654 MOZ_ASSERT(ins->isToDouble() || ins->isToFloat32() || ins->isToFloat16()); 655 656 MDefinition* in = ins->getOperand(0); 657 switch (in->type()) { 658 case MIRType::Int32: 659 case MIRType::Float32: 660 case MIRType::Double: 661 case MIRType::Value: 662 case MIRType::Null: 663 case MIRType::Undefined: 664 case MIRType::Boolean: 665 // No need for boxing for these types. 666 return true; 667 case MIRType::Object: 668 case MIRType::String: 669 case MIRType::Symbol: 670 case MIRType::BigInt: 671 // Objects might be effectful. Symbols and BigInts give TypeError. 672 break; 673 default: 674 break; 675 } 676 677 in = BoxAt(alloc, ins, in); 678 ins->replaceOperand(0, in); 679 return true; 680 } 681 682 bool ToInt32Policy::staticAdjustInputs(TempAllocator& alloc, 683 MInstruction* ins) { 684 MOZ_ASSERT(ins->isToNumberInt32() || ins->isTruncateToInt32()); 685 686 IntConversionInputKind conversion = IntConversionInputKind::Any; 687 if (ins->isToNumberInt32()) { 688 conversion = ins->toToNumberInt32()->conversion(); 689 } 690 691 MDefinition* in = ins->getOperand(0); 692 switch (in->type()) { 693 case MIRType::Int32: 694 case MIRType::Float32: 695 case MIRType::Double: 696 case MIRType::Value: 697 // No need for boxing for these types. 698 return true; 699 case MIRType::Undefined: 700 // No need for boxing when truncating. 701 if (ins->isTruncateToInt32()) { 702 return true; 703 } 704 break; 705 case MIRType::Null: 706 // No need for boxing, when we will convert. 707 if (conversion == IntConversionInputKind::Any) { 708 return true; 709 } 710 break; 711 case MIRType::Boolean: 712 // No need for boxing, when we will convert. 713 if (conversion == IntConversionInputKind::Any) { 714 return true; 715 } 716 break; 717 case MIRType::Object: 718 case MIRType::String: 719 case MIRType::Symbol: 720 case MIRType::BigInt: 721 // Objects might be effectful. Symbols and BigInts give TypeError. 722 break; 723 default: 724 break; 725 } 726 727 in = BoxAt(alloc, ins, in); 728 ins->replaceOperand(0, in); 729 return true; 730 } 731 732 bool ToBigIntPolicy::staticAdjustInputs(TempAllocator& alloc, 733 MInstruction* ins) { 734 MOZ_ASSERT(ins->isToBigInt()); 735 736 MDefinition* in = ins->getOperand(0); 737 switch (in->type()) { 738 case MIRType::BigInt: 739 case MIRType::Value: 740 // No need for boxing for these types. 741 return true; 742 default: 743 // Any other types need to be boxed. 744 break; 745 } 746 747 in = BoxAt(alloc, ins, in); 748 ins->replaceOperand(0, in); 749 return true; 750 } 751 752 bool ToStringPolicy::staticAdjustInputs(TempAllocator& alloc, 753 MInstruction* ins) { 754 MOZ_ASSERT(ins->isToString()); 755 756 MIRType type = ins->getOperand(0)->type(); 757 if (type == MIRType::Object || type == MIRType::Symbol || 758 type == MIRType::BigInt) { 759 ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); 760 return true; 761 } 762 763 // TODO remove the following line once 966957 has landed 764 EnsureOperandNotFloat32(alloc, ins, 0); 765 766 return true; 767 } 768 769 bool ToInt64Policy::staticAdjustInputs(TempAllocator& alloc, 770 MInstruction* ins) { 771 MOZ_ASSERT(ins->isToInt64()); 772 773 MDefinition* input = ins->getOperand(0); 774 MIRType type = input->type(); 775 776 switch (type) { 777 case MIRType::BigInt: { 778 auto* replace = MTruncateBigIntToInt64::New(alloc, input); 779 ins->block()->insertBefore(ins, replace); 780 ins->replaceOperand(0, replace); 781 break; 782 } 783 // No need for boxing for these types, because they are handled specially 784 // when this instruction is lowered to LIR. 785 case MIRType::Boolean: 786 case MIRType::String: 787 case MIRType::Int64: 788 case MIRType::Value: 789 break; 790 default: 791 ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); 792 break; 793 } 794 795 return true; 796 } 797 798 template <unsigned Op> 799 bool ObjectPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, 800 MInstruction* ins) { 801 MOZ_ASSERT(ins->getOperand(Op)->type() != MIRType::Slots); 802 MOZ_ASSERT(ins->getOperand(Op)->type() != MIRType::Elements); 803 804 return UnboxOperand(alloc, ins, Op, MIRType::Object); 805 } 806 807 template bool ObjectPolicy<0>::staticAdjustInputs(TempAllocator& alloc, 808 MInstruction* ins); 809 template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator& alloc, 810 MInstruction* ins); 811 template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator& alloc, 812 MInstruction* ins); 813 template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator& alloc, 814 MInstruction* ins); 815 816 bool CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const { 817 MCallBase* call; 818 if (ins->isCall()) { 819 call = ins->toCall(); 820 } else { 821 call = ins->toCallClassHook(); 822 } 823 824 MDefinition* func = call->getCallee(); 825 if (func->type() != MIRType::Object) { 826 MInstruction* unbox = 827 MUnbox::New(alloc, func, MIRType::Object, MUnbox::Fallible); 828 SetTypePolicyBailoutKind(unbox, call); 829 call->block()->insertBefore(call, unbox); 830 call->replaceCallee(unbox); 831 832 if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) { 833 return false; 834 } 835 } 836 837 for (uint32_t i = 0; i < call->numStackArgs(); i++) { 838 if (!alloc.ensureBallast()) { 839 return false; 840 } 841 EnsureOperandNotFloat32(alloc, call, MCallBase::IndexOfStackArg(i)); 842 } 843 844 return true; 845 } 846 847 bool MegamorphicSetElementPolicy::adjustInputs(TempAllocator& alloc, 848 MInstruction* ins) const { 849 // The first operand should be an object. 850 if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins)) { 851 return false; 852 } 853 854 // Box the index and value operands. 855 for (size_t i = 1, e = ins->numOperands(); i < e; i++) { 856 MDefinition* in = ins->getOperand(i); 857 if (in->type() == MIRType::Value) { 858 continue; 859 } 860 ins->replaceOperand(i, BoxAt(alloc, ins, in)); 861 } 862 return true; 863 } 864 865 bool StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc, 866 MInstruction* ins, 867 Scalar::Type writeType, 868 MDefinition* value, 869 int valueOperand) { 870 if (Scalar::isBigIntType(writeType)) { 871 return ConvertOperand<MToInt64>(alloc, ins, valueOperand, MIRType::Int64); 872 } 873 874 MDefinition* curValue = value; 875 // First, ensure the value is int32, boolean, double or Value. 876 // The conversion is based on TypedArrayObjectTemplate::setElementTail. 877 switch (value->type()) { 878 case MIRType::Int32: 879 case MIRType::Double: 880 case MIRType::Float32: 881 case MIRType::Boolean: 882 case MIRType::Value: 883 break; 884 case MIRType::Null: 885 value->setImplicitlyUsedUnchecked(); 886 value = MConstant::NewInt32(alloc, 0); 887 ins->block()->insertBefore(ins, value->toInstruction()); 888 break; 889 case MIRType::Undefined: 890 value->setImplicitlyUsedUnchecked(); 891 value = MConstant::NewDouble(alloc, JS::GenericNaN()); 892 ins->block()->insertBefore(ins, value->toInstruction()); 893 break; 894 case MIRType::Object: 895 case MIRType::String: 896 case MIRType::Symbol: 897 case MIRType::BigInt: 898 value = BoxAt(alloc, ins, value); 899 break; 900 default: 901 MOZ_CRASH("Unexpected type"); 902 } 903 904 if (value != curValue) { 905 ins->replaceOperand(valueOperand, value); 906 curValue = value; 907 } 908 909 MOZ_ASSERT( 910 value->type() == MIRType::Int32 || value->type() == MIRType::Boolean || 911 value->type() == MIRType::Double || value->type() == MIRType::Float32 || 912 value->type() == MIRType::Value); 913 914 switch (writeType) { 915 case Scalar::Int8: 916 case Scalar::Uint8: 917 case Scalar::Int16: 918 case Scalar::Uint16: 919 case Scalar::Int32: 920 case Scalar::Uint32: 921 if (value->type() != MIRType::Int32) { 922 value = MTruncateToInt32::New(alloc, value); 923 ins->block()->insertBefore(ins, value->toInstruction()); 924 } 925 break; 926 case Scalar::Uint8Clamped: 927 // The transpiler should have inserted MClampToUint8. 928 MOZ_ASSERT(value->type() == MIRType::Int32); 929 break; 930 case Scalar::Float16: 931 value = MToFloat16::New(alloc, value); 932 ins->block()->insertBefore(ins, value->toInstruction()); 933 break; 934 case Scalar::Float32: 935 if (value->type() != MIRType::Float32) { 936 value = MToFloat32::New(alloc, value); 937 ins->block()->insertBefore(ins, value->toInstruction()); 938 } 939 break; 940 case Scalar::Float64: 941 if (value->type() != MIRType::Double) { 942 value = MToDouble::New(alloc, value); 943 ins->block()->insertBefore(ins, value->toInstruction()); 944 } 945 break; 946 default: 947 MOZ_CRASH("Invalid array type"); 948 } 949 950 // Canonicalize floating point values for differential testing. 951 if (Scalar::isFloatingType(writeType) && js::SupportDifferentialTesting()) { 952 value = MCanonicalizeNaN::New(alloc, value); 953 ins->block()->insertBefore(ins, value->toInstruction()); 954 } 955 956 if (value != curValue) { 957 ins->replaceOperand(valueOperand, value); 958 } 959 960 return true; 961 } 962 963 bool StoreUnboxedScalarPolicy::adjustInputs(TempAllocator& alloc, 964 MInstruction* ins) const { 965 MStoreUnboxedScalar* store = ins->toStoreUnboxedScalar(); 966 MOZ_ASSERT(store->elements()->type() == MIRType::Elements); 967 MOZ_ASSERT(store->index()->type() == MIRType::IntPtr); 968 969 return adjustValueInput(alloc, store, store->writeType(), store->value(), 2); 970 } 971 972 bool StoreDataViewElementPolicy::adjustInputs(TempAllocator& alloc, 973 MInstruction* ins) const { 974 auto* store = ins->toStoreDataViewElement(); 975 MOZ_ASSERT(store->elements()->type() == MIRType::Elements); 976 MOZ_ASSERT(store->index()->type() == MIRType::IntPtr); 977 MOZ_ASSERT(store->littleEndian()->type() == MIRType::Boolean); 978 979 return StoreUnboxedScalarPolicy::adjustValueInput( 980 alloc, ins, store->writeType(), store->value(), 2); 981 } 982 983 bool StoreTypedArrayHolePolicy::adjustInputs(TempAllocator& alloc, 984 MInstruction* ins) const { 985 MStoreTypedArrayElementHole* store = ins->toStoreTypedArrayElementHole(); 986 MOZ_ASSERT(store->elements()->type() == MIRType::Elements); 987 MOZ_ASSERT(store->index()->type() == MIRType::IntPtr); 988 MOZ_ASSERT(store->length()->type() == MIRType::IntPtr); 989 990 return StoreUnboxedScalarPolicy::adjustValueInput( 991 alloc, ins, store->arrayType(), store->value(), 3); 992 } 993 994 bool TypedArrayFillPolicy::adjustInputs(TempAllocator& alloc, 995 MInstruction* ins) const { 996 auto* fill = ins->toTypedArrayFill(); 997 MOZ_ASSERT(fill->object()->type() == MIRType::Object); 998 MOZ_ASSERT(fill->start()->type() == MIRType::IntPtr); 999 MOZ_ASSERT(fill->end()->type() == MIRType::IntPtr); 1000 1001 return StoreUnboxedScalarPolicy::adjustValueInput( 1002 alloc, ins, fill->elementType(), fill->value(), 1); 1003 } 1004 1005 bool ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const { 1006 MDefinition* in = ins->toClampToUint8()->input(); 1007 1008 switch (in->type()) { 1009 case MIRType::Int32: 1010 case MIRType::Double: 1011 case MIRType::Value: 1012 break; 1013 default: 1014 ins->replaceOperand(0, BoxAt(alloc, ins, in)); 1015 break; 1016 } 1017 1018 return true; 1019 } 1020 1021 // Lists of all TypePolicy specializations which are used by MIR Instructions. 1022 #define TYPE_POLICY_LIST(_) \ 1023 _(AllDoublePolicy) \ 1024 _(ArithPolicy) \ 1025 _(BigIntArithPolicy) \ 1026 _(BitwisePolicy) \ 1027 _(BoxInputsPolicy) \ 1028 _(CallPolicy) \ 1029 _(MegamorphicSetElementPolicy) \ 1030 _(ClampPolicy) \ 1031 _(ComparePolicy) \ 1032 _(PowPolicy) \ 1033 _(SignPolicy) \ 1034 _(StoreDataViewElementPolicy) \ 1035 _(StoreTypedArrayHolePolicy) \ 1036 _(StoreUnboxedScalarPolicy) \ 1037 _(TestPolicy) \ 1038 _(ToDoublePolicy) \ 1039 _(ToInt32Policy) \ 1040 _(ToBigIntPolicy) \ 1041 _(ToStringPolicy) \ 1042 _(ToInt64Policy) \ 1043 _(TypedArrayFillPolicy) 1044 1045 #define TEMPLATE_TYPE_POLICY_LIST(_) \ 1046 _(BigIntPolicy<0>) \ 1047 _(BooleanPolicy<0>) \ 1048 _(BoxExceptPolicy<0, MIRType::Object>) \ 1049 _(BoxPolicy<0>) \ 1050 _(ConvertToInt32Policy<0>) \ 1051 _(ConvertToStringPolicy<0>) \ 1052 _(ConvertToStringPolicy<2>) \ 1053 _(DoublePolicy<0>) \ 1054 _(FloatingPointPolicy<0>) \ 1055 _(UnboxedInt32Policy<0>) \ 1056 _(UnboxedInt32Policy<1>) \ 1057 _(IntPtrPolicy<0>) \ 1058 _(TruncateToInt32OrToInt64Policy<2>) \ 1059 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, BoxPolicy<2>>) \ 1060 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>) \ 1061 IF_EXPLICIT_RESOURCE_MANAGEMENT( \ 1062 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2>, \ 1063 BooleanPolicy<3>>)) \ 1064 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>) \ 1065 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, UnboxedInt32Policy<2>>) \ 1066 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2>>) \ 1067 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \ 1068 _(MixPolicy<ObjectPolicy<0>, IntPtrPolicy<1>>) \ 1069 _(MixPolicy<ObjectPolicy<0>, IntPtrPolicy<1>, IntPtrPolicy<2>>) \ 1070 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<2>>) \ 1071 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, UnboxedInt32Policy<2>>) \ 1072 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, IntPtrPolicy<2>>) \ 1073 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2>>) \ 1074 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2>>) \ 1075 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, UnboxedInt32Policy<2>, \ 1076 BoxPolicy<3>>) \ 1077 _(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \ 1078 _(MixPolicy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2>>) \ 1079 _(MixPolicy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2>>) \ 1080 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, UnboxedInt32Policy<2>>) \ 1081 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2>, \ 1082 ObjectPolicy<3>>) \ 1083 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>, \ 1084 UnboxedInt32Policy<3>>) \ 1085 _(MixPolicy<TruncateToInt32OrToInt64Policy<2>, \ 1086 TruncateToInt32OrToInt64Policy<3>>) \ 1087 _(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>) \ 1088 _(MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>, \ 1089 CacheIdPolicy<2>>) \ 1090 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, IntPtrPolicy<2>, \ 1091 IntPtrPolicy<3>, IntPtrPolicy<4>>) \ 1092 _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1>>) \ 1093 _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1>>) \ 1094 _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1>>) \ 1095 _(MixPolicy<DoublePolicy<0>, DoublePolicy<1>>) \ 1096 _(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>>) \ 1097 _(MixPolicy<Int32OrIntPtrPolicy<0>, Int32OrIntPtrPolicy<1>>) \ 1098 _(MixPolicy<IntPtrPolicy<0>, IntPtrPolicy<1>>) \ 1099 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>>) \ 1100 _(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>) \ 1101 _(MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1>>) \ 1102 _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1>>) \ 1103 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>>) \ 1104 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<2>>) \ 1105 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1>>) \ 1106 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2>>) \ 1107 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3>>) \ 1108 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicyAfter<1>>) \ 1109 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>>) \ 1110 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>>) \ 1111 _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2>>) \ 1112 _(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0>>) \ 1113 _(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>>) \ 1114 _(MixPolicy<StringPolicy<0>, StringPolicy<1>>) \ 1115 _(MixPolicy<BoxPolicy<0>, BoxPolicy<1>>) \ 1116 _(MixPolicy<BoxPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>) \ 1117 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<2>, ObjectPolicy<3>>) \ 1118 _(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, ObjectPolicy<1>>) \ 1119 _(MixPolicy<UnboxedInt32Policy<0>, BigIntPolicy<1>>) \ 1120 _(MixPolicy<UnboxedInt32Policy<0>, NoFloatPolicyAfter<1>>) \ 1121 _(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>, \ 1122 NoFloatPolicyAfter<2>>) \ 1123 _(MixPolicy<IntPtrPolicy<0>, IntPtrPolicy<1>, IntPtrPolicy<2>>) \ 1124 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, NoFloatPolicy<2>>) \ 1125 _(MixPolicy<UnboxedInt32Policy<1>, NoFloatPolicy<2>>) \ 1126 _(NoFloatPolicy<0>) \ 1127 _(NoFloatPolicy<1>) \ 1128 _(NoFloatPolicy<2>) \ 1129 _(NoFloatPolicyAfter<0>) \ 1130 _(NoFloatPolicyAfter<1>) \ 1131 _(NoFloatPolicyAfter<2>) \ 1132 _(ObjectPolicy<0>) \ 1133 _(ObjectPolicy<1>) \ 1134 _(ObjectPolicy<3>) \ 1135 _(StringPolicy<0>) \ 1136 _(SymbolPolicy<0>) 1137 1138 namespace js { 1139 namespace jit { 1140 1141 // Define for all used TypePolicy specialization, the definition for 1142 // |TypePolicy::Data::thisTypePolicy|. This function returns one constant 1143 // instance of the TypePolicy which is shared among all MIR Instructions of the 1144 // same type. 1145 // 1146 // This Macro use __VA_ARGS__ to account for commas of template parameters. 1147 #define DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_(...) \ 1148 const TypePolicy* __VA_ARGS__::Data::thisTypePolicy() { \ 1149 static constexpr __VA_ARGS__ singletonType; \ 1150 return &singletonType; \ 1151 } 1152 1153 TYPE_POLICY_LIST(DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_) 1154 TEMPLATE_TYPE_POLICY_LIST(template <> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_) 1155 #undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_ 1156 1157 } // namespace jit 1158 } // namespace js 1159 1160 namespace { 1161 1162 // For extra-good measure in case an unqualified use is ever introduced. (The 1163 // main use in the macro below is explicitly qualified so as not to consult 1164 // this scope and find this function.) 1165 inline TypePolicy* thisTypePolicy() = delete; 1166 1167 static MIRType thisTypeSpecialization() { 1168 MOZ_CRASH("TypeSpecialization lacks definition of thisTypeSpecialization."); 1169 } 1170 1171 } // namespace 1172 1173 // For each MIR Instruction, this macro define the |typePolicy| method which is 1174 // using the |thisTypePolicy| method. The |thisTypePolicy| method is either a 1175 // member of the MIR Instruction, such as with MGetElementCache, a member 1176 // inherited from the TypePolicy::Data structure, or a member inherited from 1177 // NoTypePolicy if the MIR instruction has no type policy. 1178 #define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op) \ 1179 const TypePolicy* js::jit::M##op::typePolicy() { \ 1180 return M##op::thisTypePolicy(); \ 1181 } \ 1182 \ 1183 MIRType js::jit::M##op::typePolicySpecialization() { \ 1184 return thisTypeSpecialization(); \ 1185 } 1186 1187 MIR_OPCODE_LIST(DEFINE_MIR_TYPEPOLICY_MEMBERS_) 1188 #undef DEFINE_MIR_TYPEPOLICY_MEMBERS_