Bug 1885489 - Part 11: Use SnapshotIterator::readBigInt() when recovering BigInt...
[gecko.git] / js / src / jit / Recover.cpp
blobcc9f5344b4ef255cb16f0d20c16ba703f1d37493
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/. */
7 #include "jit/Recover.h"
9 #include "jsmath.h"
11 #include "builtin/Object.h"
12 #include "builtin/RegExp.h"
13 #include "builtin/String.h"
14 #include "jit/AtomicOperations.h"
15 #include "jit/Bailouts.h"
16 #include "jit/CompileInfo.h"
17 #include "jit/Ion.h"
18 #include "jit/JitSpewer.h"
19 #include "jit/JSJitFrameIter.h"
20 #include "jit/MIR.h"
21 #include "jit/MIRGraph.h"
22 #include "jit/VMFunctions.h"
23 #include "util/DifferentialTesting.h"
24 #include "vm/BigIntType.h"
25 #include "vm/EqualityOperations.h"
26 #include "vm/Interpreter.h"
27 #include "vm/Iteration.h"
28 #include "vm/JSContext.h"
29 #include "vm/JSObject.h"
30 #include "vm/PlainObject.h" // js::PlainObject
31 #include "vm/StringType.h"
32 #include "vm/Watchtower.h"
34 #include "vm/Interpreter-inl.h"
36 using namespace js;
37 using namespace js::jit;
39 bool MNode::writeRecoverData(CompactBufferWriter& writer) const {
40 MOZ_CRASH("This instruction is not serializable");
43 void RInstruction::readRecoverData(CompactBufferReader& reader,
44 RInstructionStorage* raw) {
45 uint32_t op = reader.readUnsigned();
46 switch (Opcode(op)) {
47 #define MATCH_OPCODES_(op) \
48 case Recover_##op: \
49 static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \
50 "storage space must be big enough to store R" #op); \
51 static_assert(alignof(R##op) <= alignof(RInstructionStorage), \
52 "storage space must be aligned adequate to store R" #op); \
53 new (raw->addr()) R##op(reader); \
54 break;
56 RECOVER_OPCODE_LIST(MATCH_OPCODES_)
57 #undef MATCH_OPCODES_
59 case Recover_Invalid:
60 default:
61 MOZ_CRASH("Bad decoding of the previous instruction?");
65 bool MResumePoint::writeRecoverData(CompactBufferWriter& writer) const {
66 writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint));
68 MBasicBlock* bb = block();
69 bool hasFun = bb->info().hasFunMaybeLazy();
70 uint32_t nargs = bb->info().nargs();
71 JSScript* script = bb->info().script();
72 uint32_t exprStack = stackDepth() - bb->info().ninvoke();
74 #ifdef DEBUG
75 // Ensure that all snapshot which are encoded can safely be used for
76 // bailouts.
77 uint32_t numIntermediate = NumIntermediateValues(mode());
78 if (JSContext* cx = GetJitContext()->cx) {
79 if (!AssertBailoutStackDepth(cx, script, pc(), mode(),
80 exprStack - numIntermediate)) {
81 return false;
84 #endif
86 uint32_t formalArgs = CountArgSlots(script, hasFun, nargs);
88 // Test if we honor the maximum of arguments at all times. This is a sanity
89 // check and not an algorithm limit. So check might be a bit too loose. +4
90 // to account for scope chain, return value, this value and maybe
91 // arguments_object.
92 MOZ_ASSERT(formalArgs < SNAPSHOT_MAX_NARGS + 4);
94 #ifdef JS_JITSPEW
95 uint32_t implicit = StartArgSlot(script);
96 #endif
97 uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
99 JitSpew(JitSpew_IonSnapshots,
100 "Starting frame; implicit %u, formals %u, fixed %zu, exprs %u",
101 implicit, formalArgs - implicit, script->nfixed(), exprStack);
103 uint32_t pcOff = script->pcToOffset(pc());
104 JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, mode %s, nslots %u",
105 pcOff, ResumeModeToString(mode()), nallocs);
107 uint32_t pcOffAndMode =
108 (pcOff << RResumePoint::PCOffsetShift) | uint32_t(mode());
109 MOZ_RELEASE_ASSERT((pcOffAndMode >> RResumePoint::PCOffsetShift) == pcOff,
110 "pcOff doesn't fit in pcOffAndMode");
111 writer.writeUnsigned(pcOffAndMode);
113 writer.writeUnsigned(nallocs);
114 return true;
117 RResumePoint::RResumePoint(CompactBufferReader& reader) {
118 pcOffsetAndMode_ = reader.readUnsigned();
119 numOperands_ = reader.readUnsigned();
120 JitSpew(JitSpew_IonSnapshots,
121 "Read RResumePoint (pc offset %u, mode %s, nslots %u)", pcOffset(),
122 ResumeModeToString(mode()), numOperands_);
125 bool RResumePoint::recover(JSContext* cx, SnapshotIterator& iter) const {
126 MOZ_CRASH("This instruction is not recoverable.");
129 bool MBitNot::writeRecoverData(CompactBufferWriter& writer) const {
130 // 64-bit int bitnots exist only when compiling wasm; they exist neither for
131 // JS nor asm.js. So we don't expect them here.
132 MOZ_ASSERT(type() != MIRType::Int64);
133 MOZ_ASSERT(canRecoverOnBailout());
134 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitNot));
135 return true;
138 RBitNot::RBitNot(CompactBufferReader& reader) {}
140 bool RBitNot::recover(JSContext* cx, SnapshotIterator& iter) const {
141 RootedValue operand(cx, iter.read());
142 RootedValue result(cx);
144 if (!js::BitNot(cx, &operand, &result)) {
145 return false;
148 iter.storeInstructionResult(result);
149 return true;
152 bool MBitAnd::writeRecoverData(CompactBufferWriter& writer) const {
153 MOZ_ASSERT(canRecoverOnBailout());
154 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd));
155 return true;
158 RBitAnd::RBitAnd(CompactBufferReader& reader) {}
160 bool RBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const {
161 RootedValue lhs(cx, iter.read());
162 RootedValue rhs(cx, iter.read());
163 RootedValue result(cx);
164 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
166 if (!js::BitAnd(cx, &lhs, &rhs, &result)) {
167 return false;
170 iter.storeInstructionResult(result);
171 return true;
174 bool MBitOr::writeRecoverData(CompactBufferWriter& writer) const {
175 MOZ_ASSERT(canRecoverOnBailout());
176 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitOr));
177 return true;
180 RBitOr::RBitOr(CompactBufferReader& reader) {}
182 bool RBitOr::recover(JSContext* cx, SnapshotIterator& iter) const {
183 RootedValue lhs(cx, iter.read());
184 RootedValue rhs(cx, iter.read());
185 RootedValue result(cx);
186 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
188 if (!js::BitOr(cx, &lhs, &rhs, &result)) {
189 return false;
192 iter.storeInstructionResult(result);
193 return true;
196 bool MBitXor::writeRecoverData(CompactBufferWriter& writer) const {
197 MOZ_ASSERT(canRecoverOnBailout());
198 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitXor));
199 return true;
202 RBitXor::RBitXor(CompactBufferReader& reader) {}
204 bool RBitXor::recover(JSContext* cx, SnapshotIterator& iter) const {
205 RootedValue lhs(cx, iter.read());
206 RootedValue rhs(cx, iter.read());
207 RootedValue result(cx);
209 if (!js::BitXor(cx, &lhs, &rhs, &result)) {
210 return false;
213 iter.storeInstructionResult(result);
214 return true;
217 bool MLsh::writeRecoverData(CompactBufferWriter& writer) const {
218 MOZ_ASSERT(canRecoverOnBailout());
219 writer.writeUnsigned(uint32_t(RInstruction::Recover_Lsh));
220 return true;
223 RLsh::RLsh(CompactBufferReader& reader) {}
225 bool RLsh::recover(JSContext* cx, SnapshotIterator& iter) const {
226 RootedValue lhs(cx, iter.read());
227 RootedValue rhs(cx, iter.read());
228 RootedValue result(cx);
229 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
231 if (!js::BitLsh(cx, &lhs, &rhs, &result)) {
232 return false;
235 iter.storeInstructionResult(result);
236 return true;
239 bool MRsh::writeRecoverData(CompactBufferWriter& writer) const {
240 MOZ_ASSERT(canRecoverOnBailout());
241 writer.writeUnsigned(uint32_t(RInstruction::Recover_Rsh));
242 return true;
245 RRsh::RRsh(CompactBufferReader& reader) {}
247 bool RRsh::recover(JSContext* cx, SnapshotIterator& iter) const {
248 RootedValue lhs(cx, iter.read());
249 RootedValue rhs(cx, iter.read());
250 RootedValue result(cx);
251 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
253 if (!js::BitRsh(cx, &lhs, &rhs, &result)) {
254 return false;
257 iter.storeInstructionResult(result);
258 return true;
261 bool MUrsh::writeRecoverData(CompactBufferWriter& writer) const {
262 MOZ_ASSERT(canRecoverOnBailout());
263 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ursh));
264 return true;
267 RUrsh::RUrsh(CompactBufferReader& reader) {}
269 bool RUrsh::recover(JSContext* cx, SnapshotIterator& iter) const {
270 RootedValue lhs(cx, iter.read());
271 RootedValue rhs(cx, iter.read());
272 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
274 RootedValue result(cx);
275 if (!js::UrshValues(cx, &lhs, &rhs, &result)) {
276 return false;
279 iter.storeInstructionResult(result);
280 return true;
283 bool MSignExtendInt32::writeRecoverData(CompactBufferWriter& writer) const {
284 MOZ_ASSERT(canRecoverOnBailout());
285 writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtendInt32));
286 MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
287 writer.writeByte(uint8_t(mode_));
288 return true;
291 RSignExtendInt32::RSignExtendInt32(CompactBufferReader& reader) {
292 mode_ = reader.readByte();
295 bool RSignExtendInt32::recover(JSContext* cx, SnapshotIterator& iter) const {
296 RootedValue operand(cx, iter.read());
298 int32_t i;
299 if (!ToInt32(cx, operand, &i)) {
300 return false;
303 int32_t result;
304 switch (MSignExtendInt32::Mode(mode_)) {
305 case MSignExtendInt32::Byte:
306 result = static_cast<int8_t>(i);
307 break;
308 case MSignExtendInt32::Half:
309 result = static_cast<int16_t>(i);
310 break;
313 iter.storeInstructionResult(JS::Int32Value(result));
314 return true;
317 bool MAdd::writeRecoverData(CompactBufferWriter& writer) const {
318 MOZ_ASSERT(canRecoverOnBailout());
319 writer.writeUnsigned(uint32_t(RInstruction::Recover_Add));
320 writer.writeByte(type() == MIRType::Float32);
321 return true;
324 RAdd::RAdd(CompactBufferReader& reader) {
325 isFloatOperation_ = reader.readByte();
328 bool RAdd::recover(JSContext* cx, SnapshotIterator& iter) const {
329 RootedValue lhs(cx, iter.read());
330 RootedValue rhs(cx, iter.read());
331 RootedValue result(cx);
333 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
334 if (!js::AddValues(cx, &lhs, &rhs, &result)) {
335 return false;
338 // MIRType::Float32 is a specialization embedding the fact that the result is
339 // rounded to a Float32.
340 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
341 return false;
344 iter.storeInstructionResult(result);
345 return true;
348 bool MSub::writeRecoverData(CompactBufferWriter& writer) const {
349 MOZ_ASSERT(canRecoverOnBailout());
350 writer.writeUnsigned(uint32_t(RInstruction::Recover_Sub));
351 writer.writeByte(type() == MIRType::Float32);
352 return true;
355 RSub::RSub(CompactBufferReader& reader) {
356 isFloatOperation_ = reader.readByte();
359 bool RSub::recover(JSContext* cx, SnapshotIterator& iter) const {
360 RootedValue lhs(cx, iter.read());
361 RootedValue rhs(cx, iter.read());
362 RootedValue result(cx);
364 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
365 if (!js::SubValues(cx, &lhs, &rhs, &result)) {
366 return false;
369 // MIRType::Float32 is a specialization embedding the fact that the result is
370 // rounded to a Float32.
371 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
372 return false;
375 iter.storeInstructionResult(result);
376 return true;
379 bool MMul::writeRecoverData(CompactBufferWriter& writer) const {
380 MOZ_ASSERT(canRecoverOnBailout());
381 writer.writeUnsigned(uint32_t(RInstruction::Recover_Mul));
382 writer.writeByte(type() == MIRType::Float32);
383 MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
384 writer.writeByte(uint8_t(mode_));
385 return true;
388 RMul::RMul(CompactBufferReader& reader) {
389 isFloatOperation_ = reader.readByte();
390 mode_ = reader.readByte();
393 bool RMul::recover(JSContext* cx, SnapshotIterator& iter) const {
394 RootedValue lhs(cx, iter.read());
395 RootedValue rhs(cx, iter.read());
396 RootedValue result(cx);
398 if (MMul::Mode(mode_) == MMul::Normal) {
399 if (!js::MulValues(cx, &lhs, &rhs, &result)) {
400 return false;
403 // MIRType::Float32 is a specialization embedding the fact that the
404 // result is rounded to a Float32.
405 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
406 return false;
408 } else {
409 MOZ_ASSERT(MMul::Mode(mode_) == MMul::Integer);
410 if (!js::math_imul_handle(cx, lhs, rhs, &result)) {
411 return false;
415 iter.storeInstructionResult(result);
416 return true;
419 bool MDiv::writeRecoverData(CompactBufferWriter& writer) const {
420 MOZ_ASSERT(canRecoverOnBailout());
421 writer.writeUnsigned(uint32_t(RInstruction::Recover_Div));
422 writer.writeByte(type() == MIRType::Float32);
423 return true;
426 RDiv::RDiv(CompactBufferReader& reader) {
427 isFloatOperation_ = reader.readByte();
430 bool RDiv::recover(JSContext* cx, SnapshotIterator& iter) const {
431 RootedValue lhs(cx, iter.read());
432 RootedValue rhs(cx, iter.read());
433 RootedValue result(cx);
435 if (!js::DivValues(cx, &lhs, &rhs, &result)) {
436 return false;
439 // MIRType::Float32 is a specialization embedding the fact that the result is
440 // rounded to a Float32.
441 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
442 return false;
445 iter.storeInstructionResult(result);
446 return true;
449 bool MMod::writeRecoverData(CompactBufferWriter& writer) const {
450 MOZ_ASSERT(canRecoverOnBailout());
451 writer.writeUnsigned(uint32_t(RInstruction::Recover_Mod));
452 return true;
455 RMod::RMod(CompactBufferReader& reader) {}
457 bool RMod::recover(JSContext* cx, SnapshotIterator& iter) const {
458 RootedValue lhs(cx, iter.read());
459 RootedValue rhs(cx, iter.read());
460 RootedValue result(cx);
462 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
463 if (!js::ModValues(cx, &lhs, &rhs, &result)) {
464 return false;
467 iter.storeInstructionResult(result);
468 return true;
471 bool MNot::writeRecoverData(CompactBufferWriter& writer) const {
472 MOZ_ASSERT(canRecoverOnBailout());
473 writer.writeUnsigned(uint32_t(RInstruction::Recover_Not));
474 return true;
477 RNot::RNot(CompactBufferReader& reader) {}
479 bool RNot::recover(JSContext* cx, SnapshotIterator& iter) const {
480 RootedValue v(cx, iter.read());
481 RootedValue result(cx);
483 result.setBoolean(!ToBoolean(v));
485 iter.storeInstructionResult(result);
486 return true;
489 bool MBigIntAdd::writeRecoverData(CompactBufferWriter& writer) const {
490 MOZ_ASSERT(canRecoverOnBailout());
491 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAdd));
492 return true;
495 RBigIntAdd::RBigIntAdd(CompactBufferReader& reader) {}
497 bool RBigIntAdd::recover(JSContext* cx, SnapshotIterator& iter) const {
498 Rooted<BigInt*> lhs(cx, iter.readBigInt());
499 Rooted<BigInt*> rhs(cx, iter.readBigInt());
501 BigInt* result = BigInt::add(cx, lhs, rhs);
502 if (!result) {
503 return false;
506 iter.storeInstructionResult(BigIntValue(result));
507 return true;
510 bool MBigIntSub::writeRecoverData(CompactBufferWriter& writer) const {
511 MOZ_ASSERT(canRecoverOnBailout());
512 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntSub));
513 return true;
516 RBigIntSub::RBigIntSub(CompactBufferReader& reader) {}
518 bool RBigIntSub::recover(JSContext* cx, SnapshotIterator& iter) const {
519 Rooted<BigInt*> lhs(cx, iter.readBigInt());
520 Rooted<BigInt*> rhs(cx, iter.readBigInt());
522 BigInt* result = BigInt::sub(cx, lhs, rhs);
523 if (!result) {
524 return false;
527 iter.storeInstructionResult(BigIntValue(result));
528 return true;
531 bool MBigIntMul::writeRecoverData(CompactBufferWriter& writer) const {
532 MOZ_ASSERT(canRecoverOnBailout());
533 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMul));
534 return true;
537 RBigIntMul::RBigIntMul(CompactBufferReader& reader) {}
539 bool RBigIntMul::recover(JSContext* cx, SnapshotIterator& iter) const {
540 Rooted<BigInt*> lhs(cx, iter.readBigInt());
541 Rooted<BigInt*> rhs(cx, iter.readBigInt());
543 BigInt* result = BigInt::mul(cx, lhs, rhs);
544 if (!result) {
545 return false;
548 iter.storeInstructionResult(BigIntValue(result));
549 return true;
552 bool MBigIntDiv::writeRecoverData(CompactBufferWriter& writer) const {
553 MOZ_ASSERT(canRecoverOnBailout());
554 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDiv));
555 return true;
558 RBigIntDiv::RBigIntDiv(CompactBufferReader& reader) {}
560 bool RBigIntDiv::recover(JSContext* cx, SnapshotIterator& iter) const {
561 Rooted<BigInt*> lhs(cx, iter.readBigInt());
562 Rooted<BigInt*> rhs(cx, iter.readBigInt());
563 MOZ_ASSERT(!rhs->isZero(),
564 "division by zero throws and therefore can't be recovered");
566 BigInt* result = BigInt::div(cx, lhs, rhs);
567 if (!result) {
568 return false;
571 iter.storeInstructionResult(BigIntValue(result));
572 return true;
575 bool MBigIntMod::writeRecoverData(CompactBufferWriter& writer) const {
576 MOZ_ASSERT(canRecoverOnBailout());
577 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMod));
578 return true;
581 RBigIntMod::RBigIntMod(CompactBufferReader& reader) {}
583 bool RBigIntMod::recover(JSContext* cx, SnapshotIterator& iter) const {
584 Rooted<BigInt*> lhs(cx, iter.readBigInt());
585 Rooted<BigInt*> rhs(cx, iter.readBigInt());
586 MOZ_ASSERT(!rhs->isZero(),
587 "division by zero throws and therefore can't be recovered");
589 BigInt* result = BigInt::mod(cx, lhs, rhs);
590 if (!result) {
591 return false;
594 iter.storeInstructionResult(BigIntValue(result));
595 return true;
598 bool MBigIntPow::writeRecoverData(CompactBufferWriter& writer) const {
599 MOZ_ASSERT(canRecoverOnBailout());
600 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPow));
601 return true;
604 RBigIntPow::RBigIntPow(CompactBufferReader& reader) {}
606 bool RBigIntPow::recover(JSContext* cx, SnapshotIterator& iter) const {
607 Rooted<BigInt*> lhs(cx, iter.readBigInt());
608 Rooted<BigInt*> rhs(cx, iter.readBigInt());
609 MOZ_ASSERT(!rhs->isNegative(),
610 "negative exponent throws and therefore can't be recovered");
612 BigInt* result = BigInt::pow(cx, lhs, rhs);
613 if (!result) {
614 return false;
617 iter.storeInstructionResult(BigIntValue(result));
618 return true;
621 bool MBigIntBitAnd::writeRecoverData(CompactBufferWriter& writer) const {
622 MOZ_ASSERT(canRecoverOnBailout());
623 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitAnd));
624 return true;
627 RBigIntBitAnd::RBigIntBitAnd(CompactBufferReader& reader) {}
629 bool RBigIntBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const {
630 Rooted<BigInt*> lhs(cx, iter.readBigInt());
631 Rooted<BigInt*> rhs(cx, iter.readBigInt());
633 BigInt* result = BigInt::bitAnd(cx, lhs, rhs);
634 if (!result) {
635 return false;
638 iter.storeInstructionResult(BigIntValue(result));
639 return true;
642 bool MBigIntBitOr::writeRecoverData(CompactBufferWriter& writer) const {
643 MOZ_ASSERT(canRecoverOnBailout());
644 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitOr));
645 return true;
648 RBigIntBitOr::RBigIntBitOr(CompactBufferReader& reader) {}
650 bool RBigIntBitOr::recover(JSContext* cx, SnapshotIterator& iter) const {
651 Rooted<BigInt*> lhs(cx, iter.readBigInt());
652 Rooted<BigInt*> rhs(cx, iter.readBigInt());
654 BigInt* result = BigInt::bitOr(cx, lhs, rhs);
655 if (!result) {
656 return false;
659 iter.storeInstructionResult(BigIntValue(result));
660 return true;
663 bool MBigIntBitXor::writeRecoverData(CompactBufferWriter& writer) const {
664 MOZ_ASSERT(canRecoverOnBailout());
665 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitXor));
666 return true;
669 RBigIntBitXor::RBigIntBitXor(CompactBufferReader& reader) {}
671 bool RBigIntBitXor::recover(JSContext* cx, SnapshotIterator& iter) const {
672 Rooted<BigInt*> lhs(cx, iter.readBigInt());
673 Rooted<BigInt*> rhs(cx, iter.readBigInt());
675 BigInt* result = BigInt::bitXor(cx, lhs, rhs);
676 if (!result) {
677 return false;
680 iter.storeInstructionResult(BigIntValue(result));
681 return true;
684 bool MBigIntLsh::writeRecoverData(CompactBufferWriter& writer) const {
685 MOZ_ASSERT(canRecoverOnBailout());
686 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntLsh));
687 return true;
690 RBigIntLsh::RBigIntLsh(CompactBufferReader& reader) {}
692 bool RBigIntLsh::recover(JSContext* cx, SnapshotIterator& iter) const {
693 Rooted<BigInt*> lhs(cx, iter.readBigInt());
694 Rooted<BigInt*> rhs(cx, iter.readBigInt());
696 BigInt* result = BigInt::lsh(cx, lhs, rhs);
697 if (!result) {
698 return false;
701 iter.storeInstructionResult(BigIntValue(result));
702 return true;
705 bool MBigIntRsh::writeRecoverData(CompactBufferWriter& writer) const {
706 MOZ_ASSERT(canRecoverOnBailout());
707 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntRsh));
708 return true;
711 RBigIntRsh::RBigIntRsh(CompactBufferReader& reader) {}
713 bool RBigIntRsh::recover(JSContext* cx, SnapshotIterator& iter) const {
714 Rooted<BigInt*> lhs(cx, iter.readBigInt());
715 Rooted<BigInt*> rhs(cx, iter.readBigInt());
717 BigInt* result = BigInt::rsh(cx, lhs, rhs);
718 if (!result) {
719 return false;
722 iter.storeInstructionResult(BigIntValue(result));
723 return true;
726 bool MBigIntIncrement::writeRecoverData(CompactBufferWriter& writer) const {
727 MOZ_ASSERT(canRecoverOnBailout());
728 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntIncrement));
729 return true;
732 RBigIntIncrement::RBigIntIncrement(CompactBufferReader& reader) {}
734 bool RBigIntIncrement::recover(JSContext* cx, SnapshotIterator& iter) const {
735 Rooted<BigInt*> operand(cx, iter.readBigInt());
737 BigInt* result = BigInt::inc(cx, operand);
738 if (!result) {
739 return false;
742 iter.storeInstructionResult(BigIntValue(result));
743 return true;
746 bool MBigIntDecrement::writeRecoverData(CompactBufferWriter& writer) const {
747 MOZ_ASSERT(canRecoverOnBailout());
748 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDecrement));
749 return true;
752 RBigIntDecrement::RBigIntDecrement(CompactBufferReader& reader) {}
754 bool RBigIntDecrement::recover(JSContext* cx, SnapshotIterator& iter) const {
755 Rooted<BigInt*> operand(cx, iter.readBigInt());
757 BigInt* result = BigInt::dec(cx, operand);
758 if (!result) {
759 return false;
762 iter.storeInstructionResult(BigIntValue(result));
763 return true;
766 bool MBigIntNegate::writeRecoverData(CompactBufferWriter& writer) const {
767 MOZ_ASSERT(canRecoverOnBailout());
768 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntNegate));
769 return true;
772 RBigIntNegate::RBigIntNegate(CompactBufferReader& reader) {}
774 bool RBigIntNegate::recover(JSContext* cx, SnapshotIterator& iter) const {
775 Rooted<BigInt*> operand(cx, iter.readBigInt());
777 BigInt* result = BigInt::neg(cx, operand);
778 if (!result) {
779 return false;
782 iter.storeInstructionResult(BigIntValue(result));
783 return true;
786 bool MBigIntBitNot::writeRecoverData(CompactBufferWriter& writer) const {
787 MOZ_ASSERT(canRecoverOnBailout());
788 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitNot));
789 return true;
792 RBigIntBitNot::RBigIntBitNot(CompactBufferReader& reader) {}
794 bool RBigIntBitNot::recover(JSContext* cx, SnapshotIterator& iter) const {
795 Rooted<BigInt*> operand(cx, iter.readBigInt());
797 BigInt* result = BigInt::bitNot(cx, operand);
798 if (!result) {
799 return false;
802 iter.storeInstructionResult(BigIntValue(result));
803 return true;
806 bool MCompare::writeRecoverData(CompactBufferWriter& writer) const {
807 MOZ_ASSERT(canRecoverOnBailout());
808 writer.writeUnsigned(uint32_t(RInstruction::Recover_Compare));
810 static_assert(sizeof(JSOp) == sizeof(uint8_t));
811 writer.writeByte(uint8_t(jsop_));
812 return true;
815 RCompare::RCompare(CompactBufferReader& reader) {
816 jsop_ = JSOp(reader.readByte());
818 MOZ_ASSERT(IsEqualityOp(jsop_) || IsRelationalOp(jsop_));
821 bool RCompare::recover(JSContext* cx, SnapshotIterator& iter) const {
822 RootedValue lhs(cx, iter.read());
823 RootedValue rhs(cx, iter.read());
825 bool result;
826 switch (jsop_) {
827 case JSOp::Eq:
828 case JSOp::Ne:
829 if (!js::LooselyEqual(cx, lhs, rhs, &result)) {
830 return false;
832 if (jsop_ == JSOp::Ne) {
833 result = !result;
835 break;
836 case JSOp::StrictEq:
837 case JSOp::StrictNe:
838 if (!StrictlyEqual(cx, lhs, rhs, &result)) {
839 return false;
841 if (jsop_ == JSOp::StrictNe) {
842 result = !result;
844 break;
845 case JSOp::Lt:
846 if (!js::LessThan(cx, &lhs, &rhs, &result)) {
847 return false;
849 break;
850 case JSOp::Le:
851 if (!js::LessThanOrEqual(cx, &lhs, &rhs, &result)) {
852 return false;
854 break;
855 case JSOp::Gt:
856 if (!js::GreaterThan(cx, &lhs, &rhs, &result)) {
857 return false;
859 break;
860 case JSOp::Ge:
861 if (!js::GreaterThanOrEqual(cx, &lhs, &rhs, &result)) {
862 return false;
864 break;
865 default:
866 MOZ_CRASH("Unexpected op.");
869 iter.storeInstructionResult(BooleanValue(result));
870 return true;
873 bool MConcat::writeRecoverData(CompactBufferWriter& writer) const {
874 MOZ_ASSERT(canRecoverOnBailout());
875 writer.writeUnsigned(uint32_t(RInstruction::Recover_Concat));
876 return true;
879 RConcat::RConcat(CompactBufferReader& reader) {}
881 bool RConcat::recover(JSContext* cx, SnapshotIterator& iter) const {
882 RootedValue lhs(cx, iter.read());
883 RootedValue rhs(cx, iter.read());
884 RootedValue result(cx);
886 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
887 if (!js::AddValues(cx, &lhs, &rhs, &result)) {
888 return false;
891 iter.storeInstructionResult(result);
892 return true;
895 RStringLength::RStringLength(CompactBufferReader& reader) {}
897 bool RStringLength::recover(JSContext* cx, SnapshotIterator& iter) const {
898 JSString* string = iter.readString();
900 static_assert(JSString::MAX_LENGTH <= INT32_MAX,
901 "Can cast string length to int32_t");
903 iter.storeInstructionResult(Int32Value(int32_t(string->length())));
904 return true;
907 bool MStringLength::writeRecoverData(CompactBufferWriter& writer) const {
908 MOZ_ASSERT(canRecoverOnBailout());
909 writer.writeUnsigned(uint32_t(RInstruction::Recover_StringLength));
910 return true;
913 bool MArgumentsLength::writeRecoverData(CompactBufferWriter& writer) const {
914 MOZ_ASSERT(canRecoverOnBailout());
915 writer.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength));
916 return true;
919 RArgumentsLength::RArgumentsLength(CompactBufferReader& reader) {}
921 bool RArgumentsLength::recover(JSContext* cx, SnapshotIterator& iter) const {
922 uintptr_t numActualArgs = iter.frame()->numActualArgs();
924 static_assert(ARGS_LENGTH_MAX <= INT32_MAX,
925 "Can cast arguments count to int32_t");
926 MOZ_ASSERT(numActualArgs <= ARGS_LENGTH_MAX);
928 iter.storeInstructionResult(JS::Int32Value(int32_t(numActualArgs)));
929 return true;
932 bool MFloor::writeRecoverData(CompactBufferWriter& writer) const {
933 MOZ_ASSERT(canRecoverOnBailout());
934 writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
935 return true;
938 RFloor::RFloor(CompactBufferReader& reader) {}
940 bool RFloor::recover(JSContext* cx, SnapshotIterator& iter) const {
941 double num = iter.readNumber();
942 double result = js::math_floor_impl(num);
944 iter.storeInstructionResult(NumberValue(result));
945 return true;
948 bool MCeil::writeRecoverData(CompactBufferWriter& writer) const {
949 MOZ_ASSERT(canRecoverOnBailout());
950 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
951 return true;
954 RCeil::RCeil(CompactBufferReader& reader) {}
956 bool RCeil::recover(JSContext* cx, SnapshotIterator& iter) const {
957 double num = iter.readNumber();
958 double result = js::math_ceil_impl(num);
960 iter.storeInstructionResult(NumberValue(result));
961 return true;
964 bool MRound::writeRecoverData(CompactBufferWriter& writer) const {
965 MOZ_ASSERT(canRecoverOnBailout());
966 writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
967 return true;
970 RRound::RRound(CompactBufferReader& reader) {}
972 bool RRound::recover(JSContext* cx, SnapshotIterator& iter) const {
973 double num = iter.readNumber();
974 double result = js::math_round_impl(num);
976 iter.storeInstructionResult(NumberValue(result));
977 return true;
980 bool MTrunc::writeRecoverData(CompactBufferWriter& writer) const {
981 MOZ_ASSERT(canRecoverOnBailout());
982 writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc));
983 return true;
986 RTrunc::RTrunc(CompactBufferReader& reader) {}
988 bool RTrunc::recover(JSContext* cx, SnapshotIterator& iter) const {
989 double num = iter.readNumber();
990 double result = js::math_trunc_impl(num);
992 iter.storeInstructionResult(NumberValue(result));
993 return true;
996 bool MCharCodeAt::writeRecoverData(CompactBufferWriter& writer) const {
997 MOZ_ASSERT(canRecoverOnBailout());
998 writer.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt));
999 return true;
1002 RCharCodeAt::RCharCodeAt(CompactBufferReader& reader) {}
1004 bool RCharCodeAt::recover(JSContext* cx, SnapshotIterator& iter) const {
1005 JSString* string = iter.readString();
1007 // Int32 because |index| is computed from MBoundsCheck.
1008 int32_t index = iter.readInt32();
1009 MOZ_RELEASE_ASSERT(0 <= index && size_t(index) < string->length());
1011 char16_t c;
1012 if (!string->getChar(cx, index, &c)) {
1013 return false;
1016 iter.storeInstructionResult(Int32Value(c));
1017 return true;
1020 bool MFromCharCode::writeRecoverData(CompactBufferWriter& writer) const {
1021 MOZ_ASSERT(canRecoverOnBailout());
1022 writer.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode));
1023 return true;
1026 RFromCharCode::RFromCharCode(CompactBufferReader& reader) {}
1028 bool RFromCharCode::recover(JSContext* cx, SnapshotIterator& iter) const {
1029 // Number because |charCode| is computed from (recoverable) user input.
1030 int32_t charCode = JS::ToInt32(iter.readNumber());
1032 JSString* str = StringFromCharCode(cx, charCode);
1033 if (!str) {
1034 return false;
1037 iter.storeInstructionResult(StringValue(str));
1038 return true;
1041 bool MFromCharCodeEmptyIfNegative::writeRecoverData(
1042 CompactBufferWriter& writer) const {
1043 MOZ_ASSERT(canRecoverOnBailout());
1044 writer.writeUnsigned(
1045 uint32_t(RInstruction::Recover_FromCharCodeEmptyIfNegative));
1046 return true;
1049 RFromCharCodeEmptyIfNegative::RFromCharCodeEmptyIfNegative(
1050 CompactBufferReader& reader) {}
1052 bool RFromCharCodeEmptyIfNegative::recover(JSContext* cx,
1053 SnapshotIterator& iter) const {
1054 // Int32 because |charCode| is computed from MCharCodeAtOrNegative.
1055 int32_t charCode = iter.readInt32();
1057 JSString* str;
1058 if (charCode < 0) {
1059 str = cx->emptyString();
1060 } else {
1061 str = StringFromCharCode(cx, charCode);
1062 if (!str) {
1063 return false;
1067 iter.storeInstructionResult(StringValue(str));
1068 return true;
1071 bool MPow::writeRecoverData(CompactBufferWriter& writer) const {
1072 MOZ_ASSERT(canRecoverOnBailout());
1073 writer.writeUnsigned(uint32_t(RInstruction::Recover_Pow));
1074 return true;
1077 RPow::RPow(CompactBufferReader& reader) {}
1079 bool RPow::recover(JSContext* cx, SnapshotIterator& iter) const {
1080 double base = iter.readNumber();
1081 double power = iter.readNumber();
1082 double result = ecmaPow(base, power);
1084 iter.storeInstructionResult(NumberValue(result));
1085 return true;
1088 bool MPowHalf::writeRecoverData(CompactBufferWriter& writer) const {
1089 MOZ_ASSERT(canRecoverOnBailout());
1090 writer.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf));
1091 return true;
1094 RPowHalf::RPowHalf(CompactBufferReader& reader) {}
1096 bool RPowHalf::recover(JSContext* cx, SnapshotIterator& iter) const {
1097 double base = iter.readNumber();
1098 double power = 0.5;
1099 double result = ecmaPow(base, power);
1101 iter.storeInstructionResult(NumberValue(result));
1102 return true;
1105 bool MMinMax::writeRecoverData(CompactBufferWriter& writer) const {
1106 MOZ_ASSERT(canRecoverOnBailout());
1107 writer.writeUnsigned(uint32_t(RInstruction::Recover_MinMax));
1108 writer.writeByte(isMax_);
1109 return true;
1112 RMinMax::RMinMax(CompactBufferReader& reader) { isMax_ = reader.readByte(); }
1114 bool RMinMax::recover(JSContext* cx, SnapshotIterator& iter) const {
1115 double x = iter.readNumber();
1116 double y = iter.readNumber();
1118 double result;
1119 if (isMax_) {
1120 result = js::math_max_impl(x, y);
1121 } else {
1122 result = js::math_min_impl(x, y);
1125 iter.storeInstructionResult(NumberValue(result));
1126 return true;
1129 bool MAbs::writeRecoverData(CompactBufferWriter& writer) const {
1130 MOZ_ASSERT(canRecoverOnBailout());
1131 writer.writeUnsigned(uint32_t(RInstruction::Recover_Abs));
1132 return true;
1135 RAbs::RAbs(CompactBufferReader& reader) {}
1137 bool RAbs::recover(JSContext* cx, SnapshotIterator& iter) const {
1138 double num = iter.readNumber();
1139 double result = js::math_abs_impl(num);
1141 iter.storeInstructionResult(NumberValue(result));
1142 return true;
1145 bool MSqrt::writeRecoverData(CompactBufferWriter& writer) const {
1146 MOZ_ASSERT(canRecoverOnBailout());
1147 writer.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt));
1148 writer.writeByte(type() == MIRType::Float32);
1149 return true;
1152 RSqrt::RSqrt(CompactBufferReader& reader) {
1153 isFloatOperation_ = reader.readByte();
1156 bool RSqrt::recover(JSContext* cx, SnapshotIterator& iter) const {
1157 double num = iter.readNumber();
1158 double result = js::math_sqrt_impl(num);
1160 // MIRType::Float32 is a specialization embedding the fact that the result is
1161 // rounded to a Float32.
1162 if (isFloatOperation_) {
1163 result = js::RoundFloat32(result);
1166 iter.storeInstructionResult(DoubleValue(result));
1167 return true;
1170 bool MAtan2::writeRecoverData(CompactBufferWriter& writer) const {
1171 MOZ_ASSERT(canRecoverOnBailout());
1172 writer.writeUnsigned(uint32_t(RInstruction::Recover_Atan2));
1173 return true;
1176 RAtan2::RAtan2(CompactBufferReader& reader) {}
1178 bool RAtan2::recover(JSContext* cx, SnapshotIterator& iter) const {
1179 double y = iter.readNumber();
1180 double x = iter.readNumber();
1181 double result = js::ecmaAtan2(y, x);
1183 iter.storeInstructionResult(DoubleValue(result));
1184 return true;
1187 bool MHypot::writeRecoverData(CompactBufferWriter& writer) const {
1188 MOZ_ASSERT(canRecoverOnBailout());
1189 writer.writeUnsigned(uint32_t(RInstruction::Recover_Hypot));
1190 writer.writeUnsigned(uint32_t(numOperands()));
1191 return true;
1194 RHypot::RHypot(CompactBufferReader& reader)
1195 : numOperands_(reader.readUnsigned()) {}
1197 bool RHypot::recover(JSContext* cx, SnapshotIterator& iter) const {
1198 JS::RootedValueVector vec(cx);
1200 if (!vec.reserve(numOperands_)) {
1201 return false;
1204 for (uint32_t i = 0; i < numOperands_; ++i) {
1205 vec.infallibleAppend(NumberValue(iter.readNumber()));
1208 RootedValue result(cx);
1210 if (!js::math_hypot_handle(cx, vec, &result)) {
1211 return false;
1214 iter.storeInstructionResult(result);
1215 return true;
1218 bool MNearbyInt::writeRecoverData(CompactBufferWriter& writer) const {
1219 MOZ_ASSERT(canRecoverOnBailout());
1220 switch (roundingMode_) {
1221 case RoundingMode::Up:
1222 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
1223 return true;
1224 case RoundingMode::Down:
1225 writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
1226 return true;
1227 case RoundingMode::TowardsZero:
1228 writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc));
1229 return true;
1230 default:
1231 MOZ_CRASH("Unsupported rounding mode.");
1235 RNearbyInt::RNearbyInt(CompactBufferReader& reader) {
1236 roundingMode_ = reader.readByte();
1239 bool RNearbyInt::recover(JSContext* cx, SnapshotIterator& iter) const {
1240 MOZ_CRASH("Unsupported rounding mode.");
1243 bool MSign::writeRecoverData(CompactBufferWriter& writer) const {
1244 MOZ_ASSERT(canRecoverOnBailout());
1245 writer.writeUnsigned(uint32_t(RInstruction::Recover_Sign));
1246 return true;
1249 RSign::RSign(CompactBufferReader& reader) {}
1251 bool RSign::recover(JSContext* cx, SnapshotIterator& iter) const {
1252 double num = iter.readNumber();
1253 double result = js::math_sign_impl(num);
1255 iter.storeInstructionResult(NumberValue(result));
1256 return true;
1259 bool MMathFunction::writeRecoverData(CompactBufferWriter& writer) const {
1260 MOZ_ASSERT(canRecoverOnBailout());
1261 switch (function_) {
1262 case UnaryMathFunction::Ceil:
1263 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
1264 return true;
1265 case UnaryMathFunction::Floor:
1266 writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
1267 return true;
1268 case UnaryMathFunction::Round:
1269 writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
1270 return true;
1271 case UnaryMathFunction::Trunc:
1272 writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc));
1273 return true;
1274 case UnaryMathFunction::SinNative:
1275 case UnaryMathFunction::SinFdlibm:
1276 case UnaryMathFunction::CosNative:
1277 case UnaryMathFunction::CosFdlibm:
1278 case UnaryMathFunction::TanNative:
1279 case UnaryMathFunction::TanFdlibm:
1280 case UnaryMathFunction::Log:
1281 case UnaryMathFunction::Exp:
1282 case UnaryMathFunction::ACos:
1283 case UnaryMathFunction::ASin:
1284 case UnaryMathFunction::ATan:
1285 case UnaryMathFunction::Log10:
1286 case UnaryMathFunction::Log2:
1287 case UnaryMathFunction::Log1P:
1288 case UnaryMathFunction::ExpM1:
1289 case UnaryMathFunction::CosH:
1290 case UnaryMathFunction::SinH:
1291 case UnaryMathFunction::TanH:
1292 case UnaryMathFunction::ACosH:
1293 case UnaryMathFunction::ASinH:
1294 case UnaryMathFunction::ATanH:
1295 case UnaryMathFunction::Cbrt:
1296 static_assert(sizeof(UnaryMathFunction) == sizeof(uint8_t));
1297 writer.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction));
1298 writer.writeByte(uint8_t(function_));
1299 return true;
1301 MOZ_CRASH("Unknown math function.");
1304 RMathFunction::RMathFunction(CompactBufferReader& reader) {
1305 function_ = UnaryMathFunction(reader.readByte());
1308 bool RMathFunction::recover(JSContext* cx, SnapshotIterator& iter) const {
1309 double num = iter.readNumber();
1311 double result;
1312 switch (function_) {
1313 case UnaryMathFunction::SinNative:
1314 result = js::math_sin_native_impl(num);
1315 break;
1316 case UnaryMathFunction::SinFdlibm:
1317 result = js::math_sin_fdlibm_impl(num);
1318 break;
1319 case UnaryMathFunction::CosNative:
1320 result = js::math_cos_native_impl(num);
1321 break;
1322 case UnaryMathFunction::CosFdlibm:
1323 result = js::math_cos_fdlibm_impl(num);
1324 break;
1325 case UnaryMathFunction::TanNative:
1326 result = js::math_tan_native_impl(num);
1327 break;
1328 case UnaryMathFunction::TanFdlibm:
1329 result = js::math_tan_fdlibm_impl(num);
1330 break;
1331 case UnaryMathFunction::Log:
1332 result = js::math_log_impl(num);
1333 break;
1334 case UnaryMathFunction::Exp:
1335 result = js::math_exp_impl(num);
1336 break;
1337 case UnaryMathFunction::ACos:
1338 result = js::math_acos_impl(num);
1339 break;
1340 case UnaryMathFunction::ASin:
1341 result = js::math_asin_impl(num);
1342 break;
1343 case UnaryMathFunction::ATan:
1344 result = js::math_atan_impl(num);
1345 break;
1346 case UnaryMathFunction::Log10:
1347 result = js::math_log10_impl(num);
1348 break;
1349 case UnaryMathFunction::Log2:
1350 result = js::math_log2_impl(num);
1351 break;
1352 case UnaryMathFunction::Log1P:
1353 result = js::math_log1p_impl(num);
1354 break;
1355 case UnaryMathFunction::ExpM1:
1356 result = js::math_expm1_impl(num);
1357 break;
1358 case UnaryMathFunction::CosH:
1359 result = js::math_cosh_impl(num);
1360 break;
1361 case UnaryMathFunction::SinH:
1362 result = js::math_sinh_impl(num);
1363 break;
1364 case UnaryMathFunction::TanH:
1365 result = js::math_tanh_impl(num);
1366 break;
1367 case UnaryMathFunction::ACosH:
1368 result = js::math_acosh_impl(num);
1369 break;
1370 case UnaryMathFunction::ASinH:
1371 result = js::math_asinh_impl(num);
1372 break;
1373 case UnaryMathFunction::ATanH:
1374 result = js::math_atanh_impl(num);
1375 break;
1376 case UnaryMathFunction::Cbrt:
1377 result = js::math_cbrt_impl(num);
1378 break;
1380 case UnaryMathFunction::Trunc:
1381 case UnaryMathFunction::Floor:
1382 case UnaryMathFunction::Ceil:
1383 case UnaryMathFunction::Round:
1384 // These have their own recover instructions.
1385 MOZ_CRASH("Unexpected rounding math function.");
1388 iter.storeInstructionResult(DoubleValue(result));
1389 return true;
1392 bool MRandom::writeRecoverData(CompactBufferWriter& writer) const {
1393 MOZ_ASSERT(this->canRecoverOnBailout());
1394 writer.writeUnsigned(uint32_t(RInstruction::Recover_Random));
1395 return true;
1398 bool MRandom::canRecoverOnBailout() const {
1399 return !js::SupportDifferentialTesting();
1402 RRandom::RRandom(CompactBufferReader& reader) {}
1404 bool RRandom::recover(JSContext* cx, SnapshotIterator& iter) const {
1405 iter.storeInstructionResult(DoubleValue(math_random_impl(cx)));
1406 return true;
1409 bool MStringSplit::writeRecoverData(CompactBufferWriter& writer) const {
1410 MOZ_ASSERT(canRecoverOnBailout());
1411 writer.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit));
1412 return true;
1415 RStringSplit::RStringSplit(CompactBufferReader& reader) {}
1417 bool RStringSplit::recover(JSContext* cx, SnapshotIterator& iter) const {
1418 RootedString str(cx, iter.readString());
1419 RootedString sep(cx, iter.readString());
1421 JSObject* res = StringSplitString(cx, str, sep, INT32_MAX);
1422 if (!res) {
1423 return false;
1426 iter.storeInstructionResult(ObjectValue(*res));
1427 return true;
1430 bool MNaNToZero::writeRecoverData(CompactBufferWriter& writer) const {
1431 MOZ_ASSERT(canRecoverOnBailout());
1432 writer.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero));
1433 return true;
1436 RNaNToZero::RNaNToZero(CompactBufferReader& reader) {}
1438 bool RNaNToZero::recover(JSContext* cx, SnapshotIterator& iter) const {
1439 double v = iter.readNumber();
1440 if (std::isnan(v) || mozilla::IsNegativeZero(v)) {
1441 v = 0.0;
1444 iter.storeInstructionResult(DoubleValue(v));
1445 return true;
1448 bool MRegExpMatcher::writeRecoverData(CompactBufferWriter& writer) const {
1449 MOZ_ASSERT(canRecoverOnBailout());
1450 writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpMatcher));
1451 return true;
1454 RRegExpMatcher::RRegExpMatcher(CompactBufferReader& reader) {}
1456 bool RRegExpMatcher::recover(JSContext* cx, SnapshotIterator& iter) const {
1457 RootedObject regexp(cx, iter.readObject());
1458 RootedString input(cx, iter.readString());
1460 // Int32 because |lastIndex| is computed from transpiled self-hosted call.
1461 int32_t lastIndex = iter.readInt32();
1463 RootedValue result(cx);
1464 if (!RegExpMatcherRaw(cx, regexp, input, lastIndex, nullptr, &result)) {
1465 return false;
1468 iter.storeInstructionResult(result);
1469 return true;
1472 bool MTypeOf::writeRecoverData(CompactBufferWriter& writer) const {
1473 MOZ_ASSERT(canRecoverOnBailout());
1474 writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf));
1475 return true;
1478 RTypeOf::RTypeOf(CompactBufferReader& reader) {}
1480 bool RTypeOf::recover(JSContext* cx, SnapshotIterator& iter) const {
1481 JS::Value v = iter.read();
1483 iter.storeInstructionResult(Int32Value(TypeOfValue(v)));
1484 return true;
1487 bool MTypeOfName::writeRecoverData(CompactBufferWriter& writer) const {
1488 MOZ_ASSERT(canRecoverOnBailout());
1489 writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOfName));
1490 return true;
1493 RTypeOfName::RTypeOfName(CompactBufferReader& reader) {}
1495 bool RTypeOfName::recover(JSContext* cx, SnapshotIterator& iter) const {
1496 // Int32 because |type| is computed from MTypeOf.
1497 int32_t type = iter.readInt32();
1498 MOZ_ASSERT(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT);
1500 JSString* name = TypeName(JSType(type), *cx->runtime()->commonNames);
1501 iter.storeInstructionResult(StringValue(name));
1502 return true;
1505 bool MToDouble::writeRecoverData(CompactBufferWriter& writer) const {
1506 MOZ_ASSERT(canRecoverOnBailout());
1507 writer.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble));
1508 return true;
1511 RToDouble::RToDouble(CompactBufferReader& reader) {}
1513 bool RToDouble::recover(JSContext* cx, SnapshotIterator& iter) const {
1514 RootedValue v(cx, iter.read());
1516 MOZ_ASSERT(!v.isObject());
1517 MOZ_ASSERT(!v.isSymbol());
1518 MOZ_ASSERT(!v.isBigInt());
1520 double dbl;
1521 if (!ToNumber(cx, v, &dbl)) {
1522 return false;
1525 iter.storeInstructionResult(DoubleValue(dbl));
1526 return true;
1529 bool MToFloat32::writeRecoverData(CompactBufferWriter& writer) const {
1530 MOZ_ASSERT(canRecoverOnBailout());
1531 writer.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32));
1532 return true;
1535 RToFloat32::RToFloat32(CompactBufferReader& reader) {}
1537 bool RToFloat32::recover(JSContext* cx, SnapshotIterator& iter) const {
1538 double num = iter.readNumber();
1539 double result = js::RoundFloat32(num);
1541 iter.storeInstructionResult(DoubleValue(result));
1542 return true;
1545 bool MTruncateToInt32::writeRecoverData(CompactBufferWriter& writer) const {
1546 MOZ_ASSERT(canRecoverOnBailout());
1547 writer.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32));
1548 return true;
1551 RTruncateToInt32::RTruncateToInt32(CompactBufferReader& reader) {}
1553 bool RTruncateToInt32::recover(JSContext* cx, SnapshotIterator& iter) const {
1554 RootedValue value(cx, iter.read());
1556 int32_t trunc;
1557 if (!JS::ToInt32(cx, value, &trunc)) {
1558 return false;
1561 iter.storeInstructionResult(Int32Value(trunc));
1562 return true;
1565 bool MNewObject::writeRecoverData(CompactBufferWriter& writer) const {
1566 MOZ_ASSERT(canRecoverOnBailout());
1568 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewObject));
1570 // Recover instructions are only supported if we have a template object.
1571 MOZ_ASSERT(mode_ == MNewObject::ObjectCreate);
1572 return true;
1575 RNewObject::RNewObject(CompactBufferReader& reader) {}
1577 bool RNewObject::recover(JSContext* cx, SnapshotIterator& iter) const {
1578 RootedObject templateObject(cx, iter.readObject());
1580 // See CodeGenerator::visitNewObjectVMCall.
1581 // Note that recover instructions are only used if mode == ObjectCreate.
1582 JSObject* resultObject =
1583 ObjectCreateWithTemplate(cx, templateObject.as<PlainObject>());
1584 if (!resultObject) {
1585 return false;
1588 iter.storeInstructionResult(ObjectValue(*resultObject));
1589 return true;
1592 bool MNewPlainObject::writeRecoverData(CompactBufferWriter& writer) const {
1593 MOZ_ASSERT(canRecoverOnBailout());
1594 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewPlainObject));
1596 MOZ_ASSERT(gc::AllocKind(uint8_t(allocKind_)) == allocKind_);
1597 writer.writeByte(uint8_t(allocKind_));
1598 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_)) == initialHeap_);
1599 writer.writeByte(uint8_t(initialHeap_));
1600 return true;
1603 RNewPlainObject::RNewPlainObject(CompactBufferReader& reader) {
1604 allocKind_ = gc::AllocKind(reader.readByte());
1605 MOZ_ASSERT(gc::IsValidAllocKind(allocKind_));
1606 initialHeap_ = gc::Heap(reader.readByte());
1607 MOZ_ASSERT(initialHeap_ == gc::Heap::Default ||
1608 initialHeap_ == gc::Heap::Tenured);
1611 bool RNewPlainObject::recover(JSContext* cx, SnapshotIterator& iter) const {
1612 Rooted<SharedShape*> shape(cx, &iter.readGCCellPtr().as<Shape>().asShared());
1614 // See CodeGenerator::visitNewPlainObject.
1615 JSObject* resultObject =
1616 NewPlainObjectOptimizedFallback(cx, shape, allocKind_, initialHeap_);
1617 if (!resultObject) {
1618 return false;
1621 iter.storeInstructionResult(ObjectValue(*resultObject));
1622 return true;
1625 bool MNewArrayObject::writeRecoverData(CompactBufferWriter& writer) const {
1626 MOZ_ASSERT(canRecoverOnBailout());
1627 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayObject));
1629 writer.writeUnsigned(length_);
1630 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_)) == initialHeap_);
1631 writer.writeByte(uint8_t(initialHeap_));
1632 return true;
1635 RNewArrayObject::RNewArrayObject(CompactBufferReader& reader) {
1636 length_ = reader.readUnsigned();
1637 initialHeap_ = gc::Heap(reader.readByte());
1638 MOZ_ASSERT(initialHeap_ == gc::Heap::Default ||
1639 initialHeap_ == gc::Heap::Tenured);
1642 bool RNewArrayObject::recover(JSContext* cx, SnapshotIterator& iter) const {
1643 iter.read(); // Skip unused shape field.
1645 NewObjectKind kind =
1646 initialHeap_ == gc::Heap::Tenured ? TenuredObject : GenericObject;
1647 JSObject* array = NewArrayOperation(cx, length_, kind);
1648 if (!array) {
1649 return false;
1652 iter.storeInstructionResult(ObjectValue(*array));
1653 return true;
1656 bool MNewTypedArray::writeRecoverData(CompactBufferWriter& writer) const {
1657 MOZ_ASSERT(canRecoverOnBailout());
1658 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray));
1659 return true;
1662 RNewTypedArray::RNewTypedArray(CompactBufferReader& reader) {}
1664 bool RNewTypedArray::recover(JSContext* cx, SnapshotIterator& iter) const {
1665 RootedObject templateObject(cx, iter.readObject());
1667 size_t length = templateObject.as<FixedLengthTypedArrayObject>()->length();
1668 MOZ_ASSERT(length <= INT32_MAX,
1669 "Template objects are only created for int32 lengths");
1671 JSObject* resultObject =
1672 NewTypedArrayWithTemplateAndLength(cx, templateObject, length);
1673 if (!resultObject) {
1674 return false;
1677 iter.storeInstructionResult(ObjectValue(*resultObject));
1678 return true;
1681 bool MNewArray::writeRecoverData(CompactBufferWriter& writer) const {
1682 MOZ_ASSERT(canRecoverOnBailout());
1683 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray));
1684 writer.writeUnsigned(length());
1685 return true;
1688 RNewArray::RNewArray(CompactBufferReader& reader) {
1689 count_ = reader.readUnsigned();
1692 bool RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const {
1693 RootedObject templateObject(cx, iter.readObject());
1694 Rooted<Shape*> shape(cx, templateObject->shape());
1696 ArrayObject* resultObject = NewArrayWithShape(cx, count_, shape);
1697 if (!resultObject) {
1698 return false;
1701 iter.storeInstructionResult(ObjectValue(*resultObject));
1702 return true;
1705 bool MNewIterator::writeRecoverData(CompactBufferWriter& writer) const {
1706 MOZ_ASSERT(canRecoverOnBailout());
1707 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator));
1708 writer.writeByte(type_);
1709 return true;
1712 RNewIterator::RNewIterator(CompactBufferReader& reader) {
1713 type_ = reader.readByte();
1716 bool RNewIterator::recover(JSContext* cx, SnapshotIterator& iter) const {
1717 RootedObject templateObject(cx, iter.readObject());
1719 JSObject* resultObject = nullptr;
1720 switch (MNewIterator::Type(type_)) {
1721 case MNewIterator::ArrayIterator:
1722 resultObject = NewArrayIterator(cx);
1723 break;
1724 case MNewIterator::StringIterator:
1725 resultObject = NewStringIterator(cx);
1726 break;
1727 case MNewIterator::RegExpStringIterator:
1728 resultObject = NewRegExpStringIterator(cx);
1729 break;
1732 if (!resultObject) {
1733 return false;
1736 iter.storeInstructionResult(ObjectValue(*resultObject));
1737 return true;
1740 bool MLambda::writeRecoverData(CompactBufferWriter& writer) const {
1741 MOZ_ASSERT(canRecoverOnBailout());
1742 writer.writeUnsigned(uint32_t(RInstruction::Recover_Lambda));
1743 return true;
1746 RLambda::RLambda(CompactBufferReader& reader) {}
1748 bool RLambda::recover(JSContext* cx, SnapshotIterator& iter) const {
1749 RootedObject scopeChain(cx, iter.readObject());
1750 RootedFunction fun(cx, &iter.readObject()->as<JSFunction>());
1752 JSObject* resultObject = js::Lambda(cx, fun, scopeChain);
1753 if (!resultObject) {
1754 return false;
1757 iter.storeInstructionResult(ObjectValue(*resultObject));
1758 return true;
1761 bool MFunctionWithProto::writeRecoverData(CompactBufferWriter& writer) const {
1762 MOZ_ASSERT(canRecoverOnBailout());
1763 writer.writeUnsigned(uint32_t(RInstruction::Recover_FunctionWithProto));
1764 return true;
1767 RFunctionWithProto::RFunctionWithProto(CompactBufferReader& reader) {}
1769 bool RFunctionWithProto::recover(JSContext* cx, SnapshotIterator& iter) const {
1770 RootedObject scopeChain(cx, iter.readObject());
1771 RootedObject prototype(cx, iter.readObject());
1772 RootedFunction fun(cx, &iter.readObject()->as<JSFunction>());
1774 JSObject* resultObject =
1775 js::FunWithProtoOperation(cx, fun, scopeChain, prototype);
1776 if (!resultObject) {
1777 return false;
1780 iter.storeInstructionResult(ObjectValue(*resultObject));
1781 return true;
1784 bool MNewCallObject::writeRecoverData(CompactBufferWriter& writer) const {
1785 MOZ_ASSERT(canRecoverOnBailout());
1786 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewCallObject));
1787 return true;
1790 RNewCallObject::RNewCallObject(CompactBufferReader& reader) {}
1792 bool RNewCallObject::recover(JSContext* cx, SnapshotIterator& iter) const {
1793 Rooted<CallObject*> templateObj(cx, &iter.readObject()->as<CallObject>());
1795 Rooted<SharedShape*> shape(cx, templateObj->sharedShape());
1797 JSObject* resultObject = CallObject::createWithShape(cx, shape);
1798 if (!resultObject) {
1799 return false;
1802 iter.storeInstructionResult(ObjectValue(*resultObject));
1803 return true;
1806 bool MObjectKeys::canRecoverOnBailout() const {
1807 // Only claim that this operation can be recovered on bailout if some other
1808 // optimization already marked it as such.
1809 return isRecoveredOnBailout();
1812 bool MObjectKeys::writeRecoverData(CompactBufferWriter& writer) const {
1813 MOZ_ASSERT(canRecoverOnBailout());
1814 writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectKeys));
1815 return true;
1818 RObjectKeys::RObjectKeys(CompactBufferReader& reader) {}
1820 bool RObjectKeys::recover(JSContext* cx, SnapshotIterator& iter) const {
1821 Rooted<JSObject*> obj(cx, iter.readObject());
1823 JSObject* resultKeys = ObjectKeys(cx, obj);
1824 if (!resultKeys) {
1825 return false;
1828 iter.storeInstructionResult(ObjectValue(*resultKeys));
1829 return true;
1832 bool MObjectState::writeRecoverData(CompactBufferWriter& writer) const {
1833 MOZ_ASSERT(canRecoverOnBailout());
1834 writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState));
1835 writer.writeUnsigned(numSlots());
1836 return true;
1839 RObjectState::RObjectState(CompactBufferReader& reader) {
1840 numSlots_ = reader.readUnsigned();
1843 bool RObjectState::recover(JSContext* cx, SnapshotIterator& iter) const {
1844 RootedObject object(cx, iter.readObject());
1845 Handle<NativeObject*> nativeObject = object.as<NativeObject>();
1846 MOZ_ASSERT(!Watchtower::watchesPropertyModification(nativeObject));
1847 MOZ_ASSERT(nativeObject->slotSpan() == numSlots());
1849 for (size_t i = 0; i < numSlots(); i++) {
1850 Value val = iter.read();
1851 nativeObject->setSlot(i, val);
1854 iter.storeInstructionResult(ObjectValue(*object));
1855 return true;
1858 bool MArrayState::writeRecoverData(CompactBufferWriter& writer) const {
1859 MOZ_ASSERT(canRecoverOnBailout());
1860 writer.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState));
1861 writer.writeUnsigned(numElements());
1862 return true;
1865 RArrayState::RArrayState(CompactBufferReader& reader) {
1866 numElements_ = reader.readUnsigned();
1869 bool RArrayState::recover(JSContext* cx, SnapshotIterator& iter) const {
1870 ArrayObject* object = &iter.readObject()->as<ArrayObject>();
1872 // Int32 because |initLength| is computed from MConstant.
1873 uint32_t initLength = iter.readInt32();
1875 MOZ_ASSERT(object->getDenseInitializedLength() == 0,
1876 "initDenseElement call below relies on this");
1877 object->setDenseInitializedLength(initLength);
1879 for (size_t index = 0; index < numElements(); index++) {
1880 Value val = iter.read();
1882 if (index >= initLength) {
1883 MOZ_ASSERT(val.isUndefined());
1884 continue;
1887 object->initDenseElement(index, val);
1890 iter.storeInstructionResult(ObjectValue(*object));
1891 return true;
1894 bool MSetArrayLength::writeRecoverData(CompactBufferWriter& writer) const {
1895 MOZ_ASSERT(canRecoverOnBailout());
1896 // For simplicity, we capture directly the object instead of the elements
1897 // pointer.
1898 MOZ_ASSERT(elements()->type() != MIRType::Elements);
1899 writer.writeUnsigned(uint32_t(RInstruction::Recover_SetArrayLength));
1900 return true;
1903 bool MSetArrayLength::canRecoverOnBailout() const {
1904 return isRecoveredOnBailout();
1907 RSetArrayLength::RSetArrayLength(CompactBufferReader& reader) {}
1909 bool RSetArrayLength::recover(JSContext* cx, SnapshotIterator& iter) const {
1910 Rooted<ArrayObject*> obj(cx, &iter.readObject()->as<ArrayObject>());
1911 RootedValue len(cx, iter.read());
1913 RootedId id(cx, NameToId(cx->names().length));
1914 Rooted<PropertyDescriptor> desc(
1915 cx, PropertyDescriptor::Data(len, JS::PropertyAttribute::Writable));
1916 ObjectOpResult error;
1917 if (!ArraySetLength(cx, obj, id, desc, error)) {
1918 return false;
1921 iter.storeInstructionResult(ObjectValue(*obj));
1922 return true;
1925 bool MAssertRecoveredOnBailout::writeRecoverData(
1926 CompactBufferWriter& writer) const {
1927 MOZ_ASSERT(canRecoverOnBailout());
1928 MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout() == mustBeRecovered_,
1929 "assertRecoveredOnBailout failed during compilation");
1930 writer.writeUnsigned(
1931 uint32_t(RInstruction::Recover_AssertRecoveredOnBailout));
1932 return true;
1935 RAssertRecoveredOnBailout::RAssertRecoveredOnBailout(
1936 CompactBufferReader& reader) {}
1938 bool RAssertRecoveredOnBailout::recover(JSContext* cx,
1939 SnapshotIterator& iter) const {
1940 iter.read(); // skip the unused operand.
1941 iter.storeInstructionResult(UndefinedValue());
1942 return true;
1945 bool MStringReplace::writeRecoverData(CompactBufferWriter& writer) const {
1946 MOZ_ASSERT(canRecoverOnBailout());
1947 writer.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace));
1948 writer.writeByte(isFlatReplacement_);
1949 return true;
1952 RStringReplace::RStringReplace(CompactBufferReader& reader) {
1953 isFlatReplacement_ = reader.readByte();
1956 bool RStringReplace::recover(JSContext* cx, SnapshotIterator& iter) const {
1957 RootedString string(cx, iter.readString());
1958 RootedString pattern(cx, iter.readString());
1959 RootedString replace(cx, iter.readString());
1961 JSString* result =
1962 isFlatReplacement_
1963 ? js::StringFlatReplaceString(cx, string, pattern, replace)
1964 : js::str_replace_string_raw(cx, string, pattern, replace);
1966 if (!result) {
1967 return false;
1970 iter.storeInstructionResult(StringValue(result));
1971 return true;
1974 bool MSubstr::writeRecoverData(CompactBufferWriter& writer) const {
1975 MOZ_ASSERT(canRecoverOnBailout());
1976 writer.writeUnsigned(uint32_t(RInstruction::Recover_Substr));
1977 return true;
1980 RSubstr::RSubstr(CompactBufferReader& reader) {}
1982 bool RSubstr::recover(JSContext* cx, SnapshotIterator& iter) const {
1983 RootedString str(cx, iter.readString());
1985 // Int32 because |begin| is computed from MStringTrimStartIndex, MConstant,
1986 // or CallSubstringKernelResult.
1987 int32_t begin = iter.readInt32();
1989 // Int32 because |length| is computed from MSub(truncated),
1990 // MStringTrimEndIndex, or CallSubstringKernelResult.
1991 int32_t length = iter.readInt32();
1993 JSString* result = SubstringKernel(cx, str, begin, length);
1994 if (!result) {
1995 return false;
1998 iter.storeInstructionResult(StringValue(result));
1999 return true;
2002 bool MAtomicIsLockFree::writeRecoverData(CompactBufferWriter& writer) const {
2003 MOZ_ASSERT(canRecoverOnBailout());
2004 writer.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree));
2005 return true;
2008 RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader& reader) {}
2010 bool RAtomicIsLockFree::recover(JSContext* cx, SnapshotIterator& iter) const {
2011 double dsize = JS::ToInteger(iter.readNumber());
2013 int32_t size;
2014 bool result = mozilla::NumberEqualsInt32(dsize, &size) &&
2015 AtomicOperations::isLockfreeJS(size);
2016 iter.storeInstructionResult(BooleanValue(result));
2017 return true;
2020 bool MBigIntAsIntN::writeRecoverData(CompactBufferWriter& writer) const {
2021 MOZ_ASSERT(canRecoverOnBailout());
2022 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsIntN));
2023 return true;
2026 RBigIntAsIntN::RBigIntAsIntN(CompactBufferReader& reader) {}
2028 bool RBigIntAsIntN::recover(JSContext* cx, SnapshotIterator& iter) const {
2029 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2030 int32_t bits = iter.readInt32();
2031 MOZ_ASSERT(bits >= 0);
2033 RootedBigInt input(cx, iter.readBigInt());
2035 BigInt* result = BigInt::asIntN(cx, input, bits);
2036 if (!result) {
2037 return false;
2040 iter.storeInstructionResult(JS::BigIntValue(result));
2041 return true;
2044 bool MBigIntAsUintN::writeRecoverData(CompactBufferWriter& writer) const {
2045 MOZ_ASSERT(canRecoverOnBailout());
2046 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsUintN));
2047 return true;
2050 RBigIntAsUintN::RBigIntAsUintN(CompactBufferReader& reader) {}
2052 bool RBigIntAsUintN::recover(JSContext* cx, SnapshotIterator& iter) const {
2053 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2054 int32_t bits = iter.readInt32();
2055 MOZ_ASSERT(bits >= 0);
2057 RootedBigInt input(cx, iter.readBigInt());
2059 BigInt* result = BigInt::asUintN(cx, input, bits);
2060 if (!result) {
2061 return false;
2064 iter.storeInstructionResult(JS::BigIntValue(result));
2065 return true;
2068 bool MCreateArgumentsObject::writeRecoverData(
2069 CompactBufferWriter& writer) const {
2070 MOZ_ASSERT(canRecoverOnBailout());
2071 writer.writeUnsigned(uint32_t(RInstruction::Recover_CreateArgumentsObject));
2072 return true;
2075 RCreateArgumentsObject::RCreateArgumentsObject(CompactBufferReader& reader) {}
2077 bool RCreateArgumentsObject::recover(JSContext* cx,
2078 SnapshotIterator& iter) const {
2079 RootedObject callObject(cx, iter.readObject());
2080 RootedObject result(
2081 cx, ArgumentsObject::createForIon(cx, iter.frame(), callObject));
2082 if (!result) {
2083 return false;
2086 iter.storeInstructionResult(JS::ObjectValue(*result));
2087 return true;
2090 bool MCreateInlinedArgumentsObject::writeRecoverData(
2091 CompactBufferWriter& writer) const {
2092 MOZ_ASSERT(canRecoverOnBailout());
2093 writer.writeUnsigned(
2094 uint32_t(RInstruction::Recover_CreateInlinedArgumentsObject));
2095 writer.writeUnsigned(numActuals());
2096 return true;
2099 RCreateInlinedArgumentsObject::RCreateInlinedArgumentsObject(
2100 CompactBufferReader& reader) {
2101 numActuals_ = reader.readUnsigned();
2104 bool RCreateInlinedArgumentsObject::recover(JSContext* cx,
2105 SnapshotIterator& iter) const {
2106 RootedObject callObject(cx, iter.readObject());
2107 RootedFunction callee(cx, &iter.readObject()->as<JSFunction>());
2109 JS::RootedValueArray<ArgumentsObject::MaxInlinedArgs> argsArray(cx);
2110 for (uint32_t i = 0; i < numActuals_; i++) {
2111 argsArray[i].set(iter.read());
2114 ArgumentsObject* result = ArgumentsObject::createFromValueArray(
2115 cx, argsArray, callee, callObject, numActuals_);
2116 if (!result) {
2117 return false;
2120 iter.storeInstructionResult(JS::ObjectValue(*result));
2121 return true;
2124 bool MRest::writeRecoverData(CompactBufferWriter& writer) const {
2125 MOZ_ASSERT(canRecoverOnBailout());
2126 writer.writeUnsigned(uint32_t(RInstruction::Recover_Rest));
2127 writer.writeUnsigned(numFormals());
2128 return true;
2131 RRest::RRest(CompactBufferReader& reader) {
2132 numFormals_ = reader.readUnsigned();
2135 bool RRest::recover(JSContext* cx, SnapshotIterator& iter) const {
2136 JitFrameLayout* frame = iter.frame();
2138 // Int32 because |numActuals| is computed from MArgumentsLength.
2139 uint32_t numActuals = iter.readInt32();
2140 MOZ_ASSERT(numActuals == frame->numActualArgs());
2142 uint32_t numFormals = numFormals_;
2144 uint32_t length = std::max(numActuals, numFormals) - numFormals;
2145 Value* src = frame->actualArgs() + numFormals;
2146 JSObject* rest = jit::InitRestParameter(cx, length, src, nullptr);
2147 if (!rest) {
2148 return false;
2151 iter.storeInstructionResult(ObjectValue(*rest));
2152 return true;