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 "mozilla/Casting.h"
13 #include "builtin/Object.h"
14 #include "builtin/RegExp.h"
15 #include "builtin/String.h"
16 #include "jit/AtomicOperations.h"
17 #include "jit/Bailouts.h"
18 #include "jit/CompileInfo.h"
20 #include "jit/JitSpewer.h"
21 #include "jit/JSJitFrameIter.h"
23 #include "jit/MIRGraph.h"
24 #include "jit/VMFunctions.h"
25 #include "util/DifferentialTesting.h"
26 #include "vm/BigIntType.h"
27 #include "vm/EqualityOperations.h"
28 #include "vm/Interpreter.h"
29 #include "vm/Iteration.h"
30 #include "vm/JSContext.h"
31 #include "vm/JSObject.h"
32 #include "vm/PlainObject.h" // js::PlainObject
33 #include "vm/StringType.h"
34 #include "vm/Watchtower.h"
36 #include "vm/Interpreter-inl.h"
39 using namespace js::jit
;
41 bool MNode::writeRecoverData(CompactBufferWriter
& writer
) const {
42 MOZ_CRASH("This instruction is not serializable");
45 void RInstruction::readRecoverData(CompactBufferReader
& reader
,
46 RInstructionStorage
* raw
) {
47 uint32_t op
= reader
.readUnsigned();
49 #define MATCH_OPCODES_(op) \
51 static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \
52 "storage space must be big enough to store R" #op); \
53 static_assert(alignof(R##op) <= alignof(RInstructionStorage), \
54 "storage space must be aligned adequate to store R" #op); \
55 new (raw->addr()) R##op(reader); \
58 RECOVER_OPCODE_LIST(MATCH_OPCODES_
)
63 MOZ_CRASH("Bad decoding of the previous instruction?");
67 bool MResumePoint::writeRecoverData(CompactBufferWriter
& writer
) const {
68 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint
));
70 MBasicBlock
* bb
= block();
71 bool hasFun
= bb
->info().hasFunMaybeLazy();
72 uint32_t nargs
= bb
->info().nargs();
73 JSScript
* script
= bb
->info().script();
74 uint32_t exprStack
= stackDepth() - bb
->info().ninvoke();
77 // Ensure that all snapshot which are encoded can safely be used for
79 uint32_t numIntermediate
= NumIntermediateValues(mode());
80 if (JSContext
* cx
= GetJitContext()->cx
) {
81 if (!AssertBailoutStackDepth(cx
, script
, pc(), mode(),
82 exprStack
- numIntermediate
)) {
88 uint32_t formalArgs
= CountArgSlots(script
, hasFun
, nargs
);
90 // Test if we honor the maximum of arguments at all times. This is a sanity
91 // check and not an algorithm limit. So check might be a bit too loose. +4
92 // to account for scope chain, return value, this value and maybe
94 MOZ_ASSERT(formalArgs
< SNAPSHOT_MAX_NARGS
+ 4);
97 uint32_t implicit
= StartArgSlot(script
);
99 uint32_t nallocs
= formalArgs
+ script
->nfixed() + exprStack
;
101 JitSpew(JitSpew_IonSnapshots
,
102 "Starting frame; implicit %u, formals %u, fixed %zu, exprs %u",
103 implicit
, formalArgs
- implicit
, script
->nfixed(), exprStack
);
105 uint32_t pcOff
= script
->pcToOffset(pc());
106 JitSpew(JitSpew_IonSnapshots
, "Writing pc offset %u, mode %s, nslots %u",
107 pcOff
, ResumeModeToString(mode()), nallocs
);
109 uint32_t pcOffAndMode
=
110 (pcOff
<< RResumePoint::PCOffsetShift
) | uint32_t(mode());
111 MOZ_RELEASE_ASSERT((pcOffAndMode
>> RResumePoint::PCOffsetShift
) == pcOff
,
112 "pcOff doesn't fit in pcOffAndMode");
113 writer
.writeUnsigned(pcOffAndMode
);
115 writer
.writeUnsigned(nallocs
);
119 RResumePoint::RResumePoint(CompactBufferReader
& reader
) {
120 pcOffsetAndMode_
= reader
.readUnsigned();
121 numOperands_
= reader
.readUnsigned();
122 JitSpew(JitSpew_IonSnapshots
,
123 "Read RResumePoint (pc offset %u, mode %s, nslots %u)", pcOffset(),
124 ResumeModeToString(mode()), numOperands_
);
127 bool RResumePoint::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
128 MOZ_CRASH("This instruction is not recoverable.");
131 bool MBitNot::writeRecoverData(CompactBufferWriter
& writer
) const {
132 // 64-bit int bitnots exist only when compiling wasm; they exist neither for
133 // JS nor asm.js. So we don't expect them here.
134 MOZ_ASSERT(type() != MIRType::Int64
);
135 MOZ_ASSERT(canRecoverOnBailout());
136 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitNot
));
140 RBitNot::RBitNot(CompactBufferReader
& reader
) {}
142 bool RBitNot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
143 RootedValue
operand(cx
, iter
.read());
144 RootedValue
result(cx
);
146 if (!js::BitNot(cx
, &operand
, &result
)) {
150 iter
.storeInstructionResult(result
);
154 bool MBitAnd::writeRecoverData(CompactBufferWriter
& writer
) const {
155 MOZ_ASSERT(canRecoverOnBailout());
156 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd
));
160 RBitAnd::RBitAnd(CompactBufferReader
& reader
) {}
162 bool RBitAnd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
163 RootedValue
lhs(cx
, iter
.read());
164 RootedValue
rhs(cx
, iter
.read());
165 RootedValue
result(cx
);
166 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
168 if (!js::BitAnd(cx
, &lhs
, &rhs
, &result
)) {
172 iter
.storeInstructionResult(result
);
176 bool MBitOr::writeRecoverData(CompactBufferWriter
& writer
) const {
177 MOZ_ASSERT(canRecoverOnBailout());
178 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitOr
));
182 RBitOr::RBitOr(CompactBufferReader
& reader
) {}
184 bool RBitOr::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
185 RootedValue
lhs(cx
, iter
.read());
186 RootedValue
rhs(cx
, iter
.read());
187 RootedValue
result(cx
);
188 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
190 if (!js::BitOr(cx
, &lhs
, &rhs
, &result
)) {
194 iter
.storeInstructionResult(result
);
198 bool MBitXor::writeRecoverData(CompactBufferWriter
& writer
) const {
199 MOZ_ASSERT(canRecoverOnBailout());
200 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitXor
));
204 RBitXor::RBitXor(CompactBufferReader
& reader
) {}
206 bool RBitXor::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
207 RootedValue
lhs(cx
, iter
.read());
208 RootedValue
rhs(cx
, iter
.read());
209 RootedValue
result(cx
);
211 if (!js::BitXor(cx
, &lhs
, &rhs
, &result
)) {
215 iter
.storeInstructionResult(result
);
219 bool MLsh::writeRecoverData(CompactBufferWriter
& writer
) const {
220 MOZ_ASSERT(canRecoverOnBailout());
221 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Lsh
));
225 RLsh::RLsh(CompactBufferReader
& reader
) {}
227 bool RLsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
228 RootedValue
lhs(cx
, iter
.read());
229 RootedValue
rhs(cx
, iter
.read());
230 RootedValue
result(cx
);
231 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
233 if (!js::BitLsh(cx
, &lhs
, &rhs
, &result
)) {
237 iter
.storeInstructionResult(result
);
241 bool MRsh::writeRecoverData(CompactBufferWriter
& writer
) const {
242 MOZ_ASSERT(canRecoverOnBailout());
243 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Rsh
));
247 RRsh::RRsh(CompactBufferReader
& reader
) {}
249 bool RRsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
250 RootedValue
lhs(cx
, iter
.read());
251 RootedValue
rhs(cx
, iter
.read());
252 RootedValue
result(cx
);
253 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
255 if (!js::BitRsh(cx
, &lhs
, &rhs
, &result
)) {
259 iter
.storeInstructionResult(result
);
263 bool MUrsh::writeRecoverData(CompactBufferWriter
& writer
) const {
264 MOZ_ASSERT(canRecoverOnBailout());
265 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ursh
));
269 RUrsh::RUrsh(CompactBufferReader
& reader
) {}
271 bool RUrsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
272 RootedValue
lhs(cx
, iter
.read());
273 RootedValue
rhs(cx
, iter
.read());
274 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
276 RootedValue
result(cx
);
277 if (!js::UrshValues(cx
, &lhs
, &rhs
, &result
)) {
281 iter
.storeInstructionResult(result
);
285 bool MSignExtendInt32::writeRecoverData(CompactBufferWriter
& writer
) const {
286 MOZ_ASSERT(canRecoverOnBailout());
287 writer
.writeUnsigned(uint32_t(RInstruction::Recover_SignExtendInt32
));
288 MOZ_ASSERT(Mode(uint8_t(mode_
)) == mode_
);
289 writer
.writeByte(uint8_t(mode_
));
293 RSignExtendInt32::RSignExtendInt32(CompactBufferReader
& reader
) {
294 mode_
= reader
.readByte();
297 bool RSignExtendInt32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
298 RootedValue
operand(cx
, iter
.read());
301 if (!ToInt32(cx
, operand
, &i
)) {
306 switch (MSignExtendInt32::Mode(mode_
)) {
307 case MSignExtendInt32::Byte
:
308 result
= static_cast<int8_t>(i
);
310 case MSignExtendInt32::Half
:
311 result
= static_cast<int16_t>(i
);
315 iter
.storeInstructionResult(JS::Int32Value(result
));
319 bool MAdd::writeRecoverData(CompactBufferWriter
& writer
) const {
320 MOZ_ASSERT(canRecoverOnBailout());
321 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Add
));
322 writer
.writeByte(type() == MIRType::Float32
);
326 RAdd::RAdd(CompactBufferReader
& reader
) {
327 isFloatOperation_
= reader
.readByte();
330 bool RAdd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
331 RootedValue
lhs(cx
, iter
.read());
332 RootedValue
rhs(cx
, iter
.read());
333 RootedValue
result(cx
);
335 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
336 if (!js::AddValues(cx
, &lhs
, &rhs
, &result
)) {
340 // MIRType::Float32 is a specialization embedding the fact that the result is
341 // rounded to a Float32.
342 if (isFloatOperation_
&& !RoundFloat32(cx
, result
, &result
)) {
346 iter
.storeInstructionResult(result
);
350 bool MSub::writeRecoverData(CompactBufferWriter
& writer
) const {
351 MOZ_ASSERT(canRecoverOnBailout());
352 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Sub
));
353 writer
.writeByte(type() == MIRType::Float32
);
357 RSub::RSub(CompactBufferReader
& reader
) {
358 isFloatOperation_
= reader
.readByte();
361 bool RSub::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
362 RootedValue
lhs(cx
, iter
.read());
363 RootedValue
rhs(cx
, iter
.read());
364 RootedValue
result(cx
);
366 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
367 if (!js::SubValues(cx
, &lhs
, &rhs
, &result
)) {
371 // MIRType::Float32 is a specialization embedding the fact that the result is
372 // rounded to a Float32.
373 if (isFloatOperation_
&& !RoundFloat32(cx
, result
, &result
)) {
377 iter
.storeInstructionResult(result
);
381 bool MMul::writeRecoverData(CompactBufferWriter
& writer
) const {
382 MOZ_ASSERT(canRecoverOnBailout());
383 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Mul
));
384 writer
.writeByte(type() == MIRType::Float32
);
385 MOZ_ASSERT(Mode(uint8_t(mode_
)) == mode_
);
386 writer
.writeByte(uint8_t(mode_
));
390 RMul::RMul(CompactBufferReader
& reader
) {
391 isFloatOperation_
= reader
.readByte();
392 mode_
= reader
.readByte();
395 bool RMul::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
396 RootedValue
lhs(cx
, iter
.read());
397 RootedValue
rhs(cx
, iter
.read());
398 RootedValue
result(cx
);
400 if (MMul::Mode(mode_
) == MMul::Normal
) {
401 if (!js::MulValues(cx
, &lhs
, &rhs
, &result
)) {
405 // MIRType::Float32 is a specialization embedding the fact that the
406 // result is rounded to a Float32.
407 if (isFloatOperation_
&& !RoundFloat32(cx
, result
, &result
)) {
411 MOZ_ASSERT(MMul::Mode(mode_
) == MMul::Integer
);
412 if (!js::math_imul_handle(cx
, lhs
, rhs
, &result
)) {
417 iter
.storeInstructionResult(result
);
421 bool MDiv::writeRecoverData(CompactBufferWriter
& writer
) const {
422 MOZ_ASSERT(canRecoverOnBailout());
423 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Div
));
424 writer
.writeByte(type() == MIRType::Float32
);
428 RDiv::RDiv(CompactBufferReader
& reader
) {
429 isFloatOperation_
= reader
.readByte();
432 bool RDiv::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
433 RootedValue
lhs(cx
, iter
.read());
434 RootedValue
rhs(cx
, iter
.read());
435 RootedValue
result(cx
);
437 if (!js::DivValues(cx
, &lhs
, &rhs
, &result
)) {
441 // MIRType::Float32 is a specialization embedding the fact that the result is
442 // rounded to a Float32.
443 if (isFloatOperation_
&& !RoundFloat32(cx
, result
, &result
)) {
447 iter
.storeInstructionResult(result
);
451 bool MMod::writeRecoverData(CompactBufferWriter
& writer
) const {
452 MOZ_ASSERT(canRecoverOnBailout());
453 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Mod
));
457 RMod::RMod(CompactBufferReader
& reader
) {}
459 bool RMod::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
460 RootedValue
lhs(cx
, iter
.read());
461 RootedValue
rhs(cx
, iter
.read());
462 RootedValue
result(cx
);
464 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
465 if (!js::ModValues(cx
, &lhs
, &rhs
, &result
)) {
469 iter
.storeInstructionResult(result
);
473 bool MNot::writeRecoverData(CompactBufferWriter
& writer
) const {
474 MOZ_ASSERT(canRecoverOnBailout());
475 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Not
));
479 RNot::RNot(CompactBufferReader
& reader
) {}
481 bool RNot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
482 RootedValue
v(cx
, iter
.read());
483 RootedValue
result(cx
);
485 result
.setBoolean(!ToBoolean(v
));
487 iter
.storeInstructionResult(result
);
491 bool MBigIntAdd::writeRecoverData(CompactBufferWriter
& writer
) const {
492 MOZ_ASSERT(canRecoverOnBailout());
493 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAdd
));
497 RBigIntAdd::RBigIntAdd(CompactBufferReader
& reader
) {}
499 bool RBigIntAdd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
500 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
501 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
503 BigInt
* result
= BigInt::add(cx
, lhs
, rhs
);
508 iter
.storeInstructionResult(BigIntValue(result
));
512 bool MBigIntSub::writeRecoverData(CompactBufferWriter
& writer
) const {
513 MOZ_ASSERT(canRecoverOnBailout());
514 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntSub
));
518 RBigIntSub::RBigIntSub(CompactBufferReader
& reader
) {}
520 bool RBigIntSub::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
521 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
522 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
524 BigInt
* result
= BigInt::sub(cx
, lhs
, rhs
);
529 iter
.storeInstructionResult(BigIntValue(result
));
533 bool MBigIntMul::writeRecoverData(CompactBufferWriter
& writer
) const {
534 MOZ_ASSERT(canRecoverOnBailout());
535 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMul
));
539 RBigIntMul::RBigIntMul(CompactBufferReader
& reader
) {}
541 bool RBigIntMul::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
542 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
543 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
545 BigInt
* result
= BigInt::mul(cx
, lhs
, rhs
);
550 iter
.storeInstructionResult(BigIntValue(result
));
554 bool MBigIntDiv::writeRecoverData(CompactBufferWriter
& writer
) const {
555 MOZ_ASSERT(canRecoverOnBailout());
556 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDiv
));
560 RBigIntDiv::RBigIntDiv(CompactBufferReader
& reader
) {}
562 bool RBigIntDiv::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
563 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
564 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
565 MOZ_ASSERT(!rhs
->isZero(),
566 "division by zero throws and therefore can't be recovered");
568 BigInt
* result
= BigInt::div(cx
, lhs
, rhs
);
573 iter
.storeInstructionResult(BigIntValue(result
));
577 bool MBigIntMod::writeRecoverData(CompactBufferWriter
& writer
) const {
578 MOZ_ASSERT(canRecoverOnBailout());
579 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMod
));
583 RBigIntMod::RBigIntMod(CompactBufferReader
& reader
) {}
585 bool RBigIntMod::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
586 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
587 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
588 MOZ_ASSERT(!rhs
->isZero(),
589 "division by zero throws and therefore can't be recovered");
591 BigInt
* result
= BigInt::mod(cx
, lhs
, rhs
);
596 iter
.storeInstructionResult(BigIntValue(result
));
600 bool MBigIntPow::writeRecoverData(CompactBufferWriter
& writer
) const {
601 MOZ_ASSERT(canRecoverOnBailout());
602 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPow
));
606 RBigIntPow::RBigIntPow(CompactBufferReader
& reader
) {}
608 bool RBigIntPow::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
609 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
610 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
611 MOZ_ASSERT(!rhs
->isNegative(),
612 "negative exponent throws and therefore can't be recovered");
614 BigInt
* result
= BigInt::pow(cx
, lhs
, rhs
);
619 iter
.storeInstructionResult(BigIntValue(result
));
623 bool MBigIntBitAnd::writeRecoverData(CompactBufferWriter
& writer
) const {
624 MOZ_ASSERT(canRecoverOnBailout());
625 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitAnd
));
629 RBigIntBitAnd::RBigIntBitAnd(CompactBufferReader
& reader
) {}
631 bool RBigIntBitAnd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
632 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
633 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
635 BigInt
* result
= BigInt::bitAnd(cx
, lhs
, rhs
);
640 iter
.storeInstructionResult(BigIntValue(result
));
644 bool MBigIntBitOr::writeRecoverData(CompactBufferWriter
& writer
) const {
645 MOZ_ASSERT(canRecoverOnBailout());
646 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitOr
));
650 RBigIntBitOr::RBigIntBitOr(CompactBufferReader
& reader
) {}
652 bool RBigIntBitOr::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
653 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
654 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
656 BigInt
* result
= BigInt::bitOr(cx
, lhs
, rhs
);
661 iter
.storeInstructionResult(BigIntValue(result
));
665 bool MBigIntBitXor::writeRecoverData(CompactBufferWriter
& writer
) const {
666 MOZ_ASSERT(canRecoverOnBailout());
667 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitXor
));
671 RBigIntBitXor::RBigIntBitXor(CompactBufferReader
& reader
) {}
673 bool RBigIntBitXor::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
674 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
675 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
677 BigInt
* result
= BigInt::bitXor(cx
, lhs
, rhs
);
682 iter
.storeInstructionResult(BigIntValue(result
));
686 bool MBigIntLsh::writeRecoverData(CompactBufferWriter
& writer
) const {
687 MOZ_ASSERT(canRecoverOnBailout());
688 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntLsh
));
692 RBigIntLsh::RBigIntLsh(CompactBufferReader
& reader
) {}
694 bool RBigIntLsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
695 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
696 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
698 BigInt
* result
= BigInt::lsh(cx
, lhs
, rhs
);
703 iter
.storeInstructionResult(BigIntValue(result
));
707 bool MBigIntRsh::writeRecoverData(CompactBufferWriter
& writer
) const {
708 MOZ_ASSERT(canRecoverOnBailout());
709 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntRsh
));
713 RBigIntRsh::RBigIntRsh(CompactBufferReader
& reader
) {}
715 bool RBigIntRsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
716 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
717 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
719 BigInt
* result
= BigInt::rsh(cx
, lhs
, rhs
);
724 iter
.storeInstructionResult(BigIntValue(result
));
728 bool MBigIntIncrement::writeRecoverData(CompactBufferWriter
& writer
) const {
729 MOZ_ASSERT(canRecoverOnBailout());
730 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntIncrement
));
734 RBigIntIncrement::RBigIntIncrement(CompactBufferReader
& reader
) {}
736 bool RBigIntIncrement::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
737 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
739 BigInt
* result
= BigInt::inc(cx
, operand
);
744 iter
.storeInstructionResult(BigIntValue(result
));
748 bool MBigIntDecrement::writeRecoverData(CompactBufferWriter
& writer
) const {
749 MOZ_ASSERT(canRecoverOnBailout());
750 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDecrement
));
754 RBigIntDecrement::RBigIntDecrement(CompactBufferReader
& reader
) {}
756 bool RBigIntDecrement::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
757 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
759 BigInt
* result
= BigInt::dec(cx
, operand
);
764 iter
.storeInstructionResult(BigIntValue(result
));
768 bool MBigIntNegate::writeRecoverData(CompactBufferWriter
& writer
) const {
769 MOZ_ASSERT(canRecoverOnBailout());
770 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntNegate
));
774 RBigIntNegate::RBigIntNegate(CompactBufferReader
& reader
) {}
776 bool RBigIntNegate::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
777 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
779 BigInt
* result
= BigInt::neg(cx
, operand
);
784 iter
.storeInstructionResult(BigIntValue(result
));
788 bool MBigIntBitNot::writeRecoverData(CompactBufferWriter
& writer
) const {
789 MOZ_ASSERT(canRecoverOnBailout());
790 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitNot
));
794 RBigIntBitNot::RBigIntBitNot(CompactBufferReader
& reader
) {}
796 bool RBigIntBitNot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
797 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
799 BigInt
* result
= BigInt::bitNot(cx
, operand
);
804 iter
.storeInstructionResult(BigIntValue(result
));
808 bool MCompare::writeRecoverData(CompactBufferWriter
& writer
) const {
809 MOZ_ASSERT(canRecoverOnBailout());
810 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Compare
));
812 static_assert(sizeof(JSOp
) == sizeof(uint8_t));
813 writer
.writeByte(uint8_t(jsop_
));
817 RCompare::RCompare(CompactBufferReader
& reader
) {
818 jsop_
= JSOp(reader
.readByte());
820 MOZ_ASSERT(IsEqualityOp(jsop_
) || IsRelationalOp(jsop_
));
823 bool RCompare::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
824 RootedValue
lhs(cx
, iter
.read());
825 RootedValue
rhs(cx
, iter
.read());
831 if (!js::LooselyEqual(cx
, lhs
, rhs
, &result
)) {
834 if (jsop_
== JSOp::Ne
) {
840 if (!StrictlyEqual(cx
, lhs
, rhs
, &result
)) {
843 if (jsop_
== JSOp::StrictNe
) {
848 if (!js::LessThan(cx
, &lhs
, &rhs
, &result
)) {
853 if (!js::LessThanOrEqual(cx
, &lhs
, &rhs
, &result
)) {
858 if (!js::GreaterThan(cx
, &lhs
, &rhs
, &result
)) {
863 if (!js::GreaterThanOrEqual(cx
, &lhs
, &rhs
, &result
)) {
868 MOZ_CRASH("Unexpected op.");
871 iter
.storeInstructionResult(BooleanValue(result
));
875 bool MConcat::writeRecoverData(CompactBufferWriter
& writer
) const {
876 MOZ_ASSERT(canRecoverOnBailout());
877 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Concat
));
881 RConcat::RConcat(CompactBufferReader
& reader
) {}
883 bool RConcat::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
884 RootedValue
lhs(cx
, iter
.read());
885 RootedValue
rhs(cx
, iter
.read());
886 RootedValue
result(cx
);
888 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
889 if (!js::AddValues(cx
, &lhs
, &rhs
, &result
)) {
893 iter
.storeInstructionResult(result
);
897 RStringLength::RStringLength(CompactBufferReader
& reader
) {}
899 bool RStringLength::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
900 JSString
* string
= iter
.readString();
902 static_assert(JSString::MAX_LENGTH
<= INT32_MAX
,
903 "Can cast string length to int32_t");
905 iter
.storeInstructionResult(Int32Value(int32_t(string
->length())));
909 bool MStringLength::writeRecoverData(CompactBufferWriter
& writer
) const {
910 MOZ_ASSERT(canRecoverOnBailout());
911 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringLength
));
915 bool MArgumentsLength::writeRecoverData(CompactBufferWriter
& writer
) const {
916 MOZ_ASSERT(canRecoverOnBailout());
917 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength
));
921 RArgumentsLength::RArgumentsLength(CompactBufferReader
& reader
) {}
923 bool RArgumentsLength::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
924 uintptr_t numActualArgs
= iter
.frame()->numActualArgs();
926 static_assert(ARGS_LENGTH_MAX
<= INT32_MAX
,
927 "Can cast arguments count to int32_t");
928 MOZ_ASSERT(numActualArgs
<= ARGS_LENGTH_MAX
);
930 iter
.storeInstructionResult(JS::Int32Value(int32_t(numActualArgs
)));
934 bool MFloor::writeRecoverData(CompactBufferWriter
& writer
) const {
935 MOZ_ASSERT(canRecoverOnBailout());
936 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
940 RFloor::RFloor(CompactBufferReader
& reader
) {}
942 bool RFloor::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
943 double num
= iter
.readNumber();
944 double result
= js::math_floor_impl(num
);
946 iter
.storeInstructionResult(NumberValue(result
));
950 bool MCeil::writeRecoverData(CompactBufferWriter
& writer
) const {
951 MOZ_ASSERT(canRecoverOnBailout());
952 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
956 RCeil::RCeil(CompactBufferReader
& reader
) {}
958 bool RCeil::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
959 double num
= iter
.readNumber();
960 double result
= js::math_ceil_impl(num
);
962 iter
.storeInstructionResult(NumberValue(result
));
966 bool MRound::writeRecoverData(CompactBufferWriter
& writer
) const {
967 MOZ_ASSERT(canRecoverOnBailout());
968 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Round
));
972 RRound::RRound(CompactBufferReader
& reader
) {}
974 bool RRound::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
975 double num
= iter
.readNumber();
976 double result
= js::math_round_impl(num
);
978 iter
.storeInstructionResult(NumberValue(result
));
982 bool MTrunc::writeRecoverData(CompactBufferWriter
& writer
) const {
983 MOZ_ASSERT(canRecoverOnBailout());
984 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
988 RTrunc::RTrunc(CompactBufferReader
& reader
) {}
990 bool RTrunc::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
991 double num
= iter
.readNumber();
992 double result
= js::math_trunc_impl(num
);
994 iter
.storeInstructionResult(NumberValue(result
));
998 bool MCharCodeAt::writeRecoverData(CompactBufferWriter
& writer
) const {
999 MOZ_ASSERT(canRecoverOnBailout());
1000 writer
.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt
));
1004 RCharCodeAt::RCharCodeAt(CompactBufferReader
& reader
) {}
1006 bool RCharCodeAt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1007 JSString
* string
= iter
.readString();
1009 // Int32 because |index| is computed from MBoundsCheck.
1010 int32_t index
= iter
.readInt32();
1011 MOZ_RELEASE_ASSERT(0 <= index
&& size_t(index
) < string
->length());
1014 if (!string
->getChar(cx
, index
, &c
)) {
1018 iter
.storeInstructionResult(Int32Value(c
));
1022 bool MFromCharCode::writeRecoverData(CompactBufferWriter
& writer
) const {
1023 MOZ_ASSERT(canRecoverOnBailout());
1024 writer
.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode
));
1028 RFromCharCode::RFromCharCode(CompactBufferReader
& reader
) {}
1030 bool RFromCharCode::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1031 // Number because |charCode| is computed from (recoverable) user input.
1032 int32_t charCode
= JS::ToInt32(iter
.readNumber());
1034 JSString
* str
= StringFromCharCode(cx
, charCode
);
1039 iter
.storeInstructionResult(StringValue(str
));
1043 bool MFromCharCodeEmptyIfNegative::writeRecoverData(
1044 CompactBufferWriter
& writer
) const {
1045 MOZ_ASSERT(canRecoverOnBailout());
1046 writer
.writeUnsigned(
1047 uint32_t(RInstruction::Recover_FromCharCodeEmptyIfNegative
));
1051 RFromCharCodeEmptyIfNegative::RFromCharCodeEmptyIfNegative(
1052 CompactBufferReader
& reader
) {}
1054 bool RFromCharCodeEmptyIfNegative::recover(JSContext
* cx
,
1055 SnapshotIterator
& iter
) const {
1056 // Int32 because |charCode| is computed from MCharCodeAtOrNegative.
1057 int32_t charCode
= iter
.readInt32();
1061 str
= cx
->emptyString();
1063 str
= StringFromCharCode(cx
, charCode
);
1069 iter
.storeInstructionResult(StringValue(str
));
1073 bool MPow::writeRecoverData(CompactBufferWriter
& writer
) const {
1074 MOZ_ASSERT(canRecoverOnBailout());
1075 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Pow
));
1079 RPow::RPow(CompactBufferReader
& reader
) {}
1081 bool RPow::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1082 double base
= iter
.readNumber();
1083 double power
= iter
.readNumber();
1084 double result
= ecmaPow(base
, power
);
1086 iter
.storeInstructionResult(NumberValue(result
));
1090 bool MPowHalf::writeRecoverData(CompactBufferWriter
& writer
) const {
1091 MOZ_ASSERT(canRecoverOnBailout());
1092 writer
.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf
));
1096 RPowHalf::RPowHalf(CompactBufferReader
& reader
) {}
1098 bool RPowHalf::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1099 double base
= iter
.readNumber();
1101 double result
= ecmaPow(base
, power
);
1103 iter
.storeInstructionResult(NumberValue(result
));
1107 bool MMinMax::writeRecoverData(CompactBufferWriter
& writer
) const {
1108 MOZ_ASSERT(canRecoverOnBailout());
1109 writer
.writeUnsigned(uint32_t(RInstruction::Recover_MinMax
));
1110 writer
.writeByte(isMax_
);
1114 RMinMax::RMinMax(CompactBufferReader
& reader
) { isMax_
= reader
.readByte(); }
1116 bool RMinMax::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1117 double x
= iter
.readNumber();
1118 double y
= iter
.readNumber();
1122 result
= js::math_max_impl(x
, y
);
1124 result
= js::math_min_impl(x
, y
);
1127 iter
.storeInstructionResult(NumberValue(result
));
1131 bool MAbs::writeRecoverData(CompactBufferWriter
& writer
) const {
1132 MOZ_ASSERT(canRecoverOnBailout());
1133 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Abs
));
1137 RAbs::RAbs(CompactBufferReader
& reader
) {}
1139 bool RAbs::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1140 double num
= iter
.readNumber();
1141 double result
= js::math_abs_impl(num
);
1143 iter
.storeInstructionResult(NumberValue(result
));
1147 bool MSqrt::writeRecoverData(CompactBufferWriter
& writer
) const {
1148 MOZ_ASSERT(canRecoverOnBailout());
1149 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt
));
1150 writer
.writeByte(type() == MIRType::Float32
);
1154 RSqrt::RSqrt(CompactBufferReader
& reader
) {
1155 isFloatOperation_
= reader
.readByte();
1158 bool RSqrt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1159 double num
= iter
.readNumber();
1160 double result
= js::math_sqrt_impl(num
);
1162 // MIRType::Float32 is a specialization embedding the fact that the result is
1163 // rounded to a Float32.
1164 if (isFloatOperation_
) {
1165 result
= js::RoundFloat32(result
);
1168 iter
.storeInstructionResult(DoubleValue(result
));
1172 bool MAtan2::writeRecoverData(CompactBufferWriter
& writer
) const {
1173 MOZ_ASSERT(canRecoverOnBailout());
1174 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Atan2
));
1178 RAtan2::RAtan2(CompactBufferReader
& reader
) {}
1180 bool RAtan2::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1181 double y
= iter
.readNumber();
1182 double x
= iter
.readNumber();
1183 double result
= js::ecmaAtan2(y
, x
);
1185 iter
.storeInstructionResult(DoubleValue(result
));
1189 bool MHypot::writeRecoverData(CompactBufferWriter
& writer
) const {
1190 MOZ_ASSERT(canRecoverOnBailout());
1191 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Hypot
));
1192 writer
.writeUnsigned(uint32_t(numOperands()));
1196 RHypot::RHypot(CompactBufferReader
& reader
)
1197 : numOperands_(reader
.readUnsigned()) {}
1199 bool RHypot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1200 JS::RootedValueVector
vec(cx
);
1202 if (!vec
.reserve(numOperands_
)) {
1206 for (uint32_t i
= 0; i
< numOperands_
; ++i
) {
1207 vec
.infallibleAppend(NumberValue(iter
.readNumber()));
1210 RootedValue
result(cx
);
1212 if (!js::math_hypot_handle(cx
, vec
, &result
)) {
1216 iter
.storeInstructionResult(result
);
1220 bool MNearbyInt::writeRecoverData(CompactBufferWriter
& writer
) const {
1221 MOZ_ASSERT(canRecoverOnBailout());
1222 switch (roundingMode_
) {
1223 case RoundingMode::Up
:
1224 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
1226 case RoundingMode::Down
:
1227 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
1229 case RoundingMode::TowardsZero
:
1230 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
1233 MOZ_CRASH("Unsupported rounding mode.");
1237 RNearbyInt::RNearbyInt(CompactBufferReader
& reader
) {
1238 roundingMode_
= reader
.readByte();
1241 bool RNearbyInt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1242 MOZ_CRASH("Unsupported rounding mode.");
1245 bool MSign::writeRecoverData(CompactBufferWriter
& writer
) const {
1246 MOZ_ASSERT(canRecoverOnBailout());
1247 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Sign
));
1251 RSign::RSign(CompactBufferReader
& reader
) {}
1253 bool RSign::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1254 double num
= iter
.readNumber();
1255 double result
= js::math_sign_impl(num
);
1257 iter
.storeInstructionResult(NumberValue(result
));
1261 bool MMathFunction::writeRecoverData(CompactBufferWriter
& writer
) const {
1262 MOZ_ASSERT(canRecoverOnBailout());
1263 switch (function_
) {
1264 case UnaryMathFunction::Ceil
:
1265 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
1267 case UnaryMathFunction::Floor
:
1268 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
1270 case UnaryMathFunction::Round
:
1271 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Round
));
1273 case UnaryMathFunction::Trunc
:
1274 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
1276 case UnaryMathFunction::SinNative
:
1277 case UnaryMathFunction::SinFdlibm
:
1278 case UnaryMathFunction::CosNative
:
1279 case UnaryMathFunction::CosFdlibm
:
1280 case UnaryMathFunction::TanNative
:
1281 case UnaryMathFunction::TanFdlibm
:
1282 case UnaryMathFunction::Log
:
1283 case UnaryMathFunction::Exp
:
1284 case UnaryMathFunction::ACos
:
1285 case UnaryMathFunction::ASin
:
1286 case UnaryMathFunction::ATan
:
1287 case UnaryMathFunction::Log10
:
1288 case UnaryMathFunction::Log2
:
1289 case UnaryMathFunction::Log1P
:
1290 case UnaryMathFunction::ExpM1
:
1291 case UnaryMathFunction::CosH
:
1292 case UnaryMathFunction::SinH
:
1293 case UnaryMathFunction::TanH
:
1294 case UnaryMathFunction::ACosH
:
1295 case UnaryMathFunction::ASinH
:
1296 case UnaryMathFunction::ATanH
:
1297 case UnaryMathFunction::Cbrt
:
1298 static_assert(sizeof(UnaryMathFunction
) == sizeof(uint8_t));
1299 writer
.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction
));
1300 writer
.writeByte(uint8_t(function_
));
1303 MOZ_CRASH("Unknown math function.");
1306 RMathFunction::RMathFunction(CompactBufferReader
& reader
) {
1307 function_
= UnaryMathFunction(reader
.readByte());
1310 bool RMathFunction::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1311 double num
= iter
.readNumber();
1314 switch (function_
) {
1315 case UnaryMathFunction::SinNative
:
1316 result
= js::math_sin_native_impl(num
);
1318 case UnaryMathFunction::SinFdlibm
:
1319 result
= js::math_sin_fdlibm_impl(num
);
1321 case UnaryMathFunction::CosNative
:
1322 result
= js::math_cos_native_impl(num
);
1324 case UnaryMathFunction::CosFdlibm
:
1325 result
= js::math_cos_fdlibm_impl(num
);
1327 case UnaryMathFunction::TanNative
:
1328 result
= js::math_tan_native_impl(num
);
1330 case UnaryMathFunction::TanFdlibm
:
1331 result
= js::math_tan_fdlibm_impl(num
);
1333 case UnaryMathFunction::Log
:
1334 result
= js::math_log_impl(num
);
1336 case UnaryMathFunction::Exp
:
1337 result
= js::math_exp_impl(num
);
1339 case UnaryMathFunction::ACos
:
1340 result
= js::math_acos_impl(num
);
1342 case UnaryMathFunction::ASin
:
1343 result
= js::math_asin_impl(num
);
1345 case UnaryMathFunction::ATan
:
1346 result
= js::math_atan_impl(num
);
1348 case UnaryMathFunction::Log10
:
1349 result
= js::math_log10_impl(num
);
1351 case UnaryMathFunction::Log2
:
1352 result
= js::math_log2_impl(num
);
1354 case UnaryMathFunction::Log1P
:
1355 result
= js::math_log1p_impl(num
);
1357 case UnaryMathFunction::ExpM1
:
1358 result
= js::math_expm1_impl(num
);
1360 case UnaryMathFunction::CosH
:
1361 result
= js::math_cosh_impl(num
);
1363 case UnaryMathFunction::SinH
:
1364 result
= js::math_sinh_impl(num
);
1366 case UnaryMathFunction::TanH
:
1367 result
= js::math_tanh_impl(num
);
1369 case UnaryMathFunction::ACosH
:
1370 result
= js::math_acosh_impl(num
);
1372 case UnaryMathFunction::ASinH
:
1373 result
= js::math_asinh_impl(num
);
1375 case UnaryMathFunction::ATanH
:
1376 result
= js::math_atanh_impl(num
);
1378 case UnaryMathFunction::Cbrt
:
1379 result
= js::math_cbrt_impl(num
);
1382 case UnaryMathFunction::Trunc
:
1383 case UnaryMathFunction::Floor
:
1384 case UnaryMathFunction::Ceil
:
1385 case UnaryMathFunction::Round
:
1386 // These have their own recover instructions.
1387 MOZ_CRASH("Unexpected rounding math function.");
1390 iter
.storeInstructionResult(DoubleValue(result
));
1394 bool MRandom::writeRecoverData(CompactBufferWriter
& writer
) const {
1395 MOZ_ASSERT(this->canRecoverOnBailout());
1396 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Random
));
1400 bool MRandom::canRecoverOnBailout() const {
1401 return !js::SupportDifferentialTesting();
1404 RRandom::RRandom(CompactBufferReader
& reader
) {}
1406 bool RRandom::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1407 iter
.storeInstructionResult(DoubleValue(math_random_impl(cx
)));
1411 bool MStringSplit::writeRecoverData(CompactBufferWriter
& writer
) const {
1412 MOZ_ASSERT(canRecoverOnBailout());
1413 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit
));
1417 RStringSplit::RStringSplit(CompactBufferReader
& reader
) {}
1419 bool RStringSplit::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1420 RootedString
str(cx
, iter
.readString());
1421 RootedString
sep(cx
, iter
.readString());
1423 JSObject
* res
= StringSplitString(cx
, str
, sep
, INT32_MAX
);
1428 iter
.storeInstructionResult(ObjectValue(*res
));
1432 bool MNaNToZero::writeRecoverData(CompactBufferWriter
& writer
) const {
1433 MOZ_ASSERT(canRecoverOnBailout());
1434 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero
));
1438 RNaNToZero::RNaNToZero(CompactBufferReader
& reader
) {}
1440 bool RNaNToZero::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1441 double v
= iter
.readNumber();
1442 if (std::isnan(v
) || mozilla::IsNegativeZero(v
)) {
1446 iter
.storeInstructionResult(DoubleValue(v
));
1450 bool MRegExpMatcher::writeRecoverData(CompactBufferWriter
& writer
) const {
1451 MOZ_ASSERT(canRecoverOnBailout());
1452 writer
.writeUnsigned(uint32_t(RInstruction::Recover_RegExpMatcher
));
1456 RRegExpMatcher::RRegExpMatcher(CompactBufferReader
& reader
) {}
1458 bool RRegExpMatcher::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1459 RootedObject
regexp(cx
, iter
.readObject());
1460 RootedString
input(cx
, iter
.readString());
1462 // Int32 because |lastIndex| is computed from transpiled self-hosted call.
1463 int32_t lastIndex
= iter
.readInt32();
1465 RootedValue
result(cx
);
1466 if (!RegExpMatcherRaw(cx
, regexp
, input
, lastIndex
, nullptr, &result
)) {
1470 iter
.storeInstructionResult(result
);
1474 bool MTypeOf::writeRecoverData(CompactBufferWriter
& writer
) const {
1475 MOZ_ASSERT(canRecoverOnBailout());
1476 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf
));
1480 RTypeOf::RTypeOf(CompactBufferReader
& reader
) {}
1482 bool RTypeOf::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1483 JS::Value v
= iter
.read();
1485 iter
.storeInstructionResult(Int32Value(TypeOfValue(v
)));
1489 bool MTypeOfName::writeRecoverData(CompactBufferWriter
& writer
) const {
1490 MOZ_ASSERT(canRecoverOnBailout());
1491 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TypeOfName
));
1495 RTypeOfName::RTypeOfName(CompactBufferReader
& reader
) {}
1497 bool RTypeOfName::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1498 // Int32 because |type| is computed from MTypeOf.
1499 int32_t type
= iter
.readInt32();
1500 MOZ_ASSERT(JSTYPE_UNDEFINED
<= type
&& type
< JSTYPE_LIMIT
);
1502 JSString
* name
= TypeName(JSType(type
), *cx
->runtime()->commonNames
);
1503 iter
.storeInstructionResult(StringValue(name
));
1507 bool MToDouble::writeRecoverData(CompactBufferWriter
& writer
) const {
1508 MOZ_ASSERT(canRecoverOnBailout());
1509 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble
));
1513 RToDouble::RToDouble(CompactBufferReader
& reader
) {}
1515 bool RToDouble::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1516 RootedValue
v(cx
, iter
.read());
1518 MOZ_ASSERT(!v
.isObject());
1519 MOZ_ASSERT(!v
.isSymbol());
1520 MOZ_ASSERT(!v
.isBigInt());
1523 if (!ToNumber(cx
, v
, &dbl
)) {
1527 iter
.storeInstructionResult(DoubleValue(dbl
));
1531 bool MToFloat32::writeRecoverData(CompactBufferWriter
& writer
) const {
1532 MOZ_ASSERT(canRecoverOnBailout());
1533 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32
));
1537 RToFloat32::RToFloat32(CompactBufferReader
& reader
) {}
1539 bool RToFloat32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1540 double num
= iter
.readNumber();
1541 double result
= js::RoundFloat32(num
);
1543 iter
.storeInstructionResult(DoubleValue(result
));
1547 bool MTruncateToInt32::writeRecoverData(CompactBufferWriter
& writer
) const {
1548 MOZ_ASSERT(canRecoverOnBailout());
1549 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32
));
1553 RTruncateToInt32::RTruncateToInt32(CompactBufferReader
& reader
) {}
1555 bool RTruncateToInt32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1556 RootedValue
value(cx
, iter
.read());
1559 if (!JS::ToInt32(cx
, value
, &trunc
)) {
1563 iter
.storeInstructionResult(Int32Value(trunc
));
1567 bool MNewObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1568 MOZ_ASSERT(canRecoverOnBailout());
1570 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewObject
));
1572 // Recover instructions are only supported if we have a template object.
1573 MOZ_ASSERT(mode_
== MNewObject::ObjectCreate
);
1577 RNewObject::RNewObject(CompactBufferReader
& reader
) {}
1579 bool RNewObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1580 RootedObject
templateObject(cx
, iter
.readObject());
1582 // See CodeGenerator::visitNewObjectVMCall.
1583 // Note that recover instructions are only used if mode == ObjectCreate.
1584 JSObject
* resultObject
=
1585 ObjectCreateWithTemplate(cx
, templateObject
.as
<PlainObject
>());
1586 if (!resultObject
) {
1590 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1594 bool MNewPlainObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1595 MOZ_ASSERT(canRecoverOnBailout());
1596 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewPlainObject
));
1598 MOZ_ASSERT(gc::AllocKind(uint8_t(allocKind_
)) == allocKind_
);
1599 writer
.writeByte(uint8_t(allocKind_
));
1600 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_
)) == initialHeap_
);
1601 writer
.writeByte(uint8_t(initialHeap_
));
1605 RNewPlainObject::RNewPlainObject(CompactBufferReader
& reader
) {
1606 allocKind_
= gc::AllocKind(reader
.readByte());
1607 MOZ_ASSERT(gc::IsValidAllocKind(allocKind_
));
1608 initialHeap_
= gc::Heap(reader
.readByte());
1609 MOZ_ASSERT(initialHeap_
== gc::Heap::Default
||
1610 initialHeap_
== gc::Heap::Tenured
);
1613 bool RNewPlainObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1614 Rooted
<SharedShape
*> shape(cx
, &iter
.readGCCellPtr().as
<Shape
>().asShared());
1616 // See CodeGenerator::visitNewPlainObject.
1617 JSObject
* resultObject
=
1618 NewPlainObjectOptimizedFallback(cx
, shape
, allocKind_
, initialHeap_
);
1619 if (!resultObject
) {
1623 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1627 bool MNewArrayObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1628 MOZ_ASSERT(canRecoverOnBailout());
1629 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayObject
));
1631 writer
.writeUnsigned(length_
);
1632 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_
)) == initialHeap_
);
1633 writer
.writeByte(uint8_t(initialHeap_
));
1637 RNewArrayObject::RNewArrayObject(CompactBufferReader
& reader
) {
1638 length_
= reader
.readUnsigned();
1639 initialHeap_
= gc::Heap(reader
.readByte());
1640 MOZ_ASSERT(initialHeap_
== gc::Heap::Default
||
1641 initialHeap_
== gc::Heap::Tenured
);
1644 bool RNewArrayObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1645 iter
.read(); // Skip unused shape field.
1647 NewObjectKind kind
=
1648 initialHeap_
== gc::Heap::Tenured
? TenuredObject
: GenericObject
;
1649 JSObject
* array
= NewArrayOperation(cx
, length_
, kind
);
1654 iter
.storeInstructionResult(ObjectValue(*array
));
1658 bool MNewTypedArray::writeRecoverData(CompactBufferWriter
& writer
) const {
1659 MOZ_ASSERT(canRecoverOnBailout());
1660 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray
));
1664 RNewTypedArray::RNewTypedArray(CompactBufferReader
& reader
) {}
1666 bool RNewTypedArray::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1667 RootedObject
templateObject(cx
, iter
.readObject());
1669 size_t length
= templateObject
.as
<FixedLengthTypedArrayObject
>()->length();
1670 MOZ_ASSERT(length
<= INT32_MAX
,
1671 "Template objects are only created for int32 lengths");
1673 JSObject
* resultObject
=
1674 NewTypedArrayWithTemplateAndLength(cx
, templateObject
, length
);
1675 if (!resultObject
) {
1679 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1683 bool MNewArray::writeRecoverData(CompactBufferWriter
& writer
) const {
1684 MOZ_ASSERT(canRecoverOnBailout());
1685 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewArray
));
1686 writer
.writeUnsigned(length());
1690 RNewArray::RNewArray(CompactBufferReader
& reader
) {
1691 count_
= reader
.readUnsigned();
1694 bool RNewArray::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1695 RootedObject
templateObject(cx
, iter
.readObject());
1696 Rooted
<Shape
*> shape(cx
, templateObject
->shape());
1698 ArrayObject
* resultObject
= NewArrayWithShape(cx
, count_
, shape
);
1699 if (!resultObject
) {
1703 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1707 bool MNewIterator::writeRecoverData(CompactBufferWriter
& writer
) const {
1708 MOZ_ASSERT(canRecoverOnBailout());
1709 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator
));
1710 writer
.writeByte(type_
);
1714 RNewIterator::RNewIterator(CompactBufferReader
& reader
) {
1715 type_
= reader
.readByte();
1718 bool RNewIterator::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1719 RootedObject
templateObject(cx
, iter
.readObject());
1721 JSObject
* resultObject
= nullptr;
1722 switch (MNewIterator::Type(type_
)) {
1723 case MNewIterator::ArrayIterator
:
1724 resultObject
= NewArrayIterator(cx
);
1726 case MNewIterator::StringIterator
:
1727 resultObject
= NewStringIterator(cx
);
1729 case MNewIterator::RegExpStringIterator
:
1730 resultObject
= NewRegExpStringIterator(cx
);
1734 if (!resultObject
) {
1738 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1742 bool MLambda::writeRecoverData(CompactBufferWriter
& writer
) const {
1743 MOZ_ASSERT(canRecoverOnBailout());
1744 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Lambda
));
1748 RLambda::RLambda(CompactBufferReader
& reader
) {}
1750 bool RLambda::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1751 RootedObject
scopeChain(cx
, iter
.readObject());
1752 RootedFunction
fun(cx
, &iter
.readObject()->as
<JSFunction
>());
1754 JSObject
* resultObject
= js::Lambda(cx
, fun
, scopeChain
);
1755 if (!resultObject
) {
1759 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1763 bool MFunctionWithProto::writeRecoverData(CompactBufferWriter
& writer
) const {
1764 MOZ_ASSERT(canRecoverOnBailout());
1765 writer
.writeUnsigned(uint32_t(RInstruction::Recover_FunctionWithProto
));
1769 RFunctionWithProto::RFunctionWithProto(CompactBufferReader
& reader
) {}
1771 bool RFunctionWithProto::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1772 RootedObject
scopeChain(cx
, iter
.readObject());
1773 RootedObject
prototype(cx
, iter
.readObject());
1774 RootedFunction
fun(cx
, &iter
.readObject()->as
<JSFunction
>());
1776 JSObject
* resultObject
=
1777 js::FunWithProtoOperation(cx
, fun
, scopeChain
, prototype
);
1778 if (!resultObject
) {
1782 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1786 bool MNewCallObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1787 MOZ_ASSERT(canRecoverOnBailout());
1788 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewCallObject
));
1792 RNewCallObject::RNewCallObject(CompactBufferReader
& reader
) {}
1794 bool RNewCallObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1795 Rooted
<CallObject
*> templateObj(cx
, &iter
.readObject()->as
<CallObject
>());
1797 Rooted
<SharedShape
*> shape(cx
, templateObj
->sharedShape());
1799 JSObject
* resultObject
= CallObject::createWithShape(cx
, shape
);
1800 if (!resultObject
) {
1804 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1808 bool MObjectKeys::canRecoverOnBailout() const {
1809 // Only claim that this operation can be recovered on bailout if some other
1810 // optimization already marked it as such.
1811 return isRecoveredOnBailout();
1814 bool MObjectKeys::writeRecoverData(CompactBufferWriter
& writer
) const {
1815 MOZ_ASSERT(canRecoverOnBailout());
1816 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ObjectKeys
));
1820 RObjectKeys::RObjectKeys(CompactBufferReader
& reader
) {}
1822 bool RObjectKeys::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1823 Rooted
<JSObject
*> obj(cx
, iter
.readObject());
1825 JSObject
* resultKeys
= ObjectKeys(cx
, obj
);
1830 iter
.storeInstructionResult(ObjectValue(*resultKeys
));
1834 bool MObjectState::writeRecoverData(CompactBufferWriter
& writer
) const {
1835 MOZ_ASSERT(canRecoverOnBailout());
1836 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState
));
1837 writer
.writeUnsigned(numSlots());
1841 RObjectState::RObjectState(CompactBufferReader
& reader
) {
1842 numSlots_
= reader
.readUnsigned();
1845 bool RObjectState::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1846 RootedObject
object(cx
, iter
.readObject());
1847 Handle
<NativeObject
*> nativeObject
= object
.as
<NativeObject
>();
1848 MOZ_ASSERT(!Watchtower::watchesPropertyModification(nativeObject
));
1849 MOZ_ASSERT(nativeObject
->slotSpan() == numSlots());
1851 for (size_t i
= 0; i
< numSlots(); i
++) {
1852 Value val
= iter
.read();
1853 nativeObject
->setSlot(i
, val
);
1856 iter
.storeInstructionResult(ObjectValue(*object
));
1860 bool MArrayState::writeRecoverData(CompactBufferWriter
& writer
) const {
1861 MOZ_ASSERT(canRecoverOnBailout());
1862 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState
));
1863 writer
.writeUnsigned(numElements());
1867 RArrayState::RArrayState(CompactBufferReader
& reader
) {
1868 numElements_
= reader
.readUnsigned();
1871 bool RArrayState::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1872 ArrayObject
* object
= &iter
.readObject()->as
<ArrayObject
>();
1874 // Int32 because |initLength| is computed from MConstant.
1875 uint32_t initLength
= iter
.readInt32();
1877 MOZ_ASSERT(object
->getDenseInitializedLength() == 0,
1878 "initDenseElement call below relies on this");
1879 object
->setDenseInitializedLength(initLength
);
1881 for (size_t index
= 0; index
< numElements(); index
++) {
1882 Value val
= iter
.read();
1884 if (index
>= initLength
) {
1885 MOZ_ASSERT(val
.isUndefined());
1889 object
->initDenseElement(index
, val
);
1892 iter
.storeInstructionResult(ObjectValue(*object
));
1896 bool MAssertRecoveredOnBailout::writeRecoverData(
1897 CompactBufferWriter
& writer
) const {
1898 MOZ_ASSERT(canRecoverOnBailout());
1899 MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout() == mustBeRecovered_
,
1900 "assertRecoveredOnBailout failed during compilation");
1901 writer
.writeUnsigned(
1902 uint32_t(RInstruction::Recover_AssertRecoveredOnBailout
));
1906 RAssertRecoveredOnBailout::RAssertRecoveredOnBailout(
1907 CompactBufferReader
& reader
) {}
1909 bool RAssertRecoveredOnBailout::recover(JSContext
* cx
,
1910 SnapshotIterator
& iter
) const {
1911 iter
.read(); // skip the unused operand.
1912 iter
.storeInstructionResult(UndefinedValue());
1916 bool MStringReplace::writeRecoverData(CompactBufferWriter
& writer
) const {
1917 MOZ_ASSERT(canRecoverOnBailout());
1918 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace
));
1919 writer
.writeByte(isFlatReplacement_
);
1923 RStringReplace::RStringReplace(CompactBufferReader
& reader
) {
1924 isFlatReplacement_
= reader
.readByte();
1927 bool RStringReplace::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1928 RootedString
string(cx
, iter
.readString());
1929 RootedString
pattern(cx
, iter
.readString());
1930 RootedString
replace(cx
, iter
.readString());
1934 ? js::StringFlatReplaceString(cx
, string
, pattern
, replace
)
1935 : js::str_replace_string_raw(cx
, string
, pattern
, replace
);
1941 iter
.storeInstructionResult(StringValue(result
));
1945 bool MSubstr::writeRecoverData(CompactBufferWriter
& writer
) const {
1946 MOZ_ASSERT(canRecoverOnBailout());
1947 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Substr
));
1951 RSubstr::RSubstr(CompactBufferReader
& reader
) {}
1953 bool RSubstr::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1954 RootedString
str(cx
, iter
.readString());
1956 // Int32 because |begin| is computed from MStringTrimStartIndex, MConstant,
1957 // or CallSubstringKernelResult.
1958 int32_t begin
= iter
.readInt32();
1960 // |length| is computed from MSub(truncated), MStringTrimEndIndex, or
1961 // CallSubstringKernelResult. The current MSub inputs won't overflow, so when
1962 // RSub recovers the MSub instruction, the input will be representable as an
1963 // Int32. This is only true as long as RSub calls |js::SubOperation|, which in
1964 // turn calls |JS::Value::setNumber|. We don't want to rely on this exact call
1965 // sequence, so instead use |readNumber| here and then release-assert the
1966 // number is exactly representable as an Int32.
1967 int32_t length
= mozilla::ReleaseAssertedCast
<int32_t>(iter
.readNumber());
1969 JSString
* result
= SubstringKernel(cx
, str
, begin
, length
);
1974 iter
.storeInstructionResult(StringValue(result
));
1978 bool MAtomicIsLockFree::writeRecoverData(CompactBufferWriter
& writer
) const {
1979 MOZ_ASSERT(canRecoverOnBailout());
1980 writer
.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree
));
1984 RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader
& reader
) {}
1986 bool RAtomicIsLockFree::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1987 double dsize
= JS::ToInteger(iter
.readNumber());
1990 bool result
= mozilla::NumberEqualsInt32(dsize
, &size
) &&
1991 AtomicOperations::isLockfreeJS(size
);
1992 iter
.storeInstructionResult(BooleanValue(result
));
1996 bool MBigIntAsIntN::writeRecoverData(CompactBufferWriter
& writer
) const {
1997 MOZ_ASSERT(canRecoverOnBailout());
1998 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsIntN
));
2002 RBigIntAsIntN::RBigIntAsIntN(CompactBufferReader
& reader
) {}
2004 bool RBigIntAsIntN::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2005 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2006 int32_t bits
= iter
.readInt32();
2007 MOZ_ASSERT(bits
>= 0);
2009 RootedBigInt
input(cx
, iter
.readBigInt());
2011 BigInt
* result
= BigInt::asIntN(cx
, input
, bits
);
2016 iter
.storeInstructionResult(JS::BigIntValue(result
));
2020 bool MBigIntAsUintN::writeRecoverData(CompactBufferWriter
& writer
) const {
2021 MOZ_ASSERT(canRecoverOnBailout());
2022 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsUintN
));
2026 RBigIntAsUintN::RBigIntAsUintN(CompactBufferReader
& reader
) {}
2028 bool RBigIntAsUintN::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::asUintN(cx
, input
, bits
);
2040 iter
.storeInstructionResult(JS::BigIntValue(result
));
2044 bool MCreateArgumentsObject::writeRecoverData(
2045 CompactBufferWriter
& writer
) const {
2046 MOZ_ASSERT(canRecoverOnBailout());
2047 writer
.writeUnsigned(uint32_t(RInstruction::Recover_CreateArgumentsObject
));
2051 RCreateArgumentsObject::RCreateArgumentsObject(CompactBufferReader
& reader
) {}
2053 bool RCreateArgumentsObject::recover(JSContext
* cx
,
2054 SnapshotIterator
& iter
) const {
2055 RootedObject
callObject(cx
, iter
.readObject());
2056 RootedObject
result(
2057 cx
, ArgumentsObject::createForIon(cx
, iter
.frame(), callObject
));
2062 iter
.storeInstructionResult(JS::ObjectValue(*result
));
2066 bool MCreateInlinedArgumentsObject::writeRecoverData(
2067 CompactBufferWriter
& writer
) const {
2068 MOZ_ASSERT(canRecoverOnBailout());
2069 writer
.writeUnsigned(
2070 uint32_t(RInstruction::Recover_CreateInlinedArgumentsObject
));
2071 writer
.writeUnsigned(numActuals());
2075 RCreateInlinedArgumentsObject::RCreateInlinedArgumentsObject(
2076 CompactBufferReader
& reader
) {
2077 numActuals_
= reader
.readUnsigned();
2080 bool RCreateInlinedArgumentsObject::recover(JSContext
* cx
,
2081 SnapshotIterator
& iter
) const {
2082 RootedObject
callObject(cx
, iter
.readObject());
2083 RootedFunction
callee(cx
, &iter
.readObject()->as
<JSFunction
>());
2085 JS::RootedValueArray
<ArgumentsObject::MaxInlinedArgs
> argsArray(cx
);
2086 for (uint32_t i
= 0; i
< numActuals_
; i
++) {
2087 argsArray
[i
].set(iter
.read());
2090 ArgumentsObject
* result
= ArgumentsObject::createFromValueArray(
2091 cx
, argsArray
, callee
, callObject
, numActuals_
);
2096 iter
.storeInstructionResult(JS::ObjectValue(*result
));
2100 bool MRest::writeRecoverData(CompactBufferWriter
& writer
) const {
2101 MOZ_ASSERT(canRecoverOnBailout());
2102 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Rest
));
2103 writer
.writeUnsigned(numFormals());
2107 RRest::RRest(CompactBufferReader
& reader
) {
2108 numFormals_
= reader
.readUnsigned();
2111 bool RRest::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2112 JitFrameLayout
* frame
= iter
.frame();
2114 // Int32 because |numActuals| is computed from MArgumentsLength.
2115 uint32_t numActuals
= iter
.readInt32();
2116 MOZ_ASSERT(numActuals
== frame
->numActualArgs());
2118 uint32_t numFormals
= numFormals_
;
2120 uint32_t length
= std::max(numActuals
, numFormals
) - numFormals
;
2121 Value
* src
= frame
->actualArgs() + numFormals
;
2122 JSObject
* rest
= jit::InitRestParameter(cx
, length
, src
, nullptr);
2127 iter
.storeInstructionResult(ObjectValue(*rest
));