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"
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"
18 #include "jit/JitSpewer.h"
19 #include "jit/JSJitFrameIter.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"
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();
47 #define MATCH_OPCODES_(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); \
56 RECOVER_OPCODE_LIST(MATCH_OPCODES_
)
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();
75 // Ensure that all snapshot which are encoded can safely be used for
77 uint32_t numIntermediate
= NumIntermediateValues(mode());
78 if (JSContext
* cx
= GetJitContext()->cx
) {
79 if (!AssertBailoutStackDepth(cx
, script
, pc(), mode(),
80 exprStack
- numIntermediate
)) {
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
92 MOZ_ASSERT(formalArgs
< SNAPSHOT_MAX_NARGS
+ 4);
95 uint32_t implicit
= StartArgSlot(script
);
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
);
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
));
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
)) {
148 iter
.storeInstructionResult(result
);
152 bool MBitAnd::writeRecoverData(CompactBufferWriter
& writer
) const {
153 MOZ_ASSERT(canRecoverOnBailout());
154 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd
));
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
)) {
170 iter
.storeInstructionResult(result
);
174 bool MBitOr::writeRecoverData(CompactBufferWriter
& writer
) const {
175 MOZ_ASSERT(canRecoverOnBailout());
176 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitOr
));
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
)) {
192 iter
.storeInstructionResult(result
);
196 bool MBitXor::writeRecoverData(CompactBufferWriter
& writer
) const {
197 MOZ_ASSERT(canRecoverOnBailout());
198 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitXor
));
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
)) {
213 iter
.storeInstructionResult(result
);
217 bool MLsh::writeRecoverData(CompactBufferWriter
& writer
) const {
218 MOZ_ASSERT(canRecoverOnBailout());
219 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Lsh
));
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
)) {
235 iter
.storeInstructionResult(result
);
239 bool MRsh::writeRecoverData(CompactBufferWriter
& writer
) const {
240 MOZ_ASSERT(canRecoverOnBailout());
241 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Rsh
));
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
)) {
257 iter
.storeInstructionResult(result
);
261 bool MUrsh::writeRecoverData(CompactBufferWriter
& writer
) const {
262 MOZ_ASSERT(canRecoverOnBailout());
263 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ursh
));
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
)) {
279 iter
.storeInstructionResult(result
);
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_
));
291 RSignExtendInt32::RSignExtendInt32(CompactBufferReader
& reader
) {
292 mode_
= reader
.readByte();
295 bool RSignExtendInt32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
296 RootedValue
operand(cx
, iter
.read());
299 if (!ToInt32(cx
, operand
, &i
)) {
304 switch (MSignExtendInt32::Mode(mode_
)) {
305 case MSignExtendInt32::Byte
:
306 result
= static_cast<int8_t>(i
);
308 case MSignExtendInt32::Half
:
309 result
= static_cast<int16_t>(i
);
313 iter
.storeInstructionResult(JS::Int32Value(result
));
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
);
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
)) {
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
)) {
344 iter
.storeInstructionResult(result
);
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
);
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
)) {
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
)) {
375 iter
.storeInstructionResult(result
);
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_
));
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
)) {
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
)) {
409 MOZ_ASSERT(MMul::Mode(mode_
) == MMul::Integer
);
410 if (!js::math_imul_handle(cx
, lhs
, rhs
, &result
)) {
415 iter
.storeInstructionResult(result
);
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
);
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
)) {
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
)) {
445 iter
.storeInstructionResult(result
);
449 bool MMod::writeRecoverData(CompactBufferWriter
& writer
) const {
450 MOZ_ASSERT(canRecoverOnBailout());
451 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Mod
));
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
)) {
467 iter
.storeInstructionResult(result
);
471 bool MNot::writeRecoverData(CompactBufferWriter
& writer
) const {
472 MOZ_ASSERT(canRecoverOnBailout());
473 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Not
));
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
);
489 bool MBigIntAdd::writeRecoverData(CompactBufferWriter
& writer
) const {
490 MOZ_ASSERT(canRecoverOnBailout());
491 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAdd
));
495 RBigIntAdd::RBigIntAdd(CompactBufferReader
& reader
) {}
497 bool RBigIntAdd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
498 RootedValue
lhs(cx
, iter
.read());
499 RootedValue
rhs(cx
, iter
.read());
500 RootedValue
result(cx
);
502 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
503 if (!js::AddValues(cx
, &lhs
, &rhs
, &result
)) {
507 iter
.storeInstructionResult(result
);
511 bool MBigIntSub::writeRecoverData(CompactBufferWriter
& writer
) const {
512 MOZ_ASSERT(canRecoverOnBailout());
513 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntSub
));
517 RBigIntSub::RBigIntSub(CompactBufferReader
& reader
) {}
519 bool RBigIntSub::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
520 RootedValue
lhs(cx
, iter
.read());
521 RootedValue
rhs(cx
, iter
.read());
522 RootedValue
result(cx
);
524 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
525 if (!js::SubValues(cx
, &lhs
, &rhs
, &result
)) {
529 iter
.storeInstructionResult(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 RootedValue
lhs(cx
, iter
.read());
543 RootedValue
rhs(cx
, iter
.read());
544 RootedValue
result(cx
);
546 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
547 if (!js::MulValues(cx
, &lhs
, &rhs
, &result
)) {
551 iter
.storeInstructionResult(result
);
555 bool MBigIntDiv::writeRecoverData(CompactBufferWriter
& writer
) const {
556 MOZ_ASSERT(canRecoverOnBailout());
557 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDiv
));
561 RBigIntDiv::RBigIntDiv(CompactBufferReader
& reader
) {}
563 bool RBigIntDiv::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
564 RootedValue
lhs(cx
, iter
.read());
565 RootedValue
rhs(cx
, iter
.read());
566 RootedValue
result(cx
);
568 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
569 MOZ_ASSERT(!rhs
.toBigInt()->isZero(),
570 "division by zero throws and therefore can't be recovered");
571 if (!js::DivValues(cx
, &lhs
, &rhs
, &result
)) {
575 iter
.storeInstructionResult(result
);
579 bool MBigIntMod::writeRecoverData(CompactBufferWriter
& writer
) const {
580 MOZ_ASSERT(canRecoverOnBailout());
581 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMod
));
585 RBigIntMod::RBigIntMod(CompactBufferReader
& reader
) {}
587 bool RBigIntMod::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
588 RootedValue
lhs(cx
, iter
.read());
589 RootedValue
rhs(cx
, iter
.read());
590 RootedValue
result(cx
);
592 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
593 MOZ_ASSERT(!rhs
.toBigInt()->isZero(),
594 "division by zero throws and therefore can't be recovered");
595 if (!js::ModValues(cx
, &lhs
, &rhs
, &result
)) {
599 iter
.storeInstructionResult(result
);
603 bool MBigIntPow::writeRecoverData(CompactBufferWriter
& writer
) const {
604 MOZ_ASSERT(canRecoverOnBailout());
605 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPow
));
609 RBigIntPow::RBigIntPow(CompactBufferReader
& reader
) {}
611 bool RBigIntPow::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
612 RootedValue
lhs(cx
, iter
.read());
613 RootedValue
rhs(cx
, iter
.read());
614 RootedValue
result(cx
);
616 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
617 MOZ_ASSERT(!rhs
.toBigInt()->isNegative(),
618 "negative exponent throws and therefore can't be recovered");
619 if (!js::PowValues(cx
, &lhs
, &rhs
, &result
)) {
623 iter
.storeInstructionResult(result
);
627 bool MBigIntBitAnd::writeRecoverData(CompactBufferWriter
& writer
) const {
628 MOZ_ASSERT(canRecoverOnBailout());
629 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitAnd
));
633 RBigIntBitAnd::RBigIntBitAnd(CompactBufferReader
& reader
) {}
635 bool RBigIntBitAnd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
636 RootedValue
lhs(cx
, iter
.read());
637 RootedValue
rhs(cx
, iter
.read());
638 RootedValue
result(cx
);
640 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
641 if (!js::BitAnd(cx
, &lhs
, &rhs
, &result
)) {
645 iter
.storeInstructionResult(result
);
649 bool MBigIntBitOr::writeRecoverData(CompactBufferWriter
& writer
) const {
650 MOZ_ASSERT(canRecoverOnBailout());
651 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitOr
));
655 RBigIntBitOr::RBigIntBitOr(CompactBufferReader
& reader
) {}
657 bool RBigIntBitOr::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
658 RootedValue
lhs(cx
, iter
.read());
659 RootedValue
rhs(cx
, iter
.read());
660 RootedValue
result(cx
);
662 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
663 if (!js::BitOr(cx
, &lhs
, &rhs
, &result
)) {
667 iter
.storeInstructionResult(result
);
671 bool MBigIntBitXor::writeRecoverData(CompactBufferWriter
& writer
) const {
672 MOZ_ASSERT(canRecoverOnBailout());
673 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitXor
));
677 RBigIntBitXor::RBigIntBitXor(CompactBufferReader
& reader
) {}
679 bool RBigIntBitXor::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
680 RootedValue
lhs(cx
, iter
.read());
681 RootedValue
rhs(cx
, iter
.read());
682 RootedValue
result(cx
);
684 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
685 if (!js::BitXor(cx
, &lhs
, &rhs
, &result
)) {
689 iter
.storeInstructionResult(result
);
693 bool MBigIntLsh::writeRecoverData(CompactBufferWriter
& writer
) const {
694 MOZ_ASSERT(canRecoverOnBailout());
695 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntLsh
));
699 RBigIntLsh::RBigIntLsh(CompactBufferReader
& reader
) {}
701 bool RBigIntLsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
702 RootedValue
lhs(cx
, iter
.read());
703 RootedValue
rhs(cx
, iter
.read());
704 RootedValue
result(cx
);
706 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
707 if (!js::BitLsh(cx
, &lhs
, &rhs
, &result
)) {
711 iter
.storeInstructionResult(result
);
715 bool MBigIntRsh::writeRecoverData(CompactBufferWriter
& writer
) const {
716 MOZ_ASSERT(canRecoverOnBailout());
717 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntRsh
));
721 RBigIntRsh::RBigIntRsh(CompactBufferReader
& reader
) {}
723 bool RBigIntRsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
724 RootedValue
lhs(cx
, iter
.read());
725 RootedValue
rhs(cx
, iter
.read());
726 RootedValue
result(cx
);
728 MOZ_ASSERT(lhs
.isBigInt() && rhs
.isBigInt());
729 if (!js::BitRsh(cx
, &lhs
, &rhs
, &result
)) {
733 iter
.storeInstructionResult(result
);
737 bool MBigIntIncrement::writeRecoverData(CompactBufferWriter
& writer
) const {
738 MOZ_ASSERT(canRecoverOnBailout());
739 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntIncrement
));
743 RBigIntIncrement::RBigIntIncrement(CompactBufferReader
& reader
) {}
745 bool RBigIntIncrement::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
746 RootedValue
operand(cx
, iter
.read());
747 RootedValue
result(cx
);
749 MOZ_ASSERT(operand
.isBigInt());
750 if (!js::IncOperation(cx
, operand
, &result
)) {
754 iter
.storeInstructionResult(result
);
758 bool MBigIntDecrement::writeRecoverData(CompactBufferWriter
& writer
) const {
759 MOZ_ASSERT(canRecoverOnBailout());
760 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDecrement
));
764 RBigIntDecrement::RBigIntDecrement(CompactBufferReader
& reader
) {}
766 bool RBigIntDecrement::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
767 RootedValue
operand(cx
, iter
.read());
768 RootedValue
result(cx
);
770 MOZ_ASSERT(operand
.isBigInt());
771 if (!js::DecOperation(cx
, operand
, &result
)) {
775 iter
.storeInstructionResult(result
);
779 bool MBigIntNegate::writeRecoverData(CompactBufferWriter
& writer
) const {
780 MOZ_ASSERT(canRecoverOnBailout());
781 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntNegate
));
785 RBigIntNegate::RBigIntNegate(CompactBufferReader
& reader
) {}
787 bool RBigIntNegate::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
788 RootedValue
operand(cx
, iter
.read());
789 RootedValue
result(cx
);
791 MOZ_ASSERT(operand
.isBigInt());
792 if (!js::NegOperation(cx
, &operand
, &result
)) {
796 iter
.storeInstructionResult(result
);
800 bool MBigIntBitNot::writeRecoverData(CompactBufferWriter
& writer
) const {
801 MOZ_ASSERT(canRecoverOnBailout());
802 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitNot
));
806 RBigIntBitNot::RBigIntBitNot(CompactBufferReader
& reader
) {}
808 bool RBigIntBitNot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
809 RootedValue
operand(cx
, iter
.read());
810 RootedValue
result(cx
);
812 MOZ_ASSERT(operand
.isBigInt());
813 if (!js::BitNot(cx
, &operand
, &result
)) {
817 iter
.storeInstructionResult(result
);
821 bool MCompare::writeRecoverData(CompactBufferWriter
& writer
) const {
822 MOZ_ASSERT(canRecoverOnBailout());
823 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Compare
));
825 static_assert(sizeof(JSOp
) == sizeof(uint8_t));
826 writer
.writeByte(uint8_t(jsop_
));
830 RCompare::RCompare(CompactBufferReader
& reader
) {
831 jsop_
= JSOp(reader
.readByte());
833 MOZ_ASSERT(IsEqualityOp(jsop_
) || IsRelationalOp(jsop_
));
836 bool RCompare::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
837 RootedValue
lhs(cx
, iter
.read());
838 RootedValue
rhs(cx
, iter
.read());
844 if (!js::LooselyEqual(cx
, lhs
, rhs
, &result
)) {
847 if (jsop_
== JSOp::Ne
) {
853 if (!StrictlyEqual(cx
, lhs
, rhs
, &result
)) {
856 if (jsop_
== JSOp::StrictNe
) {
861 if (!js::LessThan(cx
, &lhs
, &rhs
, &result
)) {
866 if (!js::LessThanOrEqual(cx
, &lhs
, &rhs
, &result
)) {
871 if (!js::GreaterThan(cx
, &lhs
, &rhs
, &result
)) {
876 if (!js::GreaterThanOrEqual(cx
, &lhs
, &rhs
, &result
)) {
881 MOZ_CRASH("Unexpected op.");
884 iter
.storeInstructionResult(BooleanValue(result
));
888 bool MConcat::writeRecoverData(CompactBufferWriter
& writer
) const {
889 MOZ_ASSERT(canRecoverOnBailout());
890 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Concat
));
894 RConcat::RConcat(CompactBufferReader
& reader
) {}
896 bool RConcat::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
897 RootedValue
lhs(cx
, iter
.read());
898 RootedValue
rhs(cx
, iter
.read());
899 RootedValue
result(cx
);
901 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
902 if (!js::AddValues(cx
, &lhs
, &rhs
, &result
)) {
906 iter
.storeInstructionResult(result
);
910 RStringLength::RStringLength(CompactBufferReader
& reader
) {}
912 bool RStringLength::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
913 JSString
* string
= iter
.read().toString();
915 static_assert(JSString::MAX_LENGTH
<= INT32_MAX
,
916 "Can cast string length to int32_t");
918 iter
.storeInstructionResult(Int32Value(int32_t(string
->length())));
922 bool MStringLength::writeRecoverData(CompactBufferWriter
& writer
) const {
923 MOZ_ASSERT(canRecoverOnBailout());
924 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringLength
));
928 bool MArgumentsLength::writeRecoverData(CompactBufferWriter
& writer
) const {
929 MOZ_ASSERT(canRecoverOnBailout());
930 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength
));
934 RArgumentsLength::RArgumentsLength(CompactBufferReader
& reader
) {}
936 bool RArgumentsLength::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
937 uintptr_t numActualArgs
= iter
.frame()->numActualArgs();
939 static_assert(ARGS_LENGTH_MAX
<= INT32_MAX
,
940 "Can cast arguments count to int32_t");
941 MOZ_ASSERT(numActualArgs
<= ARGS_LENGTH_MAX
);
943 iter
.storeInstructionResult(JS::Int32Value(int32_t(numActualArgs
)));
947 bool MFloor::writeRecoverData(CompactBufferWriter
& writer
) const {
948 MOZ_ASSERT(canRecoverOnBailout());
949 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
953 RFloor::RFloor(CompactBufferReader
& reader
) {}
955 bool RFloor::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
956 double num
= iter
.readNumber();
957 double result
= js::math_floor_impl(num
);
959 iter
.storeInstructionResult(NumberValue(result
));
963 bool MCeil::writeRecoverData(CompactBufferWriter
& writer
) const {
964 MOZ_ASSERT(canRecoverOnBailout());
965 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
969 RCeil::RCeil(CompactBufferReader
& reader
) {}
971 bool RCeil::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
972 double num
= iter
.readNumber();
973 double result
= js::math_ceil_impl(num
);
975 iter
.storeInstructionResult(NumberValue(result
));
979 bool MRound::writeRecoverData(CompactBufferWriter
& writer
) const {
980 MOZ_ASSERT(canRecoverOnBailout());
981 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Round
));
985 RRound::RRound(CompactBufferReader
& reader
) {}
987 bool RRound::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
988 double num
= iter
.readNumber();
989 double result
= js::math_round_impl(num
);
991 iter
.storeInstructionResult(NumberValue(result
));
995 bool MTrunc::writeRecoverData(CompactBufferWriter
& writer
) const {
996 MOZ_ASSERT(canRecoverOnBailout());
997 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
1001 RTrunc::RTrunc(CompactBufferReader
& reader
) {}
1003 bool RTrunc::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1004 double num
= iter
.readNumber();
1005 double result
= js::math_trunc_impl(num
);
1007 iter
.storeInstructionResult(NumberValue(result
));
1011 bool MCharCodeAt::writeRecoverData(CompactBufferWriter
& writer
) const {
1012 MOZ_ASSERT(canRecoverOnBailout());
1013 writer
.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt
));
1017 RCharCodeAt::RCharCodeAt(CompactBufferReader
& reader
) {}
1019 bool RCharCodeAt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1020 JSString
* string
= iter
.read().toString();
1022 // Int32 because |index| is computed from MBoundsCheck.
1023 int32_t index
= iter
.readInt32();
1024 MOZ_RELEASE_ASSERT(0 <= index
&& size_t(index
) < string
->length());
1027 if (!string
->getChar(cx
, index
, &c
)) {
1031 iter
.storeInstructionResult(Int32Value(c
));
1035 bool MFromCharCode::writeRecoverData(CompactBufferWriter
& writer
) const {
1036 MOZ_ASSERT(canRecoverOnBailout());
1037 writer
.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode
));
1041 RFromCharCode::RFromCharCode(CompactBufferReader
& reader
) {}
1043 bool RFromCharCode::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1044 // Number because |charCode| is computed from (recoverable) user input.
1045 int32_t charCode
= JS::ToInt32(iter
.readNumber());
1047 JSString
* str
= StringFromCharCode(cx
, charCode
);
1052 iter
.storeInstructionResult(StringValue(str
));
1056 bool MFromCharCodeEmptyIfNegative::writeRecoverData(
1057 CompactBufferWriter
& writer
) const {
1058 MOZ_ASSERT(canRecoverOnBailout());
1059 writer
.writeUnsigned(
1060 uint32_t(RInstruction::Recover_FromCharCodeEmptyIfNegative
));
1064 RFromCharCodeEmptyIfNegative::RFromCharCodeEmptyIfNegative(
1065 CompactBufferReader
& reader
) {}
1067 bool RFromCharCodeEmptyIfNegative::recover(JSContext
* cx
,
1068 SnapshotIterator
& iter
) const {
1069 // Int32 because |charCode| is computed from MCharCodeAtOrNegative.
1070 int32_t charCode
= iter
.readInt32();
1074 str
= cx
->emptyString();
1076 str
= StringFromCharCode(cx
, charCode
);
1082 iter
.storeInstructionResult(StringValue(str
));
1086 bool MPow::writeRecoverData(CompactBufferWriter
& writer
) const {
1087 MOZ_ASSERT(canRecoverOnBailout());
1088 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Pow
));
1092 RPow::RPow(CompactBufferReader
& reader
) {}
1094 bool RPow::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1095 double base
= iter
.readNumber();
1096 double power
= iter
.readNumber();
1097 double result
= ecmaPow(base
, power
);
1099 iter
.storeInstructionResult(NumberValue(result
));
1103 bool MPowHalf::writeRecoverData(CompactBufferWriter
& writer
) const {
1104 MOZ_ASSERT(canRecoverOnBailout());
1105 writer
.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf
));
1109 RPowHalf::RPowHalf(CompactBufferReader
& reader
) {}
1111 bool RPowHalf::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1112 double base
= iter
.readNumber();
1114 double result
= ecmaPow(base
, power
);
1116 iter
.storeInstructionResult(NumberValue(result
));
1120 bool MMinMax::writeRecoverData(CompactBufferWriter
& writer
) const {
1121 MOZ_ASSERT(canRecoverOnBailout());
1122 writer
.writeUnsigned(uint32_t(RInstruction::Recover_MinMax
));
1123 writer
.writeByte(isMax_
);
1127 RMinMax::RMinMax(CompactBufferReader
& reader
) { isMax_
= reader
.readByte(); }
1129 bool RMinMax::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1130 double x
= iter
.readNumber();
1131 double y
= iter
.readNumber();
1135 result
= js::math_max_impl(x
, y
);
1137 result
= js::math_min_impl(x
, y
);
1140 iter
.storeInstructionResult(NumberValue(result
));
1144 bool MAbs::writeRecoverData(CompactBufferWriter
& writer
) const {
1145 MOZ_ASSERT(canRecoverOnBailout());
1146 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Abs
));
1150 RAbs::RAbs(CompactBufferReader
& reader
) {}
1152 bool RAbs::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1153 double num
= iter
.readNumber();
1154 double result
= js::math_abs_impl(num
);
1156 iter
.storeInstructionResult(NumberValue(result
));
1160 bool MSqrt::writeRecoverData(CompactBufferWriter
& writer
) const {
1161 MOZ_ASSERT(canRecoverOnBailout());
1162 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt
));
1163 writer
.writeByte(type() == MIRType::Float32
);
1167 RSqrt::RSqrt(CompactBufferReader
& reader
) {
1168 isFloatOperation_
= reader
.readByte();
1171 bool RSqrt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1172 double num
= iter
.readNumber();
1173 double result
= js::math_sqrt_impl(num
);
1175 // MIRType::Float32 is a specialization embedding the fact that the result is
1176 // rounded to a Float32.
1177 if (isFloatOperation_
) {
1178 result
= js::RoundFloat32(result
);
1181 iter
.storeInstructionResult(DoubleValue(result
));
1185 bool MAtan2::writeRecoverData(CompactBufferWriter
& writer
) const {
1186 MOZ_ASSERT(canRecoverOnBailout());
1187 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Atan2
));
1191 RAtan2::RAtan2(CompactBufferReader
& reader
) {}
1193 bool RAtan2::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1194 double y
= iter
.readNumber();
1195 double x
= iter
.readNumber();
1196 double result
= js::ecmaAtan2(y
, x
);
1198 iter
.storeInstructionResult(DoubleValue(result
));
1202 bool MHypot::writeRecoverData(CompactBufferWriter
& writer
) const {
1203 MOZ_ASSERT(canRecoverOnBailout());
1204 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Hypot
));
1205 writer
.writeUnsigned(uint32_t(numOperands()));
1209 RHypot::RHypot(CompactBufferReader
& reader
)
1210 : numOperands_(reader
.readUnsigned()) {}
1212 bool RHypot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1213 JS::RootedValueVector
vec(cx
);
1215 if (!vec
.reserve(numOperands_
)) {
1219 for (uint32_t i
= 0; i
< numOperands_
; ++i
) {
1220 vec
.infallibleAppend(NumberValue(iter
.readNumber()));
1223 RootedValue
result(cx
);
1225 if (!js::math_hypot_handle(cx
, vec
, &result
)) {
1229 iter
.storeInstructionResult(result
);
1233 bool MNearbyInt::writeRecoverData(CompactBufferWriter
& writer
) const {
1234 MOZ_ASSERT(canRecoverOnBailout());
1235 switch (roundingMode_
) {
1236 case RoundingMode::Up
:
1237 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
1239 case RoundingMode::Down
:
1240 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
1242 case RoundingMode::TowardsZero
:
1243 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
1246 MOZ_CRASH("Unsupported rounding mode.");
1250 RNearbyInt::RNearbyInt(CompactBufferReader
& reader
) {
1251 roundingMode_
= reader
.readByte();
1254 bool RNearbyInt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1255 MOZ_CRASH("Unsupported rounding mode.");
1258 bool MSign::writeRecoverData(CompactBufferWriter
& writer
) const {
1259 MOZ_ASSERT(canRecoverOnBailout());
1260 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Sign
));
1264 RSign::RSign(CompactBufferReader
& reader
) {}
1266 bool RSign::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1267 double num
= iter
.readNumber();
1268 double result
= js::math_sign_impl(num
);
1270 iter
.storeInstructionResult(NumberValue(result
));
1274 bool MMathFunction::writeRecoverData(CompactBufferWriter
& writer
) const {
1275 MOZ_ASSERT(canRecoverOnBailout());
1276 switch (function_
) {
1277 case UnaryMathFunction::Ceil
:
1278 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
1280 case UnaryMathFunction::Floor
:
1281 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
1283 case UnaryMathFunction::Round
:
1284 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Round
));
1286 case UnaryMathFunction::Trunc
:
1287 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
1289 case UnaryMathFunction::SinNative
:
1290 case UnaryMathFunction::SinFdlibm
:
1291 case UnaryMathFunction::CosNative
:
1292 case UnaryMathFunction::CosFdlibm
:
1293 case UnaryMathFunction::TanNative
:
1294 case UnaryMathFunction::TanFdlibm
:
1295 case UnaryMathFunction::Log
:
1296 case UnaryMathFunction::Exp
:
1297 case UnaryMathFunction::ACos
:
1298 case UnaryMathFunction::ASin
:
1299 case UnaryMathFunction::ATan
:
1300 case UnaryMathFunction::Log10
:
1301 case UnaryMathFunction::Log2
:
1302 case UnaryMathFunction::Log1P
:
1303 case UnaryMathFunction::ExpM1
:
1304 case UnaryMathFunction::CosH
:
1305 case UnaryMathFunction::SinH
:
1306 case UnaryMathFunction::TanH
:
1307 case UnaryMathFunction::ACosH
:
1308 case UnaryMathFunction::ASinH
:
1309 case UnaryMathFunction::ATanH
:
1310 case UnaryMathFunction::Cbrt
:
1311 static_assert(sizeof(UnaryMathFunction
) == sizeof(uint8_t));
1312 writer
.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction
));
1313 writer
.writeByte(uint8_t(function_
));
1316 MOZ_CRASH("Unknown math function.");
1319 RMathFunction::RMathFunction(CompactBufferReader
& reader
) {
1320 function_
= UnaryMathFunction(reader
.readByte());
1323 bool RMathFunction::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1324 double num
= iter
.readNumber();
1327 switch (function_
) {
1328 case UnaryMathFunction::SinNative
:
1329 result
= js::math_sin_native_impl(num
);
1331 case UnaryMathFunction::SinFdlibm
:
1332 result
= js::math_sin_fdlibm_impl(num
);
1334 case UnaryMathFunction::CosNative
:
1335 result
= js::math_cos_native_impl(num
);
1337 case UnaryMathFunction::CosFdlibm
:
1338 result
= js::math_cos_fdlibm_impl(num
);
1340 case UnaryMathFunction::TanNative
:
1341 result
= js::math_tan_native_impl(num
);
1343 case UnaryMathFunction::TanFdlibm
:
1344 result
= js::math_tan_fdlibm_impl(num
);
1346 case UnaryMathFunction::Log
:
1347 result
= js::math_log_impl(num
);
1349 case UnaryMathFunction::Exp
:
1350 result
= js::math_exp_impl(num
);
1352 case UnaryMathFunction::ACos
:
1353 result
= js::math_acos_impl(num
);
1355 case UnaryMathFunction::ASin
:
1356 result
= js::math_asin_impl(num
);
1358 case UnaryMathFunction::ATan
:
1359 result
= js::math_atan_impl(num
);
1361 case UnaryMathFunction::Log10
:
1362 result
= js::math_log10_impl(num
);
1364 case UnaryMathFunction::Log2
:
1365 result
= js::math_log2_impl(num
);
1367 case UnaryMathFunction::Log1P
:
1368 result
= js::math_log1p_impl(num
);
1370 case UnaryMathFunction::ExpM1
:
1371 result
= js::math_expm1_impl(num
);
1373 case UnaryMathFunction::CosH
:
1374 result
= js::math_cosh_impl(num
);
1376 case UnaryMathFunction::SinH
:
1377 result
= js::math_sinh_impl(num
);
1379 case UnaryMathFunction::TanH
:
1380 result
= js::math_tanh_impl(num
);
1382 case UnaryMathFunction::ACosH
:
1383 result
= js::math_acosh_impl(num
);
1385 case UnaryMathFunction::ASinH
:
1386 result
= js::math_asinh_impl(num
);
1388 case UnaryMathFunction::ATanH
:
1389 result
= js::math_atanh_impl(num
);
1391 case UnaryMathFunction::Cbrt
:
1392 result
= js::math_cbrt_impl(num
);
1395 case UnaryMathFunction::Trunc
:
1396 case UnaryMathFunction::Floor
:
1397 case UnaryMathFunction::Ceil
:
1398 case UnaryMathFunction::Round
:
1399 // These have their own recover instructions.
1400 MOZ_CRASH("Unexpected rounding math function.");
1403 iter
.storeInstructionResult(DoubleValue(result
));
1407 bool MRandom::writeRecoverData(CompactBufferWriter
& writer
) const {
1408 MOZ_ASSERT(this->canRecoverOnBailout());
1409 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Random
));
1413 bool MRandom::canRecoverOnBailout() const {
1414 return !js::SupportDifferentialTesting();
1417 RRandom::RRandom(CompactBufferReader
& reader
) {}
1419 bool RRandom::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1420 iter
.storeInstructionResult(DoubleValue(math_random_impl(cx
)));
1424 bool MStringSplit::writeRecoverData(CompactBufferWriter
& writer
) const {
1425 MOZ_ASSERT(canRecoverOnBailout());
1426 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit
));
1430 RStringSplit::RStringSplit(CompactBufferReader
& reader
) {}
1432 bool RStringSplit::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1433 RootedString
str(cx
, iter
.read().toString());
1434 RootedString
sep(cx
, iter
.read().toString());
1436 JSObject
* res
= StringSplitString(cx
, str
, sep
, INT32_MAX
);
1441 iter
.storeInstructionResult(ObjectValue(*res
));
1445 bool MNaNToZero::writeRecoverData(CompactBufferWriter
& writer
) const {
1446 MOZ_ASSERT(canRecoverOnBailout());
1447 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero
));
1451 RNaNToZero::RNaNToZero(CompactBufferReader
& reader
) {}
1453 bool RNaNToZero::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1454 double v
= iter
.readNumber();
1455 if (std::isnan(v
) || mozilla::IsNegativeZero(v
)) {
1459 iter
.storeInstructionResult(DoubleValue(v
));
1463 bool MRegExpMatcher::writeRecoverData(CompactBufferWriter
& writer
) const {
1464 MOZ_ASSERT(canRecoverOnBailout());
1465 writer
.writeUnsigned(uint32_t(RInstruction::Recover_RegExpMatcher
));
1469 RRegExpMatcher::RRegExpMatcher(CompactBufferReader
& reader
) {}
1471 bool RRegExpMatcher::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1472 RootedObject
regexp(cx
, &iter
.read().toObject());
1473 RootedString
input(cx
, iter
.read().toString());
1475 // Int32 because |lastIndex| is computed from transpiled self-hosted call.
1476 int32_t lastIndex
= iter
.readInt32();
1478 RootedValue
result(cx
);
1479 if (!RegExpMatcherRaw(cx
, regexp
, input
, lastIndex
, nullptr, &result
)) {
1483 iter
.storeInstructionResult(result
);
1487 bool MTypeOf::writeRecoverData(CompactBufferWriter
& writer
) const {
1488 MOZ_ASSERT(canRecoverOnBailout());
1489 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf
));
1493 RTypeOf::RTypeOf(CompactBufferReader
& reader
) {}
1495 bool RTypeOf::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1496 JS::Value v
= iter
.read();
1498 iter
.storeInstructionResult(Int32Value(TypeOfValue(v
)));
1502 bool MTypeOfName::writeRecoverData(CompactBufferWriter
& writer
) const {
1503 MOZ_ASSERT(canRecoverOnBailout());
1504 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TypeOfName
));
1508 RTypeOfName::RTypeOfName(CompactBufferReader
& reader
) {}
1510 bool RTypeOfName::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1511 // Int32 because |type| is computed from MTypeOf.
1512 int32_t type
= iter
.readInt32();
1513 MOZ_ASSERT(JSTYPE_UNDEFINED
<= type
&& type
< JSTYPE_LIMIT
);
1515 JSString
* name
= TypeName(JSType(type
), *cx
->runtime()->commonNames
);
1516 iter
.storeInstructionResult(StringValue(name
));
1520 bool MToDouble::writeRecoverData(CompactBufferWriter
& writer
) const {
1521 MOZ_ASSERT(canRecoverOnBailout());
1522 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble
));
1526 RToDouble::RToDouble(CompactBufferReader
& reader
) {}
1528 bool RToDouble::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1529 RootedValue
v(cx
, iter
.read());
1531 MOZ_ASSERT(!v
.isObject());
1532 MOZ_ASSERT(!v
.isSymbol());
1533 MOZ_ASSERT(!v
.isBigInt());
1536 if (!ToNumber(cx
, v
, &dbl
)) {
1540 iter
.storeInstructionResult(DoubleValue(dbl
));
1544 bool MToFloat32::writeRecoverData(CompactBufferWriter
& writer
) const {
1545 MOZ_ASSERT(canRecoverOnBailout());
1546 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32
));
1550 RToFloat32::RToFloat32(CompactBufferReader
& reader
) {}
1552 bool RToFloat32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1553 double num
= iter
.readNumber();
1554 double result
= js::RoundFloat32(num
);
1556 iter
.storeInstructionResult(DoubleValue(result
));
1560 bool MTruncateToInt32::writeRecoverData(CompactBufferWriter
& writer
) const {
1561 MOZ_ASSERT(canRecoverOnBailout());
1562 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32
));
1566 RTruncateToInt32::RTruncateToInt32(CompactBufferReader
& reader
) {}
1568 bool RTruncateToInt32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1569 RootedValue
value(cx
, iter
.read());
1572 if (!JS::ToInt32(cx
, value
, &trunc
)) {
1576 iter
.storeInstructionResult(Int32Value(trunc
));
1580 bool MNewObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1581 MOZ_ASSERT(canRecoverOnBailout());
1583 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewObject
));
1585 // Recover instructions are only supported if we have a template object.
1586 MOZ_ASSERT(mode_
== MNewObject::ObjectCreate
);
1590 RNewObject::RNewObject(CompactBufferReader
& reader
) {}
1592 bool RNewObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1593 RootedObject
templateObject(cx
, &iter
.read().toObject());
1595 // See CodeGenerator::visitNewObjectVMCall.
1596 // Note that recover instructions are only used if mode == ObjectCreate.
1597 JSObject
* resultObject
=
1598 ObjectCreateWithTemplate(cx
, templateObject
.as
<PlainObject
>());
1599 if (!resultObject
) {
1603 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1607 bool MNewPlainObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1608 MOZ_ASSERT(canRecoverOnBailout());
1609 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewPlainObject
));
1611 MOZ_ASSERT(gc::AllocKind(uint8_t(allocKind_
)) == allocKind_
);
1612 writer
.writeByte(uint8_t(allocKind_
));
1613 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_
)) == initialHeap_
);
1614 writer
.writeByte(uint8_t(initialHeap_
));
1618 RNewPlainObject::RNewPlainObject(CompactBufferReader
& reader
) {
1619 allocKind_
= gc::AllocKind(reader
.readByte());
1620 MOZ_ASSERT(gc::IsValidAllocKind(allocKind_
));
1621 initialHeap_
= gc::Heap(reader
.readByte());
1622 MOZ_ASSERT(initialHeap_
== gc::Heap::Default
||
1623 initialHeap_
== gc::Heap::Tenured
);
1626 bool RNewPlainObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1627 Rooted
<SharedShape
*> shape(cx
,
1628 &iter
.read().toGCCellPtr().as
<Shape
>().asShared());
1630 // See CodeGenerator::visitNewPlainObject.
1631 JSObject
* resultObject
=
1632 NewPlainObjectOptimizedFallback(cx
, shape
, allocKind_
, initialHeap_
);
1633 if (!resultObject
) {
1637 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1641 bool MNewArrayObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1642 MOZ_ASSERT(canRecoverOnBailout());
1643 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayObject
));
1645 writer
.writeUnsigned(length_
);
1646 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_
)) == initialHeap_
);
1647 writer
.writeByte(uint8_t(initialHeap_
));
1651 RNewArrayObject::RNewArrayObject(CompactBufferReader
& reader
) {
1652 length_
= reader
.readUnsigned();
1653 initialHeap_
= gc::Heap(reader
.readByte());
1654 MOZ_ASSERT(initialHeap_
== gc::Heap::Default
||
1655 initialHeap_
== gc::Heap::Tenured
);
1658 bool RNewArrayObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1659 iter
.read(); // Skip unused shape field.
1661 NewObjectKind kind
=
1662 initialHeap_
== gc::Heap::Tenured
? TenuredObject
: GenericObject
;
1663 JSObject
* array
= NewArrayOperation(cx
, length_
, kind
);
1668 iter
.storeInstructionResult(ObjectValue(*array
));
1672 bool MNewTypedArray::writeRecoverData(CompactBufferWriter
& writer
) const {
1673 MOZ_ASSERT(canRecoverOnBailout());
1674 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray
));
1678 RNewTypedArray::RNewTypedArray(CompactBufferReader
& reader
) {}
1680 bool RNewTypedArray::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1681 RootedObject
templateObject(cx
, &iter
.read().toObject());
1683 size_t length
= templateObject
.as
<FixedLengthTypedArrayObject
>()->length();
1684 MOZ_ASSERT(length
<= INT32_MAX
,
1685 "Template objects are only created for int32 lengths");
1687 JSObject
* resultObject
=
1688 NewTypedArrayWithTemplateAndLength(cx
, templateObject
, length
);
1689 if (!resultObject
) {
1693 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1697 bool MNewArray::writeRecoverData(CompactBufferWriter
& writer
) const {
1698 MOZ_ASSERT(canRecoverOnBailout());
1699 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewArray
));
1700 writer
.writeUnsigned(length());
1704 RNewArray::RNewArray(CompactBufferReader
& reader
) {
1705 count_
= reader
.readUnsigned();
1708 bool RNewArray::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1709 RootedObject
templateObject(cx
, &iter
.read().toObject());
1710 Rooted
<Shape
*> shape(cx
, templateObject
->shape());
1712 ArrayObject
* resultObject
= NewArrayWithShape(cx
, count_
, shape
);
1713 if (!resultObject
) {
1717 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1721 bool MNewIterator::writeRecoverData(CompactBufferWriter
& writer
) const {
1722 MOZ_ASSERT(canRecoverOnBailout());
1723 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator
));
1724 writer
.writeByte(type_
);
1728 RNewIterator::RNewIterator(CompactBufferReader
& reader
) {
1729 type_
= reader
.readByte();
1732 bool RNewIterator::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1733 RootedObject
templateObject(cx
, &iter
.read().toObject());
1735 JSObject
* resultObject
= nullptr;
1736 switch (MNewIterator::Type(type_
)) {
1737 case MNewIterator::ArrayIterator
:
1738 resultObject
= NewArrayIterator(cx
);
1740 case MNewIterator::StringIterator
:
1741 resultObject
= NewStringIterator(cx
);
1743 case MNewIterator::RegExpStringIterator
:
1744 resultObject
= NewRegExpStringIterator(cx
);
1748 if (!resultObject
) {
1752 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1756 bool MLambda::writeRecoverData(CompactBufferWriter
& writer
) const {
1757 MOZ_ASSERT(canRecoverOnBailout());
1758 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Lambda
));
1762 RLambda::RLambda(CompactBufferReader
& reader
) {}
1764 bool RLambda::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1765 RootedObject
scopeChain(cx
, &iter
.read().toObject());
1766 RootedFunction
fun(cx
, &iter
.read().toObject().as
<JSFunction
>());
1768 JSObject
* resultObject
= js::Lambda(cx
, fun
, scopeChain
);
1769 if (!resultObject
) {
1773 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1777 bool MFunctionWithProto::writeRecoverData(CompactBufferWriter
& writer
) const {
1778 MOZ_ASSERT(canRecoverOnBailout());
1779 writer
.writeUnsigned(uint32_t(RInstruction::Recover_FunctionWithProto
));
1783 RFunctionWithProto::RFunctionWithProto(CompactBufferReader
& reader
) {}
1785 bool RFunctionWithProto::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1786 RootedObject
scopeChain(cx
, &iter
.read().toObject());
1787 RootedObject
prototype(cx
, &iter
.read().toObject());
1788 RootedFunction
fun(cx
, &iter
.read().toObject().as
<JSFunction
>());
1790 JSObject
* resultObject
=
1791 js::FunWithProtoOperation(cx
, fun
, scopeChain
, prototype
);
1792 if (!resultObject
) {
1796 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1800 bool MNewCallObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1801 MOZ_ASSERT(canRecoverOnBailout());
1802 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewCallObject
));
1806 RNewCallObject::RNewCallObject(CompactBufferReader
& reader
) {}
1808 bool RNewCallObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1809 Rooted
<CallObject
*> templateObj(cx
, &iter
.read().toObject().as
<CallObject
>());
1811 Rooted
<SharedShape
*> shape(cx
, templateObj
->sharedShape());
1813 JSObject
* resultObject
= CallObject::createWithShape(cx
, shape
);
1814 if (!resultObject
) {
1818 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1822 bool MObjectKeys::canRecoverOnBailout() const {
1823 // Only claim that this operation can be recovered on bailout if some other
1824 // optimization already marked it as such.
1825 return isRecoveredOnBailout();
1828 bool MObjectKeys::writeRecoverData(CompactBufferWriter
& writer
) const {
1829 MOZ_ASSERT(canRecoverOnBailout());
1830 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ObjectKeys
));
1834 RObjectKeys::RObjectKeys(CompactBufferReader
& reader
) {}
1836 bool RObjectKeys::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1837 Rooted
<JSObject
*> obj(cx
, &iter
.read().toObject());
1839 JSObject
* resultKeys
= ObjectKeys(cx
, obj
);
1844 iter
.storeInstructionResult(ObjectValue(*resultKeys
));
1848 bool MObjectState::writeRecoverData(CompactBufferWriter
& writer
) const {
1849 MOZ_ASSERT(canRecoverOnBailout());
1850 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState
));
1851 writer
.writeUnsigned(numSlots());
1855 RObjectState::RObjectState(CompactBufferReader
& reader
) {
1856 numSlots_
= reader
.readUnsigned();
1859 bool RObjectState::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1860 RootedObject
object(cx
, &iter
.read().toObject());
1861 Handle
<NativeObject
*> nativeObject
= object
.as
<NativeObject
>();
1862 MOZ_ASSERT(!Watchtower::watchesPropertyModification(nativeObject
));
1863 MOZ_ASSERT(nativeObject
->slotSpan() == numSlots());
1865 for (size_t i
= 0; i
< numSlots(); i
++) {
1866 Value val
= iter
.read();
1867 nativeObject
->setSlot(i
, val
);
1870 iter
.storeInstructionResult(ObjectValue(*object
));
1874 bool MArrayState::writeRecoverData(CompactBufferWriter
& writer
) const {
1875 MOZ_ASSERT(canRecoverOnBailout());
1876 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState
));
1877 writer
.writeUnsigned(numElements());
1881 RArrayState::RArrayState(CompactBufferReader
& reader
) {
1882 numElements_
= reader
.readUnsigned();
1885 bool RArrayState::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1886 ArrayObject
* object
= &iter
.read().toObject().as
<ArrayObject
>();
1888 // Int32 because |initLength| is computed from MConstant.
1889 uint32_t initLength
= iter
.readInt32();
1891 MOZ_ASSERT(object
->getDenseInitializedLength() == 0,
1892 "initDenseElement call below relies on this");
1893 object
->setDenseInitializedLength(initLength
);
1895 for (size_t index
= 0; index
< numElements(); index
++) {
1896 Value val
= iter
.read();
1898 if (index
>= initLength
) {
1899 MOZ_ASSERT(val
.isUndefined());
1903 object
->initDenseElement(index
, val
);
1906 iter
.storeInstructionResult(ObjectValue(*object
));
1910 bool MSetArrayLength::writeRecoverData(CompactBufferWriter
& writer
) const {
1911 MOZ_ASSERT(canRecoverOnBailout());
1912 // For simplicity, we capture directly the object instead of the elements
1914 MOZ_ASSERT(elements()->type() != MIRType::Elements
);
1915 writer
.writeUnsigned(uint32_t(RInstruction::Recover_SetArrayLength
));
1919 bool MSetArrayLength::canRecoverOnBailout() const {
1920 return isRecoveredOnBailout();
1923 RSetArrayLength::RSetArrayLength(CompactBufferReader
& reader
) {}
1925 bool RSetArrayLength::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1926 Rooted
<ArrayObject
*> obj(cx
, &iter
.read().toObject().as
<ArrayObject
>());
1927 RootedValue
len(cx
, iter
.read());
1929 RootedId
id(cx
, NameToId(cx
->names().length
));
1930 Rooted
<PropertyDescriptor
> desc(
1931 cx
, PropertyDescriptor::Data(len
, JS::PropertyAttribute::Writable
));
1932 ObjectOpResult error
;
1933 if (!ArraySetLength(cx
, obj
, id
, desc
, error
)) {
1937 iter
.storeInstructionResult(ObjectValue(*obj
));
1941 bool MAssertRecoveredOnBailout::writeRecoverData(
1942 CompactBufferWriter
& writer
) const {
1943 MOZ_ASSERT(canRecoverOnBailout());
1944 MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout() == mustBeRecovered_
,
1945 "assertRecoveredOnBailout failed during compilation");
1946 writer
.writeUnsigned(
1947 uint32_t(RInstruction::Recover_AssertRecoveredOnBailout
));
1951 RAssertRecoveredOnBailout::RAssertRecoveredOnBailout(
1952 CompactBufferReader
& reader
) {}
1954 bool RAssertRecoveredOnBailout::recover(JSContext
* cx
,
1955 SnapshotIterator
& iter
) const {
1956 iter
.read(); // skip the unused operand.
1957 iter
.storeInstructionResult(UndefinedValue());
1961 bool MStringReplace::writeRecoverData(CompactBufferWriter
& writer
) const {
1962 MOZ_ASSERT(canRecoverOnBailout());
1963 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace
));
1964 writer
.writeByte(isFlatReplacement_
);
1968 RStringReplace::RStringReplace(CompactBufferReader
& reader
) {
1969 isFlatReplacement_
= reader
.readByte();
1972 bool RStringReplace::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1973 RootedString
string(cx
, iter
.read().toString());
1974 RootedString
pattern(cx
, iter
.read().toString());
1975 RootedString
replace(cx
, iter
.read().toString());
1979 ? js::StringFlatReplaceString(cx
, string
, pattern
, replace
)
1980 : js::str_replace_string_raw(cx
, string
, pattern
, replace
);
1986 iter
.storeInstructionResult(StringValue(result
));
1990 bool MSubstr::writeRecoverData(CompactBufferWriter
& writer
) const {
1991 MOZ_ASSERT(canRecoverOnBailout());
1992 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Substr
));
1996 RSubstr::RSubstr(CompactBufferReader
& reader
) {}
1998 bool RSubstr::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1999 RootedString
str(cx
, iter
.read().toString());
2002 // Int32 because |begin| is computed from MStringTrimStartIndex, MConstant,
2003 // or CallSubstringKernelResult.
2004 int32_t begin
= iter
.readInt32();
2006 // Int32 because |length| is computed from MSub(truncated),
2007 // MStringTrimEndIndex, or CallSubstringKernelResult.
2008 int32_t length
= iter
.readInt32();
2010 JSString
* result
= SubstringKernel(cx
, str
, begin
, length
);
2015 iter
.storeInstructionResult(StringValue(result
));
2019 bool MAtomicIsLockFree::writeRecoverData(CompactBufferWriter
& writer
) const {
2020 MOZ_ASSERT(canRecoverOnBailout());
2021 writer
.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree
));
2025 RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader
& reader
) {}
2027 bool RAtomicIsLockFree::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2028 double dsize
= JS::ToInteger(iter
.readNumber());
2031 bool result
= mozilla::NumberEqualsInt32(dsize
, &size
) &&
2032 AtomicOperations::isLockfreeJS(size
);
2033 iter
.storeInstructionResult(BooleanValue(result
));
2037 bool MBigIntAsIntN::writeRecoverData(CompactBufferWriter
& writer
) const {
2038 MOZ_ASSERT(canRecoverOnBailout());
2039 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsIntN
));
2043 RBigIntAsIntN::RBigIntAsIntN(CompactBufferReader
& reader
) {}
2045 bool RBigIntAsIntN::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2046 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2047 int32_t bits
= iter
.readInt32();
2048 MOZ_ASSERT(bits
>= 0);
2050 RootedBigInt
input(cx
, iter
.read().toBigInt());
2052 BigInt
* result
= BigInt::asIntN(cx
, input
, bits
);
2057 iter
.storeInstructionResult(JS::BigIntValue(result
));
2061 bool MBigIntAsUintN::writeRecoverData(CompactBufferWriter
& writer
) const {
2062 MOZ_ASSERT(canRecoverOnBailout());
2063 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsUintN
));
2067 RBigIntAsUintN::RBigIntAsUintN(CompactBufferReader
& reader
) {}
2069 bool RBigIntAsUintN::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2070 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2071 int32_t bits
= iter
.readInt32();
2072 MOZ_ASSERT(bits
>= 0);
2074 RootedBigInt
input(cx
, iter
.read().toBigInt());
2076 BigInt
* result
= BigInt::asUintN(cx
, input
, bits
);
2081 iter
.storeInstructionResult(JS::BigIntValue(result
));
2085 bool MCreateArgumentsObject::writeRecoverData(
2086 CompactBufferWriter
& writer
) const {
2087 MOZ_ASSERT(canRecoverOnBailout());
2088 writer
.writeUnsigned(uint32_t(RInstruction::Recover_CreateArgumentsObject
));
2092 RCreateArgumentsObject::RCreateArgumentsObject(CompactBufferReader
& reader
) {}
2094 bool RCreateArgumentsObject::recover(JSContext
* cx
,
2095 SnapshotIterator
& iter
) const {
2096 RootedObject
callObject(cx
, &iter
.read().toObject());
2097 RootedObject
result(
2098 cx
, ArgumentsObject::createForIon(cx
, iter
.frame(), callObject
));
2103 iter
.storeInstructionResult(JS::ObjectValue(*result
));
2107 bool MCreateInlinedArgumentsObject::writeRecoverData(
2108 CompactBufferWriter
& writer
) const {
2109 MOZ_ASSERT(canRecoverOnBailout());
2110 writer
.writeUnsigned(
2111 uint32_t(RInstruction::Recover_CreateInlinedArgumentsObject
));
2112 writer
.writeUnsigned(numActuals());
2116 RCreateInlinedArgumentsObject::RCreateInlinedArgumentsObject(
2117 CompactBufferReader
& reader
) {
2118 numActuals_
= reader
.readUnsigned();
2121 bool RCreateInlinedArgumentsObject::recover(JSContext
* cx
,
2122 SnapshotIterator
& iter
) const {
2123 RootedObject
callObject(cx
, &iter
.read().toObject());
2124 RootedFunction
callee(cx
, &iter
.read().toObject().as
<JSFunction
>());
2126 JS::RootedValueArray
<ArgumentsObject::MaxInlinedArgs
> argsArray(cx
);
2127 for (uint32_t i
= 0; i
< numActuals_
; i
++) {
2128 argsArray
[i
].set(iter
.read());
2131 ArgumentsObject
* result
= ArgumentsObject::createFromValueArray(
2132 cx
, argsArray
, callee
, callObject
, numActuals_
);
2137 iter
.storeInstructionResult(JS::ObjectValue(*result
));
2141 bool MRest::writeRecoverData(CompactBufferWriter
& writer
) const {
2142 MOZ_ASSERT(canRecoverOnBailout());
2143 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Rest
));
2144 writer
.writeUnsigned(numFormals());
2148 RRest::RRest(CompactBufferReader
& reader
) {
2149 numFormals_
= reader
.readUnsigned();
2152 bool RRest::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2153 JitFrameLayout
* frame
= iter
.frame();
2155 // Int32 because |numActuals| is computed from MArgumentsLength.
2156 uint32_t numActuals
= iter
.readInt32();
2157 MOZ_ASSERT(numActuals
== frame
->numActualArgs());
2159 uint32_t numFormals
= numFormals_
;
2161 uint32_t length
= std::max(numActuals
, numFormals
) - numFormals
;
2162 Value
* src
= frame
->actualArgs() + numFormals
;
2163 JSObject
* rest
= jit::InitRestParameter(cx
, length
, src
, nullptr);
2168 iter
.storeInstructionResult(ObjectValue(*rest
));