1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jit/Recover.h"
9 #include "mozilla/Casting.h"
13 #include "builtin/Object.h"
14 #include "builtin/RegExp.h"
15 #include "builtin/String.h"
16 #include "jit/AtomicOperations.h"
17 #include "jit/Bailouts.h"
18 #include "jit/CompileInfo.h"
20 #include "jit/JitSpewer.h"
21 #include "jit/JSJitFrameIter.h"
22 #include "jit/MIR-wasm.h"
24 #include "jit/MIRGraph.h"
25 #include "jit/VMFunctions.h"
26 #include "util/DifferentialTesting.h"
27 #include "vm/BigIntType.h"
28 #include "vm/EqualityOperations.h"
29 #include "vm/Interpreter.h"
30 #include "vm/Iteration.h"
31 #include "vm/JSContext.h"
32 #include "vm/JSObject.h"
33 #include "vm/PlainObject.h" // js::PlainObject
34 #include "vm/StringType.h"
35 #include "vm/Watchtower.h"
37 #include "vm/Interpreter-inl.h"
40 using namespace js::jit
;
42 bool MNode::writeRecoverData(CompactBufferWriter
& writer
) const {
43 MOZ_CRASH("This instruction is not serializable");
46 void RInstruction::readRecoverData(CompactBufferReader
& reader
,
47 RInstructionStorage
* raw
) {
48 uint32_t op
= reader
.readUnsigned();
50 #define MATCH_OPCODES_(op) \
52 static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \
53 "storage space must be big enough to store R" #op); \
54 static_assert(alignof(R##op) <= alignof(RInstructionStorage), \
55 "storage space must be aligned adequate to store R" #op); \
56 new (raw->addr()) R##op(reader); \
59 RECOVER_OPCODE_LIST(MATCH_OPCODES_
)
64 MOZ_CRASH("Bad decoding of the previous instruction?");
68 bool MResumePoint::writeRecoverData(CompactBufferWriter
& writer
) const {
69 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint
));
71 MBasicBlock
* bb
= block();
72 bool hasFun
= bb
->info().hasFunMaybeLazy();
73 uint32_t nargs
= bb
->info().nargs();
74 JSScript
* script
= bb
->info().script();
75 uint32_t exprStack
= stackDepth() - bb
->info().ninvoke();
78 // Ensure that all snapshot which are encoded can safely be used for
80 uint32_t numIntermediate
= NumIntermediateValues(mode());
81 if (JSContext
* cx
= GetJitContext()->cx
) {
82 if (!AssertBailoutStackDepth(cx
, script
, pc(), mode(),
83 exprStack
- numIntermediate
)) {
89 uint32_t formalArgs
= CountArgSlots(script
, hasFun
, nargs
);
91 // Test if we honor the maximum of arguments at all times. This is a sanity
92 // check and not an algorithm limit. So check might be a bit too loose. +4
93 // to account for scope chain, return value, this value and maybe
95 MOZ_ASSERT(formalArgs
< SNAPSHOT_MAX_NARGS
+ 4);
98 uint32_t implicit
= StartArgSlot(script
);
100 uint32_t nallocs
= formalArgs
+ script
->nfixed() + exprStack
;
102 JitSpew(JitSpew_IonSnapshots
,
103 "Starting frame; implicit %u, formals %u, fixed %zu, exprs %u",
104 implicit
, formalArgs
- implicit
, script
->nfixed(), exprStack
);
106 uint32_t pcOff
= script
->pcToOffset(pc());
107 JitSpew(JitSpew_IonSnapshots
, "Writing pc offset %u, mode %s, nslots %u",
108 pcOff
, ResumeModeToString(mode()), nallocs
);
110 uint32_t pcOffAndMode
=
111 (pcOff
<< RResumePoint::PCOffsetShift
) | uint32_t(mode());
112 MOZ_RELEASE_ASSERT((pcOffAndMode
>> RResumePoint::PCOffsetShift
) == pcOff
,
113 "pcOff doesn't fit in pcOffAndMode");
114 writer
.writeUnsigned(pcOffAndMode
);
116 writer
.writeUnsigned(nallocs
);
120 RResumePoint::RResumePoint(CompactBufferReader
& reader
) {
121 pcOffsetAndMode_
= reader
.readUnsigned();
122 numOperands_
= reader
.readUnsigned();
123 JitSpew(JitSpew_IonSnapshots
,
124 "Read RResumePoint (pc offset %u, mode %s, nslots %u)", pcOffset(),
125 ResumeModeToString(mode()), numOperands_
);
128 bool RResumePoint::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
129 MOZ_CRASH("This instruction is not recoverable.");
132 bool MBitNot::writeRecoverData(CompactBufferWriter
& writer
) const {
133 // 64-bit int bitnots exist only when compiling wasm; they exist neither for
134 // JS nor asm.js. So we don't expect them here.
135 MOZ_ASSERT(type() != MIRType::Int64
);
136 MOZ_ASSERT(canRecoverOnBailout());
137 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitNot
));
141 RBitNot::RBitNot(CompactBufferReader
& reader
) {}
143 bool RBitNot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
144 RootedValue
operand(cx
, iter
.read());
145 RootedValue
result(cx
);
147 if (!js::BitNot(cx
, &operand
, &result
)) {
151 iter
.storeInstructionResult(result
);
155 bool MBitAnd::writeRecoverData(CompactBufferWriter
& writer
) const {
156 MOZ_ASSERT(canRecoverOnBailout());
157 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd
));
161 RBitAnd::RBitAnd(CompactBufferReader
& reader
) {}
163 bool RBitAnd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
164 RootedValue
lhs(cx
, iter
.read());
165 RootedValue
rhs(cx
, iter
.read());
166 RootedValue
result(cx
);
167 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
169 if (!js::BitAnd(cx
, &lhs
, &rhs
, &result
)) {
173 iter
.storeInstructionResult(result
);
177 bool MBitOr::writeRecoverData(CompactBufferWriter
& writer
) const {
178 MOZ_ASSERT(canRecoverOnBailout());
179 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitOr
));
183 RBitOr::RBitOr(CompactBufferReader
& reader
) {}
185 bool RBitOr::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
186 RootedValue
lhs(cx
, iter
.read());
187 RootedValue
rhs(cx
, iter
.read());
188 RootedValue
result(cx
);
189 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
191 if (!js::BitOr(cx
, &lhs
, &rhs
, &result
)) {
195 iter
.storeInstructionResult(result
);
199 bool MBitXor::writeRecoverData(CompactBufferWriter
& writer
) const {
200 MOZ_ASSERT(canRecoverOnBailout());
201 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BitXor
));
205 RBitXor::RBitXor(CompactBufferReader
& reader
) {}
207 bool RBitXor::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
208 RootedValue
lhs(cx
, iter
.read());
209 RootedValue
rhs(cx
, iter
.read());
210 RootedValue
result(cx
);
212 if (!js::BitXor(cx
, &lhs
, &rhs
, &result
)) {
216 iter
.storeInstructionResult(result
);
220 bool MLsh::writeRecoverData(CompactBufferWriter
& writer
) const {
221 MOZ_ASSERT(canRecoverOnBailout());
222 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Lsh
));
226 RLsh::RLsh(CompactBufferReader
& reader
) {}
228 bool RLsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
229 RootedValue
lhs(cx
, iter
.read());
230 RootedValue
rhs(cx
, iter
.read());
231 RootedValue
result(cx
);
232 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
234 if (!js::BitLsh(cx
, &lhs
, &rhs
, &result
)) {
238 iter
.storeInstructionResult(result
);
242 bool MRsh::writeRecoverData(CompactBufferWriter
& writer
) const {
243 MOZ_ASSERT(canRecoverOnBailout());
244 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Rsh
));
248 RRsh::RRsh(CompactBufferReader
& reader
) {}
250 bool RRsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
251 RootedValue
lhs(cx
, iter
.read());
252 RootedValue
rhs(cx
, iter
.read());
253 RootedValue
result(cx
);
254 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
256 if (!js::BitRsh(cx
, &lhs
, &rhs
, &result
)) {
260 iter
.storeInstructionResult(result
);
264 bool MUrsh::writeRecoverData(CompactBufferWriter
& writer
) const {
265 MOZ_ASSERT(canRecoverOnBailout());
266 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ursh
));
270 RUrsh::RUrsh(CompactBufferReader
& reader
) {}
272 bool RUrsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
273 RootedValue
lhs(cx
, iter
.read());
274 RootedValue
rhs(cx
, iter
.read());
275 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
277 RootedValue
result(cx
);
278 if (!js::UrshValues(cx
, &lhs
, &rhs
, &result
)) {
282 iter
.storeInstructionResult(result
);
286 bool MSignExtendInt32::writeRecoverData(CompactBufferWriter
& writer
) const {
287 MOZ_ASSERT(canRecoverOnBailout());
288 writer
.writeUnsigned(uint32_t(RInstruction::Recover_SignExtendInt32
));
289 MOZ_ASSERT(Mode(uint8_t(mode_
)) == mode_
);
290 writer
.writeByte(uint8_t(mode_
));
294 RSignExtendInt32::RSignExtendInt32(CompactBufferReader
& reader
) {
295 mode_
= reader
.readByte();
298 bool RSignExtendInt32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
299 RootedValue
operand(cx
, iter
.read());
302 if (!ToInt32(cx
, operand
, &i
)) {
307 switch (MSignExtendInt32::Mode(mode_
)) {
308 case MSignExtendInt32::Byte
:
309 result
= static_cast<int8_t>(i
);
311 case MSignExtendInt32::Half
:
312 result
= static_cast<int16_t>(i
);
316 iter
.storeInstructionResult(JS::Int32Value(result
));
320 bool MAdd::writeRecoverData(CompactBufferWriter
& writer
) const {
321 MOZ_ASSERT(canRecoverOnBailout());
322 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Add
));
323 writer
.writeByte(type() == MIRType::Float32
);
327 RAdd::RAdd(CompactBufferReader
& reader
) {
328 isFloatOperation_
= reader
.readByte();
331 bool RAdd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
332 RootedValue
lhs(cx
, iter
.read());
333 RootedValue
rhs(cx
, iter
.read());
334 RootedValue
result(cx
);
336 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
337 if (!js::AddValues(cx
, &lhs
, &rhs
, &result
)) {
341 // MIRType::Float32 is a specialization embedding the fact that the result is
342 // rounded to a Float32.
343 if (isFloatOperation_
&& !RoundFloat32(cx
, result
, &result
)) {
347 iter
.storeInstructionResult(result
);
351 bool MSub::writeRecoverData(CompactBufferWriter
& writer
) const {
352 MOZ_ASSERT(canRecoverOnBailout());
353 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Sub
));
354 writer
.writeByte(type() == MIRType::Float32
);
358 RSub::RSub(CompactBufferReader
& reader
) {
359 isFloatOperation_
= reader
.readByte();
362 bool RSub::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
363 RootedValue
lhs(cx
, iter
.read());
364 RootedValue
rhs(cx
, iter
.read());
365 RootedValue
result(cx
);
367 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
368 if (!js::SubValues(cx
, &lhs
, &rhs
, &result
)) {
372 // MIRType::Float32 is a specialization embedding the fact that the result is
373 // rounded to a Float32.
374 if (isFloatOperation_
&& !RoundFloat32(cx
, result
, &result
)) {
378 iter
.storeInstructionResult(result
);
382 bool MMul::writeRecoverData(CompactBufferWriter
& writer
) const {
383 MOZ_ASSERT(canRecoverOnBailout());
384 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Mul
));
385 writer
.writeByte(type() == MIRType::Float32
);
386 MOZ_ASSERT(Mode(uint8_t(mode_
)) == mode_
);
387 writer
.writeByte(uint8_t(mode_
));
391 RMul::RMul(CompactBufferReader
& reader
) {
392 isFloatOperation_
= reader
.readByte();
393 mode_
= reader
.readByte();
396 bool RMul::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
397 RootedValue
lhs(cx
, iter
.read());
398 RootedValue
rhs(cx
, iter
.read());
399 RootedValue
result(cx
);
401 if (MMul::Mode(mode_
) == MMul::Normal
) {
402 if (!js::MulValues(cx
, &lhs
, &rhs
, &result
)) {
406 // MIRType::Float32 is a specialization embedding the fact that the
407 // result is rounded to a Float32.
408 if (isFloatOperation_
&& !RoundFloat32(cx
, result
, &result
)) {
412 MOZ_ASSERT(MMul::Mode(mode_
) == MMul::Integer
);
413 if (!js::math_imul_handle(cx
, lhs
, rhs
, &result
)) {
418 iter
.storeInstructionResult(result
);
422 bool MDiv::writeRecoverData(CompactBufferWriter
& writer
) const {
423 MOZ_ASSERT(canRecoverOnBailout());
424 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Div
));
425 writer
.writeByte(type() == MIRType::Float32
);
429 RDiv::RDiv(CompactBufferReader
& reader
) {
430 isFloatOperation_
= reader
.readByte();
433 bool RDiv::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
434 RootedValue
lhs(cx
, iter
.read());
435 RootedValue
rhs(cx
, iter
.read());
436 RootedValue
result(cx
);
438 if (!js::DivValues(cx
, &lhs
, &rhs
, &result
)) {
442 // MIRType::Float32 is a specialization embedding the fact that the result is
443 // rounded to a Float32.
444 if (isFloatOperation_
&& !RoundFloat32(cx
, result
, &result
)) {
448 iter
.storeInstructionResult(result
);
452 bool MMod::writeRecoverData(CompactBufferWriter
& writer
) const {
453 MOZ_ASSERT(canRecoverOnBailout());
454 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Mod
));
458 RMod::RMod(CompactBufferReader
& reader
) {}
460 bool RMod::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
461 RootedValue
lhs(cx
, iter
.read());
462 RootedValue
rhs(cx
, iter
.read());
463 RootedValue
result(cx
);
465 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
466 if (!js::ModValues(cx
, &lhs
, &rhs
, &result
)) {
470 iter
.storeInstructionResult(result
);
474 bool MNot::writeRecoverData(CompactBufferWriter
& writer
) const {
475 MOZ_ASSERT(canRecoverOnBailout());
476 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Not
));
480 RNot::RNot(CompactBufferReader
& reader
) {}
482 bool RNot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
483 RootedValue
v(cx
, iter
.read());
484 RootedValue
result(cx
);
486 result
.setBoolean(!ToBoolean(v
));
488 iter
.storeInstructionResult(result
);
492 bool MBigIntAdd::writeRecoverData(CompactBufferWriter
& writer
) const {
493 MOZ_ASSERT(canRecoverOnBailout());
494 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAdd
));
498 RBigIntAdd::RBigIntAdd(CompactBufferReader
& reader
) {}
500 bool RBigIntAdd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
501 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
502 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
504 BigInt
* result
= BigInt::add(cx
, lhs
, rhs
);
509 iter
.storeInstructionResult(BigIntValue(result
));
513 bool MBigIntSub::writeRecoverData(CompactBufferWriter
& writer
) const {
514 MOZ_ASSERT(canRecoverOnBailout());
515 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntSub
));
519 RBigIntSub::RBigIntSub(CompactBufferReader
& reader
) {}
521 bool RBigIntSub::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
522 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
523 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
525 BigInt
* result
= BigInt::sub(cx
, lhs
, rhs
);
530 iter
.storeInstructionResult(BigIntValue(result
));
534 bool MBigIntMul::writeRecoverData(CompactBufferWriter
& writer
) const {
535 MOZ_ASSERT(canRecoverOnBailout());
536 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMul
));
540 RBigIntMul::RBigIntMul(CompactBufferReader
& reader
) {}
542 bool RBigIntMul::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
543 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
544 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
546 BigInt
* result
= BigInt::mul(cx
, lhs
, rhs
);
551 iter
.storeInstructionResult(BigIntValue(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 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
565 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
566 MOZ_ASSERT(!rhs
->isZero(),
567 "division by zero throws and therefore can't be recovered");
569 BigInt
* result
= BigInt::div(cx
, lhs
, rhs
);
574 iter
.storeInstructionResult(BigIntValue(result
));
578 bool MBigIntMod::writeRecoverData(CompactBufferWriter
& writer
) const {
579 MOZ_ASSERT(canRecoverOnBailout());
580 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMod
));
584 RBigIntMod::RBigIntMod(CompactBufferReader
& reader
) {}
586 bool RBigIntMod::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
587 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
588 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
589 MOZ_ASSERT(!rhs
->isZero(),
590 "division by zero throws and therefore can't be recovered");
592 BigInt
* result
= BigInt::mod(cx
, lhs
, rhs
);
597 iter
.storeInstructionResult(BigIntValue(result
));
601 bool MBigIntPow::writeRecoverData(CompactBufferWriter
& writer
) const {
602 MOZ_ASSERT(canRecoverOnBailout());
603 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPow
));
607 RBigIntPow::RBigIntPow(CompactBufferReader
& reader
) {}
609 bool RBigIntPow::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
610 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
611 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
612 MOZ_ASSERT(!rhs
->isNegative(),
613 "negative exponent throws and therefore can't be recovered");
615 BigInt
* result
= BigInt::pow(cx
, lhs
, rhs
);
620 iter
.storeInstructionResult(BigIntValue(result
));
624 bool MBigIntBitAnd::writeRecoverData(CompactBufferWriter
& writer
) const {
625 MOZ_ASSERT(canRecoverOnBailout());
626 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitAnd
));
630 RBigIntBitAnd::RBigIntBitAnd(CompactBufferReader
& reader
) {}
632 bool RBigIntBitAnd::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
633 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
634 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
636 BigInt
* result
= BigInt::bitAnd(cx
, lhs
, rhs
);
641 iter
.storeInstructionResult(BigIntValue(result
));
645 bool MBigIntBitOr::writeRecoverData(CompactBufferWriter
& writer
) const {
646 MOZ_ASSERT(canRecoverOnBailout());
647 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitOr
));
651 RBigIntBitOr::RBigIntBitOr(CompactBufferReader
& reader
) {}
653 bool RBigIntBitOr::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
654 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
655 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
657 BigInt
* result
= BigInt::bitOr(cx
, lhs
, rhs
);
662 iter
.storeInstructionResult(BigIntValue(result
));
666 bool MBigIntBitXor::writeRecoverData(CompactBufferWriter
& writer
) const {
667 MOZ_ASSERT(canRecoverOnBailout());
668 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitXor
));
672 RBigIntBitXor::RBigIntBitXor(CompactBufferReader
& reader
) {}
674 bool RBigIntBitXor::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
675 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
676 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
678 BigInt
* result
= BigInt::bitXor(cx
, lhs
, rhs
);
683 iter
.storeInstructionResult(BigIntValue(result
));
687 bool MBigIntLsh::writeRecoverData(CompactBufferWriter
& writer
) const {
688 MOZ_ASSERT(canRecoverOnBailout());
689 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntLsh
));
693 RBigIntLsh::RBigIntLsh(CompactBufferReader
& reader
) {}
695 bool RBigIntLsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
696 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
697 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
699 BigInt
* result
= BigInt::lsh(cx
, lhs
, rhs
);
704 iter
.storeInstructionResult(BigIntValue(result
));
708 bool MBigIntRsh::writeRecoverData(CompactBufferWriter
& writer
) const {
709 MOZ_ASSERT(canRecoverOnBailout());
710 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntRsh
));
714 RBigIntRsh::RBigIntRsh(CompactBufferReader
& reader
) {}
716 bool RBigIntRsh::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
717 Rooted
<BigInt
*> lhs(cx
, iter
.readBigInt());
718 Rooted
<BigInt
*> rhs(cx
, iter
.readBigInt());
720 BigInt
* result
= BigInt::rsh(cx
, lhs
, rhs
);
725 iter
.storeInstructionResult(BigIntValue(result
));
729 bool MBigIntIncrement::writeRecoverData(CompactBufferWriter
& writer
) const {
730 MOZ_ASSERT(canRecoverOnBailout());
731 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntIncrement
));
735 RBigIntIncrement::RBigIntIncrement(CompactBufferReader
& reader
) {}
737 bool RBigIntIncrement::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
738 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
740 BigInt
* result
= BigInt::inc(cx
, operand
);
745 iter
.storeInstructionResult(BigIntValue(result
));
749 bool MBigIntDecrement::writeRecoverData(CompactBufferWriter
& writer
) const {
750 MOZ_ASSERT(canRecoverOnBailout());
751 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDecrement
));
755 RBigIntDecrement::RBigIntDecrement(CompactBufferReader
& reader
) {}
757 bool RBigIntDecrement::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
758 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
760 BigInt
* result
= BigInt::dec(cx
, operand
);
765 iter
.storeInstructionResult(BigIntValue(result
));
769 bool MBigIntNegate::writeRecoverData(CompactBufferWriter
& writer
) const {
770 MOZ_ASSERT(canRecoverOnBailout());
771 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntNegate
));
775 RBigIntNegate::RBigIntNegate(CompactBufferReader
& reader
) {}
777 bool RBigIntNegate::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
778 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
780 BigInt
* result
= BigInt::neg(cx
, operand
);
785 iter
.storeInstructionResult(BigIntValue(result
));
789 bool MBigIntBitNot::writeRecoverData(CompactBufferWriter
& writer
) const {
790 MOZ_ASSERT(canRecoverOnBailout());
791 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitNot
));
795 RBigIntBitNot::RBigIntBitNot(CompactBufferReader
& reader
) {}
797 bool RBigIntBitNot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
798 Rooted
<BigInt
*> operand(cx
, iter
.readBigInt());
800 BigInt
* result
= BigInt::bitNot(cx
, operand
);
805 iter
.storeInstructionResult(BigIntValue(result
));
809 bool MCompare::writeRecoverData(CompactBufferWriter
& writer
) const {
810 MOZ_ASSERT(canRecoverOnBailout());
811 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Compare
));
813 static_assert(sizeof(JSOp
) == sizeof(uint8_t));
814 writer
.writeByte(uint8_t(jsop_
));
818 RCompare::RCompare(CompactBufferReader
& reader
) {
819 jsop_
= JSOp(reader
.readByte());
821 MOZ_ASSERT(IsEqualityOp(jsop_
) || IsRelationalOp(jsop_
));
824 bool RCompare::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
825 RootedValue
lhs(cx
, iter
.read());
826 RootedValue
rhs(cx
, iter
.read());
832 if (!js::LooselyEqual(cx
, lhs
, rhs
, &result
)) {
835 if (jsop_
== JSOp::Ne
) {
841 if (!StrictlyEqual(cx
, lhs
, rhs
, &result
)) {
844 if (jsop_
== JSOp::StrictNe
) {
849 if (!js::LessThan(cx
, &lhs
, &rhs
, &result
)) {
854 if (!js::LessThanOrEqual(cx
, &lhs
, &rhs
, &result
)) {
859 if (!js::GreaterThan(cx
, &lhs
, &rhs
, &result
)) {
864 if (!js::GreaterThanOrEqual(cx
, &lhs
, &rhs
, &result
)) {
869 MOZ_CRASH("Unexpected op.");
872 iter
.storeInstructionResult(BooleanValue(result
));
876 bool MConcat::writeRecoverData(CompactBufferWriter
& writer
) const {
877 MOZ_ASSERT(canRecoverOnBailout());
878 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Concat
));
882 RConcat::RConcat(CompactBufferReader
& reader
) {}
884 bool RConcat::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
885 RootedValue
lhs(cx
, iter
.read());
886 RootedValue
rhs(cx
, iter
.read());
887 RootedValue
result(cx
);
889 MOZ_ASSERT(!lhs
.isObject() && !rhs
.isObject());
890 if (!js::AddValues(cx
, &lhs
, &rhs
, &result
)) {
894 iter
.storeInstructionResult(result
);
898 RStringLength::RStringLength(CompactBufferReader
& reader
) {}
900 bool RStringLength::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
901 JSString
* string
= iter
.readString();
903 static_assert(JSString::MAX_LENGTH
<= INT32_MAX
,
904 "Can cast string length to int32_t");
906 iter
.storeInstructionResult(Int32Value(int32_t(string
->length())));
910 bool MStringLength::writeRecoverData(CompactBufferWriter
& writer
) const {
911 MOZ_ASSERT(canRecoverOnBailout());
912 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringLength
));
916 bool MArgumentsLength::writeRecoverData(CompactBufferWriter
& writer
) const {
917 MOZ_ASSERT(canRecoverOnBailout());
918 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength
));
922 RArgumentsLength::RArgumentsLength(CompactBufferReader
& reader
) {}
924 bool RArgumentsLength::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
925 uintptr_t numActualArgs
= iter
.frame()->numActualArgs();
927 static_assert(ARGS_LENGTH_MAX
<= INT32_MAX
,
928 "Can cast arguments count to int32_t");
929 MOZ_ASSERT(numActualArgs
<= ARGS_LENGTH_MAX
);
931 iter
.storeInstructionResult(JS::Int32Value(int32_t(numActualArgs
)));
935 bool MFloor::writeRecoverData(CompactBufferWriter
& writer
) const {
936 MOZ_ASSERT(canRecoverOnBailout());
937 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
941 RFloor::RFloor(CompactBufferReader
& reader
) {}
943 bool RFloor::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
944 double num
= iter
.readNumber();
945 double result
= js::math_floor_impl(num
);
947 iter
.storeInstructionResult(NumberValue(result
));
951 bool MCeil::writeRecoverData(CompactBufferWriter
& writer
) const {
952 MOZ_ASSERT(canRecoverOnBailout());
953 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
957 RCeil::RCeil(CompactBufferReader
& reader
) {}
959 bool RCeil::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
960 double num
= iter
.readNumber();
961 double result
= js::math_ceil_impl(num
);
963 iter
.storeInstructionResult(NumberValue(result
));
967 bool MRound::writeRecoverData(CompactBufferWriter
& writer
) const {
968 MOZ_ASSERT(canRecoverOnBailout());
969 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Round
));
973 RRound::RRound(CompactBufferReader
& reader
) {}
975 bool RRound::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
976 double num
= iter
.readNumber();
977 double result
= js::math_round_impl(num
);
979 iter
.storeInstructionResult(NumberValue(result
));
983 bool MTrunc::writeRecoverData(CompactBufferWriter
& writer
) const {
984 MOZ_ASSERT(canRecoverOnBailout());
985 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
989 RTrunc::RTrunc(CompactBufferReader
& reader
) {}
991 bool RTrunc::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
992 double num
= iter
.readNumber();
993 double result
= js::math_trunc_impl(num
);
995 iter
.storeInstructionResult(NumberValue(result
));
999 bool MCharCodeAt::writeRecoverData(CompactBufferWriter
& writer
) const {
1000 MOZ_ASSERT(canRecoverOnBailout());
1001 writer
.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt
));
1005 RCharCodeAt::RCharCodeAt(CompactBufferReader
& reader
) {}
1007 bool RCharCodeAt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1008 JSString
* string
= iter
.readString();
1010 // Int32 because |index| is computed from MBoundsCheck.
1011 int32_t index
= iter
.readInt32();
1012 MOZ_RELEASE_ASSERT(0 <= index
&& size_t(index
) < string
->length());
1015 if (!string
->getChar(cx
, index
, &c
)) {
1019 iter
.storeInstructionResult(Int32Value(c
));
1023 bool MFromCharCode::writeRecoverData(CompactBufferWriter
& writer
) const {
1024 MOZ_ASSERT(canRecoverOnBailout());
1025 writer
.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode
));
1029 RFromCharCode::RFromCharCode(CompactBufferReader
& reader
) {}
1031 bool RFromCharCode::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1032 // Number because |charCode| is computed from (recoverable) user input.
1033 int32_t charCode
= JS::ToInt32(iter
.readNumber());
1035 JSString
* str
= StringFromCharCode(cx
, charCode
);
1040 iter
.storeInstructionResult(StringValue(str
));
1044 bool MFromCharCodeEmptyIfNegative::writeRecoverData(
1045 CompactBufferWriter
& writer
) const {
1046 MOZ_ASSERT(canRecoverOnBailout());
1047 writer
.writeUnsigned(
1048 uint32_t(RInstruction::Recover_FromCharCodeEmptyIfNegative
));
1052 RFromCharCodeEmptyIfNegative::RFromCharCodeEmptyIfNegative(
1053 CompactBufferReader
& reader
) {}
1055 bool RFromCharCodeEmptyIfNegative::recover(JSContext
* cx
,
1056 SnapshotIterator
& iter
) const {
1057 // Int32 because |charCode| is computed from MCharCodeAtOrNegative.
1058 int32_t charCode
= iter
.readInt32();
1062 str
= cx
->emptyString();
1064 str
= StringFromCharCode(cx
, charCode
);
1070 iter
.storeInstructionResult(StringValue(str
));
1074 bool MPow::writeRecoverData(CompactBufferWriter
& writer
) const {
1075 MOZ_ASSERT(canRecoverOnBailout());
1076 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Pow
));
1080 RPow::RPow(CompactBufferReader
& reader
) {}
1082 bool RPow::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1083 double base
= iter
.readNumber();
1084 double power
= iter
.readNumber();
1085 double result
= ecmaPow(base
, power
);
1087 iter
.storeInstructionResult(NumberValue(result
));
1091 bool MPowHalf::writeRecoverData(CompactBufferWriter
& writer
) const {
1092 MOZ_ASSERT(canRecoverOnBailout());
1093 writer
.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf
));
1097 RPowHalf::RPowHalf(CompactBufferReader
& reader
) {}
1099 bool RPowHalf::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1100 double base
= iter
.readNumber();
1102 double result
= ecmaPow(base
, power
);
1104 iter
.storeInstructionResult(NumberValue(result
));
1108 bool MMinMax::writeRecoverData(CompactBufferWriter
& writer
) const {
1109 MOZ_ASSERT(canRecoverOnBailout());
1110 writer
.writeUnsigned(uint32_t(RInstruction::Recover_MinMax
));
1111 writer
.writeByte(isMax_
);
1115 RMinMax::RMinMax(CompactBufferReader
& reader
) { isMax_
= reader
.readByte(); }
1117 bool RMinMax::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1118 double x
= iter
.readNumber();
1119 double y
= iter
.readNumber();
1123 result
= js::math_max_impl(x
, y
);
1125 result
= js::math_min_impl(x
, y
);
1128 iter
.storeInstructionResult(NumberValue(result
));
1132 bool MAbs::writeRecoverData(CompactBufferWriter
& writer
) const {
1133 MOZ_ASSERT(canRecoverOnBailout());
1134 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Abs
));
1138 RAbs::RAbs(CompactBufferReader
& reader
) {}
1140 bool RAbs::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1141 double num
= iter
.readNumber();
1142 double result
= js::math_abs_impl(num
);
1144 iter
.storeInstructionResult(NumberValue(result
));
1148 bool MSqrt::writeRecoverData(CompactBufferWriter
& writer
) const {
1149 MOZ_ASSERT(canRecoverOnBailout());
1150 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt
));
1151 writer
.writeByte(type() == MIRType::Float32
);
1155 RSqrt::RSqrt(CompactBufferReader
& reader
) {
1156 isFloatOperation_
= reader
.readByte();
1159 bool RSqrt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1160 double num
= iter
.readNumber();
1161 double result
= js::math_sqrt_impl(num
);
1163 // MIRType::Float32 is a specialization embedding the fact that the result is
1164 // rounded to a Float32.
1165 if (isFloatOperation_
) {
1166 result
= js::RoundFloat32(result
);
1169 iter
.storeInstructionResult(DoubleValue(result
));
1173 bool MAtan2::writeRecoverData(CompactBufferWriter
& writer
) const {
1174 MOZ_ASSERT(canRecoverOnBailout());
1175 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Atan2
));
1179 RAtan2::RAtan2(CompactBufferReader
& reader
) {}
1181 bool RAtan2::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1182 double y
= iter
.readNumber();
1183 double x
= iter
.readNumber();
1184 double result
= js::ecmaAtan2(y
, x
);
1186 iter
.storeInstructionResult(DoubleValue(result
));
1190 bool MHypot::writeRecoverData(CompactBufferWriter
& writer
) const {
1191 MOZ_ASSERT(canRecoverOnBailout());
1192 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Hypot
));
1193 writer
.writeUnsigned(uint32_t(numOperands()));
1197 RHypot::RHypot(CompactBufferReader
& reader
)
1198 : numOperands_(reader
.readUnsigned()) {}
1200 bool RHypot::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1201 JS::RootedValueVector
vec(cx
);
1203 if (!vec
.reserve(numOperands_
)) {
1207 for (uint32_t i
= 0; i
< numOperands_
; ++i
) {
1208 vec
.infallibleAppend(NumberValue(iter
.readNumber()));
1211 RootedValue
result(cx
);
1213 if (!js::math_hypot_handle(cx
, vec
, &result
)) {
1217 iter
.storeInstructionResult(result
);
1221 bool MNearbyInt::writeRecoverData(CompactBufferWriter
& writer
) const {
1222 MOZ_ASSERT(canRecoverOnBailout());
1223 switch (roundingMode_
) {
1224 case RoundingMode::Up
:
1225 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
1227 case RoundingMode::Down
:
1228 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
1230 case RoundingMode::TowardsZero
:
1231 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
1234 MOZ_CRASH("Unsupported rounding mode.");
1238 RNearbyInt::RNearbyInt(CompactBufferReader
& reader
) {
1239 roundingMode_
= reader
.readByte();
1242 bool RNearbyInt::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1243 MOZ_CRASH("Unsupported rounding mode.");
1246 bool MSign::writeRecoverData(CompactBufferWriter
& writer
) const {
1247 MOZ_ASSERT(canRecoverOnBailout());
1248 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Sign
));
1252 RSign::RSign(CompactBufferReader
& reader
) {}
1254 bool RSign::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1255 double num
= iter
.readNumber();
1256 double result
= js::math_sign_impl(num
);
1258 iter
.storeInstructionResult(NumberValue(result
));
1262 bool MMathFunction::writeRecoverData(CompactBufferWriter
& writer
) const {
1263 MOZ_ASSERT(canRecoverOnBailout());
1264 switch (function_
) {
1265 case UnaryMathFunction::Ceil
:
1266 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Ceil
));
1268 case UnaryMathFunction::Floor
:
1269 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Floor
));
1271 case UnaryMathFunction::Round
:
1272 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Round
));
1274 case UnaryMathFunction::Trunc
:
1275 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Trunc
));
1277 case UnaryMathFunction::SinNative
:
1278 case UnaryMathFunction::SinFdlibm
:
1279 case UnaryMathFunction::CosNative
:
1280 case UnaryMathFunction::CosFdlibm
:
1281 case UnaryMathFunction::TanNative
:
1282 case UnaryMathFunction::TanFdlibm
:
1283 case UnaryMathFunction::Log
:
1284 case UnaryMathFunction::Exp
:
1285 case UnaryMathFunction::ACos
:
1286 case UnaryMathFunction::ASin
:
1287 case UnaryMathFunction::ATan
:
1288 case UnaryMathFunction::Log10
:
1289 case UnaryMathFunction::Log2
:
1290 case UnaryMathFunction::Log1P
:
1291 case UnaryMathFunction::ExpM1
:
1292 case UnaryMathFunction::CosH
:
1293 case UnaryMathFunction::SinH
:
1294 case UnaryMathFunction::TanH
:
1295 case UnaryMathFunction::ACosH
:
1296 case UnaryMathFunction::ASinH
:
1297 case UnaryMathFunction::ATanH
:
1298 case UnaryMathFunction::Cbrt
:
1299 static_assert(sizeof(UnaryMathFunction
) == sizeof(uint8_t));
1300 writer
.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction
));
1301 writer
.writeByte(uint8_t(function_
));
1304 MOZ_CRASH("Unknown math function.");
1307 RMathFunction::RMathFunction(CompactBufferReader
& reader
) {
1308 function_
= UnaryMathFunction(reader
.readByte());
1311 bool RMathFunction::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1312 double num
= iter
.readNumber();
1315 switch (function_
) {
1316 case UnaryMathFunction::SinNative
:
1317 result
= js::math_sin_native_impl(num
);
1319 case UnaryMathFunction::SinFdlibm
:
1320 result
= js::math_sin_fdlibm_impl(num
);
1322 case UnaryMathFunction::CosNative
:
1323 result
= js::math_cos_native_impl(num
);
1325 case UnaryMathFunction::CosFdlibm
:
1326 result
= js::math_cos_fdlibm_impl(num
);
1328 case UnaryMathFunction::TanNative
:
1329 result
= js::math_tan_native_impl(num
);
1331 case UnaryMathFunction::TanFdlibm
:
1332 result
= js::math_tan_fdlibm_impl(num
);
1334 case UnaryMathFunction::Log
:
1335 result
= js::math_log_impl(num
);
1337 case UnaryMathFunction::Exp
:
1338 result
= js::math_exp_impl(num
);
1340 case UnaryMathFunction::ACos
:
1341 result
= js::math_acos_impl(num
);
1343 case UnaryMathFunction::ASin
:
1344 result
= js::math_asin_impl(num
);
1346 case UnaryMathFunction::ATan
:
1347 result
= js::math_atan_impl(num
);
1349 case UnaryMathFunction::Log10
:
1350 result
= js::math_log10_impl(num
);
1352 case UnaryMathFunction::Log2
:
1353 result
= js::math_log2_impl(num
);
1355 case UnaryMathFunction::Log1P
:
1356 result
= js::math_log1p_impl(num
);
1358 case UnaryMathFunction::ExpM1
:
1359 result
= js::math_expm1_impl(num
);
1361 case UnaryMathFunction::CosH
:
1362 result
= js::math_cosh_impl(num
);
1364 case UnaryMathFunction::SinH
:
1365 result
= js::math_sinh_impl(num
);
1367 case UnaryMathFunction::TanH
:
1368 result
= js::math_tanh_impl(num
);
1370 case UnaryMathFunction::ACosH
:
1371 result
= js::math_acosh_impl(num
);
1373 case UnaryMathFunction::ASinH
:
1374 result
= js::math_asinh_impl(num
);
1376 case UnaryMathFunction::ATanH
:
1377 result
= js::math_atanh_impl(num
);
1379 case UnaryMathFunction::Cbrt
:
1380 result
= js::math_cbrt_impl(num
);
1383 case UnaryMathFunction::Trunc
:
1384 case UnaryMathFunction::Floor
:
1385 case UnaryMathFunction::Ceil
:
1386 case UnaryMathFunction::Round
:
1387 // These have their own recover instructions.
1388 MOZ_CRASH("Unexpected rounding math function.");
1391 iter
.storeInstructionResult(DoubleValue(result
));
1395 bool MRandom::writeRecoverData(CompactBufferWriter
& writer
) const {
1396 MOZ_ASSERT(this->canRecoverOnBailout());
1397 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Random
));
1401 bool MRandom::canRecoverOnBailout() const {
1402 return !js::SupportDifferentialTesting();
1405 RRandom::RRandom(CompactBufferReader
& reader
) {}
1407 bool RRandom::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1408 iter
.storeInstructionResult(DoubleValue(math_random_impl(cx
)));
1412 bool MStringSplit::writeRecoverData(CompactBufferWriter
& writer
) const {
1413 MOZ_ASSERT(canRecoverOnBailout());
1414 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit
));
1418 RStringSplit::RStringSplit(CompactBufferReader
& reader
) {}
1420 bool RStringSplit::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1421 RootedString
str(cx
, iter
.readString());
1422 RootedString
sep(cx
, iter
.readString());
1424 JSObject
* res
= StringSplitString(cx
, str
, sep
, INT32_MAX
);
1429 iter
.storeInstructionResult(ObjectValue(*res
));
1433 bool MNaNToZero::writeRecoverData(CompactBufferWriter
& writer
) const {
1434 MOZ_ASSERT(canRecoverOnBailout());
1435 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero
));
1439 RNaNToZero::RNaNToZero(CompactBufferReader
& reader
) {}
1441 bool RNaNToZero::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1442 double v
= iter
.readNumber();
1443 if (std::isnan(v
) || mozilla::IsNegativeZero(v
)) {
1447 iter
.storeInstructionResult(DoubleValue(v
));
1451 bool MRegExpMatcher::writeRecoverData(CompactBufferWriter
& writer
) const {
1452 MOZ_ASSERT(canRecoverOnBailout());
1453 writer
.writeUnsigned(uint32_t(RInstruction::Recover_RegExpMatcher
));
1457 RRegExpMatcher::RRegExpMatcher(CompactBufferReader
& reader
) {}
1459 bool RRegExpMatcher::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1460 RootedObject
regexp(cx
, iter
.readObject());
1461 RootedString
input(cx
, iter
.readString());
1463 // Int32 because |lastIndex| is computed from transpiled self-hosted call.
1464 int32_t lastIndex
= iter
.readInt32();
1466 RootedValue
result(cx
);
1467 if (!RegExpMatcherRaw(cx
, regexp
, input
, lastIndex
, nullptr, &result
)) {
1471 iter
.storeInstructionResult(result
);
1475 bool MTypeOf::writeRecoverData(CompactBufferWriter
& writer
) const {
1476 MOZ_ASSERT(canRecoverOnBailout());
1477 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf
));
1481 RTypeOf::RTypeOf(CompactBufferReader
& reader
) {}
1483 bool RTypeOf::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1484 JS::Value v
= iter
.read();
1486 iter
.storeInstructionResult(Int32Value(TypeOfValue(v
)));
1490 bool MTypeOfName::writeRecoverData(CompactBufferWriter
& writer
) const {
1491 MOZ_ASSERT(canRecoverOnBailout());
1492 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TypeOfName
));
1496 RTypeOfName::RTypeOfName(CompactBufferReader
& reader
) {}
1498 bool RTypeOfName::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1499 // Int32 because |type| is computed from MTypeOf.
1500 int32_t type
= iter
.readInt32();
1501 MOZ_ASSERT(JSTYPE_UNDEFINED
<= type
&& type
< JSTYPE_LIMIT
);
1503 JSString
* name
= TypeName(JSType(type
), *cx
->runtime()->commonNames
);
1504 iter
.storeInstructionResult(StringValue(name
));
1508 bool MToDouble::writeRecoverData(CompactBufferWriter
& writer
) const {
1509 MOZ_ASSERT(canRecoverOnBailout());
1510 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble
));
1514 RToDouble::RToDouble(CompactBufferReader
& reader
) {}
1516 bool RToDouble::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1517 RootedValue
v(cx
, iter
.read());
1519 MOZ_ASSERT(!v
.isObject());
1520 MOZ_ASSERT(!v
.isSymbol());
1521 MOZ_ASSERT(!v
.isBigInt());
1524 if (!ToNumber(cx
, v
, &dbl
)) {
1528 iter
.storeInstructionResult(DoubleValue(dbl
));
1532 bool MToFloat32::writeRecoverData(CompactBufferWriter
& writer
) const {
1533 MOZ_ASSERT(canRecoverOnBailout());
1534 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32
));
1538 RToFloat32::RToFloat32(CompactBufferReader
& reader
) {}
1540 bool RToFloat32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1541 double num
= iter
.readNumber();
1542 double result
= js::RoundFloat32(num
);
1544 iter
.storeInstructionResult(DoubleValue(result
));
1548 bool MTruncateToInt32::writeRecoverData(CompactBufferWriter
& writer
) const {
1549 MOZ_ASSERT(canRecoverOnBailout());
1550 writer
.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32
));
1554 RTruncateToInt32::RTruncateToInt32(CompactBufferReader
& reader
) {}
1556 bool RTruncateToInt32::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1557 RootedValue
value(cx
, iter
.read());
1560 if (!JS::ToInt32(cx
, value
, &trunc
)) {
1564 iter
.storeInstructionResult(Int32Value(trunc
));
1568 bool MNewObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1569 MOZ_ASSERT(canRecoverOnBailout());
1571 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewObject
));
1573 // Recover instructions are only supported if we have a template object.
1574 MOZ_ASSERT(mode_
== MNewObject::ObjectCreate
);
1578 RNewObject::RNewObject(CompactBufferReader
& reader
) {}
1580 bool RNewObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1581 RootedObject
templateObject(cx
, iter
.readObject());
1583 // See CodeGenerator::visitNewObjectVMCall.
1584 // Note that recover instructions are only used if mode == ObjectCreate.
1585 JSObject
* resultObject
=
1586 ObjectCreateWithTemplate(cx
, templateObject
.as
<PlainObject
>());
1587 if (!resultObject
) {
1591 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1595 bool MNewPlainObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1596 MOZ_ASSERT(canRecoverOnBailout());
1597 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewPlainObject
));
1599 MOZ_ASSERT(gc::AllocKind(uint8_t(allocKind_
)) == allocKind_
);
1600 writer
.writeByte(uint8_t(allocKind_
));
1601 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_
)) == initialHeap_
);
1602 writer
.writeByte(uint8_t(initialHeap_
));
1606 RNewPlainObject::RNewPlainObject(CompactBufferReader
& reader
) {
1607 allocKind_
= gc::AllocKind(reader
.readByte());
1608 MOZ_ASSERT(gc::IsValidAllocKind(allocKind_
));
1609 initialHeap_
= gc::Heap(reader
.readByte());
1610 MOZ_ASSERT(initialHeap_
== gc::Heap::Default
||
1611 initialHeap_
== gc::Heap::Tenured
);
1614 bool RNewPlainObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1615 Rooted
<SharedShape
*> shape(cx
, &iter
.readGCCellPtr().as
<Shape
>().asShared());
1617 // See CodeGenerator::visitNewPlainObject.
1618 JSObject
* resultObject
=
1619 NewPlainObjectOptimizedFallback(cx
, shape
, allocKind_
, initialHeap_
);
1620 if (!resultObject
) {
1624 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1628 bool MNewArrayObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1629 MOZ_ASSERT(canRecoverOnBailout());
1630 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayObject
));
1632 writer
.writeUnsigned(length_
);
1633 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_
)) == initialHeap_
);
1634 writer
.writeByte(uint8_t(initialHeap_
));
1638 RNewArrayObject::RNewArrayObject(CompactBufferReader
& reader
) {
1639 length_
= reader
.readUnsigned();
1640 initialHeap_
= gc::Heap(reader
.readByte());
1641 MOZ_ASSERT(initialHeap_
== gc::Heap::Default
||
1642 initialHeap_
== gc::Heap::Tenured
);
1645 bool RNewArrayObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1646 iter
.read(); // Skip unused shape field.
1648 NewObjectKind kind
=
1649 initialHeap_
== gc::Heap::Tenured
? TenuredObject
: GenericObject
;
1650 JSObject
* array
= NewArrayOperation(cx
, length_
, kind
);
1655 iter
.storeInstructionResult(ObjectValue(*array
));
1659 bool MNewTypedArray::writeRecoverData(CompactBufferWriter
& writer
) const {
1660 MOZ_ASSERT(canRecoverOnBailout());
1661 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray
));
1665 RNewTypedArray::RNewTypedArray(CompactBufferReader
& reader
) {}
1667 bool RNewTypedArray::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1668 RootedObject
templateObject(cx
, iter
.readObject());
1670 size_t length
= templateObject
.as
<FixedLengthTypedArrayObject
>()->length();
1671 MOZ_ASSERT(length
<= INT32_MAX
,
1672 "Template objects are only created for int32 lengths");
1674 JSObject
* resultObject
=
1675 NewTypedArrayWithTemplateAndLength(cx
, templateObject
, length
);
1676 if (!resultObject
) {
1680 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1684 bool MNewArray::writeRecoverData(CompactBufferWriter
& writer
) const {
1685 MOZ_ASSERT(canRecoverOnBailout());
1686 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewArray
));
1687 writer
.writeUnsigned(length());
1691 RNewArray::RNewArray(CompactBufferReader
& reader
) {
1692 count_
= reader
.readUnsigned();
1695 bool RNewArray::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1696 RootedObject
templateObject(cx
, iter
.readObject());
1697 Rooted
<Shape
*> shape(cx
, templateObject
->shape());
1699 ArrayObject
* resultObject
= NewArrayWithShape(cx
, count_
, shape
);
1700 if (!resultObject
) {
1704 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1708 bool MNewIterator::writeRecoverData(CompactBufferWriter
& writer
) const {
1709 MOZ_ASSERT(canRecoverOnBailout());
1710 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator
));
1711 writer
.writeByte(type_
);
1715 RNewIterator::RNewIterator(CompactBufferReader
& reader
) {
1716 type_
= reader
.readByte();
1719 bool RNewIterator::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1720 RootedObject
templateObject(cx
, iter
.readObject());
1722 JSObject
* resultObject
= nullptr;
1723 switch (MNewIterator::Type(type_
)) {
1724 case MNewIterator::ArrayIterator
:
1725 resultObject
= NewArrayIterator(cx
);
1727 case MNewIterator::StringIterator
:
1728 resultObject
= NewStringIterator(cx
);
1730 case MNewIterator::RegExpStringIterator
:
1731 resultObject
= NewRegExpStringIterator(cx
);
1735 if (!resultObject
) {
1739 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1743 bool MLambda::writeRecoverData(CompactBufferWriter
& writer
) const {
1744 MOZ_ASSERT(canRecoverOnBailout());
1745 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Lambda
));
1749 RLambda::RLambda(CompactBufferReader
& reader
) {}
1751 bool RLambda::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1752 RootedObject
scopeChain(cx
, iter
.readObject());
1753 RootedFunction
fun(cx
, &iter
.readObject()->as
<JSFunction
>());
1755 JSObject
* resultObject
= js::Lambda(cx
, fun
, scopeChain
);
1756 if (!resultObject
) {
1760 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1764 bool MFunctionWithProto::writeRecoverData(CompactBufferWriter
& writer
) const {
1765 MOZ_ASSERT(canRecoverOnBailout());
1766 writer
.writeUnsigned(uint32_t(RInstruction::Recover_FunctionWithProto
));
1770 RFunctionWithProto::RFunctionWithProto(CompactBufferReader
& reader
) {}
1772 bool RFunctionWithProto::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1773 RootedObject
scopeChain(cx
, iter
.readObject());
1774 RootedObject
prototype(cx
, iter
.readObject());
1775 RootedFunction
fun(cx
, &iter
.readObject()->as
<JSFunction
>());
1777 JSObject
* resultObject
=
1778 js::FunWithProtoOperation(cx
, fun
, scopeChain
, prototype
);
1779 if (!resultObject
) {
1783 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1787 bool MNewCallObject::writeRecoverData(CompactBufferWriter
& writer
) const {
1788 MOZ_ASSERT(canRecoverOnBailout());
1789 writer
.writeUnsigned(uint32_t(RInstruction::Recover_NewCallObject
));
1793 RNewCallObject::RNewCallObject(CompactBufferReader
& reader
) {}
1795 bool RNewCallObject::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1796 Rooted
<CallObject
*> templateObj(cx
, &iter
.readObject()->as
<CallObject
>());
1798 Rooted
<SharedShape
*> shape(cx
, templateObj
->sharedShape());
1800 JSObject
* resultObject
= CallObject::createWithShape(cx
, shape
);
1801 if (!resultObject
) {
1805 iter
.storeInstructionResult(ObjectValue(*resultObject
));
1809 bool MObjectKeys::canRecoverOnBailout() const {
1810 // Only claim that this operation can be recovered on bailout if some other
1811 // optimization already marked it as such.
1812 return isRecoveredOnBailout();
1815 bool MObjectKeys::writeRecoverData(CompactBufferWriter
& writer
) const {
1816 MOZ_ASSERT(canRecoverOnBailout());
1817 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ObjectKeys
));
1821 RObjectKeys::RObjectKeys(CompactBufferReader
& reader
) {}
1823 bool RObjectKeys::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1824 Rooted
<JSObject
*> obj(cx
, iter
.readObject());
1826 JSObject
* resultKeys
= ObjectKeys(cx
, obj
);
1831 iter
.storeInstructionResult(ObjectValue(*resultKeys
));
1835 bool MObjectState::writeRecoverData(CompactBufferWriter
& writer
) const {
1836 MOZ_ASSERT(canRecoverOnBailout());
1837 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState
));
1838 writer
.writeUnsigned(numSlots());
1842 RObjectState::RObjectState(CompactBufferReader
& reader
) {
1843 numSlots_
= reader
.readUnsigned();
1846 bool RObjectState::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1847 RootedObject
object(cx
, iter
.readObject());
1848 Handle
<NativeObject
*> nativeObject
= object
.as
<NativeObject
>();
1849 MOZ_ASSERT(!Watchtower::watchesPropertyModification(nativeObject
));
1850 MOZ_ASSERT(nativeObject
->slotSpan() == numSlots());
1852 for (size_t i
= 0; i
< numSlots(); i
++) {
1853 Value val
= iter
.read();
1854 nativeObject
->setSlot(i
, val
);
1857 iter
.storeInstructionResult(ObjectValue(*object
));
1861 bool MArrayState::writeRecoverData(CompactBufferWriter
& writer
) const {
1862 MOZ_ASSERT(canRecoverOnBailout());
1863 writer
.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState
));
1864 writer
.writeUnsigned(numElements());
1868 RArrayState::RArrayState(CompactBufferReader
& reader
) {
1869 numElements_
= reader
.readUnsigned();
1872 bool RArrayState::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1873 ArrayObject
* object
= &iter
.readObject()->as
<ArrayObject
>();
1875 // Int32 because |initLength| is computed from MConstant.
1876 uint32_t initLength
= iter
.readInt32();
1878 MOZ_ASSERT(object
->getDenseInitializedLength() == 0,
1879 "initDenseElement call below relies on this");
1880 object
->setDenseInitializedLength(initLength
);
1882 for (size_t index
= 0; index
< numElements(); index
++) {
1883 Value val
= iter
.read();
1885 if (index
>= initLength
) {
1886 MOZ_ASSERT(val
.isUndefined());
1890 object
->initDenseElement(index
, val
);
1893 iter
.storeInstructionResult(ObjectValue(*object
));
1897 bool MAssertRecoveredOnBailout::writeRecoverData(
1898 CompactBufferWriter
& writer
) const {
1899 MOZ_ASSERT(canRecoverOnBailout());
1900 MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout() == mustBeRecovered_
,
1901 "assertRecoveredOnBailout failed during compilation");
1902 writer
.writeUnsigned(
1903 uint32_t(RInstruction::Recover_AssertRecoveredOnBailout
));
1907 RAssertRecoveredOnBailout::RAssertRecoveredOnBailout(
1908 CompactBufferReader
& reader
) {}
1910 bool RAssertRecoveredOnBailout::recover(JSContext
* cx
,
1911 SnapshotIterator
& iter
) const {
1912 iter
.read(); // skip the unused operand.
1913 iter
.storeInstructionResult(UndefinedValue());
1917 bool MStringReplace::writeRecoverData(CompactBufferWriter
& writer
) const {
1918 MOZ_ASSERT(canRecoverOnBailout());
1919 writer
.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace
));
1920 writer
.writeByte(isFlatReplacement_
);
1924 RStringReplace::RStringReplace(CompactBufferReader
& reader
) {
1925 isFlatReplacement_
= reader
.readByte();
1928 bool RStringReplace::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1929 RootedString
string(cx
, iter
.readString());
1930 RootedString
pattern(cx
, iter
.readString());
1931 RootedString
replace(cx
, iter
.readString());
1935 ? js::StringFlatReplaceString(cx
, string
, pattern
, replace
)
1936 : js::str_replace_string_raw(cx
, string
, pattern
, replace
);
1942 iter
.storeInstructionResult(StringValue(result
));
1946 bool MSubstr::writeRecoverData(CompactBufferWriter
& writer
) const {
1947 MOZ_ASSERT(canRecoverOnBailout());
1948 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Substr
));
1952 RSubstr::RSubstr(CompactBufferReader
& reader
) {}
1954 bool RSubstr::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1955 RootedString
str(cx
, iter
.readString());
1957 // Int32 because |begin| is computed from MStringTrimStartIndex, MConstant,
1958 // or CallSubstringKernelResult.
1959 int32_t begin
= iter
.readInt32();
1961 // |length| is computed from MSub(truncated), MStringTrimEndIndex, or
1962 // CallSubstringKernelResult. The current MSub inputs won't overflow, so when
1963 // RSub recovers the MSub instruction, the input will be representable as an
1964 // Int32. This is only true as long as RSub calls |js::SubOperation|, which in
1965 // turn calls |JS::Value::setNumber|. We don't want to rely on this exact call
1966 // sequence, so instead use |readNumber| here and then release-assert the
1967 // number is exactly representable as an Int32.
1968 int32_t length
= mozilla::ReleaseAssertedCast
<int32_t>(iter
.readNumber());
1970 JSString
* result
= SubstringKernel(cx
, str
, begin
, length
);
1975 iter
.storeInstructionResult(StringValue(result
));
1979 bool MAtomicIsLockFree::writeRecoverData(CompactBufferWriter
& writer
) const {
1980 MOZ_ASSERT(canRecoverOnBailout());
1981 writer
.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree
));
1985 RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader
& reader
) {}
1987 bool RAtomicIsLockFree::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
1988 double dsize
= JS::ToInteger(iter
.readNumber());
1991 bool result
= mozilla::NumberEqualsInt32(dsize
, &size
) &&
1992 AtomicOperations::isLockfreeJS(size
);
1993 iter
.storeInstructionResult(BooleanValue(result
));
1997 bool MBigIntAsIntN::writeRecoverData(CompactBufferWriter
& writer
) const {
1998 MOZ_ASSERT(canRecoverOnBailout());
1999 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsIntN
));
2003 RBigIntAsIntN::RBigIntAsIntN(CompactBufferReader
& reader
) {}
2005 bool RBigIntAsIntN::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2006 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2007 int32_t bits
= iter
.readInt32();
2008 MOZ_ASSERT(bits
>= 0);
2010 RootedBigInt
input(cx
, iter
.readBigInt());
2012 BigInt
* result
= BigInt::asIntN(cx
, input
, bits
);
2017 iter
.storeInstructionResult(JS::BigIntValue(result
));
2021 bool MBigIntAsUintN::writeRecoverData(CompactBufferWriter
& writer
) const {
2022 MOZ_ASSERT(canRecoverOnBailout());
2023 writer
.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsUintN
));
2027 RBigIntAsUintN::RBigIntAsUintN(CompactBufferReader
& reader
) {}
2029 bool RBigIntAsUintN::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2030 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2031 int32_t bits
= iter
.readInt32();
2032 MOZ_ASSERT(bits
>= 0);
2034 RootedBigInt
input(cx
, iter
.readBigInt());
2036 BigInt
* result
= BigInt::asUintN(cx
, input
, bits
);
2041 iter
.storeInstructionResult(JS::BigIntValue(result
));
2045 bool MCreateArgumentsObject::writeRecoverData(
2046 CompactBufferWriter
& writer
) const {
2047 MOZ_ASSERT(canRecoverOnBailout());
2048 writer
.writeUnsigned(uint32_t(RInstruction::Recover_CreateArgumentsObject
));
2052 RCreateArgumentsObject::RCreateArgumentsObject(CompactBufferReader
& reader
) {}
2054 bool RCreateArgumentsObject::recover(JSContext
* cx
,
2055 SnapshotIterator
& iter
) const {
2056 RootedObject
callObject(cx
, iter
.readObject());
2057 RootedObject
result(
2058 cx
, ArgumentsObject::createForIon(cx
, iter
.frame(), callObject
));
2063 iter
.storeInstructionResult(JS::ObjectValue(*result
));
2067 bool MCreateInlinedArgumentsObject::writeRecoverData(
2068 CompactBufferWriter
& writer
) const {
2069 MOZ_ASSERT(canRecoverOnBailout());
2070 writer
.writeUnsigned(
2071 uint32_t(RInstruction::Recover_CreateInlinedArgumentsObject
));
2072 writer
.writeUnsigned(numActuals());
2076 RCreateInlinedArgumentsObject::RCreateInlinedArgumentsObject(
2077 CompactBufferReader
& reader
) {
2078 numActuals_
= reader
.readUnsigned();
2081 bool RCreateInlinedArgumentsObject::recover(JSContext
* cx
,
2082 SnapshotIterator
& iter
) const {
2083 RootedObject
callObject(cx
, iter
.readObject());
2084 RootedFunction
callee(cx
, &iter
.readObject()->as
<JSFunction
>());
2086 JS::RootedValueArray
<ArgumentsObject::MaxInlinedArgs
> argsArray(cx
);
2087 for (uint32_t i
= 0; i
< numActuals_
; i
++) {
2088 argsArray
[i
].set(iter
.read());
2091 ArgumentsObject
* result
= ArgumentsObject::createFromValueArray(
2092 cx
, argsArray
, callee
, callObject
, numActuals_
);
2097 iter
.storeInstructionResult(JS::ObjectValue(*result
));
2101 bool MRest::writeRecoverData(CompactBufferWriter
& writer
) const {
2102 MOZ_ASSERT(canRecoverOnBailout());
2103 writer
.writeUnsigned(uint32_t(RInstruction::Recover_Rest
));
2104 writer
.writeUnsigned(numFormals());
2108 RRest::RRest(CompactBufferReader
& reader
) {
2109 numFormals_
= reader
.readUnsigned();
2112 bool RRest::recover(JSContext
* cx
, SnapshotIterator
& iter
) const {
2113 JitFrameLayout
* frame
= iter
.frame();
2115 // Int32 because |numActuals| is computed from MArgumentsLength.
2116 uint32_t numActuals
= iter
.readInt32();
2117 MOZ_ASSERT(numActuals
== frame
->numActualArgs());
2119 uint32_t numFormals
= numFormals_
;
2121 uint32_t length
= std::max(numActuals
, numFormals
) - numFormals
;
2122 Value
* src
= frame
->actualArgs() + numFormals
;
2123 JSObject
* rest
= jit::InitRestParameter(cx
, length
, src
, nullptr);
2128 iter
.storeInstructionResult(ObjectValue(*rest
));