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