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 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
499 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
501 BigInt
* result
= BigInt::add(cx
, lhs
, rhs
);
506 iter
.storeInstructionResult(BigIntValue(result
));
510 bool MBigIntSub::writeRecoverData(CompactBufferWriter
& writer
) const {
511 MOZ_ASSERT(canRecoverOnBailout());
512 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntSub
));
516 RBigIntSub::RBigIntSub(CompactBufferReader
& reader
) {}
518 bool RBigIntSub::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
519 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
520 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
522 BigInt
* result
= BigInt::sub(cx
, lhs
, rhs
);
527 iter
.storeInstructionResult(BigIntValue(result
));
531 bool MBigIntMul::writeRecoverData(CompactBufferWriter
& writer
) const {
532 MOZ_ASSERT(canRecoverOnBailout());
533 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMul
));
537 RBigIntMul::RBigIntMul(CompactBufferReader
& reader
) {}
539 bool RBigIntMul::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
540 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
541 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
543 BigInt
* result
= BigInt::mul(cx
, lhs
, rhs
);
548 iter
.storeInstructionResult(BigIntValue(result
));
552 bool MBigIntDiv::writeRecoverData(CompactBufferWriter
& writer
) const {
553 MOZ_ASSERT(canRecoverOnBailout());
554 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDiv
));
558 RBigIntDiv::RBigIntDiv(CompactBufferReader
& reader
) {}
560 bool RBigIntDiv::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
561 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
562 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
563 MOZ_ASSERT(!rhs
->isZero(),
564 "division by zero throws and therefore can't be recovered");
566 BigInt
* result
= BigInt::div(cx
, lhs
, rhs
);
571 iter
.storeInstructionResult(BigIntValue(result
));
575 bool MBigIntMod::writeRecoverData(CompactBufferWriter
& writer
) const {
576 MOZ_ASSERT(canRecoverOnBailout());
577 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMod
));
581 RBigIntMod::RBigIntMod(CompactBufferReader
& reader
) {}
583 bool RBigIntMod::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
584 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
585 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
586 MOZ_ASSERT(!rhs
->isZero(),
587 "division by zero throws and therefore can't be recovered");
589 BigInt
* result
= BigInt::mod(cx
, lhs
, rhs
);
594 iter
.storeInstructionResult(BigIntValue(result
));
598 bool MBigIntPow::writeRecoverData(CompactBufferWriter
& writer
) const {
599 MOZ_ASSERT(canRecoverOnBailout());
600 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPow
));
604 RBigIntPow::RBigIntPow(CompactBufferReader
& reader
) {}
606 bool RBigIntPow::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
607 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
608 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
609 MOZ_ASSERT(!rhs
->isNegative(),
610 "negative exponent throws and therefore can't be recovered");
612 BigInt
* result
= BigInt::pow(cx
, lhs
, rhs
);
617 iter
.storeInstructionResult(BigIntValue(result
));
621 bool MBigIntBitAnd::writeRecoverData(CompactBufferWriter
& writer
) const {
622 MOZ_ASSERT(canRecoverOnBailout());
623 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitAnd
));
627 RBigIntBitAnd::RBigIntBitAnd(CompactBufferReader
& reader
) {}
629 bool RBigIntBitAnd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
630 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
631 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
633 BigInt
* result
= BigInt::bitAnd(cx
, lhs
, rhs
);
638 iter
.storeInstructionResult(BigIntValue(result
));
642 bool MBigIntBitOr::writeRecoverData(CompactBufferWriter
& writer
) const {
643 MOZ_ASSERT(canRecoverOnBailout());
644 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitOr
));
648 RBigIntBitOr::RBigIntBitOr(CompactBufferReader
& reader
) {}
650 bool RBigIntBitOr::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
651 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
652 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
654 BigInt
* result
= BigInt::bitOr(cx
, lhs
, rhs
);
659 iter
.storeInstructionResult(BigIntValue(result
));
663 bool MBigIntBitXor::writeRecoverData(CompactBufferWriter
& writer
) const {
664 MOZ_ASSERT(canRecoverOnBailout());
665 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitXor
));
669 RBigIntBitXor::RBigIntBitXor(CompactBufferReader
& reader
) {}
671 bool RBigIntBitXor::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
672 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
673 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
675 BigInt
* result
= BigInt::bitXor(cx
, lhs
, rhs
);
680 iter
.storeInstructionResult(BigIntValue(result
));
684 bool MBigIntLsh::writeRecoverData(CompactBufferWriter
& writer
) const {
685 MOZ_ASSERT(canRecoverOnBailout());
686 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntLsh
));
690 RBigIntLsh::RBigIntLsh(CompactBufferReader
& reader
) {}
692 bool RBigIntLsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
693 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
694 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
696 BigInt
* result
= BigInt::lsh(cx
, lhs
, rhs
);
701 iter
.storeInstructionResult(BigIntValue(result
));
705 bool MBigIntRsh::writeRecoverData(CompactBufferWriter
& writer
) const {
706 MOZ_ASSERT(canRecoverOnBailout());
707 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntRsh
));
711 RBigIntRsh::RBigIntRsh(CompactBufferReader
& reader
) {}
713 bool RBigIntRsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
714 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
715 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
717 BigInt
* result
= BigInt::rsh(cx
, lhs
, rhs
);
722 iter
.storeInstructionResult(BigIntValue(result
));
726 bool MBigIntIncrement::writeRecoverData(CompactBufferWriter
& writer
) const {
727 MOZ_ASSERT(canRecoverOnBailout());
728 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntIncrement
));
732 RBigIntIncrement::RBigIntIncrement(CompactBufferReader
& reader
) {}
734 bool RBigIntIncrement::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
735 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
737 BigInt
* result
= BigInt::inc(cx
, operand
);
742 iter
.storeInstructionResult(BigIntValue(result
));
746 bool MBigIntDecrement::writeRecoverData(CompactBufferWriter
& writer
) const {
747 MOZ_ASSERT(canRecoverOnBailout());
748 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDecrement
));
752 RBigIntDecrement::RBigIntDecrement(CompactBufferReader
& reader
) {}
754 bool RBigIntDecrement::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
755 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
757 BigInt
* result
= BigInt::dec(cx
, operand
);
762 iter
.storeInstructionResult(BigIntValue(result
));
766 bool MBigIntNegate::writeRecoverData(CompactBufferWriter
& writer
) const {
767 MOZ_ASSERT(canRecoverOnBailout());
768 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntNegate
));
772 RBigIntNegate::RBigIntNegate(CompactBufferReader
& reader
) {}
774 bool RBigIntNegate::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
775 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
777 BigInt
* result
= BigInt::neg(cx
, operand
);
782 iter
.storeInstructionResult(BigIntValue(result
));
786 bool MBigIntBitNot::writeRecoverData(CompactBufferWriter
& writer
) const {
787 MOZ_ASSERT(canRecoverOnBailout());
788 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitNot
));
792 RBigIntBitNot::RBigIntBitNot(CompactBufferReader
& reader
) {}
794 bool RBigIntBitNot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
795 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
797 BigInt
* result
= BigInt::bitNot(cx
, operand
);
802 iter
.storeInstructionResult(BigIntValue(result
));
806 bool MCompare::writeRecoverData(CompactBufferWriter
& writer
) const {
807 MOZ_ASSERT(canRecoverOnBailout());
808 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Compare
));
810 static_assert(sizeof(JSOp
) == sizeof(uint8_t));
811 writer
.writeByte(uint8_t(jsop_
));
815 RCompare::RCompare(CompactBufferReader
& reader
) {
816 jsop_
= JSOp(reader
.readByte());
818 MOZ_ASSERT(IsEqualityOp(jsop_
) || IsRelationalOp(jsop_
));
821 bool RCompare::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
822 RootedValue
lhs(cx
, iter
.read());
823 RootedValue
rhs(cx
, iter
.read());
829 if (!js::LooselyEqual(cx
, lhs
, rhs
, &result
)) {
832 if (jsop_
== JSOp::Ne
) {
838 if (!StrictlyEqual(cx
, lhs
, rhs
, &result
)) {
841 if (jsop_
== JSOp::StrictNe
) {
846 if (!js::LessThan(cx
, &lhs
, &rhs
, &result
)) {
851 if (!js::LessThanOrEqual(cx
, &lhs
, &rhs
, &result
)) {
856 if (!js::GreaterThan(cx
, &lhs
, &rhs
, &result
)) {
861 if (!js::GreaterThanOrEqual(cx
, &lhs
, &rhs
, &result
)) {
866 MOZ_CRASH("Unexpected op.");
869 iter
.storeInstructionResult(BooleanValue(result
));
873 bool MConcat::writeRecoverData(CompactBufferWriter
& writer
) const {
874 MOZ_ASSERT(canRecoverOnBailout());
875 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Concat
));
879 RConcat::RConcat(CompactBufferReader
& reader
) {}
881 bool RConcat::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
882 RootedValue
lhs(cx
, iter
.read());
883 RootedValue
rhs(cx
, iter
.read());
884 RootedValue
result(cx
);
886 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
887 if (!js::AddValues(cx
, &lhs
, &rhs
, &result
)) {
891 iter
.storeInstructionResult(result
);
895 RStringLength::RStringLength(CompactBufferReader
& reader
) {}
897 bool RStringLength::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
898 JSString
* string
= iter
.readString();
900 static_assert(JSString::MAX_LENGTH
<= INT32_MAX
,
901 "Can cast string length to int32_t");
903 iter
.storeInstructionResult(Int32Value(int32_t(string
->length())));
907 bool MStringLength::writeRecoverData(CompactBufferWriter
& writer
) const {
908 MOZ_ASSERT(canRecoverOnBailout());
909 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringLength
));
913 bool MArgumentsLength::writeRecoverData(CompactBufferWriter
& writer
) const {
914 MOZ_ASSERT(canRecoverOnBailout());
915 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength
));
919 RArgumentsLength::RArgumentsLength(CompactBufferReader
& reader
) {}
921 bool RArgumentsLength::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
922 uintptr_t numActualArgs
= iter
.frame()->numActualArgs();
924 static_assert(ARGS_LENGTH_MAX
<= INT32_MAX
,
925 "Can cast arguments count to int32_t");
926 MOZ_ASSERT(numActualArgs
<= ARGS_LENGTH_MAX
);
928 iter
.storeInstructionResult(JS::Int32Value(int32_t(numActualArgs
)));
932 bool MFloor::writeRecoverData(CompactBufferWriter
& writer
) const {
933 MOZ_ASSERT(canRecoverOnBailout());
934 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
938 RFloor::RFloor(CompactBufferReader
& reader
) {}
940 bool RFloor::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
941 double num
= iter
.readNumber();
942 double result
= js::math_floor_impl(num
);
944 iter
.storeInstructionResult(NumberValue(result
));
948 bool MCeil::writeRecoverData(CompactBufferWriter
& writer
) const {
949 MOZ_ASSERT(canRecoverOnBailout());
950 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
954 RCeil::RCeil(CompactBufferReader
& reader
) {}
956 bool RCeil::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
957 double num
= iter
.readNumber();
958 double result
= js::math_ceil_impl(num
);
960 iter
.storeInstructionResult(NumberValue(result
));
964 bool MRound::writeRecoverData(CompactBufferWriter
& writer
) const {
965 MOZ_ASSERT(canRecoverOnBailout());
966 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Round
));
970 RRound::RRound(CompactBufferReader
& reader
) {}
972 bool RRound::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
973 double num
= iter
.readNumber();
974 double result
= js::math_round_impl(num
);
976 iter
.storeInstructionResult(NumberValue(result
));
980 bool MTrunc::writeRecoverData(CompactBufferWriter
& writer
) const {
981 MOZ_ASSERT(canRecoverOnBailout());
982 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
986 RTrunc::RTrunc(CompactBufferReader
& reader
) {}
988 bool RTrunc::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
989 double num
= iter
.readNumber();
990 double result
= js::math_trunc_impl(num
);
992 iter
.storeInstructionResult(NumberValue(result
));
996 bool MCharCodeAt::writeRecoverData(CompactBufferWriter
& writer
) const {
997 MOZ_ASSERT(canRecoverOnBailout());
998 writer
.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt
));
1002 RCharCodeAt::RCharCodeAt(CompactBufferReader
& reader
) {}
1004 bool RCharCodeAt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1005 JSString
* string
= iter
.readString();
1007 // Int32 because |index| is computed from MBoundsCheck.
1008 int32_t index
= iter
.readInt32();
1009 MOZ_RELEASE_ASSERT(0 <= index
&& size_t(index
) < string
->length());
1012 if (!string
->getChar(cx
, index
, &c
)) {
1016 iter
.storeInstructionResult(Int32Value(c
));
1020 bool MFromCharCode::writeRecoverData(CompactBufferWriter
& writer
) const {
1021 MOZ_ASSERT(canRecoverOnBailout());
1022 writer
.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode
));
1026 RFromCharCode::RFromCharCode(CompactBufferReader
& reader
) {}
1028 bool RFromCharCode::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1029 // Number because |charCode| is computed from (recoverable) user input.
1030 int32_t charCode
= JS::ToInt32(iter
.readNumber());
1032 JSString
* str
= StringFromCharCode(cx
, charCode
);
1037 iter
.storeInstructionResult(StringValue(str
));
1041 bool MFromCharCodeEmptyIfNegative::writeRecoverData(
1042 CompactBufferWriter
& writer
) const {
1043 MOZ_ASSERT(canRecoverOnBailout());
1044 writer
.writeUnsigned(
1045 uint32_t(RInstruction::Recover_FromCharCodeEmptyIfNegative
));
1049 RFromCharCodeEmptyIfNegative::RFromCharCodeEmptyIfNegative(
1050 CompactBufferReader
& reader
) {}
1052 bool RFromCharCodeEmptyIfNegative::recover(JSContext
* cx
,
1053 SnapshotIterator
& iter
) const {
1054 // Int32 because |charCode| is computed from MCharCodeAtOrNegative.
1055 int32_t charCode
= iter
.readInt32();
1059 str
= cx
->emptyString();
1061 str
= StringFromCharCode(cx
, charCode
);
1067 iter
.storeInstructionResult(StringValue(str
));
1071 bool MPow::writeRecoverData(CompactBufferWriter
& writer
) const {
1072 MOZ_ASSERT(canRecoverOnBailout());
1073 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Pow
));
1077 RPow::RPow(CompactBufferReader
& reader
) {}
1079 bool RPow::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1080 double base
= iter
.readNumber();
1081 double power
= iter
.readNumber();
1082 double result
= ecmaPow(base
, power
);
1084 iter
.storeInstructionResult(NumberValue(result
));
1088 bool MPowHalf::writeRecoverData(CompactBufferWriter
& writer
) const {
1089 MOZ_ASSERT(canRecoverOnBailout());
1090 writer
.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf
));
1094 RPowHalf::RPowHalf(CompactBufferReader
& reader
) {}
1096 bool RPowHalf::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1097 double base
= iter
.readNumber();
1099 double result
= ecmaPow(base
, power
);
1101 iter
.storeInstructionResult(NumberValue(result
));
1105 bool MMinMax::writeRecoverData(CompactBufferWriter
& writer
) const {
1106 MOZ_ASSERT(canRecoverOnBailout());
1107 writer
.writeUnsigned(uint32_t(RInstruction::Recover_MinMax
));
1108 writer
.writeByte(isMax_
);
1112 RMinMax::RMinMax(CompactBufferReader
& reader
) { isMax_
= reader
.readByte(); }
1114 bool RMinMax::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1115 double x
= iter
.readNumber();
1116 double y
= iter
.readNumber();
1120 result
= js::math_max_impl(x
, y
);
1122 result
= js::math_min_impl(x
, y
);
1125 iter
.storeInstructionResult(NumberValue(result
));
1129 bool MAbs::writeRecoverData(CompactBufferWriter
& writer
) const {
1130 MOZ_ASSERT(canRecoverOnBailout());
1131 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Abs
));
1135 RAbs::RAbs(CompactBufferReader
& reader
) {}
1137 bool RAbs::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1138 double num
= iter
.readNumber();
1139 double result
= js::math_abs_impl(num
);
1141 iter
.storeInstructionResult(NumberValue(result
));
1145 bool MSqrt::writeRecoverData(CompactBufferWriter
& writer
) const {
1146 MOZ_ASSERT(canRecoverOnBailout());
1147 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt
));
1148 writer
.writeByte(type() == MIRType::Float32
);
1152 RSqrt::RSqrt(CompactBufferReader
& reader
) {
1153 isFloatOperation_
= reader
.readByte();
1156 bool RSqrt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1157 double num
= iter
.readNumber();
1158 double result
= js::math_sqrt_impl(num
);
1160 // MIRType::Float32 is a specialization embedding the fact that the result is
1161 // rounded to a Float32.
1162 if (isFloatOperation_
) {
1163 result
= js::RoundFloat32(result
);
1166 iter
.storeInstructionResult(DoubleValue(result
));
1170 bool MAtan2::writeRecoverData(CompactBufferWriter
& writer
) const {
1171 MOZ_ASSERT(canRecoverOnBailout());
1172 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Atan2
));
1176 RAtan2::RAtan2(CompactBufferReader
& reader
) {}
1178 bool RAtan2::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1179 double y
= iter
.readNumber();
1180 double x
= iter
.readNumber();
1181 double result
= js::ecmaAtan2(y
, x
);
1183 iter
.storeInstructionResult(DoubleValue(result
));
1187 bool MHypot::writeRecoverData(CompactBufferWriter
& writer
) const {
1188 MOZ_ASSERT(canRecoverOnBailout());
1189 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Hypot
));
1190 writer
.writeUnsigned(uint32_t(numOperands()));
1194 RHypot::RHypot(CompactBufferReader
& reader
)
1195 : numOperands_(reader
.readUnsigned()) {}
1197 bool RHypot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1198 JS::RootedValueVector
vec(cx
);
1200 if (!vec
.reserve(numOperands_
)) {
1204 for (uint32_t i
= 0; i
< numOperands_
; ++i
) {
1205 vec
.infallibleAppend(NumberValue(iter
.readNumber()));
1208 RootedValue
result(cx
);
1210 if (!js::math_hypot_handle(cx
, vec
, &result
)) {
1214 iter
.storeInstructionResult(result
);
1218 bool MNearbyInt::writeRecoverData(CompactBufferWriter
& writer
) const {
1219 MOZ_ASSERT(canRecoverOnBailout());
1220 switch (roundingMode_
) {
1221 case RoundingMode::Up
:
1222 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
1224 case RoundingMode::Down
:
1225 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
1227 case RoundingMode::TowardsZero
:
1228 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
1231 MOZ_CRASH("Unsupported rounding mode.");
1235 RNearbyInt::RNearbyInt(CompactBufferReader
& reader
) {
1236 roundingMode_
= reader
.readByte();
1239 bool RNearbyInt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1240 MOZ_CRASH("Unsupported rounding mode.");
1243 bool MSign::writeRecoverData(CompactBufferWriter
& writer
) const {
1244 MOZ_ASSERT(canRecoverOnBailout());
1245 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Sign
));
1249 RSign::RSign(CompactBufferReader
& reader
) {}
1251 bool RSign::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1252 double num
= iter
.readNumber();
1253 double result
= js::math_sign_impl(num
);
1255 iter
.storeInstructionResult(NumberValue(result
));
1259 bool MMathFunction::writeRecoverData(CompactBufferWriter
& writer
) const {
1260 MOZ_ASSERT(canRecoverOnBailout());
1261 switch (function_
) {
1262 case UnaryMathFunction::Ceil
:
1263 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
1265 case UnaryMathFunction::Floor
:
1266 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
1268 case UnaryMathFunction::Round
:
1269 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Round
));
1271 case UnaryMathFunction::Trunc
:
1272 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
1274 case UnaryMathFunction::SinNative
:
1275 case UnaryMathFunction::SinFdlibm
:
1276 case UnaryMathFunction::CosNative
:
1277 case UnaryMathFunction::CosFdlibm
:
1278 case UnaryMathFunction::TanNative
:
1279 case UnaryMathFunction::TanFdlibm
:
1280 case UnaryMathFunction::Log
:
1281 case UnaryMathFunction::Exp
:
1282 case UnaryMathFunction::ACos
:
1283 case UnaryMathFunction::ASin
:
1284 case UnaryMathFunction::ATan
:
1285 case UnaryMathFunction::Log10
:
1286 case UnaryMathFunction::Log2
:
1287 case UnaryMathFunction::Log1P
:
1288 case UnaryMathFunction::ExpM1
:
1289 case UnaryMathFunction::CosH
:
1290 case UnaryMathFunction::SinH
:
1291 case UnaryMathFunction::TanH
:
1292 case UnaryMathFunction::ACosH
:
1293 case UnaryMathFunction::ASinH
:
1294 case UnaryMathFunction::ATanH
:
1295 case UnaryMathFunction::Cbrt
:
1296 static_assert(sizeof(UnaryMathFunction
) == sizeof(uint8_t));
1297 writer
.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction
));
1298 writer
.writeByte(uint8_t(function_
));
1301 MOZ_CRASH("Unknown math function.");
1304 RMathFunction::RMathFunction(CompactBufferReader
& reader
) {
1305 function_
= UnaryMathFunction(reader
.readByte());
1308 bool RMathFunction::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1309 double num
= iter
.readNumber();
1312 switch (function_
) {
1313 case UnaryMathFunction::SinNative
:
1314 result
= js::math_sin_native_impl(num
);
1316 case UnaryMathFunction::SinFdlibm
:
1317 result
= js::math_sin_fdlibm_impl(num
);
1319 case UnaryMathFunction::CosNative
:
1320 result
= js::math_cos_native_impl(num
);
1322 case UnaryMathFunction::CosFdlibm
:
1323 result
= js::math_cos_fdlibm_impl(num
);
1325 case UnaryMathFunction::TanNative
:
1326 result
= js::math_tan_native_impl(num
);
1328 case UnaryMathFunction::TanFdlibm
:
1329 result
= js::math_tan_fdlibm_impl(num
);
1331 case UnaryMathFunction::Log
:
1332 result
= js::math_log_impl(num
);
1334 case UnaryMathFunction::Exp
:
1335 result
= js::math_exp_impl(num
);
1337 case UnaryMathFunction::ACos
:
1338 result
= js::math_acos_impl(num
);
1340 case UnaryMathFunction::ASin
:
1341 result
= js::math_asin_impl(num
);
1343 case UnaryMathFunction::ATan
:
1344 result
= js::math_atan_impl(num
);
1346 case UnaryMathFunction::Log10
:
1347 result
= js::math_log10_impl(num
);
1349 case UnaryMathFunction::Log2
:
1350 result
= js::math_log2_impl(num
);
1352 case UnaryMathFunction::Log1P
:
1353 result
= js::math_log1p_impl(num
);
1355 case UnaryMathFunction::ExpM1
:
1356 result
= js::math_expm1_impl(num
);
1358 case UnaryMathFunction::CosH
:
1359 result
= js::math_cosh_impl(num
);
1361 case UnaryMathFunction::SinH
:
1362 result
= js::math_sinh_impl(num
);
1364 case UnaryMathFunction::TanH
:
1365 result
= js::math_tanh_impl(num
);
1367 case UnaryMathFunction::ACosH
:
1368 result
= js::math_acosh_impl(num
);
1370 case UnaryMathFunction::ASinH
:
1371 result
= js::math_asinh_impl(num
);
1373 case UnaryMathFunction::ATanH
:
1374 result
= js::math_atanh_impl(num
);
1376 case UnaryMathFunction::Cbrt
:
1377 result
= js::math_cbrt_impl(num
);
1380 case UnaryMathFunction::Trunc
:
1381 case UnaryMathFunction::Floor
:
1382 case UnaryMathFunction::Ceil
:
1383 case UnaryMathFunction::Round
:
1384 // These have their own recover instructions.
1385 MOZ_CRASH("Unexpected rounding math function.");
1388 iter
.storeInstructionResult(DoubleValue(result
));
1392 bool MRandom::writeRecoverData(CompactBufferWriter
& writer
) const {
1393 MOZ_ASSERT(this->canRecoverOnBailout());
1394 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Random
));
1398 bool MRandom::canRecoverOnBailout() const {
1399 return !js::SupportDifferentialTesting();
1402 RRandom::RRandom(CompactBufferReader
& reader
) {}
1404 bool RRandom::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1405 iter
.storeInstructionResult(DoubleValue(math_random_impl(cx
)));
1409 bool MStringSplit::writeRecoverData(CompactBufferWriter
& writer
) const {
1410 MOZ_ASSERT(canRecoverOnBailout());
1411 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit
));
1415 RStringSplit::RStringSplit(CompactBufferReader
& reader
) {}
1417 bool RStringSplit::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1418 RootedString
str(cx
, iter
.readString());
1419 RootedString
sep(cx
, iter
.readString());
1421 JSObject
* res
= StringSplitString(cx
, str
, sep
, INT32_MAX
);
1426 iter
.storeInstructionResult(ObjectValue(*res
));
1430 bool MNaNToZero::writeRecoverData(CompactBufferWriter
& writer
) const {
1431 MOZ_ASSERT(canRecoverOnBailout());
1432 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero
));
1436 RNaNToZero::RNaNToZero(CompactBufferReader
& reader
) {}
1438 bool RNaNToZero::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1439 double v
= iter
.readNumber();
1440 if (std::isnan(v
) || mozilla::IsNegativeZero(v
)) {
1444 iter
.storeInstructionResult(DoubleValue(v
));
1448 bool MRegExpMatcher::writeRecoverData(CompactBufferWriter
& writer
) const {
1449 MOZ_ASSERT(canRecoverOnBailout());
1450 writer
.writeUnsigned(uint32_t(RInstruction::Recover_RegExpMatcher
));
1454 RRegExpMatcher::RRegExpMatcher(CompactBufferReader
& reader
) {}
1456 bool RRegExpMatcher::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1457 RootedObject
regexp(cx
, iter
.readObject());
1458 RootedString
input(cx
, iter
.readString());
1460 // Int32 because |lastIndex| is computed from transpiled self-hosted call.
1461 int32_t lastIndex
= iter
.readInt32();
1463 RootedValue
result(cx
);
1464 if (!RegExpMatcherRaw(cx
, regexp
, input
, lastIndex
, nullptr, &result
)) {
1468 iter
.storeInstructionResult(result
);
1472 bool MTypeOf::writeRecoverData(CompactBufferWriter
& writer
) const {
1473 MOZ_ASSERT(canRecoverOnBailout());
1474 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf
));
1478 RTypeOf::RTypeOf(CompactBufferReader
& reader
) {}
1480 bool RTypeOf::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1481 JS::Value v
= iter
.read();
1483 iter
.storeInstructionResult(Int32Value(TypeOfValue(v
)));
1487 bool MTypeOfName::writeRecoverData(CompactBufferWriter
& writer
) const {
1488 MOZ_ASSERT(canRecoverOnBailout());
1489 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TypeOfName
));
1493 RTypeOfName::RTypeOfName(CompactBufferReader
& reader
) {}
1495 bool RTypeOfName::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1496 // Int32 because |type| is computed from MTypeOf.
1497 int32_t type
= iter
.readInt32();
1498 MOZ_ASSERT(JSTYPE_UNDEFINED
<= type
&& type
< JSTYPE_LIMIT
);
1500 JSString
* name
= TypeName(JSType(type
), *cx
->runtime()->commonNames
);
1501 iter
.storeInstructionResult(StringValue(name
));
1505 bool MToDouble::writeRecoverData(CompactBufferWriter
& writer
) const {
1506 MOZ_ASSERT(canRecoverOnBailout());
1507 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble
));
1511 RToDouble::RToDouble(CompactBufferReader
& reader
) {}
1513 bool RToDouble::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1514 RootedValue
v(cx
, iter
.read());
1516 MOZ_ASSERT(!v
.isObject());
1517 MOZ_ASSERT(!v
.isSymbol());
1518 MOZ_ASSERT(!v
.isBigInt());
1521 if (!ToNumber(cx
, v
, &dbl
)) {
1525 iter
.storeInstructionResult(DoubleValue(dbl
));
1529 bool MToFloat32::writeRecoverData(CompactBufferWriter
& writer
) const {
1530 MOZ_ASSERT(canRecoverOnBailout());
1531 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32
));
1535 RToFloat32::RToFloat32(CompactBufferReader
& reader
) {}
1537 bool RToFloat32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1538 double num
= iter
.readNumber();
1539 double result
= js::RoundFloat32(num
);
1541 iter
.storeInstructionResult(DoubleValue(result
));
1545 bool MTruncateToInt32::writeRecoverData(CompactBufferWriter
& writer
) const {
1546 MOZ_ASSERT(canRecoverOnBailout());
1547 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32
));
1551 RTruncateToInt32::RTruncateToInt32(CompactBufferReader
& reader
) {}
1553 bool RTruncateToInt32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1554 RootedValue
value(cx
, iter
.read());
1557 if (!JS::ToInt32(cx
, value
, &trunc
)) {
1561 iter
.storeInstructionResult(Int32Value(trunc
));
1565 bool MNewObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1566 MOZ_ASSERT(canRecoverOnBailout());
1568 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewObject
));
1570 // Recover instructions are only supported if we have a template object.
1571 MOZ_ASSERT(mode_
== MNewObject::ObjectCreate
);
1575 RNewObject::RNewObject(CompactBufferReader
& reader
) {}
1577 bool RNewObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1578 RootedObject
templateObject(cx
, iter
.readObject());
1580 // See CodeGenerator::visitNewObjectVMCall.
1581 // Note that recover instructions are only used if mode == ObjectCreate.
1582 JSObject
* resultObject
=
1583 ObjectCreateWithTemplate(cx
, templateObject
.as
<PlainObject
>());
1584 if (!resultObject
) {
1588 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1592 bool MNewPlainObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1593 MOZ_ASSERT(canRecoverOnBailout());
1594 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewPlainObject
));
1596 MOZ_ASSERT(gc::AllocKind(uint8_t(allocKind_
)) == allocKind_
);
1597 writer
.writeByte(uint8_t(allocKind_
));
1598 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_
)) == initialHeap_
);
1599 writer
.writeByte(uint8_t(initialHeap_
));
1603 RNewPlainObject::RNewPlainObject(CompactBufferReader
& reader
) {
1604 allocKind_
= gc::AllocKind(reader
.readByte());
1605 MOZ_ASSERT(gc::IsValidAllocKind(allocKind_
));
1606 initialHeap_
= gc::Heap(reader
.readByte());
1607 MOZ_ASSERT(initialHeap_
== gc::Heap::Default
||
1608 initialHeap_
== gc::Heap::Tenured
);
1611 bool RNewPlainObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1612 Rooted
<SharedShape
*> shape(cx
, &iter
.readGCCellPtr().as
<Shape
>().asShared());
1614 // See CodeGenerator::visitNewPlainObject.
1615 JSObject
* resultObject
=
1616 NewPlainObjectOptimizedFallback(cx
, shape
, allocKind_
, initialHeap_
);
1617 if (!resultObject
) {
1621 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1625 bool MNewArrayObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1626 MOZ_ASSERT(canRecoverOnBailout());
1627 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayObject
));
1629 writer
.writeUnsigned(length_
);
1630 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_
)) == initialHeap_
);
1631 writer
.writeByte(uint8_t(initialHeap_
));
1635 RNewArrayObject::RNewArrayObject(CompactBufferReader
& reader
) {
1636 length_
= reader
.readUnsigned();
1637 initialHeap_
= gc::Heap(reader
.readByte());
1638 MOZ_ASSERT(initialHeap_
== gc::Heap::Default
||
1639 initialHeap_
== gc::Heap::Tenured
);
1642 bool RNewArrayObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1643 iter
.read(); // Skip unused shape field.
1645 NewObjectKind kind
=
1646 initialHeap_
== gc::Heap::Tenured
? TenuredObject
: GenericObject
;
1647 JSObject
* array
= NewArrayOperation(cx
, length_
, kind
);
1652 iter
.storeInstructionResult(ObjectValue(*array
));
1656 bool MNewTypedArray::writeRecoverData(CompactBufferWriter
& writer
) const {
1657 MOZ_ASSERT(canRecoverOnBailout());
1658 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray
));
1662 RNewTypedArray::RNewTypedArray(CompactBufferReader
& reader
) {}
1664 bool RNewTypedArray::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1665 RootedObject
templateObject(cx
, iter
.readObject());
1667 size_t length
= templateObject
.as
<FixedLengthTypedArrayObject
>()->length();
1668 MOZ_ASSERT(length
<= INT32_MAX
,
1669 "Template objects are only created for int32 lengths");
1671 JSObject
* resultObject
=
1672 NewTypedArrayWithTemplateAndLength(cx
, templateObject
, length
);
1673 if (!resultObject
) {
1677 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1681 bool MNewArray::writeRecoverData(CompactBufferWriter
& writer
) const {
1682 MOZ_ASSERT(canRecoverOnBailout());
1683 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewArray
));
1684 writer
.writeUnsigned(length());
1688 RNewArray::RNewArray(CompactBufferReader
& reader
) {
1689 count_
= reader
.readUnsigned();
1692 bool RNewArray::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1693 RootedObject
templateObject(cx
, iter
.readObject());
1694 Rooted
<Shape
*> shape(cx
, templateObject
->shape());
1696 ArrayObject
* resultObject
= NewArrayWithShape(cx
, count_
, shape
);
1697 if (!resultObject
) {
1701 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1705 bool MNewIterator::writeRecoverData(CompactBufferWriter
& writer
) const {
1706 MOZ_ASSERT(canRecoverOnBailout());
1707 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator
));
1708 writer
.writeByte(type_
);
1712 RNewIterator::RNewIterator(CompactBufferReader
& reader
) {
1713 type_
= reader
.readByte();
1716 bool RNewIterator::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1717 RootedObject
templateObject(cx
, iter
.readObject());
1719 JSObject
* resultObject
= nullptr;
1720 switch (MNewIterator::Type(type_
)) {
1721 case MNewIterator::ArrayIterator
:
1722 resultObject
= NewArrayIterator(cx
);
1724 case MNewIterator::StringIterator
:
1725 resultObject
= NewStringIterator(cx
);
1727 case MNewIterator::RegExpStringIterator
:
1728 resultObject
= NewRegExpStringIterator(cx
);
1732 if (!resultObject
) {
1736 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1740 bool MLambda::writeRecoverData(CompactBufferWriter
& writer
) const {
1741 MOZ_ASSERT(canRecoverOnBailout());
1742 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Lambda
));
1746 RLambda::RLambda(CompactBufferReader
& reader
) {}
1748 bool RLambda::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1749 RootedObject
scopeChain(cx
, iter
.readObject());
1750 RootedFunction
fun(cx
, &iter
.readObject()->as
<JSFunction
>());
1752 JSObject
* resultObject
= js::Lambda(cx
, fun
, scopeChain
);
1753 if (!resultObject
) {
1757 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1761 bool MFunctionWithProto::writeRecoverData(CompactBufferWriter
& writer
) const {
1762 MOZ_ASSERT(canRecoverOnBailout());
1763 writer
.writeUnsigned(uint32_t(RInstruction::Recover_FunctionWithProto
));
1767 RFunctionWithProto::RFunctionWithProto(CompactBufferReader
& reader
) {}
1769 bool RFunctionWithProto::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1770 RootedObject
scopeChain(cx
, iter
.readObject());
1771 RootedObject
prototype(cx
, iter
.readObject());
1772 RootedFunction
fun(cx
, &iter
.readObject()->as
<JSFunction
>());
1774 JSObject
* resultObject
=
1775 js::FunWithProtoOperation(cx
, fun
, scopeChain
, prototype
);
1776 if (!resultObject
) {
1780 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1784 bool MNewCallObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1785 MOZ_ASSERT(canRecoverOnBailout());
1786 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewCallObject
));
1790 RNewCallObject::RNewCallObject(CompactBufferReader
& reader
) {}
1792 bool RNewCallObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1793 Rooted
<CallObject
*> templateObj(cx
, &iter
.readObject()->as
<CallObject
>());
1795 Rooted
<SharedShape
*> shape(cx
, templateObj
->sharedShape());
1797 JSObject
* resultObject
= CallObject::createWithShape(cx
, shape
);
1798 if (!resultObject
) {
1802 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1806 bool MObjectKeys::canRecoverOnBailout() const {
1807 // Only claim that this operation can be recovered on bailout if some other
1808 // optimization already marked it as such.
1809 return isRecoveredOnBailout();
1812 bool MObjectKeys::writeRecoverData(CompactBufferWriter
& writer
) const {
1813 MOZ_ASSERT(canRecoverOnBailout());
1814 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ObjectKeys
));
1818 RObjectKeys::RObjectKeys(CompactBufferReader
& reader
) {}
1820 bool RObjectKeys::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1821 Rooted
<JSObject
*> obj(cx
, iter
.readObject());
1823 JSObject
* resultKeys
= ObjectKeys(cx
, obj
);
1828 iter
.storeInstructionResult(ObjectValue(*resultKeys
));
1832 bool MObjectState::writeRecoverData(CompactBufferWriter
& writer
) const {
1833 MOZ_ASSERT(canRecoverOnBailout());
1834 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState
));
1835 writer
.writeUnsigned(numSlots());
1839 RObjectState::RObjectState(CompactBufferReader
& reader
) {
1840 numSlots_
= reader
.readUnsigned();
1843 bool RObjectState::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1844 RootedObject
object(cx
, iter
.readObject());
1845 Handle
<NativeObject
*> nativeObject
= object
.as
<NativeObject
>();
1846 MOZ_ASSERT(!Watchtower::watchesPropertyModification(nativeObject
));
1847 MOZ_ASSERT(nativeObject
->slotSpan() == numSlots());
1849 for (size_t i
= 0; i
< numSlots(); i
++) {
1850 Value val
= iter
.read();
1851 nativeObject
->setSlot(i
, val
);
1854 iter
.storeInstructionResult(ObjectValue(*object
));
1858 bool MArrayState::writeRecoverData(CompactBufferWriter
& writer
) const {
1859 MOZ_ASSERT(canRecoverOnBailout());
1860 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState
));
1861 writer
.writeUnsigned(numElements());
1865 RArrayState::RArrayState(CompactBufferReader
& reader
) {
1866 numElements_
= reader
.readUnsigned();
1869 bool RArrayState::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1870 ArrayObject
* object
= &iter
.readObject()->as
<ArrayObject
>();
1872 // Int32 because |initLength| is computed from MConstant.
1873 uint32_t initLength
= iter
.readInt32();
1875 MOZ_ASSERT(object
->getDenseInitializedLength() == 0,
1876 "initDenseElement call below relies on this");
1877 object
->setDenseInitializedLength(initLength
);
1879 for (size_t index
= 0; index
< numElements(); index
++) {
1880 Value val
= iter
.read();
1882 if (index
>= initLength
) {
1883 MOZ_ASSERT(val
.isUndefined());
1887 object
->initDenseElement(index
, val
);
1890 iter
.storeInstructionResult(ObjectValue(*object
));
1894 bool MSetArrayLength::writeRecoverData(CompactBufferWriter
& writer
) const {
1895 MOZ_ASSERT(canRecoverOnBailout());
1896 // For simplicity, we capture directly the object instead of the elements
1898 MOZ_ASSERT(elements()->type() != MIRType::Elements
);
1899 writer
.writeUnsigned(uint32_t(RInstruction::Recover_SetArrayLength
));
1903 bool MSetArrayLength::canRecoverOnBailout() const {
1904 return isRecoveredOnBailout();
1907 RSetArrayLength::RSetArrayLength(CompactBufferReader
& reader
) {}
1909 bool RSetArrayLength::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1910 Rooted
<ArrayObject
*> obj(cx
, &iter
.readObject()->as
<ArrayObject
>());
1911 RootedValue
len(cx
, iter
.read());
1913 RootedId
id(cx
, NameToId(cx
->names().length
));
1914 Rooted
<PropertyDescriptor
> desc(
1915 cx
, PropertyDescriptor::Data(len
, JS::PropertyAttribute::Writable
));
1916 ObjectOpResult error
;
1917 if (!ArraySetLength(cx
, obj
, id
, desc
, error
)) {
1921 iter
.storeInstructionResult(ObjectValue(*obj
));
1925 bool MAssertRecoveredOnBailout::writeRecoverData(
1926 CompactBufferWriter
& writer
) const {
1927 MOZ_ASSERT(canRecoverOnBailout());
1928 MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout() == mustBeRecovered_
,
1929 "assertRecoveredOnBailout failed during compilation");
1930 writer
.writeUnsigned(
1931 uint32_t(RInstruction::Recover_AssertRecoveredOnBailout
));
1935 RAssertRecoveredOnBailout::RAssertRecoveredOnBailout(
1936 CompactBufferReader
& reader
) {}
1938 bool RAssertRecoveredOnBailout::recover(JSContext
* cx
,
1939 SnapshotIterator
& iter
) const {
1940 iter
.read(); // skip the unused operand.
1941 iter
.storeInstructionResult(UndefinedValue());
1945 bool MStringReplace::writeRecoverData(CompactBufferWriter
& writer
) const {
1946 MOZ_ASSERT(canRecoverOnBailout());
1947 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace
));
1948 writer
.writeByte(isFlatReplacement_
);
1952 RStringReplace::RStringReplace(CompactBufferReader
& reader
) {
1953 isFlatReplacement_
= reader
.readByte();
1956 bool RStringReplace::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1957 RootedString
string(cx
, iter
.readString());
1958 RootedString
pattern(cx
, iter
.readString());
1959 RootedString
replace(cx
, iter
.readString());
1963 ? js::StringFlatReplaceString(cx
, string
, pattern
, replace
)
1964 : js::str_replace_string_raw(cx
, string
, pattern
, replace
);
1970 iter
.storeInstructionResult(StringValue(result
));
1974 bool MSubstr::writeRecoverData(CompactBufferWriter
& writer
) const {
1975 MOZ_ASSERT(canRecoverOnBailout());
1976 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Substr
));
1980 RSubstr::RSubstr(CompactBufferReader
& reader
) {}
1982 bool RSubstr::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1983 RootedString
str(cx
, iter
.readString());
1985 // Int32 because |begin| is computed from MStringTrimStartIndex, MConstant,
1986 // or CallSubstringKernelResult.
1987 int32_t begin
= iter
.readInt32();
1989 // Int32 because |length| is computed from MSub(truncated),
1990 // MStringTrimEndIndex, or CallSubstringKernelResult.
1991 int32_t length
= iter
.readInt32();
1993 JSString
* result
= SubstringKernel(cx
, str
, begin
, length
);
1998 iter
.storeInstructionResult(StringValue(result
));
2002 bool MAtomicIsLockFree::writeRecoverData(CompactBufferWriter
& writer
) const {
2003 MOZ_ASSERT(canRecoverOnBailout());
2004 writer
.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree
));
2008 RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader
& reader
) {}
2010 bool RAtomicIsLockFree::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2011 double dsize
= JS::ToInteger(iter
.readNumber());
2014 bool result
= mozilla::NumberEqualsInt32(dsize
, &size
) &&
2015 AtomicOperations::isLockfreeJS(size
);
2016 iter
.storeInstructionResult(BooleanValue(result
));
2020 bool MBigIntAsIntN::writeRecoverData(CompactBufferWriter
& writer
) const {
2021 MOZ_ASSERT(canRecoverOnBailout());
2022 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsIntN
));
2026 RBigIntAsIntN::RBigIntAsIntN(CompactBufferReader
& reader
) {}
2028 bool RBigIntAsIntN::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2029 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2030 int32_t bits
= iter
.readInt32();
2031 MOZ_ASSERT(bits
>= 0);
2033 RootedBigInt
input(cx
, iter
.readBigInt());
2035 BigInt
* result
= BigInt::asIntN(cx
, input
, bits
);
2040 iter
.storeInstructionResult(JS::BigIntValue(result
));
2044 bool MBigIntAsUintN::writeRecoverData(CompactBufferWriter
& writer
) const {
2045 MOZ_ASSERT(canRecoverOnBailout());
2046 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsUintN
));
2050 RBigIntAsUintN::RBigIntAsUintN(CompactBufferReader
& reader
) {}
2052 bool RBigIntAsUintN::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2053 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2054 int32_t bits
= iter
.readInt32();
2055 MOZ_ASSERT(bits
>= 0);
2057 RootedBigInt
input(cx
, iter
.readBigInt());
2059 BigInt
* result
= BigInt::asUintN(cx
, input
, bits
);
2064 iter
.storeInstructionResult(JS::BigIntValue(result
));
2068 bool MCreateArgumentsObject::writeRecoverData(
2069 CompactBufferWriter
& writer
) const {
2070 MOZ_ASSERT(canRecoverOnBailout());
2071 writer
.writeUnsigned(uint32_t(RInstruction::Recover_CreateArgumentsObject
));
2075 RCreateArgumentsObject::RCreateArgumentsObject(CompactBufferReader
& reader
) {}
2077 bool RCreateArgumentsObject::recover(JSContext
* cx
,
2078 SnapshotIterator
& iter
) const {
2079 RootedObject
callObject(cx
, iter
.readObject());
2080 RootedObject
result(
2081 cx
, ArgumentsObject::createForIon(cx
, iter
.frame(), callObject
));
2086 iter
.storeInstructionResult(JS::ObjectValue(*result
));
2090 bool MCreateInlinedArgumentsObject::writeRecoverData(
2091 CompactBufferWriter
& writer
) const {
2092 MOZ_ASSERT(canRecoverOnBailout());
2093 writer
.writeUnsigned(
2094 uint32_t(RInstruction::Recover_CreateInlinedArgumentsObject
));
2095 writer
.writeUnsigned(numActuals());
2099 RCreateInlinedArgumentsObject::RCreateInlinedArgumentsObject(
2100 CompactBufferReader
& reader
) {
2101 numActuals_
= reader
.readUnsigned();
2104 bool RCreateInlinedArgumentsObject::recover(JSContext
* cx
,
2105 SnapshotIterator
& iter
) const {
2106 RootedObject
callObject(cx
, iter
.readObject());
2107 RootedFunction
callee(cx
, &iter
.readObject()->as
<JSFunction
>());
2109 JS::RootedValueArray
<ArgumentsObject::MaxInlinedArgs
> argsArray(cx
);
2110 for (uint32_t i
= 0; i
< numActuals_
; i
++) {
2111 argsArray
[i
].set(iter
.read());
2114 ArgumentsObject
* result
= ArgumentsObject::createFromValueArray(
2115 cx
, argsArray
, callee
, callObject
, numActuals_
);
2120 iter
.storeInstructionResult(JS::ObjectValue(*result
));
2124 bool MRest::writeRecoverData(CompactBufferWriter
& writer
) const {
2125 MOZ_ASSERT(canRecoverOnBailout());
2126 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Rest
));
2127 writer
.writeUnsigned(numFormals());
2131 RRest::RRest(CompactBufferReader
& reader
) {
2132 numFormals_
= reader
.readUnsigned();
2135 bool RRest::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2136 JitFrameLayout
* frame
= iter
.frame();
2138 // Int32 because |numActuals| is computed from MArgumentsLength.
2139 uint32_t numActuals
= iter
.readInt32();
2140 MOZ_ASSERT(numActuals
== frame
->numActualArgs());
2142 uint32_t numFormals
= numFormals_
;
2144 uint32_t length
= std::max(numActuals
, numFormals
) - numFormals
;
2145 Value
* src
= frame
->actualArgs() + numFormals
;
2146 JSObject
* rest
= jit::InitRestParameter(cx
, length
, src
, nullptr);
2151 iter
.storeInstructionResult(ObjectValue(*rest
));