Recover.cpp (75611B)
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/Recover.h" 8 9 #include "mozilla/Casting.h" 10 11 #include "jsmath.h" 12 13 #include "builtin/Object.h" 14 #include "builtin/String.h" 15 #include "jit/AtomicOperations.h" 16 #include "jit/Bailouts.h" 17 #include "jit/CompileInfo.h" 18 #include "jit/Ion.h" 19 #include "jit/JitSpewer.h" 20 #include "jit/JSJitFrameIter.h" 21 #include "jit/MIR-wasm.h" 22 #include "jit/MIR.h" 23 #include "jit/MIRGraph.h" 24 #include "jit/VMFunctions.h" 25 #include "js/ScalarType.h" 26 #include "util/DifferentialTesting.h" 27 #include "vm/BigIntType.h" 28 #include "vm/EqualityOperations.h" 29 #include "vm/Interpreter.h" 30 #include "vm/Iteration.h" 31 #include "vm/JSContext.h" 32 #include "vm/JSObject.h" 33 #include "vm/PlainObject.h" // js::PlainObject 34 #include "vm/StringType.h" 35 #include "vm/Watchtower.h" 36 37 #include "vm/Interpreter-inl.h" 38 39 using namespace js; 40 using namespace js::jit; 41 42 bool MNode::writeRecoverData(CompactBufferWriter& writer) const { 43 MOZ_CRASH("This instruction is not serializable"); 44 } 45 46 void RInstruction::readRecoverData(CompactBufferReader& reader, 47 RInstructionStorage* raw) { 48 uint32_t op = reader.readUnsigned(); 49 switch (Opcode(op)) { 50 #define MATCH_OPCODES_(op) \ 51 case Recover_##op: \ 52 static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \ 53 "storage space must be big enough to store R" #op); \ 54 static_assert(alignof(R##op) <= alignof(RInstructionStorage), \ 55 "storage space must be aligned adequate to store R" #op); \ 56 new (raw->addr()) R##op(reader); \ 57 break; 58 59 RECOVER_OPCODE_LIST(MATCH_OPCODES_) 60 #undef MATCH_OPCODES_ 61 62 case Recover_Invalid: 63 default: 64 MOZ_CRASH("Bad decoding of the previous instruction?"); 65 } 66 } 67 68 bool MResumePoint::writeRecoverData(CompactBufferWriter& writer) const { 69 writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint)); 70 71 MBasicBlock* bb = block(); 72 bool hasFun = bb->info().hasFunMaybeLazy(); 73 uint32_t nargs = bb->info().nargs(); 74 JSScript* script = bb->info().script(); 75 uint32_t exprStack = stackDepth() - bb->info().ninvoke(); 76 77 #ifdef DEBUG 78 // Ensure that all snapshot which are encoded can safely be used for 79 // bailouts. 80 uint32_t numIntermediate = NumIntermediateValues(mode()); 81 if (JSContext* cx = GetJitContext()->cx) { 82 if (!AssertBailoutStackDepth(cx, script, pc(), mode(), 83 exprStack - numIntermediate)) { 84 return false; 85 } 86 } 87 #endif 88 89 uint32_t formalArgs = CountArgSlots(script, hasFun, nargs); 90 91 // Test if we honor the maximum of arguments at all times. This is a sanity 92 // check and not an algorithm limit. So check might be a bit too loose. +4 93 // to account for scope chain, return value, this value and maybe 94 // arguments_object. 95 MOZ_ASSERT(formalArgs < SNAPSHOT_MAX_NARGS + 4); 96 97 #ifdef JS_JITSPEW 98 uint32_t implicit = StartArgSlot(script); 99 #endif 100 uint32_t nallocs = formalArgs + script->nfixed() + exprStack; 101 102 JitSpew(JitSpew_IonSnapshots, 103 "Starting frame; implicit %u, formals %u, fixed %zu, exprs %u", 104 implicit, formalArgs - implicit, script->nfixed(), exprStack); 105 106 uint32_t pcOff = script->pcToOffset(pc()); 107 JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, mode %s, nslots %u", 108 pcOff, ResumeModeToString(mode()), nallocs); 109 110 uint32_t pcOffAndMode = 111 (pcOff << RResumePoint::PCOffsetShift) | uint32_t(mode()); 112 MOZ_RELEASE_ASSERT((pcOffAndMode >> RResumePoint::PCOffsetShift) == pcOff, 113 "pcOff doesn't fit in pcOffAndMode"); 114 writer.writeUnsigned(pcOffAndMode); 115 116 writer.writeUnsigned(nallocs); 117 return true; 118 } 119 120 RResumePoint::RResumePoint(CompactBufferReader& reader) { 121 pcOffsetAndMode_ = reader.readUnsigned(); 122 numOperands_ = reader.readUnsigned(); 123 JitSpew(JitSpew_IonSnapshots, 124 "Read RResumePoint (pc offset %u, mode %s, nslots %u)", pcOffset(), 125 ResumeModeToString(mode()), numOperands_); 126 } 127 128 bool RResumePoint::recover(JSContext* cx, SnapshotIterator& iter) const { 129 MOZ_CRASH("This instruction is not recoverable."); 130 } 131 132 bool MBitNot::writeRecoverData(CompactBufferWriter& writer) const { 133 // 64-bit int bitnots exist only when compiling wasm; they exist neither for 134 // JS nor asm.js. So we don't expect them here. 135 MOZ_ASSERT(type() != MIRType::Int64); 136 MOZ_ASSERT(canRecoverOnBailout()); 137 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitNot)); 138 return true; 139 } 140 141 RBitNot::RBitNot(CompactBufferReader& reader) {} 142 143 bool RBitNot::recover(JSContext* cx, SnapshotIterator& iter) const { 144 RootedValue operand(cx, iter.read()); 145 RootedValue result(cx); 146 147 if (!js::BitNot(cx, &operand, &result)) { 148 return false; 149 } 150 151 iter.storeInstructionResult(result); 152 return true; 153 } 154 155 bool MBitAnd::writeRecoverData(CompactBufferWriter& writer) const { 156 MOZ_ASSERT(canRecoverOnBailout()); 157 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd)); 158 return true; 159 } 160 161 RBitAnd::RBitAnd(CompactBufferReader& reader) {} 162 163 bool RBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const { 164 RootedValue lhs(cx, iter.read()); 165 RootedValue rhs(cx, iter.read()); 166 RootedValue result(cx); 167 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); 168 169 if (!js::BitAnd(cx, &lhs, &rhs, &result)) { 170 return false; 171 } 172 173 iter.storeInstructionResult(result); 174 return true; 175 } 176 177 bool MBitOr::writeRecoverData(CompactBufferWriter& writer) const { 178 MOZ_ASSERT(canRecoverOnBailout()); 179 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitOr)); 180 return true; 181 } 182 183 RBitOr::RBitOr(CompactBufferReader& reader) {} 184 185 bool RBitOr::recover(JSContext* cx, SnapshotIterator& iter) const { 186 RootedValue lhs(cx, iter.read()); 187 RootedValue rhs(cx, iter.read()); 188 RootedValue result(cx); 189 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); 190 191 if (!js::BitOr(cx, &lhs, &rhs, &result)) { 192 return false; 193 } 194 195 iter.storeInstructionResult(result); 196 return true; 197 } 198 199 bool MBitXor::writeRecoverData(CompactBufferWriter& writer) const { 200 MOZ_ASSERT(canRecoverOnBailout()); 201 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitXor)); 202 return true; 203 } 204 205 RBitXor::RBitXor(CompactBufferReader& reader) {} 206 207 bool RBitXor::recover(JSContext* cx, SnapshotIterator& iter) const { 208 RootedValue lhs(cx, iter.read()); 209 RootedValue rhs(cx, iter.read()); 210 RootedValue result(cx); 211 212 if (!js::BitXor(cx, &lhs, &rhs, &result)) { 213 return false; 214 } 215 216 iter.storeInstructionResult(result); 217 return true; 218 } 219 220 bool MLsh::writeRecoverData(CompactBufferWriter& writer) const { 221 MOZ_ASSERT(canRecoverOnBailout()); 222 writer.writeUnsigned(uint32_t(RInstruction::Recover_Lsh)); 223 return true; 224 } 225 226 RLsh::RLsh(CompactBufferReader& reader) {} 227 228 bool RLsh::recover(JSContext* cx, SnapshotIterator& iter) const { 229 RootedValue lhs(cx, iter.read()); 230 RootedValue rhs(cx, iter.read()); 231 RootedValue result(cx); 232 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); 233 234 if (!js::BitLsh(cx, &lhs, &rhs, &result)) { 235 return false; 236 } 237 238 iter.storeInstructionResult(result); 239 return true; 240 } 241 242 bool MRsh::writeRecoverData(CompactBufferWriter& writer) const { 243 MOZ_ASSERT(canRecoverOnBailout()); 244 writer.writeUnsigned(uint32_t(RInstruction::Recover_Rsh)); 245 return true; 246 } 247 248 RRsh::RRsh(CompactBufferReader& reader) {} 249 250 bool RRsh::recover(JSContext* cx, SnapshotIterator& iter) const { 251 RootedValue lhs(cx, iter.read()); 252 RootedValue rhs(cx, iter.read()); 253 RootedValue result(cx); 254 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); 255 256 if (!js::BitRsh(cx, &lhs, &rhs, &result)) { 257 return false; 258 } 259 260 iter.storeInstructionResult(result); 261 return true; 262 } 263 264 bool MUrsh::writeRecoverData(CompactBufferWriter& writer) const { 265 MOZ_ASSERT(canRecoverOnBailout()); 266 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ursh)); 267 return true; 268 } 269 270 RUrsh::RUrsh(CompactBufferReader& reader) {} 271 272 bool RUrsh::recover(JSContext* cx, SnapshotIterator& iter) const { 273 RootedValue lhs(cx, iter.read()); 274 RootedValue rhs(cx, iter.read()); 275 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); 276 277 RootedValue result(cx); 278 if (!js::UrshValues(cx, &lhs, &rhs, &result)) { 279 return false; 280 } 281 282 iter.storeInstructionResult(result); 283 return true; 284 } 285 286 bool MSignExtendInt32::writeRecoverData(CompactBufferWriter& writer) const { 287 MOZ_ASSERT(canRecoverOnBailout()); 288 writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtendInt32)); 289 MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_); 290 writer.writeByte(uint8_t(mode_)); 291 return true; 292 } 293 294 RSignExtendInt32::RSignExtendInt32(CompactBufferReader& reader) { 295 mode_ = reader.readByte(); 296 } 297 298 bool RSignExtendInt32::recover(JSContext* cx, SnapshotIterator& iter) const { 299 RootedValue operand(cx, iter.read()); 300 301 int32_t i; 302 if (!ToInt32(cx, operand, &i)) { 303 return false; 304 } 305 306 int32_t result; 307 switch (MSignExtendInt32::Mode(mode_)) { 308 case MSignExtendInt32::Byte: 309 result = static_cast<int8_t>(i); 310 break; 311 case MSignExtendInt32::Half: 312 result = static_cast<int16_t>(i); 313 break; 314 } 315 316 iter.storeInstructionResult(JS::Int32Value(result)); 317 return true; 318 } 319 320 bool MAdd::writeRecoverData(CompactBufferWriter& writer) const { 321 MOZ_ASSERT(canRecoverOnBailout()); 322 writer.writeUnsigned(uint32_t(RInstruction::Recover_Add)); 323 writer.writeByte(type() == MIRType::Float32); 324 return true; 325 } 326 327 RAdd::RAdd(CompactBufferReader& reader) { 328 isFloatOperation_ = reader.readByte(); 329 } 330 331 bool RAdd::recover(JSContext* cx, SnapshotIterator& iter) const { 332 RootedValue lhs(cx, iter.read()); 333 RootedValue rhs(cx, iter.read()); 334 RootedValue result(cx); 335 336 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); 337 if (!js::AddValues(cx, &lhs, &rhs, &result)) { 338 return false; 339 } 340 341 // MIRType::Float32 is a specialization embedding the fact that the result is 342 // rounded to a Float32. 343 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) { 344 return false; 345 } 346 347 iter.storeInstructionResult(result); 348 return true; 349 } 350 351 bool MSub::writeRecoverData(CompactBufferWriter& writer) const { 352 MOZ_ASSERT(canRecoverOnBailout()); 353 writer.writeUnsigned(uint32_t(RInstruction::Recover_Sub)); 354 writer.writeByte(type() == MIRType::Float32); 355 return true; 356 } 357 358 RSub::RSub(CompactBufferReader& reader) { 359 isFloatOperation_ = reader.readByte(); 360 } 361 362 bool RSub::recover(JSContext* cx, SnapshotIterator& iter) const { 363 RootedValue lhs(cx, iter.read()); 364 RootedValue rhs(cx, iter.read()); 365 RootedValue result(cx); 366 367 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); 368 if (!js::SubValues(cx, &lhs, &rhs, &result)) { 369 return false; 370 } 371 372 // MIRType::Float32 is a specialization embedding the fact that the result is 373 // rounded to a Float32. 374 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) { 375 return false; 376 } 377 378 iter.storeInstructionResult(result); 379 return true; 380 } 381 382 bool MMul::writeRecoverData(CompactBufferWriter& writer) const { 383 MOZ_ASSERT(canRecoverOnBailout()); 384 writer.writeUnsigned(uint32_t(RInstruction::Recover_Mul)); 385 writer.writeByte(type() == MIRType::Float32); 386 MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_); 387 writer.writeByte(uint8_t(mode_)); 388 return true; 389 } 390 391 RMul::RMul(CompactBufferReader& reader) { 392 isFloatOperation_ = reader.readByte(); 393 mode_ = reader.readByte(); 394 } 395 396 bool RMul::recover(JSContext* cx, SnapshotIterator& iter) const { 397 RootedValue lhs(cx, iter.read()); 398 RootedValue rhs(cx, iter.read()); 399 RootedValue result(cx); 400 401 if (MMul::Mode(mode_) == MMul::Normal) { 402 if (!js::MulValues(cx, &lhs, &rhs, &result)) { 403 return false; 404 } 405 406 // MIRType::Float32 is a specialization embedding the fact that the 407 // result is rounded to a Float32. 408 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) { 409 return false; 410 } 411 } else { 412 MOZ_ASSERT(MMul::Mode(mode_) == MMul::Integer); 413 if (!js::math_imul_handle(cx, lhs, rhs, &result)) { 414 return false; 415 } 416 } 417 418 iter.storeInstructionResult(result); 419 return true; 420 } 421 422 bool MDiv::writeRecoverData(CompactBufferWriter& writer) const { 423 MOZ_ASSERT(canRecoverOnBailout()); 424 writer.writeUnsigned(uint32_t(RInstruction::Recover_Div)); 425 writer.writeByte(type() == MIRType::Float32); 426 return true; 427 } 428 429 RDiv::RDiv(CompactBufferReader& reader) { 430 isFloatOperation_ = reader.readByte(); 431 } 432 433 bool RDiv::recover(JSContext* cx, SnapshotIterator& iter) const { 434 RootedValue lhs(cx, iter.read()); 435 RootedValue rhs(cx, iter.read()); 436 RootedValue result(cx); 437 438 if (!js::DivValues(cx, &lhs, &rhs, &result)) { 439 return false; 440 } 441 442 // MIRType::Float32 is a specialization embedding the fact that the result is 443 // rounded to a Float32. 444 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) { 445 return false; 446 } 447 448 iter.storeInstructionResult(result); 449 return true; 450 } 451 452 bool MMod::writeRecoverData(CompactBufferWriter& writer) const { 453 MOZ_ASSERT(canRecoverOnBailout()); 454 writer.writeUnsigned(uint32_t(RInstruction::Recover_Mod)); 455 return true; 456 } 457 458 RMod::RMod(CompactBufferReader& reader) {} 459 460 bool RMod::recover(JSContext* cx, SnapshotIterator& iter) const { 461 RootedValue lhs(cx, iter.read()); 462 RootedValue rhs(cx, iter.read()); 463 RootedValue result(cx); 464 465 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); 466 if (!js::ModValues(cx, &lhs, &rhs, &result)) { 467 return false; 468 } 469 470 iter.storeInstructionResult(result); 471 return true; 472 } 473 474 bool MNot::writeRecoverData(CompactBufferWriter& writer) const { 475 MOZ_ASSERT(canRecoverOnBailout()); 476 writer.writeUnsigned(uint32_t(RInstruction::Recover_Not)); 477 return true; 478 } 479 480 RNot::RNot(CompactBufferReader& reader) {} 481 482 bool RNot::recover(JSContext* cx, SnapshotIterator& iter) const { 483 Rooted<Value> value(cx); 484 if (!iter.readMaybeUnpackedBigInt(cx, &value)) { 485 return false; 486 } 487 488 bool result = !ToBoolean(value); 489 iter.storeInstructionResult(BooleanValue(result)); 490 return true; 491 } 492 493 bool MBigIntAdd::writeRecoverData(CompactBufferWriter& writer) const { 494 MOZ_ASSERT(canRecoverOnBailout()); 495 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAdd)); 496 return true; 497 } 498 499 RBigIntAdd::RBigIntAdd(CompactBufferReader& reader) {} 500 501 bool RBigIntAdd::recover(JSContext* cx, SnapshotIterator& iter) const { 502 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 503 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 504 505 BigInt* result = BigInt::add(cx, lhs, rhs); 506 if (!result) { 507 return false; 508 } 509 510 iter.storeInstructionResult(BigIntValue(result)); 511 return true; 512 } 513 514 bool MBigIntSub::writeRecoverData(CompactBufferWriter& writer) const { 515 MOZ_ASSERT(canRecoverOnBailout()); 516 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntSub)); 517 return true; 518 } 519 520 RBigIntSub::RBigIntSub(CompactBufferReader& reader) {} 521 522 bool RBigIntSub::recover(JSContext* cx, SnapshotIterator& iter) const { 523 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 524 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 525 526 BigInt* result = BigInt::sub(cx, lhs, rhs); 527 if (!result) { 528 return false; 529 } 530 531 iter.storeInstructionResult(BigIntValue(result)); 532 return true; 533 } 534 535 bool MBigIntMul::writeRecoverData(CompactBufferWriter& writer) const { 536 MOZ_ASSERT(canRecoverOnBailout()); 537 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMul)); 538 return true; 539 } 540 541 RBigIntMul::RBigIntMul(CompactBufferReader& reader) {} 542 543 bool RBigIntMul::recover(JSContext* cx, SnapshotIterator& iter) const { 544 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 545 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 546 547 BigInt* result = BigInt::mul(cx, lhs, rhs); 548 if (!result) { 549 return false; 550 } 551 552 iter.storeInstructionResult(BigIntValue(result)); 553 return true; 554 } 555 556 bool MBigIntDiv::writeRecoverData(CompactBufferWriter& writer) const { 557 MOZ_ASSERT(canRecoverOnBailout()); 558 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDiv)); 559 return true; 560 } 561 562 RBigIntDiv::RBigIntDiv(CompactBufferReader& reader) {} 563 564 bool RBigIntDiv::recover(JSContext* cx, SnapshotIterator& iter) const { 565 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 566 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 567 MOZ_ASSERT(!rhs->isZero(), 568 "division by zero throws and therefore can't be recovered"); 569 570 BigInt* result = BigInt::div(cx, lhs, rhs); 571 if (!result) { 572 return false; 573 } 574 575 iter.storeInstructionResult(BigIntValue(result)); 576 return true; 577 } 578 579 bool MBigIntMod::writeRecoverData(CompactBufferWriter& writer) const { 580 MOZ_ASSERT(canRecoverOnBailout()); 581 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMod)); 582 return true; 583 } 584 585 RBigIntMod::RBigIntMod(CompactBufferReader& reader) {} 586 587 bool RBigIntMod::recover(JSContext* cx, SnapshotIterator& iter) const { 588 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 589 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 590 MOZ_ASSERT(!rhs->isZero(), 591 "division by zero throws and therefore can't be recovered"); 592 593 BigInt* result = BigInt::mod(cx, lhs, rhs); 594 if (!result) { 595 return false; 596 } 597 598 iter.storeInstructionResult(BigIntValue(result)); 599 return true; 600 } 601 602 bool MBigIntPow::writeRecoverData(CompactBufferWriter& writer) const { 603 MOZ_ASSERT(canRecoverOnBailout()); 604 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPow)); 605 return true; 606 } 607 608 RBigIntPow::RBigIntPow(CompactBufferReader& reader) {} 609 610 bool RBigIntPow::recover(JSContext* cx, SnapshotIterator& iter) const { 611 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 612 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 613 MOZ_ASSERT(!rhs->isNegative(), 614 "negative exponent throws and therefore can't be recovered"); 615 616 BigInt* result = BigInt::pow(cx, lhs, rhs); 617 if (!result) { 618 return false; 619 } 620 621 iter.storeInstructionResult(BigIntValue(result)); 622 return true; 623 } 624 625 bool MBigIntBitAnd::writeRecoverData(CompactBufferWriter& writer) const { 626 MOZ_ASSERT(canRecoverOnBailout()); 627 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitAnd)); 628 return true; 629 } 630 631 RBigIntBitAnd::RBigIntBitAnd(CompactBufferReader& reader) {} 632 633 bool RBigIntBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const { 634 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 635 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 636 637 BigInt* result = BigInt::bitAnd(cx, lhs, rhs); 638 if (!result) { 639 return false; 640 } 641 642 iter.storeInstructionResult(BigIntValue(result)); 643 return true; 644 } 645 646 bool MBigIntBitOr::writeRecoverData(CompactBufferWriter& writer) const { 647 MOZ_ASSERT(canRecoverOnBailout()); 648 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitOr)); 649 return true; 650 } 651 652 RBigIntBitOr::RBigIntBitOr(CompactBufferReader& reader) {} 653 654 bool RBigIntBitOr::recover(JSContext* cx, SnapshotIterator& iter) const { 655 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 656 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 657 658 BigInt* result = BigInt::bitOr(cx, lhs, rhs); 659 if (!result) { 660 return false; 661 } 662 663 iter.storeInstructionResult(BigIntValue(result)); 664 return true; 665 } 666 667 bool MBigIntBitXor::writeRecoverData(CompactBufferWriter& writer) const { 668 MOZ_ASSERT(canRecoverOnBailout()); 669 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitXor)); 670 return true; 671 } 672 673 RBigIntBitXor::RBigIntBitXor(CompactBufferReader& reader) {} 674 675 bool RBigIntBitXor::recover(JSContext* cx, SnapshotIterator& iter) const { 676 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 677 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 678 679 BigInt* result = BigInt::bitXor(cx, lhs, rhs); 680 if (!result) { 681 return false; 682 } 683 684 iter.storeInstructionResult(BigIntValue(result)); 685 return true; 686 } 687 688 bool MBigIntLsh::writeRecoverData(CompactBufferWriter& writer) const { 689 MOZ_ASSERT(canRecoverOnBailout()); 690 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntLsh)); 691 return true; 692 } 693 694 RBigIntLsh::RBigIntLsh(CompactBufferReader& reader) {} 695 696 bool RBigIntLsh::recover(JSContext* cx, SnapshotIterator& iter) const { 697 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 698 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 699 700 BigInt* result = BigInt::lsh(cx, lhs, rhs); 701 if (!result) { 702 return false; 703 } 704 705 iter.storeInstructionResult(BigIntValue(result)); 706 return true; 707 } 708 709 bool MBigIntRsh::writeRecoverData(CompactBufferWriter& writer) const { 710 MOZ_ASSERT(canRecoverOnBailout()); 711 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntRsh)); 712 return true; 713 } 714 715 RBigIntRsh::RBigIntRsh(CompactBufferReader& reader) {} 716 717 bool RBigIntRsh::recover(JSContext* cx, SnapshotIterator& iter) const { 718 Rooted<BigInt*> lhs(cx, iter.readBigInt()); 719 Rooted<BigInt*> rhs(cx, iter.readBigInt()); 720 721 BigInt* result = BigInt::rsh(cx, lhs, rhs); 722 if (!result) { 723 return false; 724 } 725 726 iter.storeInstructionResult(BigIntValue(result)); 727 return true; 728 } 729 730 bool MBigIntIncrement::writeRecoverData(CompactBufferWriter& writer) const { 731 MOZ_ASSERT(canRecoverOnBailout()); 732 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntIncrement)); 733 return true; 734 } 735 736 RBigIntIncrement::RBigIntIncrement(CompactBufferReader& reader) {} 737 738 bool RBigIntIncrement::recover(JSContext* cx, SnapshotIterator& iter) const { 739 Rooted<BigInt*> operand(cx, iter.readBigInt()); 740 741 BigInt* result = BigInt::inc(cx, operand); 742 if (!result) { 743 return false; 744 } 745 746 iter.storeInstructionResult(BigIntValue(result)); 747 return true; 748 } 749 750 bool MBigIntDecrement::writeRecoverData(CompactBufferWriter& writer) const { 751 MOZ_ASSERT(canRecoverOnBailout()); 752 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDecrement)); 753 return true; 754 } 755 756 RBigIntDecrement::RBigIntDecrement(CompactBufferReader& reader) {} 757 758 bool RBigIntDecrement::recover(JSContext* cx, SnapshotIterator& iter) const { 759 Rooted<BigInt*> operand(cx, iter.readBigInt()); 760 761 BigInt* result = BigInt::dec(cx, operand); 762 if (!result) { 763 return false; 764 } 765 766 iter.storeInstructionResult(BigIntValue(result)); 767 return true; 768 } 769 770 bool MBigIntNegate::writeRecoverData(CompactBufferWriter& writer) const { 771 MOZ_ASSERT(canRecoverOnBailout()); 772 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntNegate)); 773 return true; 774 } 775 776 RBigIntNegate::RBigIntNegate(CompactBufferReader& reader) {} 777 778 bool RBigIntNegate::recover(JSContext* cx, SnapshotIterator& iter) const { 779 Rooted<BigInt*> operand(cx, iter.readBigInt()); 780 781 BigInt* result = BigInt::neg(cx, operand); 782 if (!result) { 783 return false; 784 } 785 786 iter.storeInstructionResult(BigIntValue(result)); 787 return true; 788 } 789 790 bool MBigIntBitNot::writeRecoverData(CompactBufferWriter& writer) const { 791 MOZ_ASSERT(canRecoverOnBailout()); 792 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitNot)); 793 return true; 794 } 795 796 RBigIntBitNot::RBigIntBitNot(CompactBufferReader& reader) {} 797 798 bool RBigIntBitNot::recover(JSContext* cx, SnapshotIterator& iter) const { 799 Rooted<BigInt*> operand(cx, iter.readBigInt()); 800 801 BigInt* result = BigInt::bitNot(cx, operand); 802 if (!result) { 803 return false; 804 } 805 806 iter.storeInstructionResult(BigIntValue(result)); 807 return true; 808 } 809 810 bool MBigIntToIntPtr::writeRecoverData(CompactBufferWriter& writer) const { 811 MOZ_ASSERT(canRecoverOnBailout()); 812 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntToIntPtr)); 813 return true; 814 } 815 816 RBigIntToIntPtr::RBigIntToIntPtr(CompactBufferReader& reader) {} 817 818 bool RBigIntToIntPtr::recover(JSContext* cx, SnapshotIterator& iter) const { 819 Value input = iter.read(); 820 MOZ_ASSERT(input.isBigInt()); 821 822 iter.storeInstructionResult(input); 823 return true; 824 } 825 826 bool MIntPtrToBigInt::writeRecoverData(CompactBufferWriter& writer) const { 827 MOZ_ASSERT(canRecoverOnBailout()); 828 writer.writeUnsigned(uint32_t(RInstruction::Recover_IntPtrToBigInt)); 829 return true; 830 } 831 832 RIntPtrToBigInt::RIntPtrToBigInt(CompactBufferReader& reader) {} 833 834 bool RIntPtrToBigInt::recover(JSContext* cx, SnapshotIterator& iter) const { 835 BigInt* input = iter.readBigInt(cx); 836 if (!input) { 837 return false; 838 } 839 840 iter.storeInstructionResult(JS::BigIntValue(input)); 841 return true; 842 } 843 844 bool MBigIntPtrAdd::writeRecoverData(CompactBufferWriter& writer) const { 845 MOZ_ASSERT(canRecoverOnBailout()); 846 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrAdd)); 847 return true; 848 } 849 850 RBigIntPtrAdd::RBigIntPtrAdd(CompactBufferReader& reader) {} 851 852 bool RBigIntPtrAdd::recover(JSContext* cx, SnapshotIterator& iter) const { 853 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 854 if (!lhs) { 855 return false; 856 } 857 858 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 859 if (!rhs) { 860 return false; 861 } 862 863 BigInt* result = BigInt::add(cx, lhs, rhs); 864 if (!result) { 865 return false; 866 } 867 868 iter.storeInstructionResult(JS::BigIntValue(result)); 869 return true; 870 } 871 872 bool MBigIntPtrSub::writeRecoverData(CompactBufferWriter& writer) const { 873 MOZ_ASSERT(canRecoverOnBailout()); 874 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrSub)); 875 return true; 876 } 877 878 RBigIntPtrSub::RBigIntPtrSub(CompactBufferReader& reader) {} 879 880 bool RBigIntPtrSub::recover(JSContext* cx, SnapshotIterator& iter) const { 881 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 882 if (!lhs) { 883 return false; 884 } 885 886 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 887 if (!rhs) { 888 return false; 889 } 890 891 BigInt* result = BigInt::sub(cx, lhs, rhs); 892 if (!result) { 893 return false; 894 } 895 896 iter.storeInstructionResult(JS::BigIntValue(result)); 897 return true; 898 } 899 900 bool MBigIntPtrMul::writeRecoverData(CompactBufferWriter& writer) const { 901 MOZ_ASSERT(canRecoverOnBailout()); 902 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrMul)); 903 return true; 904 } 905 906 RBigIntPtrMul::RBigIntPtrMul(CompactBufferReader& reader) {} 907 908 bool RBigIntPtrMul::recover(JSContext* cx, SnapshotIterator& iter) const { 909 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 910 if (!lhs) { 911 return false; 912 } 913 914 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 915 if (!rhs) { 916 return false; 917 } 918 919 BigInt* result = BigInt::mul(cx, lhs, rhs); 920 if (!result) { 921 return false; 922 } 923 924 iter.storeInstructionResult(JS::BigIntValue(result)); 925 return true; 926 } 927 928 bool MBigIntPtrDiv::writeRecoverData(CompactBufferWriter& writer) const { 929 MOZ_ASSERT(canRecoverOnBailout()); 930 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrDiv)); 931 return true; 932 } 933 934 RBigIntPtrDiv::RBigIntPtrDiv(CompactBufferReader& reader) {} 935 936 bool RBigIntPtrDiv::recover(JSContext* cx, SnapshotIterator& iter) const { 937 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 938 if (!lhs) { 939 return false; 940 } 941 942 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 943 if (!rhs) { 944 return false; 945 } 946 947 BigInt* result = BigInt::div(cx, lhs, rhs); 948 if (!result) { 949 return false; 950 } 951 952 iter.storeInstructionResult(JS::BigIntValue(result)); 953 return true; 954 } 955 956 bool MBigIntPtrMod::writeRecoverData(CompactBufferWriter& writer) const { 957 MOZ_ASSERT(canRecoverOnBailout()); 958 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrMod)); 959 return true; 960 } 961 962 RBigIntPtrMod::RBigIntPtrMod(CompactBufferReader& reader) {} 963 964 bool RBigIntPtrMod::recover(JSContext* cx, SnapshotIterator& iter) const { 965 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 966 if (!lhs) { 967 return false; 968 } 969 970 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 971 if (!rhs) { 972 return false; 973 } 974 975 BigInt* result = BigInt::mod(cx, lhs, rhs); 976 if (!result) { 977 return false; 978 } 979 980 iter.storeInstructionResult(JS::BigIntValue(result)); 981 return true; 982 } 983 984 bool MBigIntPtrPow::writeRecoverData(CompactBufferWriter& writer) const { 985 MOZ_ASSERT(canRecoverOnBailout()); 986 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrPow)); 987 return true; 988 } 989 990 RBigIntPtrPow::RBigIntPtrPow(CompactBufferReader& reader) {} 991 992 bool RBigIntPtrPow::recover(JSContext* cx, SnapshotIterator& iter) const { 993 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 994 if (!lhs) { 995 return false; 996 } 997 998 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 999 if (!rhs) { 1000 return false; 1001 } 1002 1003 BigInt* result = BigInt::pow(cx, lhs, rhs); 1004 if (!result) { 1005 return false; 1006 } 1007 1008 iter.storeInstructionResult(JS::BigIntValue(result)); 1009 return true; 1010 } 1011 1012 bool MBigIntPtrBitAnd::writeRecoverData(CompactBufferWriter& writer) const { 1013 MOZ_ASSERT(canRecoverOnBailout()); 1014 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrBitAnd)); 1015 return true; 1016 } 1017 1018 RBigIntPtrBitAnd::RBigIntPtrBitAnd(CompactBufferReader& reader) {} 1019 1020 bool RBigIntPtrBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const { 1021 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 1022 if (!lhs) { 1023 return false; 1024 } 1025 1026 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 1027 if (!rhs) { 1028 return false; 1029 } 1030 1031 BigInt* result = BigInt::bitAnd(cx, lhs, rhs); 1032 if (!result) { 1033 return false; 1034 } 1035 1036 iter.storeInstructionResult(JS::BigIntValue(result)); 1037 return true; 1038 } 1039 1040 bool MBigIntPtrBitOr::writeRecoverData(CompactBufferWriter& writer) const { 1041 MOZ_ASSERT(canRecoverOnBailout()); 1042 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrBitOr)); 1043 return true; 1044 } 1045 1046 RBigIntPtrBitOr::RBigIntPtrBitOr(CompactBufferReader& reader) {} 1047 1048 bool RBigIntPtrBitOr::recover(JSContext* cx, SnapshotIterator& iter) const { 1049 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 1050 if (!lhs) { 1051 return false; 1052 } 1053 1054 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 1055 if (!rhs) { 1056 return false; 1057 } 1058 1059 BigInt* result = BigInt::bitOr(cx, lhs, rhs); 1060 if (!result) { 1061 return false; 1062 } 1063 1064 iter.storeInstructionResult(JS::BigIntValue(result)); 1065 return true; 1066 } 1067 1068 bool MBigIntPtrBitXor::writeRecoverData(CompactBufferWriter& writer) const { 1069 MOZ_ASSERT(canRecoverOnBailout()); 1070 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrBitXor)); 1071 return true; 1072 } 1073 1074 RBigIntPtrBitXor::RBigIntPtrBitXor(CompactBufferReader& reader) {} 1075 1076 bool RBigIntPtrBitXor::recover(JSContext* cx, SnapshotIterator& iter) const { 1077 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 1078 if (!lhs) { 1079 return false; 1080 } 1081 1082 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 1083 if (!rhs) { 1084 return false; 1085 } 1086 1087 BigInt* result = BigInt::bitXor(cx, lhs, rhs); 1088 if (!result) { 1089 return false; 1090 } 1091 1092 iter.storeInstructionResult(JS::BigIntValue(result)); 1093 return true; 1094 } 1095 1096 bool MBigIntPtrLsh::writeRecoverData(CompactBufferWriter& writer) const { 1097 MOZ_ASSERT(canRecoverOnBailout()); 1098 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrLsh)); 1099 return true; 1100 } 1101 1102 RBigIntPtrLsh::RBigIntPtrLsh(CompactBufferReader& reader) {} 1103 1104 bool RBigIntPtrLsh::recover(JSContext* cx, SnapshotIterator& iter) const { 1105 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 1106 if (!lhs) { 1107 return false; 1108 } 1109 1110 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 1111 if (!rhs) { 1112 return false; 1113 } 1114 1115 BigInt* result = BigInt::lsh(cx, lhs, rhs); 1116 if (!result) { 1117 return false; 1118 } 1119 1120 iter.storeInstructionResult(JS::BigIntValue(result)); 1121 return true; 1122 } 1123 1124 bool MBigIntPtrRsh::writeRecoverData(CompactBufferWriter& writer) const { 1125 MOZ_ASSERT(canRecoverOnBailout()); 1126 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrRsh)); 1127 return true; 1128 } 1129 1130 RBigIntPtrRsh::RBigIntPtrRsh(CompactBufferReader& reader) {} 1131 1132 bool RBigIntPtrRsh::recover(JSContext* cx, SnapshotIterator& iter) const { 1133 Rooted<BigInt*> lhs(cx, iter.readBigInt(cx)); 1134 if (!lhs) { 1135 return false; 1136 } 1137 1138 Rooted<BigInt*> rhs(cx, iter.readBigInt(cx)); 1139 if (!rhs) { 1140 return false; 1141 } 1142 1143 BigInt* result = BigInt::rsh(cx, lhs, rhs); 1144 if (!result) { 1145 return false; 1146 } 1147 1148 iter.storeInstructionResult(JS::BigIntValue(result)); 1149 return true; 1150 } 1151 1152 bool MBigIntPtrBitNot::writeRecoverData(CompactBufferWriter& writer) const { 1153 MOZ_ASSERT(canRecoverOnBailout()); 1154 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrBitNot)); 1155 return true; 1156 } 1157 1158 RBigIntPtrBitNot::RBigIntPtrBitNot(CompactBufferReader& reader) {} 1159 1160 bool RBigIntPtrBitNot::recover(JSContext* cx, SnapshotIterator& iter) const { 1161 Rooted<BigInt*> operand(cx, iter.readBigInt(cx)); 1162 if (!operand) { 1163 return false; 1164 } 1165 1166 BigInt* result = BigInt::bitNot(cx, operand); 1167 if (!result) { 1168 return false; 1169 } 1170 1171 iter.storeInstructionResult(JS::BigIntValue(result)); 1172 return true; 1173 } 1174 1175 bool MCompare::writeRecoverData(CompactBufferWriter& writer) const { 1176 MOZ_ASSERT(canRecoverOnBailout()); 1177 writer.writeUnsigned(uint32_t(RInstruction::Recover_Compare)); 1178 1179 static_assert(sizeof(JSOp) == sizeof(uint8_t)); 1180 writer.writeByte(uint8_t(jsop_)); 1181 return true; 1182 } 1183 1184 RCompare::RCompare(CompactBufferReader& reader) { 1185 jsop_ = JSOp(reader.readByte()); 1186 1187 MOZ_ASSERT(IsEqualityOp(jsop_) || IsRelationalOp(jsop_)); 1188 } 1189 1190 bool RCompare::recover(JSContext* cx, SnapshotIterator& iter) const { 1191 RootedValue lhs(cx, iter.read()); 1192 RootedValue rhs(cx, iter.read()); 1193 1194 bool result; 1195 switch (jsop_) { 1196 case JSOp::Eq: 1197 case JSOp::Ne: 1198 if (!js::LooselyEqual(cx, lhs, rhs, &result)) { 1199 return false; 1200 } 1201 if (jsop_ == JSOp::Ne) { 1202 result = !result; 1203 } 1204 break; 1205 case JSOp::StrictEq: 1206 case JSOp::StrictNe: 1207 if (!StrictlyEqual(cx, lhs, rhs, &result)) { 1208 return false; 1209 } 1210 if (jsop_ == JSOp::StrictNe) { 1211 result = !result; 1212 } 1213 break; 1214 case JSOp::Lt: 1215 if (!js::LessThan(cx, &lhs, &rhs, &result)) { 1216 return false; 1217 } 1218 break; 1219 case JSOp::Le: 1220 if (!js::LessThanOrEqual(cx, &lhs, &rhs, &result)) { 1221 return false; 1222 } 1223 break; 1224 case JSOp::Gt: 1225 if (!js::GreaterThan(cx, &lhs, &rhs, &result)) { 1226 return false; 1227 } 1228 break; 1229 case JSOp::Ge: 1230 if (!js::GreaterThanOrEqual(cx, &lhs, &rhs, &result)) { 1231 return false; 1232 } 1233 break; 1234 default: 1235 MOZ_CRASH("Unexpected op."); 1236 } 1237 1238 iter.storeInstructionResult(BooleanValue(result)); 1239 return true; 1240 } 1241 1242 bool MStrictConstantCompareInt32::writeRecoverData( 1243 CompactBufferWriter& writer) const { 1244 MOZ_ASSERT(canRecoverOnBailout()); 1245 writer.writeUnsigned( 1246 uint32_t(RInstruction::Recover_StrictConstantCompareInt32)); 1247 1248 writer.writeByte(uint8_t(jsop_)); 1249 writer.writeSigned(constant_); 1250 return true; 1251 } 1252 1253 RStrictConstantCompareInt32::RStrictConstantCompareInt32( 1254 CompactBufferReader& reader) { 1255 jsop_ = JSOp(reader.readByte()); 1256 constant_ = reader.readSigned(); 1257 MOZ_ASSERT(IsStrictEqualityOp(jsop_)); 1258 } 1259 1260 bool RStrictConstantCompareInt32::recover(JSContext* cx, 1261 SnapshotIterator& iter) const { 1262 JS::Value lhs = iter.read(); 1263 1264 bool result = lhs.isNumber() && lhs.toNumber() == constant_; 1265 if (jsop_ == JSOp::StrictNe) { 1266 result = !result; 1267 } 1268 iter.storeInstructionResult(BooleanValue(result)); 1269 return true; 1270 } 1271 1272 bool MStrictConstantCompareBoolean::writeRecoverData( 1273 CompactBufferWriter& writer) const { 1274 MOZ_ASSERT(canRecoverOnBailout()); 1275 writer.writeUnsigned( 1276 uint32_t(RInstruction::Recover_StrictConstantCompareBoolean)); 1277 1278 writer.writeByte(uint8_t(jsop_)); 1279 writer.writeUnsigned(constant_); 1280 return true; 1281 } 1282 1283 RStrictConstantCompareBoolean::RStrictConstantCompareBoolean( 1284 CompactBufferReader& reader) { 1285 jsop_ = JSOp(reader.readByte()); 1286 constant_ = reader.readUnsigned(); 1287 MOZ_ASSERT(IsStrictEqualityOp(jsop_)); 1288 } 1289 1290 bool RStrictConstantCompareBoolean::recover(JSContext* cx, 1291 SnapshotIterator& iter) const { 1292 JS::Value lhs = iter.read(); 1293 1294 bool result = lhs == BooleanValue(constant_); 1295 if (jsop_ == JSOp::StrictNe) { 1296 result = !result; 1297 } 1298 iter.storeInstructionResult(BooleanValue(result)); 1299 return true; 1300 } 1301 1302 bool MConcat::writeRecoverData(CompactBufferWriter& writer) const { 1303 MOZ_ASSERT(canRecoverOnBailout()); 1304 writer.writeUnsigned(uint32_t(RInstruction::Recover_Concat)); 1305 return true; 1306 } 1307 1308 RConcat::RConcat(CompactBufferReader& reader) {} 1309 1310 bool RConcat::recover(JSContext* cx, SnapshotIterator& iter) const { 1311 RootedValue lhs(cx, iter.read()); 1312 RootedValue rhs(cx, iter.read()); 1313 RootedValue result(cx); 1314 1315 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); 1316 if (!js::AddValues(cx, &lhs, &rhs, &result)) { 1317 return false; 1318 } 1319 1320 iter.storeInstructionResult(result); 1321 return true; 1322 } 1323 1324 RStringLength::RStringLength(CompactBufferReader& reader) {} 1325 1326 bool RStringLength::recover(JSContext* cx, SnapshotIterator& iter) const { 1327 JSString* string = iter.readString(); 1328 1329 static_assert(JSString::MAX_LENGTH <= INT32_MAX, 1330 "Can cast string length to int32_t"); 1331 1332 iter.storeInstructionResult(Int32Value(int32_t(string->length()))); 1333 return true; 1334 } 1335 1336 bool MStringLength::writeRecoverData(CompactBufferWriter& writer) const { 1337 MOZ_ASSERT(canRecoverOnBailout()); 1338 writer.writeUnsigned(uint32_t(RInstruction::Recover_StringLength)); 1339 return true; 1340 } 1341 1342 bool MArgumentsLength::writeRecoverData(CompactBufferWriter& writer) const { 1343 MOZ_ASSERT(canRecoverOnBailout()); 1344 writer.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength)); 1345 return true; 1346 } 1347 1348 RArgumentsLength::RArgumentsLength(CompactBufferReader& reader) {} 1349 1350 bool RArgumentsLength::recover(JSContext* cx, SnapshotIterator& iter) const { 1351 uintptr_t numActualArgs = iter.frame()->numActualArgs(); 1352 1353 static_assert(ARGS_LENGTH_MAX <= INT32_MAX, 1354 "Can cast arguments count to int32_t"); 1355 MOZ_ASSERT(numActualArgs <= ARGS_LENGTH_MAX); 1356 1357 iter.storeInstructionResult(JS::Int32Value(int32_t(numActualArgs))); 1358 return true; 1359 } 1360 1361 bool MFloor::writeRecoverData(CompactBufferWriter& writer) const { 1362 MOZ_ASSERT(canRecoverOnBailout()); 1363 writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor)); 1364 return true; 1365 } 1366 1367 RFloor::RFloor(CompactBufferReader& reader) {} 1368 1369 bool RFloor::recover(JSContext* cx, SnapshotIterator& iter) const { 1370 double num = iter.readNumber(); 1371 double result = js::math_floor_impl(num); 1372 1373 iter.storeInstructionResult(NumberValue(result)); 1374 return true; 1375 } 1376 1377 bool MCeil::writeRecoverData(CompactBufferWriter& writer) const { 1378 MOZ_ASSERT(canRecoverOnBailout()); 1379 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil)); 1380 return true; 1381 } 1382 1383 RCeil::RCeil(CompactBufferReader& reader) {} 1384 1385 bool RCeil::recover(JSContext* cx, SnapshotIterator& iter) const { 1386 double num = iter.readNumber(); 1387 double result = js::math_ceil_impl(num); 1388 1389 iter.storeInstructionResult(NumberValue(result)); 1390 return true; 1391 } 1392 1393 bool MRound::writeRecoverData(CompactBufferWriter& writer) const { 1394 MOZ_ASSERT(canRecoverOnBailout()); 1395 writer.writeUnsigned(uint32_t(RInstruction::Recover_Round)); 1396 return true; 1397 } 1398 1399 RRound::RRound(CompactBufferReader& reader) {} 1400 1401 bool RRound::recover(JSContext* cx, SnapshotIterator& iter) const { 1402 double num = iter.readNumber(); 1403 double result = js::math_round_impl(num); 1404 1405 iter.storeInstructionResult(NumberValue(result)); 1406 return true; 1407 } 1408 1409 bool MTrunc::writeRecoverData(CompactBufferWriter& writer) const { 1410 MOZ_ASSERT(canRecoverOnBailout()); 1411 writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc)); 1412 return true; 1413 } 1414 1415 RTrunc::RTrunc(CompactBufferReader& reader) {} 1416 1417 bool RTrunc::recover(JSContext* cx, SnapshotIterator& iter) const { 1418 double num = iter.readNumber(); 1419 double result = js::math_trunc_impl(num); 1420 1421 iter.storeInstructionResult(NumberValue(result)); 1422 return true; 1423 } 1424 1425 bool MCharCodeAt::writeRecoverData(CompactBufferWriter& writer) const { 1426 MOZ_ASSERT(canRecoverOnBailout()); 1427 writer.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt)); 1428 return true; 1429 } 1430 1431 RCharCodeAt::RCharCodeAt(CompactBufferReader& reader) {} 1432 1433 bool RCharCodeAt::recover(JSContext* cx, SnapshotIterator& iter) const { 1434 JSString* string = iter.readString(); 1435 1436 // Int32 because |index| is computed from MBoundsCheck. 1437 int32_t index = iter.readInt32(); 1438 MOZ_RELEASE_ASSERT(0 <= index && size_t(index) < string->length()); 1439 1440 char16_t c; 1441 if (!string->getChar(cx, index, &c)) { 1442 return false; 1443 } 1444 1445 iter.storeInstructionResult(Int32Value(c)); 1446 return true; 1447 } 1448 1449 bool MFromCharCode::writeRecoverData(CompactBufferWriter& writer) const { 1450 MOZ_ASSERT(canRecoverOnBailout()); 1451 writer.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode)); 1452 return true; 1453 } 1454 1455 RFromCharCode::RFromCharCode(CompactBufferReader& reader) {} 1456 1457 bool RFromCharCode::recover(JSContext* cx, SnapshotIterator& iter) const { 1458 // Number because |charCode| is computed from (recoverable) user input. 1459 int32_t charCode = JS::ToInt32(iter.readNumber()); 1460 1461 JSString* str = StringFromCharCode(cx, charCode); 1462 if (!str) { 1463 return false; 1464 } 1465 1466 iter.storeInstructionResult(StringValue(str)); 1467 return true; 1468 } 1469 1470 bool MFromCharCodeEmptyIfNegative::writeRecoverData( 1471 CompactBufferWriter& writer) const { 1472 MOZ_ASSERT(canRecoverOnBailout()); 1473 writer.writeUnsigned( 1474 uint32_t(RInstruction::Recover_FromCharCodeEmptyIfNegative)); 1475 return true; 1476 } 1477 1478 RFromCharCodeEmptyIfNegative::RFromCharCodeEmptyIfNegative( 1479 CompactBufferReader& reader) {} 1480 1481 bool RFromCharCodeEmptyIfNegative::recover(JSContext* cx, 1482 SnapshotIterator& iter) const { 1483 // Int32 because |charCode| is computed from MCharCodeAtOrNegative. 1484 int32_t charCode = iter.readInt32(); 1485 1486 JSString* str; 1487 if (charCode < 0) { 1488 str = cx->emptyString(); 1489 } else { 1490 str = StringFromCharCode(cx, charCode); 1491 if (!str) { 1492 return false; 1493 } 1494 } 1495 1496 iter.storeInstructionResult(StringValue(str)); 1497 return true; 1498 } 1499 1500 bool MPow::writeRecoverData(CompactBufferWriter& writer) const { 1501 MOZ_ASSERT(canRecoverOnBailout()); 1502 writer.writeUnsigned(uint32_t(RInstruction::Recover_Pow)); 1503 return true; 1504 } 1505 1506 RPow::RPow(CompactBufferReader& reader) {} 1507 1508 bool RPow::recover(JSContext* cx, SnapshotIterator& iter) const { 1509 double base = iter.readNumber(); 1510 double power = iter.readNumber(); 1511 double result = ecmaPow(base, power); 1512 1513 iter.storeInstructionResult(NumberValue(result)); 1514 return true; 1515 } 1516 1517 bool MPowHalf::writeRecoverData(CompactBufferWriter& writer) const { 1518 MOZ_ASSERT(canRecoverOnBailout()); 1519 writer.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf)); 1520 return true; 1521 } 1522 1523 RPowHalf::RPowHalf(CompactBufferReader& reader) {} 1524 1525 bool RPowHalf::recover(JSContext* cx, SnapshotIterator& iter) const { 1526 double base = iter.readNumber(); 1527 double power = 0.5; 1528 double result = ecmaPow(base, power); 1529 1530 iter.storeInstructionResult(NumberValue(result)); 1531 return true; 1532 } 1533 1534 bool MMinMax::writeRecoverData(CompactBufferWriter& writer) const { 1535 MOZ_ASSERT(canRecoverOnBailout()); 1536 writer.writeUnsigned(uint32_t(RInstruction::Recover_MinMax)); 1537 writer.writeByte(isMax_); 1538 return true; 1539 } 1540 1541 RMinMax::RMinMax(CompactBufferReader& reader) { isMax_ = reader.readByte(); } 1542 1543 bool RMinMax::recover(JSContext* cx, SnapshotIterator& iter) const { 1544 double x = iter.readNumber(); 1545 double y = iter.readNumber(); 1546 1547 double result; 1548 if (isMax_) { 1549 result = js::math_max_impl(x, y); 1550 } else { 1551 result = js::math_min_impl(x, y); 1552 } 1553 1554 iter.storeInstructionResult(NumberValue(result)); 1555 return true; 1556 } 1557 1558 bool MAbs::writeRecoverData(CompactBufferWriter& writer) const { 1559 MOZ_ASSERT(canRecoverOnBailout()); 1560 writer.writeUnsigned(uint32_t(RInstruction::Recover_Abs)); 1561 return true; 1562 } 1563 1564 RAbs::RAbs(CompactBufferReader& reader) {} 1565 1566 bool RAbs::recover(JSContext* cx, SnapshotIterator& iter) const { 1567 double num = iter.readNumber(); 1568 double result = js::math_abs_impl(num); 1569 1570 iter.storeInstructionResult(NumberValue(result)); 1571 return true; 1572 } 1573 1574 bool MSqrt::writeRecoverData(CompactBufferWriter& writer) const { 1575 MOZ_ASSERT(canRecoverOnBailout()); 1576 writer.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt)); 1577 writer.writeByte(type() == MIRType::Float32); 1578 return true; 1579 } 1580 1581 RSqrt::RSqrt(CompactBufferReader& reader) { 1582 isFloatOperation_ = reader.readByte(); 1583 } 1584 1585 bool RSqrt::recover(JSContext* cx, SnapshotIterator& iter) const { 1586 double num = iter.readNumber(); 1587 double result = js::math_sqrt_impl(num); 1588 1589 // MIRType::Float32 is a specialization embedding the fact that the result is 1590 // rounded to a Float32. 1591 if (isFloatOperation_) { 1592 result = js::RoundFloat32(result); 1593 } 1594 1595 iter.storeInstructionResult(DoubleValue(result)); 1596 return true; 1597 } 1598 1599 bool MAtan2::writeRecoverData(CompactBufferWriter& writer) const { 1600 MOZ_ASSERT(canRecoverOnBailout()); 1601 writer.writeUnsigned(uint32_t(RInstruction::Recover_Atan2)); 1602 return true; 1603 } 1604 1605 RAtan2::RAtan2(CompactBufferReader& reader) {} 1606 1607 bool RAtan2::recover(JSContext* cx, SnapshotIterator& iter) const { 1608 double y = iter.readNumber(); 1609 double x = iter.readNumber(); 1610 double result = js::ecmaAtan2(y, x); 1611 1612 iter.storeInstructionResult(DoubleValue(result)); 1613 return true; 1614 } 1615 1616 bool MHypot::writeRecoverData(CompactBufferWriter& writer) const { 1617 MOZ_ASSERT(canRecoverOnBailout()); 1618 writer.writeUnsigned(uint32_t(RInstruction::Recover_Hypot)); 1619 writer.writeUnsigned(uint32_t(numOperands())); 1620 return true; 1621 } 1622 1623 RHypot::RHypot(CompactBufferReader& reader) 1624 : numOperands_(reader.readUnsigned()) {} 1625 1626 bool RHypot::recover(JSContext* cx, SnapshotIterator& iter) const { 1627 JS::RootedValueVector vec(cx); 1628 1629 if (!vec.reserve(numOperands_)) { 1630 return false; 1631 } 1632 1633 for (uint32_t i = 0; i < numOperands_; ++i) { 1634 vec.infallibleAppend(NumberValue(iter.readNumber())); 1635 } 1636 1637 RootedValue result(cx); 1638 1639 if (!js::math_hypot_handle(cx, vec, &result)) { 1640 return false; 1641 } 1642 1643 iter.storeInstructionResult(result); 1644 return true; 1645 } 1646 1647 bool MNearbyInt::writeRecoverData(CompactBufferWriter& writer) const { 1648 MOZ_ASSERT(canRecoverOnBailout()); 1649 switch (roundingMode_) { 1650 case RoundingMode::Up: 1651 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil)); 1652 return true; 1653 case RoundingMode::Down: 1654 writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor)); 1655 return true; 1656 case RoundingMode::TowardsZero: 1657 writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc)); 1658 return true; 1659 default: 1660 MOZ_CRASH("Unsupported rounding mode."); 1661 } 1662 } 1663 1664 bool MRoundToDouble::writeRecoverData(CompactBufferWriter& writer) const { 1665 MOZ_ASSERT(canRecoverOnBailout()); 1666 writer.writeUnsigned(uint32_t(RInstruction::Recover_Round)); 1667 return true; 1668 } 1669 1670 bool MSign::writeRecoverData(CompactBufferWriter& writer) const { 1671 MOZ_ASSERT(canRecoverOnBailout()); 1672 writer.writeUnsigned(uint32_t(RInstruction::Recover_Sign)); 1673 return true; 1674 } 1675 1676 RSign::RSign(CompactBufferReader& reader) {} 1677 1678 bool RSign::recover(JSContext* cx, SnapshotIterator& iter) const { 1679 double num = iter.readNumber(); 1680 double result = js::math_sign_impl(num); 1681 1682 iter.storeInstructionResult(NumberValue(result)); 1683 return true; 1684 } 1685 1686 bool MMathFunction::writeRecoverData(CompactBufferWriter& writer) const { 1687 MOZ_ASSERT(canRecoverOnBailout()); 1688 switch (function_) { 1689 case UnaryMathFunction::Ceil: 1690 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil)); 1691 return true; 1692 case UnaryMathFunction::Floor: 1693 writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor)); 1694 return true; 1695 case UnaryMathFunction::Round: 1696 writer.writeUnsigned(uint32_t(RInstruction::Recover_Round)); 1697 return true; 1698 case UnaryMathFunction::Trunc: 1699 writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc)); 1700 return true; 1701 case UnaryMathFunction::SinNative: 1702 case UnaryMathFunction::SinFdlibm: 1703 case UnaryMathFunction::CosNative: 1704 case UnaryMathFunction::CosFdlibm: 1705 case UnaryMathFunction::TanNative: 1706 case UnaryMathFunction::TanFdlibm: 1707 case UnaryMathFunction::Log: 1708 case UnaryMathFunction::Exp: 1709 case UnaryMathFunction::ACos: 1710 case UnaryMathFunction::ASin: 1711 case UnaryMathFunction::ATan: 1712 case UnaryMathFunction::Log10: 1713 case UnaryMathFunction::Log2: 1714 case UnaryMathFunction::Log1P: 1715 case UnaryMathFunction::ExpM1: 1716 case UnaryMathFunction::CosH: 1717 case UnaryMathFunction::SinH: 1718 case UnaryMathFunction::TanH: 1719 case UnaryMathFunction::ACosH: 1720 case UnaryMathFunction::ASinH: 1721 case UnaryMathFunction::ATanH: 1722 case UnaryMathFunction::Cbrt: 1723 static_assert(sizeof(UnaryMathFunction) == sizeof(uint8_t)); 1724 writer.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction)); 1725 writer.writeByte(uint8_t(function_)); 1726 return true; 1727 } 1728 MOZ_CRASH("Unknown math function."); 1729 } 1730 1731 RMathFunction::RMathFunction(CompactBufferReader& reader) { 1732 function_ = UnaryMathFunction(reader.readByte()); 1733 } 1734 1735 bool RMathFunction::recover(JSContext* cx, SnapshotIterator& iter) const { 1736 double num = iter.readNumber(); 1737 1738 double result; 1739 switch (function_) { 1740 case UnaryMathFunction::SinNative: 1741 result = js::math_sin_native_impl(num); 1742 break; 1743 case UnaryMathFunction::SinFdlibm: 1744 result = js::math_sin_fdlibm_impl(num); 1745 break; 1746 case UnaryMathFunction::CosNative: 1747 result = js::math_cos_native_impl(num); 1748 break; 1749 case UnaryMathFunction::CosFdlibm: 1750 result = js::math_cos_fdlibm_impl(num); 1751 break; 1752 case UnaryMathFunction::TanNative: 1753 result = js::math_tan_native_impl(num); 1754 break; 1755 case UnaryMathFunction::TanFdlibm: 1756 result = js::math_tan_fdlibm_impl(num); 1757 break; 1758 case UnaryMathFunction::Log: 1759 result = js::math_log_impl(num); 1760 break; 1761 case UnaryMathFunction::Exp: 1762 result = js::math_exp_impl(num); 1763 break; 1764 case UnaryMathFunction::ACos: 1765 result = js::math_acos_impl(num); 1766 break; 1767 case UnaryMathFunction::ASin: 1768 result = js::math_asin_impl(num); 1769 break; 1770 case UnaryMathFunction::ATan: 1771 result = js::math_atan_impl(num); 1772 break; 1773 case UnaryMathFunction::Log10: 1774 result = js::math_log10_impl(num); 1775 break; 1776 case UnaryMathFunction::Log2: 1777 result = js::math_log2_impl(num); 1778 break; 1779 case UnaryMathFunction::Log1P: 1780 result = js::math_log1p_impl(num); 1781 break; 1782 case UnaryMathFunction::ExpM1: 1783 result = js::math_expm1_impl(num); 1784 break; 1785 case UnaryMathFunction::CosH: 1786 result = js::math_cosh_impl(num); 1787 break; 1788 case UnaryMathFunction::SinH: 1789 result = js::math_sinh_impl(num); 1790 break; 1791 case UnaryMathFunction::TanH: 1792 result = js::math_tanh_impl(num); 1793 break; 1794 case UnaryMathFunction::ACosH: 1795 result = js::math_acosh_impl(num); 1796 break; 1797 case UnaryMathFunction::ASinH: 1798 result = js::math_asinh_impl(num); 1799 break; 1800 case UnaryMathFunction::ATanH: 1801 result = js::math_atanh_impl(num); 1802 break; 1803 case UnaryMathFunction::Cbrt: 1804 result = js::math_cbrt_impl(num); 1805 break; 1806 1807 case UnaryMathFunction::Trunc: 1808 case UnaryMathFunction::Floor: 1809 case UnaryMathFunction::Ceil: 1810 case UnaryMathFunction::Round: 1811 // These have their own recover instructions. 1812 MOZ_CRASH("Unexpected rounding math function."); 1813 } 1814 1815 iter.storeInstructionResult(DoubleValue(result)); 1816 return true; 1817 } 1818 1819 bool MRandom::writeRecoverData(CompactBufferWriter& writer) const { 1820 MOZ_ASSERT(this->canRecoverOnBailout()); 1821 writer.writeUnsigned(uint32_t(RInstruction::Recover_Random)); 1822 return true; 1823 } 1824 1825 bool MRandom::canRecoverOnBailout() const { 1826 return !js::SupportDifferentialTesting(); 1827 } 1828 1829 RRandom::RRandom(CompactBufferReader& reader) {} 1830 1831 bool RRandom::recover(JSContext* cx, SnapshotIterator& iter) const { 1832 iter.storeInstructionResult(DoubleValue(math_random_impl(cx))); 1833 return true; 1834 } 1835 1836 bool MStringSplit::writeRecoverData(CompactBufferWriter& writer) const { 1837 MOZ_ASSERT(canRecoverOnBailout()); 1838 writer.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit)); 1839 return true; 1840 } 1841 1842 RStringSplit::RStringSplit(CompactBufferReader& reader) {} 1843 1844 bool RStringSplit::recover(JSContext* cx, SnapshotIterator& iter) const { 1845 RootedString str(cx, iter.readString()); 1846 RootedString sep(cx, iter.readString()); 1847 1848 JSObject* res = StringSplitString(cx, str, sep, INT32_MAX); 1849 if (!res) { 1850 return false; 1851 } 1852 1853 iter.storeInstructionResult(ObjectValue(*res)); 1854 return true; 1855 } 1856 1857 bool MNaNToZero::writeRecoverData(CompactBufferWriter& writer) const { 1858 MOZ_ASSERT(canRecoverOnBailout()); 1859 writer.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero)); 1860 return true; 1861 } 1862 1863 RNaNToZero::RNaNToZero(CompactBufferReader& reader) {} 1864 1865 bool RNaNToZero::recover(JSContext* cx, SnapshotIterator& iter) const { 1866 double v = iter.readNumber(); 1867 if (std::isnan(v) || mozilla::IsNegativeZero(v)) { 1868 v = 0.0; 1869 } 1870 1871 iter.storeInstructionResult(DoubleValue(v)); 1872 return true; 1873 } 1874 1875 bool MTypeOf::writeRecoverData(CompactBufferWriter& writer) const { 1876 MOZ_ASSERT(canRecoverOnBailout()); 1877 writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf)); 1878 return true; 1879 } 1880 1881 RTypeOf::RTypeOf(CompactBufferReader& reader) {} 1882 1883 bool RTypeOf::recover(JSContext* cx, SnapshotIterator& iter) const { 1884 JS::Value v = iter.read(); 1885 1886 iter.storeInstructionResult(Int32Value(TypeOfValue(v))); 1887 return true; 1888 } 1889 1890 bool MTypeOfName::writeRecoverData(CompactBufferWriter& writer) const { 1891 MOZ_ASSERT(canRecoverOnBailout()); 1892 writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOfName)); 1893 return true; 1894 } 1895 1896 RTypeOfName::RTypeOfName(CompactBufferReader& reader) {} 1897 1898 bool RTypeOfName::recover(JSContext* cx, SnapshotIterator& iter) const { 1899 // Int32 because |type| is computed from MTypeOf. 1900 int32_t type = iter.readInt32(); 1901 MOZ_ASSERT(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT); 1902 1903 JSString* name = TypeName(JSType(type), *cx->runtime()->commonNames); 1904 iter.storeInstructionResult(StringValue(name)); 1905 return true; 1906 } 1907 1908 bool MToDouble::writeRecoverData(CompactBufferWriter& writer) const { 1909 MOZ_ASSERT(canRecoverOnBailout()); 1910 writer.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble)); 1911 return true; 1912 } 1913 1914 RToDouble::RToDouble(CompactBufferReader& reader) {} 1915 1916 bool RToDouble::recover(JSContext* cx, SnapshotIterator& iter) const { 1917 RootedValue v(cx, iter.read()); 1918 1919 MOZ_ASSERT(!v.isObject()); 1920 MOZ_ASSERT(!v.isSymbol()); 1921 MOZ_ASSERT(!v.isBigInt()); 1922 1923 double dbl; 1924 if (!ToNumber(cx, v, &dbl)) { 1925 return false; 1926 } 1927 1928 iter.storeInstructionResult(DoubleValue(dbl)); 1929 return true; 1930 } 1931 1932 bool MToFloat32::writeRecoverData(CompactBufferWriter& writer) const { 1933 MOZ_ASSERT(canRecoverOnBailout()); 1934 writer.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32)); 1935 return true; 1936 } 1937 1938 RToFloat32::RToFloat32(CompactBufferReader& reader) {} 1939 1940 bool RToFloat32::recover(JSContext* cx, SnapshotIterator& iter) const { 1941 double num = iter.readNumber(); 1942 double result = js::RoundFloat32(num); 1943 1944 iter.storeInstructionResult(DoubleValue(result)); 1945 return true; 1946 } 1947 1948 bool MToFloat16::writeRecoverData(CompactBufferWriter& writer) const { 1949 MOZ_ASSERT(canRecoverOnBailout()); 1950 writer.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat16)); 1951 return true; 1952 } 1953 1954 RToFloat16::RToFloat16(CompactBufferReader& reader) {} 1955 1956 bool RToFloat16::recover(JSContext* cx, SnapshotIterator& iter) const { 1957 double num = iter.readNumber(); 1958 double result = js::RoundFloat16(num); 1959 1960 iter.storeInstructionResult(DoubleValue(result)); 1961 return true; 1962 } 1963 1964 bool MTruncateToInt32::writeRecoverData(CompactBufferWriter& writer) const { 1965 MOZ_ASSERT(canRecoverOnBailout()); 1966 writer.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32)); 1967 return true; 1968 } 1969 1970 RTruncateToInt32::RTruncateToInt32(CompactBufferReader& reader) {} 1971 1972 bool RTruncateToInt32::recover(JSContext* cx, SnapshotIterator& iter) const { 1973 RootedValue value(cx, iter.read()); 1974 1975 int32_t trunc; 1976 if (!JS::ToInt32(cx, value, &trunc)) { 1977 return false; 1978 } 1979 1980 iter.storeInstructionResult(Int32Value(trunc)); 1981 return true; 1982 } 1983 1984 bool MNewObject::writeRecoverData(CompactBufferWriter& writer) const { 1985 MOZ_ASSERT(canRecoverOnBailout()); 1986 1987 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewObject)); 1988 1989 // Recover instructions are only supported if we have a template object. 1990 MOZ_ASSERT(mode_ == MNewObject::ObjectCreate); 1991 return true; 1992 } 1993 1994 RNewObject::RNewObject(CompactBufferReader& reader) {} 1995 1996 bool RNewObject::recover(JSContext* cx, SnapshotIterator& iter) const { 1997 RootedObject templateObject(cx, iter.readObject()); 1998 1999 // See CodeGenerator::visitNewObjectVMCall. 2000 // Note that recover instructions are only used if mode == ObjectCreate. 2001 JSObject* resultObject = 2002 ObjectCreateWithTemplate(cx, templateObject.as<PlainObject>()); 2003 if (!resultObject) { 2004 return false; 2005 } 2006 2007 iter.storeInstructionResult(ObjectValue(*resultObject)); 2008 return true; 2009 } 2010 2011 bool MNewPlainObject::writeRecoverData(CompactBufferWriter& writer) const { 2012 MOZ_ASSERT(canRecoverOnBailout()); 2013 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewPlainObject)); 2014 2015 MOZ_ASSERT(gc::AllocKind(uint8_t(allocKind_)) == allocKind_); 2016 writer.writeByte(uint8_t(allocKind_)); 2017 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_)) == initialHeap_); 2018 writer.writeByte(uint8_t(initialHeap_)); 2019 return true; 2020 } 2021 2022 RNewPlainObject::RNewPlainObject(CompactBufferReader& reader) { 2023 allocKind_ = gc::AllocKind(reader.readByte()); 2024 MOZ_ASSERT(gc::IsValidAllocKind(allocKind_)); 2025 initialHeap_ = gc::Heap(reader.readByte()); 2026 MOZ_ASSERT(initialHeap_ == gc::Heap::Default || 2027 initialHeap_ == gc::Heap::Tenured); 2028 } 2029 2030 bool RNewPlainObject::recover(JSContext* cx, SnapshotIterator& iter) const { 2031 Rooted<SharedShape*> shape(cx, &iter.readGCCellPtr().as<Shape>().asShared()); 2032 2033 // See CodeGenerator::visitNewPlainObject. 2034 JSObject* resultObject = 2035 NewPlainObjectOptimizedFallback(cx, shape, allocKind_, initialHeap_); 2036 if (!resultObject) { 2037 return false; 2038 } 2039 2040 iter.storeInstructionResult(ObjectValue(*resultObject)); 2041 return true; 2042 } 2043 2044 bool MNewArrayObject::writeRecoverData(CompactBufferWriter& writer) const { 2045 MOZ_ASSERT(canRecoverOnBailout()); 2046 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayObject)); 2047 2048 writer.writeUnsigned(length_); 2049 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_)) == initialHeap_); 2050 writer.writeByte(uint8_t(initialHeap_)); 2051 return true; 2052 } 2053 2054 RNewArrayObject::RNewArrayObject(CompactBufferReader& reader) { 2055 length_ = reader.readUnsigned(); 2056 initialHeap_ = gc::Heap(reader.readByte()); 2057 MOZ_ASSERT(initialHeap_ == gc::Heap::Default || 2058 initialHeap_ == gc::Heap::Tenured); 2059 } 2060 2061 bool RNewArrayObject::recover(JSContext* cx, SnapshotIterator& iter) const { 2062 iter.read(); // Skip unused shape field. 2063 2064 NewObjectKind kind = 2065 initialHeap_ == gc::Heap::Tenured ? TenuredObject : GenericObject; 2066 JSObject* array = NewArrayOperation(cx, length_, kind); 2067 if (!array) { 2068 return false; 2069 } 2070 2071 iter.storeInstructionResult(ObjectValue(*array)); 2072 return true; 2073 } 2074 2075 bool MNewTypedArray::writeRecoverData(CompactBufferWriter& writer) const { 2076 MOZ_ASSERT(canRecoverOnBailout()); 2077 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray)); 2078 return true; 2079 } 2080 2081 RNewTypedArray::RNewTypedArray(CompactBufferReader& reader) {} 2082 2083 bool RNewTypedArray::recover(JSContext* cx, SnapshotIterator& iter) const { 2084 RootedObject templateObject(cx, iter.readObject()); 2085 2086 size_t length = templateObject.as<FixedLengthTypedArrayObject>()->length(); 2087 MOZ_ASSERT(length <= INT32_MAX, 2088 "Template objects are only created for int32 lengths"); 2089 2090 JSObject* resultObject = 2091 NewTypedArrayWithTemplateAndLength(cx, templateObject, length); 2092 if (!resultObject) { 2093 return false; 2094 } 2095 2096 iter.storeInstructionResult(ObjectValue(*resultObject)); 2097 return true; 2098 } 2099 2100 bool MNewArray::writeRecoverData(CompactBufferWriter& writer) const { 2101 MOZ_ASSERT(canRecoverOnBailout()); 2102 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray)); 2103 writer.writeUnsigned(length()); 2104 return true; 2105 } 2106 2107 RNewArray::RNewArray(CompactBufferReader& reader) { 2108 count_ = reader.readUnsigned(); 2109 } 2110 2111 bool RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const { 2112 JSObject* templateObject = iter.readObject(); 2113 Rooted<Shape*> shape(cx, templateObject->shape()); 2114 2115 ArrayObject* resultObject = NewArrayWithShape(cx, count_, shape); 2116 if (!resultObject) { 2117 return false; 2118 } 2119 2120 iter.storeInstructionResult(ObjectValue(*resultObject)); 2121 return true; 2122 } 2123 2124 bool MNewIterator::writeRecoverData(CompactBufferWriter& writer) const { 2125 MOZ_ASSERT(canRecoverOnBailout()); 2126 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator)); 2127 writer.writeByte(type_); 2128 return true; 2129 } 2130 2131 RNewIterator::RNewIterator(CompactBufferReader& reader) { 2132 type_ = reader.readByte(); 2133 } 2134 2135 bool RNewIterator::recover(JSContext* cx, SnapshotIterator& iter) const { 2136 // Template object is not used when recovering MNewIterator. 2137 (void)iter.readObject(); 2138 2139 JSObject* resultObject = nullptr; 2140 switch (MNewIterator::Type(type_)) { 2141 case MNewIterator::ArrayIterator: 2142 resultObject = NewArrayIterator(cx); 2143 break; 2144 case MNewIterator::StringIterator: 2145 resultObject = NewStringIterator(cx); 2146 break; 2147 case MNewIterator::RegExpStringIterator: 2148 resultObject = NewRegExpStringIterator(cx); 2149 break; 2150 } 2151 2152 if (!resultObject) { 2153 return false; 2154 } 2155 2156 iter.storeInstructionResult(ObjectValue(*resultObject)); 2157 return true; 2158 } 2159 2160 bool MLambda::writeRecoverData(CompactBufferWriter& writer) const { 2161 MOZ_ASSERT(canRecoverOnBailout()); 2162 writer.writeUnsigned(uint32_t(RInstruction::Recover_Lambda)); 2163 return true; 2164 } 2165 2166 RLambda::RLambda(CompactBufferReader& reader) {} 2167 2168 bool RLambda::recover(JSContext* cx, SnapshotIterator& iter) const { 2169 RootedObject scopeChain(cx, iter.readObject()); 2170 RootedFunction fun(cx, &iter.readObject()->as<JSFunction>()); 2171 2172 JSObject* resultObject = js::Lambda(cx, fun, scopeChain); 2173 if (!resultObject) { 2174 return false; 2175 } 2176 2177 iter.storeInstructionResult(ObjectValue(*resultObject)); 2178 return true; 2179 } 2180 2181 bool MFunctionWithProto::writeRecoverData(CompactBufferWriter& writer) const { 2182 MOZ_ASSERT(canRecoverOnBailout()); 2183 writer.writeUnsigned(uint32_t(RInstruction::Recover_FunctionWithProto)); 2184 return true; 2185 } 2186 2187 RFunctionWithProto::RFunctionWithProto(CompactBufferReader& reader) {} 2188 2189 bool RFunctionWithProto::recover(JSContext* cx, SnapshotIterator& iter) const { 2190 RootedObject scopeChain(cx, iter.readObject()); 2191 RootedObject prototype(cx, iter.readObject()); 2192 RootedFunction fun(cx, &iter.readObject()->as<JSFunction>()); 2193 2194 JSObject* resultObject = 2195 js::FunWithProtoOperation(cx, fun, scopeChain, prototype); 2196 if (!resultObject) { 2197 return false; 2198 } 2199 2200 iter.storeInstructionResult(ObjectValue(*resultObject)); 2201 return true; 2202 } 2203 2204 bool MCallee::writeRecoverData(CompactBufferWriter& writer) const { 2205 MOZ_ASSERT(canRecoverOnBailout()); 2206 writer.writeUnsigned(uint32_t(RInstruction::Recover_Callee)); 2207 return true; 2208 } 2209 2210 RCallee::RCallee(CompactBufferReader& reader) {} 2211 2212 bool RCallee::recover(JSContext* cx, SnapshotIterator& iter) const { 2213 JSFunction* callee = CalleeTokenToFunction(iter.frame()->calleeToken()); 2214 iter.storeInstructionResult(ObjectValue(*callee)); 2215 return true; 2216 } 2217 2218 bool MFunctionEnvironment::writeRecoverData(CompactBufferWriter& writer) const { 2219 MOZ_ASSERT(canRecoverOnBailout()); 2220 writer.writeUnsigned(uint32_t(RInstruction::Recover_FunctionEnvironment)); 2221 return true; 2222 } 2223 2224 RFunctionEnvironment::RFunctionEnvironment(CompactBufferReader& reader) {} 2225 2226 bool RFunctionEnvironment::recover(JSContext* cx, 2227 SnapshotIterator& iter) const { 2228 JSObject* obj = iter.readObject(); 2229 JSObject* env = obj->as<JSFunction>().environment(); 2230 iter.storeInstructionResult(ObjectValue(*env)); 2231 return true; 2232 } 2233 2234 bool MNewCallObject::writeRecoverData(CompactBufferWriter& writer) const { 2235 MOZ_ASSERT(canRecoverOnBailout()); 2236 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewCallObject)); 2237 return true; 2238 } 2239 2240 RNewCallObject::RNewCallObject(CompactBufferReader& reader) {} 2241 2242 bool RNewCallObject::recover(JSContext* cx, SnapshotIterator& iter) const { 2243 CallObject* templateObj = &iter.readObject()->as<CallObject>(); 2244 2245 Rooted<SharedShape*> shape(cx, templateObj->sharedShape()); 2246 2247 JSObject* resultObject = CallObject::createWithShape(cx, shape); 2248 if (!resultObject) { 2249 return false; 2250 } 2251 2252 iter.storeInstructionResult(ObjectValue(*resultObject)); 2253 return true; 2254 } 2255 2256 bool MObjectKeys::canRecoverOnBailout() const { 2257 // Only claim that this operation can be recovered on bailout if some other 2258 // optimization already marked it as such. 2259 return isRecoveredOnBailout(); 2260 } 2261 2262 bool MObjectKeys::writeRecoverData(CompactBufferWriter& writer) const { 2263 MOZ_ASSERT(canRecoverOnBailout()); 2264 writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectKeys)); 2265 return true; 2266 } 2267 2268 RObjectKeys::RObjectKeys(CompactBufferReader& reader) {} 2269 2270 bool RObjectKeys::recover(JSContext* cx, SnapshotIterator& iter) const { 2271 Rooted<JSObject*> obj(cx, iter.readObject()); 2272 2273 JSObject* resultKeys = ObjectKeys(cx, obj); 2274 if (!resultKeys) { 2275 return false; 2276 } 2277 2278 iter.storeInstructionResult(ObjectValue(*resultKeys)); 2279 return true; 2280 } 2281 2282 bool MObjectKeysFromIterator::writeRecoverData( 2283 CompactBufferWriter& writer) const { 2284 MOZ_ASSERT(canRecoverOnBailout()); 2285 writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectKeysFromIterator)); 2286 return true; 2287 } 2288 2289 RObjectKeysFromIterator::RObjectKeysFromIterator(CompactBufferReader& reader) {} 2290 2291 bool RObjectKeysFromIterator::recover(JSContext* cx, 2292 SnapshotIterator& iter) const { 2293 Rooted<JSObject*> iterObj(cx, iter.readObject()); 2294 2295 JSObject* resultKeys = ObjectKeysFromIterator(cx, iterObj); 2296 if (!resultKeys) { 2297 return false; 2298 } 2299 2300 iter.storeInstructionResult(ObjectValue(*resultKeys)); 2301 return true; 2302 } 2303 2304 bool MObjectState::writeRecoverData(CompactBufferWriter& writer) const { 2305 MOZ_ASSERT(canRecoverOnBailout()); 2306 writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState)); 2307 writer.writeUnsigned(numSlots()); 2308 return true; 2309 } 2310 2311 RObjectState::RObjectState(CompactBufferReader& reader) { 2312 numSlots_ = reader.readUnsigned(); 2313 } 2314 2315 bool RObjectState::recover(JSContext* cx, SnapshotIterator& iter) const { 2316 JSObject* object = iter.readObject(); 2317 NativeObject* nativeObject = &object->as<NativeObject>(); 2318 MOZ_ASSERT(!Watchtower::watchesPropertyValueChange(nativeObject)); 2319 MOZ_ASSERT(nativeObject->slotSpan() == numSlots()); 2320 2321 for (size_t i = 0; i < numSlots(); i++) { 2322 Value val = iter.read(); 2323 nativeObject->setSlot(i, val); 2324 } 2325 2326 iter.storeInstructionResult(ObjectValue(*object)); 2327 return true; 2328 } 2329 2330 bool MArrayState::writeRecoverData(CompactBufferWriter& writer) const { 2331 MOZ_ASSERT(canRecoverOnBailout()); 2332 writer.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState)); 2333 writer.writeUnsigned(numElements()); 2334 return true; 2335 } 2336 2337 RArrayState::RArrayState(CompactBufferReader& reader) { 2338 numElements_ = reader.readUnsigned(); 2339 } 2340 2341 bool RArrayState::recover(JSContext* cx, SnapshotIterator& iter) const { 2342 ArrayObject* object = &iter.readObject()->as<ArrayObject>(); 2343 2344 // Int32 because |initLength| is computed from MConstant. 2345 uint32_t initLength = iter.readInt32(); 2346 2347 MOZ_ASSERT(object->getDenseInitializedLength() == 0, 2348 "initDenseElement call below relies on this"); 2349 object->setDenseInitializedLength(initLength); 2350 2351 for (size_t index = 0; index < numElements(); index++) { 2352 Value val = iter.read(); 2353 2354 if (index >= initLength) { 2355 MOZ_ASSERT(val.isUndefined()); 2356 continue; 2357 } 2358 2359 object->initDenseElement(index, val); 2360 } 2361 2362 iter.storeInstructionResult(ObjectValue(*object)); 2363 return true; 2364 } 2365 2366 bool MAssertRecoveredOnBailout::writeRecoverData( 2367 CompactBufferWriter& writer) const { 2368 MOZ_ASSERT(canRecoverOnBailout()); 2369 MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout() == mustBeRecovered_, 2370 "assertRecoveredOnBailout failed during compilation"); 2371 writer.writeUnsigned( 2372 uint32_t(RInstruction::Recover_AssertRecoveredOnBailout)); 2373 return true; 2374 } 2375 2376 RAssertRecoveredOnBailout::RAssertRecoveredOnBailout( 2377 CompactBufferReader& reader) {} 2378 2379 bool RAssertRecoveredOnBailout::recover(JSContext* cx, 2380 SnapshotIterator& iter) const { 2381 iter.read(); // skip the unused operand. 2382 iter.storeInstructionResult(UndefinedValue()); 2383 return true; 2384 } 2385 2386 bool MStringReplace::writeRecoverData(CompactBufferWriter& writer) const { 2387 MOZ_ASSERT(canRecoverOnBailout()); 2388 writer.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace)); 2389 writer.writeByte(isFlatReplacement_); 2390 return true; 2391 } 2392 2393 RStringReplace::RStringReplace(CompactBufferReader& reader) { 2394 isFlatReplacement_ = reader.readByte(); 2395 } 2396 2397 bool RStringReplace::recover(JSContext* cx, SnapshotIterator& iter) const { 2398 RootedString string(cx, iter.readString()); 2399 RootedString pattern(cx, iter.readString()); 2400 RootedString replace(cx, iter.readString()); 2401 2402 JSString* result = 2403 isFlatReplacement_ 2404 ? js::StringFlatReplaceString(cx, string, pattern, replace) 2405 : js::str_replace_string_raw(cx, string, pattern, replace); 2406 2407 if (!result) { 2408 return false; 2409 } 2410 2411 iter.storeInstructionResult(StringValue(result)); 2412 return true; 2413 } 2414 2415 bool MSubstr::writeRecoverData(CompactBufferWriter& writer) const { 2416 MOZ_ASSERT(canRecoverOnBailout()); 2417 writer.writeUnsigned(uint32_t(RInstruction::Recover_Substr)); 2418 return true; 2419 } 2420 2421 RSubstr::RSubstr(CompactBufferReader& reader) {} 2422 2423 bool RSubstr::recover(JSContext* cx, SnapshotIterator& iter) const { 2424 RootedString str(cx, iter.readString()); 2425 2426 // Int32 because |begin| is computed from MStringTrimStartIndex, MConstant, 2427 // or CallSubstringKernelResult. 2428 int32_t begin = iter.readInt32(); 2429 2430 // |length| is computed from MSub(truncated), MStringTrimEndIndex, or 2431 // CallSubstringKernelResult. The current MSub inputs won't overflow, so when 2432 // RSub recovers the MSub instruction, the input will be representable as an 2433 // Int32. This is only true as long as RSub calls |js::SubOperation|, which in 2434 // turn calls |JS::Value::setNumber|. We don't want to rely on this exact call 2435 // sequence, so instead use |readNumber| here and then release-assert the 2436 // number is exactly representable as an Int32. 2437 int32_t length = mozilla::ReleaseAssertedCast<int32_t>(iter.readNumber()); 2438 2439 JSString* result = SubstringKernel(cx, str, begin, length); 2440 if (!result) { 2441 return false; 2442 } 2443 2444 iter.storeInstructionResult(StringValue(result)); 2445 return true; 2446 } 2447 2448 bool MAtomicIsLockFree::writeRecoverData(CompactBufferWriter& writer) const { 2449 MOZ_ASSERT(canRecoverOnBailout()); 2450 writer.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree)); 2451 return true; 2452 } 2453 2454 RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader& reader) {} 2455 2456 bool RAtomicIsLockFree::recover(JSContext* cx, SnapshotIterator& iter) const { 2457 double dsize = JS::ToInteger(iter.readNumber()); 2458 2459 int32_t size; 2460 bool result = mozilla::NumberEqualsInt32(dsize, &size) && 2461 AtomicOperations::isLockfreeJS(size); 2462 iter.storeInstructionResult(BooleanValue(result)); 2463 return true; 2464 } 2465 2466 bool MInt64ToBigInt::writeRecoverData(CompactBufferWriter& writer) const { 2467 MOZ_ASSERT(canRecoverOnBailout()); 2468 writer.writeUnsigned(uint32_t(RInstruction::Recover_Int64ToBigInt)); 2469 writer.writeByte(isSigned()); 2470 return true; 2471 } 2472 2473 RInt64ToBigInt::RInt64ToBigInt(CompactBufferReader& reader) { 2474 isSigned_ = bool(reader.readByte()); 2475 } 2476 2477 bool RInt64ToBigInt::recover(JSContext* cx, SnapshotIterator& iter) const { 2478 int64_t n = iter.readInt64(); 2479 2480 BigInt* result; 2481 if (isSigned_) { 2482 result = BigInt::createFromInt64(cx, n); 2483 } else { 2484 result = BigInt::createFromUint64(cx, uint64_t(n)); 2485 } 2486 if (!result) { 2487 return false; 2488 } 2489 2490 iter.storeInstructionResult(JS::BigIntValue(result)); 2491 return true; 2492 } 2493 2494 bool MBigIntAsIntN::writeRecoverData(CompactBufferWriter& writer) const { 2495 MOZ_ASSERT(canRecoverOnBailout()); 2496 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsIntN)); 2497 return true; 2498 } 2499 2500 RBigIntAsIntN::RBigIntAsIntN(CompactBufferReader& reader) {} 2501 2502 bool RBigIntAsIntN::recover(JSContext* cx, SnapshotIterator& iter) const { 2503 // Int32 because |bits| is computed from MGuardInt32IsNonNegative. 2504 int32_t bits = iter.readInt32(); 2505 MOZ_ASSERT(bits >= 0); 2506 2507 RootedBigInt input(cx, iter.readBigInt()); 2508 2509 BigInt* result = BigInt::asIntN(cx, input, bits); 2510 if (!result) { 2511 return false; 2512 } 2513 2514 iter.storeInstructionResult(JS::BigIntValue(result)); 2515 return true; 2516 } 2517 2518 bool MBigIntAsUintN::writeRecoverData(CompactBufferWriter& writer) const { 2519 MOZ_ASSERT(canRecoverOnBailout()); 2520 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsUintN)); 2521 return true; 2522 } 2523 2524 RBigIntAsUintN::RBigIntAsUintN(CompactBufferReader& reader) {} 2525 2526 bool RBigIntAsUintN::recover(JSContext* cx, SnapshotIterator& iter) const { 2527 // Int32 because |bits| is computed from MGuardInt32IsNonNegative. 2528 int32_t bits = iter.readInt32(); 2529 MOZ_ASSERT(bits >= 0); 2530 2531 RootedBigInt input(cx, iter.readBigInt()); 2532 2533 BigInt* result = BigInt::asUintN(cx, input, bits); 2534 if (!result) { 2535 return false; 2536 } 2537 2538 iter.storeInstructionResult(JS::BigIntValue(result)); 2539 return true; 2540 } 2541 2542 bool MCreateArgumentsObject::writeRecoverData( 2543 CompactBufferWriter& writer) const { 2544 MOZ_ASSERT(canRecoverOnBailout()); 2545 writer.writeUnsigned(uint32_t(RInstruction::Recover_CreateArgumentsObject)); 2546 return true; 2547 } 2548 2549 RCreateArgumentsObject::RCreateArgumentsObject(CompactBufferReader& reader) {} 2550 2551 bool RCreateArgumentsObject::recover(JSContext* cx, 2552 SnapshotIterator& iter) const { 2553 RootedObject callObject(cx, iter.readObject()); 2554 ArgumentsObject* result = 2555 ArgumentsObject::createForIon(cx, iter.frame(), callObject); 2556 if (!result) { 2557 return false; 2558 } 2559 2560 iter.storeInstructionResult(JS::ObjectValue(*result)); 2561 return true; 2562 } 2563 2564 bool MCreateInlinedArgumentsObject::writeRecoverData( 2565 CompactBufferWriter& writer) const { 2566 MOZ_ASSERT(canRecoverOnBailout()); 2567 writer.writeUnsigned( 2568 uint32_t(RInstruction::Recover_CreateInlinedArgumentsObject)); 2569 writer.writeUnsigned(numActuals()); 2570 return true; 2571 } 2572 2573 RCreateInlinedArgumentsObject::RCreateInlinedArgumentsObject( 2574 CompactBufferReader& reader) { 2575 numActuals_ = reader.readUnsigned(); 2576 } 2577 2578 bool RCreateInlinedArgumentsObject::recover(JSContext* cx, 2579 SnapshotIterator& iter) const { 2580 RootedObject callObject(cx, iter.readObject()); 2581 RootedFunction callee(cx, &iter.readObject()->as<JSFunction>()); 2582 2583 JS::RootedValueArray<ArgumentsObject::MaxInlinedArgs> argsArray(cx); 2584 for (uint32_t i = 0; i < numActuals_; i++) { 2585 argsArray[i].set(iter.read()); 2586 } 2587 2588 ArgumentsObject* result = ArgumentsObject::createFromValueArray( 2589 cx, argsArray, callee, callObject, numActuals_); 2590 if (!result) { 2591 return false; 2592 } 2593 2594 iter.storeInstructionResult(JS::ObjectValue(*result)); 2595 return true; 2596 } 2597 2598 bool MRest::writeRecoverData(CompactBufferWriter& writer) const { 2599 MOZ_ASSERT(canRecoverOnBailout()); 2600 writer.writeUnsigned(uint32_t(RInstruction::Recover_Rest)); 2601 writer.writeUnsigned(numFormals()); 2602 return true; 2603 } 2604 2605 RRest::RRest(CompactBufferReader& reader) { 2606 numFormals_ = reader.readUnsigned(); 2607 } 2608 2609 bool RRest::recover(JSContext* cx, SnapshotIterator& iter) const { 2610 JitFrameLayout* frame = iter.frame(); 2611 2612 // Int32 because |numActuals| is computed from MArgumentsLength. 2613 uint32_t numActuals = iter.readInt32(); 2614 MOZ_ASSERT(numActuals == frame->numActualArgs()); 2615 2616 uint32_t numFormals = numFormals_; 2617 2618 uint32_t length = std::max(numActuals, numFormals) - numFormals; 2619 Value* src = frame->actualArgs() + numFormals; 2620 JSObject* rest = jit::InitRestParameter(cx, length, src, nullptr); 2621 if (!rest) { 2622 return false; 2623 } 2624 2625 iter.storeInstructionResult(ObjectValue(*rest)); 2626 return true; 2627 } 2628 2629 bool MTypedArraySubarray::writeRecoverData(CompactBufferWriter& writer) const { 2630 MOZ_ASSERT(canRecoverOnBailout()); 2631 writer.writeUnsigned(uint32_t(RInstruction::Recover_TypedArraySubarray)); 2632 return true; 2633 } 2634 2635 RTypedArraySubarray::RTypedArraySubarray(CompactBufferReader& reader) {} 2636 2637 bool RTypedArraySubarray::recover(JSContext* cx, SnapshotIterator& iter) const { 2638 Rooted<TypedArrayObject*> obj(cx, &iter.readObject()->as<TypedArrayObject>()); 2639 intptr_t start = iter.readIntPtr(); 2640 intptr_t length = iter.readIntPtr(); 2641 2642 auto* result = TypedArraySubarrayRecover(cx, obj, start, length); 2643 if (!result) { 2644 return false; 2645 } 2646 2647 iter.storeInstructionResult(ObjectValue(*result)); 2648 return true; 2649 }