Bug 1885489 - Part 6: Add SnapshotIterator::readNumber(). r=iain
[gecko.git] / js / src / jit / Recover.cpp
blobe5e07fe017f4ae4d3e1434fd023ee35a6321f892
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 "jsmath.h"
11 #include "builtin/Object.h"
12 #include "builtin/RegExp.h"
13 #include "builtin/String.h"
14 #include "jit/AtomicOperations.h"
15 #include "jit/Bailouts.h"
16 #include "jit/CompileInfo.h"
17 #include "jit/Ion.h"
18 #include "jit/JitSpewer.h"
19 #include "jit/JSJitFrameIter.h"
20 #include "jit/MIR.h"
21 #include "jit/MIRGraph.h"
22 #include "jit/VMFunctions.h"
23 #include "util/DifferentialTesting.h"
24 #include "vm/BigIntType.h"
25 #include "vm/EqualityOperations.h"
26 #include "vm/Interpreter.h"
27 #include "vm/Iteration.h"
28 #include "vm/JSContext.h"
29 #include "vm/JSObject.h"
30 #include "vm/PlainObject.h" // js::PlainObject
31 #include "vm/StringType.h"
32 #include "vm/Watchtower.h"
34 #include "vm/Interpreter-inl.h"
36 using namespace js;
37 using namespace js::jit;
39 bool MNode::writeRecoverData(CompactBufferWriter& writer) const {
40 MOZ_CRASH("This instruction is not serializable");
43 void RInstruction::readRecoverData(CompactBufferReader& reader,
44 RInstructionStorage* raw) {
45 uint32_t op = reader.readUnsigned();
46 switch (Opcode(op)) {
47 #define MATCH_OPCODES_(op) \
48 case Recover_##op: \
49 static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \
50 "storage space must be big enough to store R" #op); \
51 static_assert(alignof(R##op) <= alignof(RInstructionStorage), \
52 "storage space must be aligned adequate to store R" #op); \
53 new (raw->addr()) R##op(reader); \
54 break;
56 RECOVER_OPCODE_LIST(MATCH_OPCODES_)
57 #undef MATCH_OPCODES_
59 case Recover_Invalid:
60 default:
61 MOZ_CRASH("Bad decoding of the previous instruction?");
65 bool MResumePoint::writeRecoverData(CompactBufferWriter& writer) const {
66 writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint));
68 MBasicBlock* bb = block();
69 bool hasFun = bb->info().hasFunMaybeLazy();
70 uint32_t nargs = bb->info().nargs();
71 JSScript* script = bb->info().script();
72 uint32_t exprStack = stackDepth() - bb->info().ninvoke();
74 #ifdef DEBUG
75 // Ensure that all snapshot which are encoded can safely be used for
76 // bailouts.
77 uint32_t numIntermediate = NumIntermediateValues(mode());
78 if (JSContext* cx = GetJitContext()->cx) {
79 if (!AssertBailoutStackDepth(cx, script, pc(), mode(),
80 exprStack - numIntermediate)) {
81 return false;
84 #endif
86 uint32_t formalArgs = CountArgSlots(script, hasFun, nargs);
88 // Test if we honor the maximum of arguments at all times. This is a sanity
89 // check and not an algorithm limit. So check might be a bit too loose. +4
90 // to account for scope chain, return value, this value and maybe
91 // arguments_object.
92 MOZ_ASSERT(formalArgs < SNAPSHOT_MAX_NARGS + 4);
94 #ifdef JS_JITSPEW
95 uint32_t implicit = StartArgSlot(script);
96 #endif
97 uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
99 JitSpew(JitSpew_IonSnapshots,
100 "Starting frame; implicit %u, formals %u, fixed %zu, exprs %u",
101 implicit, formalArgs - implicit, script->nfixed(), exprStack);
103 uint32_t pcOff = script->pcToOffset(pc());
104 JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, mode %s, nslots %u",
105 pcOff, ResumeModeToString(mode()), nallocs);
107 uint32_t pcOffAndMode =
108 (pcOff << RResumePoint::PCOffsetShift) | uint32_t(mode());
109 MOZ_RELEASE_ASSERT((pcOffAndMode >> RResumePoint::PCOffsetShift) == pcOff,
110 "pcOff doesn't fit in pcOffAndMode");
111 writer.writeUnsigned(pcOffAndMode);
113 writer.writeUnsigned(nallocs);
114 return true;
117 RResumePoint::RResumePoint(CompactBufferReader& reader) {
118 pcOffsetAndMode_ = reader.readUnsigned();
119 numOperands_ = reader.readUnsigned();
120 JitSpew(JitSpew_IonSnapshots,
121 "Read RResumePoint (pc offset %u, mode %s, nslots %u)", pcOffset(),
122 ResumeModeToString(mode()), numOperands_);
125 bool RResumePoint::recover(JSContext* cx, SnapshotIterator& iter) const {
126 MOZ_CRASH("This instruction is not recoverable.");
129 bool MBitNot::writeRecoverData(CompactBufferWriter& writer) const {
130 // 64-bit int bitnots exist only when compiling wasm; they exist neither for
131 // JS nor asm.js. So we don't expect them here.
132 MOZ_ASSERT(type() != MIRType::Int64);
133 MOZ_ASSERT(canRecoverOnBailout());
134 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitNot));
135 return true;
138 RBitNot::RBitNot(CompactBufferReader& reader) {}
140 bool RBitNot::recover(JSContext* cx, SnapshotIterator& iter) const {
141 RootedValue operand(cx, iter.read());
142 RootedValue result(cx);
144 if (!js::BitNot(cx, &operand, &result)) {
145 return false;
148 iter.storeInstructionResult(result);
149 return true;
152 bool MBitAnd::writeRecoverData(CompactBufferWriter& writer) const {
153 MOZ_ASSERT(canRecoverOnBailout());
154 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd));
155 return true;
158 RBitAnd::RBitAnd(CompactBufferReader& reader) {}
160 bool RBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const {
161 RootedValue lhs(cx, iter.read());
162 RootedValue rhs(cx, iter.read());
163 RootedValue result(cx);
164 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
166 if (!js::BitAnd(cx, &lhs, &rhs, &result)) {
167 return false;
170 iter.storeInstructionResult(result);
171 return true;
174 bool MBitOr::writeRecoverData(CompactBufferWriter& writer) const {
175 MOZ_ASSERT(canRecoverOnBailout());
176 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitOr));
177 return true;
180 RBitOr::RBitOr(CompactBufferReader& reader) {}
182 bool RBitOr::recover(JSContext* cx, SnapshotIterator& iter) const {
183 RootedValue lhs(cx, iter.read());
184 RootedValue rhs(cx, iter.read());
185 RootedValue result(cx);
186 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
188 if (!js::BitOr(cx, &lhs, &rhs, &result)) {
189 return false;
192 iter.storeInstructionResult(result);
193 return true;
196 bool MBitXor::writeRecoverData(CompactBufferWriter& writer) const {
197 MOZ_ASSERT(canRecoverOnBailout());
198 writer.writeUnsigned(uint32_t(RInstruction::Recover_BitXor));
199 return true;
202 RBitXor::RBitXor(CompactBufferReader& reader) {}
204 bool RBitXor::recover(JSContext* cx, SnapshotIterator& iter) const {
205 RootedValue lhs(cx, iter.read());
206 RootedValue rhs(cx, iter.read());
207 RootedValue result(cx);
209 if (!js::BitXor(cx, &lhs, &rhs, &result)) {
210 return false;
213 iter.storeInstructionResult(result);
214 return true;
217 bool MLsh::writeRecoverData(CompactBufferWriter& writer) const {
218 MOZ_ASSERT(canRecoverOnBailout());
219 writer.writeUnsigned(uint32_t(RInstruction::Recover_Lsh));
220 return true;
223 RLsh::RLsh(CompactBufferReader& reader) {}
225 bool RLsh::recover(JSContext* cx, SnapshotIterator& iter) const {
226 RootedValue lhs(cx, iter.read());
227 RootedValue rhs(cx, iter.read());
228 RootedValue result(cx);
229 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
231 if (!js::BitLsh(cx, &lhs, &rhs, &result)) {
232 return false;
235 iter.storeInstructionResult(result);
236 return true;
239 bool MRsh::writeRecoverData(CompactBufferWriter& writer) const {
240 MOZ_ASSERT(canRecoverOnBailout());
241 writer.writeUnsigned(uint32_t(RInstruction::Recover_Rsh));
242 return true;
245 RRsh::RRsh(CompactBufferReader& reader) {}
247 bool RRsh::recover(JSContext* cx, SnapshotIterator& iter) const {
248 RootedValue lhs(cx, iter.read());
249 RootedValue rhs(cx, iter.read());
250 RootedValue result(cx);
251 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
253 if (!js::BitRsh(cx, &lhs, &rhs, &result)) {
254 return false;
257 iter.storeInstructionResult(result);
258 return true;
261 bool MUrsh::writeRecoverData(CompactBufferWriter& writer) const {
262 MOZ_ASSERT(canRecoverOnBailout());
263 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ursh));
264 return true;
267 RUrsh::RUrsh(CompactBufferReader& reader) {}
269 bool RUrsh::recover(JSContext* cx, SnapshotIterator& iter) const {
270 RootedValue lhs(cx, iter.read());
271 RootedValue rhs(cx, iter.read());
272 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
274 RootedValue result(cx);
275 if (!js::UrshValues(cx, &lhs, &rhs, &result)) {
276 return false;
279 iter.storeInstructionResult(result);
280 return true;
283 bool MSignExtendInt32::writeRecoverData(CompactBufferWriter& writer) const {
284 MOZ_ASSERT(canRecoverOnBailout());
285 writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtendInt32));
286 MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
287 writer.writeByte(uint8_t(mode_));
288 return true;
291 RSignExtendInt32::RSignExtendInt32(CompactBufferReader& reader) {
292 mode_ = reader.readByte();
295 bool RSignExtendInt32::recover(JSContext* cx, SnapshotIterator& iter) const {
296 RootedValue operand(cx, iter.read());
298 int32_t i;
299 if (!ToInt32(cx, operand, &i)) {
300 return false;
303 int32_t result;
304 switch (MSignExtendInt32::Mode(mode_)) {
305 case MSignExtendInt32::Byte:
306 result = static_cast<int8_t>(i);
307 break;
308 case MSignExtendInt32::Half:
309 result = static_cast<int16_t>(i);
310 break;
313 iter.storeInstructionResult(JS::Int32Value(result));
314 return true;
317 bool MAdd::writeRecoverData(CompactBufferWriter& writer) const {
318 MOZ_ASSERT(canRecoverOnBailout());
319 writer.writeUnsigned(uint32_t(RInstruction::Recover_Add));
320 writer.writeByte(type() == MIRType::Float32);
321 return true;
324 RAdd::RAdd(CompactBufferReader& reader) {
325 isFloatOperation_ = reader.readByte();
328 bool RAdd::recover(JSContext* cx, SnapshotIterator& iter) const {
329 RootedValue lhs(cx, iter.read());
330 RootedValue rhs(cx, iter.read());
331 RootedValue result(cx);
333 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
334 if (!js::AddValues(cx, &lhs, &rhs, &result)) {
335 return false;
338 // MIRType::Float32 is a specialization embedding the fact that the result is
339 // rounded to a Float32.
340 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
341 return false;
344 iter.storeInstructionResult(result);
345 return true;
348 bool MSub::writeRecoverData(CompactBufferWriter& writer) const {
349 MOZ_ASSERT(canRecoverOnBailout());
350 writer.writeUnsigned(uint32_t(RInstruction::Recover_Sub));
351 writer.writeByte(type() == MIRType::Float32);
352 return true;
355 RSub::RSub(CompactBufferReader& reader) {
356 isFloatOperation_ = reader.readByte();
359 bool RSub::recover(JSContext* cx, SnapshotIterator& iter) const {
360 RootedValue lhs(cx, iter.read());
361 RootedValue rhs(cx, iter.read());
362 RootedValue result(cx);
364 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
365 if (!js::SubValues(cx, &lhs, &rhs, &result)) {
366 return false;
369 // MIRType::Float32 is a specialization embedding the fact that the result is
370 // rounded to a Float32.
371 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
372 return false;
375 iter.storeInstructionResult(result);
376 return true;
379 bool MMul::writeRecoverData(CompactBufferWriter& writer) const {
380 MOZ_ASSERT(canRecoverOnBailout());
381 writer.writeUnsigned(uint32_t(RInstruction::Recover_Mul));
382 writer.writeByte(type() == MIRType::Float32);
383 MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
384 writer.writeByte(uint8_t(mode_));
385 return true;
388 RMul::RMul(CompactBufferReader& reader) {
389 isFloatOperation_ = reader.readByte();
390 mode_ = reader.readByte();
393 bool RMul::recover(JSContext* cx, SnapshotIterator& iter) const {
394 RootedValue lhs(cx, iter.read());
395 RootedValue rhs(cx, iter.read());
396 RootedValue result(cx);
398 if (MMul::Mode(mode_) == MMul::Normal) {
399 if (!js::MulValues(cx, &lhs, &rhs, &result)) {
400 return false;
403 // MIRType::Float32 is a specialization embedding the fact that the
404 // result is rounded to a Float32.
405 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
406 return false;
408 } else {
409 MOZ_ASSERT(MMul::Mode(mode_) == MMul::Integer);
410 if (!js::math_imul_handle(cx, lhs, rhs, &result)) {
411 return false;
415 iter.storeInstructionResult(result);
416 return true;
419 bool MDiv::writeRecoverData(CompactBufferWriter& writer) const {
420 MOZ_ASSERT(canRecoverOnBailout());
421 writer.writeUnsigned(uint32_t(RInstruction::Recover_Div));
422 writer.writeByte(type() == MIRType::Float32);
423 return true;
426 RDiv::RDiv(CompactBufferReader& reader) {
427 isFloatOperation_ = reader.readByte();
430 bool RDiv::recover(JSContext* cx, SnapshotIterator& iter) const {
431 RootedValue lhs(cx, iter.read());
432 RootedValue rhs(cx, iter.read());
433 RootedValue result(cx);
435 if (!js::DivValues(cx, &lhs, &rhs, &result)) {
436 return false;
439 // MIRType::Float32 is a specialization embedding the fact that the result is
440 // rounded to a Float32.
441 if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
442 return false;
445 iter.storeInstructionResult(result);
446 return true;
449 bool MMod::writeRecoverData(CompactBufferWriter& writer) const {
450 MOZ_ASSERT(canRecoverOnBailout());
451 writer.writeUnsigned(uint32_t(RInstruction::Recover_Mod));
452 return true;
455 RMod::RMod(CompactBufferReader& reader) {}
457 bool RMod::recover(JSContext* cx, SnapshotIterator& iter) const {
458 RootedValue lhs(cx, iter.read());
459 RootedValue rhs(cx, iter.read());
460 RootedValue result(cx);
462 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
463 if (!js::ModValues(cx, &lhs, &rhs, &result)) {
464 return false;
467 iter.storeInstructionResult(result);
468 return true;
471 bool MNot::writeRecoverData(CompactBufferWriter& writer) const {
472 MOZ_ASSERT(canRecoverOnBailout());
473 writer.writeUnsigned(uint32_t(RInstruction::Recover_Not));
474 return true;
477 RNot::RNot(CompactBufferReader& reader) {}
479 bool RNot::recover(JSContext* cx, SnapshotIterator& iter) const {
480 RootedValue v(cx, iter.read());
481 RootedValue result(cx);
483 result.setBoolean(!ToBoolean(v));
485 iter.storeInstructionResult(result);
486 return true;
489 bool MBigIntAdd::writeRecoverData(CompactBufferWriter& writer) const {
490 MOZ_ASSERT(canRecoverOnBailout());
491 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAdd));
492 return true;
495 RBigIntAdd::RBigIntAdd(CompactBufferReader& reader) {}
497 bool RBigIntAdd::recover(JSContext* cx, SnapshotIterator& iter) const {
498 RootedValue lhs(cx, iter.read());
499 RootedValue rhs(cx, iter.read());
500 RootedValue result(cx);
502 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
503 if (!js::AddValues(cx, &lhs, &rhs, &result)) {
504 return false;
507 iter.storeInstructionResult(result);
508 return true;
511 bool MBigIntSub::writeRecoverData(CompactBufferWriter& writer) const {
512 MOZ_ASSERT(canRecoverOnBailout());
513 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntSub));
514 return true;
517 RBigIntSub::RBigIntSub(CompactBufferReader& reader) {}
519 bool RBigIntSub::recover(JSContext* cx, SnapshotIterator& iter) const {
520 RootedValue lhs(cx, iter.read());
521 RootedValue rhs(cx, iter.read());
522 RootedValue result(cx);
524 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
525 if (!js::SubValues(cx, &lhs, &rhs, &result)) {
526 return false;
529 iter.storeInstructionResult(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 RootedValue lhs(cx, iter.read());
543 RootedValue rhs(cx, iter.read());
544 RootedValue result(cx);
546 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
547 if (!js::MulValues(cx, &lhs, &rhs, &result)) {
548 return false;
551 iter.storeInstructionResult(result);
552 return true;
555 bool MBigIntDiv::writeRecoverData(CompactBufferWriter& writer) const {
556 MOZ_ASSERT(canRecoverOnBailout());
557 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDiv));
558 return true;
561 RBigIntDiv::RBigIntDiv(CompactBufferReader& reader) {}
563 bool RBigIntDiv::recover(JSContext* cx, SnapshotIterator& iter) const {
564 RootedValue lhs(cx, iter.read());
565 RootedValue rhs(cx, iter.read());
566 RootedValue result(cx);
568 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
569 MOZ_ASSERT(!rhs.toBigInt()->isZero(),
570 "division by zero throws and therefore can't be recovered");
571 if (!js::DivValues(cx, &lhs, &rhs, &result)) {
572 return false;
575 iter.storeInstructionResult(result);
576 return true;
579 bool MBigIntMod::writeRecoverData(CompactBufferWriter& writer) const {
580 MOZ_ASSERT(canRecoverOnBailout());
581 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMod));
582 return true;
585 RBigIntMod::RBigIntMod(CompactBufferReader& reader) {}
587 bool RBigIntMod::recover(JSContext* cx, SnapshotIterator& iter) const {
588 RootedValue lhs(cx, iter.read());
589 RootedValue rhs(cx, iter.read());
590 RootedValue result(cx);
592 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
593 MOZ_ASSERT(!rhs.toBigInt()->isZero(),
594 "division by zero throws and therefore can't be recovered");
595 if (!js::ModValues(cx, &lhs, &rhs, &result)) {
596 return false;
599 iter.storeInstructionResult(result);
600 return true;
603 bool MBigIntPow::writeRecoverData(CompactBufferWriter& writer) const {
604 MOZ_ASSERT(canRecoverOnBailout());
605 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPow));
606 return true;
609 RBigIntPow::RBigIntPow(CompactBufferReader& reader) {}
611 bool RBigIntPow::recover(JSContext* cx, SnapshotIterator& iter) const {
612 RootedValue lhs(cx, iter.read());
613 RootedValue rhs(cx, iter.read());
614 RootedValue result(cx);
616 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
617 MOZ_ASSERT(!rhs.toBigInt()->isNegative(),
618 "negative exponent throws and therefore can't be recovered");
619 if (!js::PowValues(cx, &lhs, &rhs, &result)) {
620 return false;
623 iter.storeInstructionResult(result);
624 return true;
627 bool MBigIntBitAnd::writeRecoverData(CompactBufferWriter& writer) const {
628 MOZ_ASSERT(canRecoverOnBailout());
629 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitAnd));
630 return true;
633 RBigIntBitAnd::RBigIntBitAnd(CompactBufferReader& reader) {}
635 bool RBigIntBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const {
636 RootedValue lhs(cx, iter.read());
637 RootedValue rhs(cx, iter.read());
638 RootedValue result(cx);
640 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
641 if (!js::BitAnd(cx, &lhs, &rhs, &result)) {
642 return false;
645 iter.storeInstructionResult(result);
646 return true;
649 bool MBigIntBitOr::writeRecoverData(CompactBufferWriter& writer) const {
650 MOZ_ASSERT(canRecoverOnBailout());
651 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitOr));
652 return true;
655 RBigIntBitOr::RBigIntBitOr(CompactBufferReader& reader) {}
657 bool RBigIntBitOr::recover(JSContext* cx, SnapshotIterator& iter) const {
658 RootedValue lhs(cx, iter.read());
659 RootedValue rhs(cx, iter.read());
660 RootedValue result(cx);
662 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
663 if (!js::BitOr(cx, &lhs, &rhs, &result)) {
664 return false;
667 iter.storeInstructionResult(result);
668 return true;
671 bool MBigIntBitXor::writeRecoverData(CompactBufferWriter& writer) const {
672 MOZ_ASSERT(canRecoverOnBailout());
673 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitXor));
674 return true;
677 RBigIntBitXor::RBigIntBitXor(CompactBufferReader& reader) {}
679 bool RBigIntBitXor::recover(JSContext* cx, SnapshotIterator& iter) const {
680 RootedValue lhs(cx, iter.read());
681 RootedValue rhs(cx, iter.read());
682 RootedValue result(cx);
684 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
685 if (!js::BitXor(cx, &lhs, &rhs, &result)) {
686 return false;
689 iter.storeInstructionResult(result);
690 return true;
693 bool MBigIntLsh::writeRecoverData(CompactBufferWriter& writer) const {
694 MOZ_ASSERT(canRecoverOnBailout());
695 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntLsh));
696 return true;
699 RBigIntLsh::RBigIntLsh(CompactBufferReader& reader) {}
701 bool RBigIntLsh::recover(JSContext* cx, SnapshotIterator& iter) const {
702 RootedValue lhs(cx, iter.read());
703 RootedValue rhs(cx, iter.read());
704 RootedValue result(cx);
706 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
707 if (!js::BitLsh(cx, &lhs, &rhs, &result)) {
708 return false;
711 iter.storeInstructionResult(result);
712 return true;
715 bool MBigIntRsh::writeRecoverData(CompactBufferWriter& writer) const {
716 MOZ_ASSERT(canRecoverOnBailout());
717 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntRsh));
718 return true;
721 RBigIntRsh::RBigIntRsh(CompactBufferReader& reader) {}
723 bool RBigIntRsh::recover(JSContext* cx, SnapshotIterator& iter) const {
724 RootedValue lhs(cx, iter.read());
725 RootedValue rhs(cx, iter.read());
726 RootedValue result(cx);
728 MOZ_ASSERT(lhs.isBigInt() && rhs.isBigInt());
729 if (!js::BitRsh(cx, &lhs, &rhs, &result)) {
730 return false;
733 iter.storeInstructionResult(result);
734 return true;
737 bool MBigIntIncrement::writeRecoverData(CompactBufferWriter& writer) const {
738 MOZ_ASSERT(canRecoverOnBailout());
739 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntIncrement));
740 return true;
743 RBigIntIncrement::RBigIntIncrement(CompactBufferReader& reader) {}
745 bool RBigIntIncrement::recover(JSContext* cx, SnapshotIterator& iter) const {
746 RootedValue operand(cx, iter.read());
747 RootedValue result(cx);
749 MOZ_ASSERT(operand.isBigInt());
750 if (!js::IncOperation(cx, operand, &result)) {
751 return false;
754 iter.storeInstructionResult(result);
755 return true;
758 bool MBigIntDecrement::writeRecoverData(CompactBufferWriter& writer) const {
759 MOZ_ASSERT(canRecoverOnBailout());
760 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDecrement));
761 return true;
764 RBigIntDecrement::RBigIntDecrement(CompactBufferReader& reader) {}
766 bool RBigIntDecrement::recover(JSContext* cx, SnapshotIterator& iter) const {
767 RootedValue operand(cx, iter.read());
768 RootedValue result(cx);
770 MOZ_ASSERT(operand.isBigInt());
771 if (!js::DecOperation(cx, operand, &result)) {
772 return false;
775 iter.storeInstructionResult(result);
776 return true;
779 bool MBigIntNegate::writeRecoverData(CompactBufferWriter& writer) const {
780 MOZ_ASSERT(canRecoverOnBailout());
781 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntNegate));
782 return true;
785 RBigIntNegate::RBigIntNegate(CompactBufferReader& reader) {}
787 bool RBigIntNegate::recover(JSContext* cx, SnapshotIterator& iter) const {
788 RootedValue operand(cx, iter.read());
789 RootedValue result(cx);
791 MOZ_ASSERT(operand.isBigInt());
792 if (!js::NegOperation(cx, &operand, &result)) {
793 return false;
796 iter.storeInstructionResult(result);
797 return true;
800 bool MBigIntBitNot::writeRecoverData(CompactBufferWriter& writer) const {
801 MOZ_ASSERT(canRecoverOnBailout());
802 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitNot));
803 return true;
806 RBigIntBitNot::RBigIntBitNot(CompactBufferReader& reader) {}
808 bool RBigIntBitNot::recover(JSContext* cx, SnapshotIterator& iter) const {
809 RootedValue operand(cx, iter.read());
810 RootedValue result(cx);
812 MOZ_ASSERT(operand.isBigInt());
813 if (!js::BitNot(cx, &operand, &result)) {
814 return false;
817 iter.storeInstructionResult(result);
818 return true;
821 bool MCompare::writeRecoverData(CompactBufferWriter& writer) const {
822 MOZ_ASSERT(canRecoverOnBailout());
823 writer.writeUnsigned(uint32_t(RInstruction::Recover_Compare));
825 static_assert(sizeof(JSOp) == sizeof(uint8_t));
826 writer.writeByte(uint8_t(jsop_));
827 return true;
830 RCompare::RCompare(CompactBufferReader& reader) {
831 jsop_ = JSOp(reader.readByte());
833 MOZ_ASSERT(IsEqualityOp(jsop_) || IsRelationalOp(jsop_));
836 bool RCompare::recover(JSContext* cx, SnapshotIterator& iter) const {
837 RootedValue lhs(cx, iter.read());
838 RootedValue rhs(cx, iter.read());
840 bool result;
841 switch (jsop_) {
842 case JSOp::Eq:
843 case JSOp::Ne:
844 if (!js::LooselyEqual(cx, lhs, rhs, &result)) {
845 return false;
847 if (jsop_ == JSOp::Ne) {
848 result = !result;
850 break;
851 case JSOp::StrictEq:
852 case JSOp::StrictNe:
853 if (!StrictlyEqual(cx, lhs, rhs, &result)) {
854 return false;
856 if (jsop_ == JSOp::StrictNe) {
857 result = !result;
859 break;
860 case JSOp::Lt:
861 if (!js::LessThan(cx, &lhs, &rhs, &result)) {
862 return false;
864 break;
865 case JSOp::Le:
866 if (!js::LessThanOrEqual(cx, &lhs, &rhs, &result)) {
867 return false;
869 break;
870 case JSOp::Gt:
871 if (!js::GreaterThan(cx, &lhs, &rhs, &result)) {
872 return false;
874 break;
875 case JSOp::Ge:
876 if (!js::GreaterThanOrEqual(cx, &lhs, &rhs, &result)) {
877 return false;
879 break;
880 default:
881 MOZ_CRASH("Unexpected op.");
884 iter.storeInstructionResult(BooleanValue(result));
885 return true;
888 bool MConcat::writeRecoverData(CompactBufferWriter& writer) const {
889 MOZ_ASSERT(canRecoverOnBailout());
890 writer.writeUnsigned(uint32_t(RInstruction::Recover_Concat));
891 return true;
894 RConcat::RConcat(CompactBufferReader& reader) {}
896 bool RConcat::recover(JSContext* cx, SnapshotIterator& iter) const {
897 RootedValue lhs(cx, iter.read());
898 RootedValue rhs(cx, iter.read());
899 RootedValue result(cx);
901 MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
902 if (!js::AddValues(cx, &lhs, &rhs, &result)) {
903 return false;
906 iter.storeInstructionResult(result);
907 return true;
910 RStringLength::RStringLength(CompactBufferReader& reader) {}
912 bool RStringLength::recover(JSContext* cx, SnapshotIterator& iter) const {
913 JSString* string = iter.read().toString();
915 static_assert(JSString::MAX_LENGTH <= INT32_MAX,
916 "Can cast string length to int32_t");
918 iter.storeInstructionResult(Int32Value(int32_t(string->length())));
919 return true;
922 bool MStringLength::writeRecoverData(CompactBufferWriter& writer) const {
923 MOZ_ASSERT(canRecoverOnBailout());
924 writer.writeUnsigned(uint32_t(RInstruction::Recover_StringLength));
925 return true;
928 bool MArgumentsLength::writeRecoverData(CompactBufferWriter& writer) const {
929 MOZ_ASSERT(canRecoverOnBailout());
930 writer.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength));
931 return true;
934 RArgumentsLength::RArgumentsLength(CompactBufferReader& reader) {}
936 bool RArgumentsLength::recover(JSContext* cx, SnapshotIterator& iter) const {
937 uintptr_t numActualArgs = iter.frame()->numActualArgs();
939 static_assert(ARGS_LENGTH_MAX <= INT32_MAX,
940 "Can cast arguments count to int32_t");
941 MOZ_ASSERT(numActualArgs <= ARGS_LENGTH_MAX);
943 iter.storeInstructionResult(JS::Int32Value(int32_t(numActualArgs)));
944 return true;
947 bool MFloor::writeRecoverData(CompactBufferWriter& writer) const {
948 MOZ_ASSERT(canRecoverOnBailout());
949 writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
950 return true;
953 RFloor::RFloor(CompactBufferReader& reader) {}
955 bool RFloor::recover(JSContext* cx, SnapshotIterator& iter) const {
956 double num = iter.readNumber();
957 double result = js::math_floor_impl(num);
959 iter.storeInstructionResult(NumberValue(result));
960 return true;
963 bool MCeil::writeRecoverData(CompactBufferWriter& writer) const {
964 MOZ_ASSERT(canRecoverOnBailout());
965 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
966 return true;
969 RCeil::RCeil(CompactBufferReader& reader) {}
971 bool RCeil::recover(JSContext* cx, SnapshotIterator& iter) const {
972 double num = iter.readNumber();
973 double result = js::math_ceil_impl(num);
975 iter.storeInstructionResult(NumberValue(result));
976 return true;
979 bool MRound::writeRecoverData(CompactBufferWriter& writer) const {
980 MOZ_ASSERT(canRecoverOnBailout());
981 writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
982 return true;
985 RRound::RRound(CompactBufferReader& reader) {}
987 bool RRound::recover(JSContext* cx, SnapshotIterator& iter) const {
988 double num = iter.readNumber();
989 double result = js::math_round_impl(num);
991 iter.storeInstructionResult(NumberValue(result));
992 return true;
995 bool MTrunc::writeRecoverData(CompactBufferWriter& writer) const {
996 MOZ_ASSERT(canRecoverOnBailout());
997 writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc));
998 return true;
1001 RTrunc::RTrunc(CompactBufferReader& reader) {}
1003 bool RTrunc::recover(JSContext* cx, SnapshotIterator& iter) const {
1004 double num = iter.readNumber();
1005 double result = js::math_trunc_impl(num);
1007 iter.storeInstructionResult(NumberValue(result));
1008 return true;
1011 bool MCharCodeAt::writeRecoverData(CompactBufferWriter& writer) const {
1012 MOZ_ASSERT(canRecoverOnBailout());
1013 writer.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt));
1014 return true;
1017 RCharCodeAt::RCharCodeAt(CompactBufferReader& reader) {}
1019 bool RCharCodeAt::recover(JSContext* cx, SnapshotIterator& iter) const {
1020 JSString* string = iter.read().toString();
1022 // Int32 because |index| is computed from MBoundsCheck.
1023 int32_t index = iter.readInt32();
1024 MOZ_RELEASE_ASSERT(0 <= index && size_t(index) < string->length());
1026 char16_t c;
1027 if (!string->getChar(cx, index, &c)) {
1028 return false;
1031 iter.storeInstructionResult(Int32Value(c));
1032 return true;
1035 bool MFromCharCode::writeRecoverData(CompactBufferWriter& writer) const {
1036 MOZ_ASSERT(canRecoverOnBailout());
1037 writer.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode));
1038 return true;
1041 RFromCharCode::RFromCharCode(CompactBufferReader& reader) {}
1043 bool RFromCharCode::recover(JSContext* cx, SnapshotIterator& iter) const {
1044 // Number because |charCode| is computed from (recoverable) user input.
1045 int32_t charCode = JS::ToInt32(iter.readNumber());
1047 JSString* str = StringFromCharCode(cx, charCode);
1048 if (!str) {
1049 return false;
1052 iter.storeInstructionResult(StringValue(str));
1053 return true;
1056 bool MFromCharCodeEmptyIfNegative::writeRecoverData(
1057 CompactBufferWriter& writer) const {
1058 MOZ_ASSERT(canRecoverOnBailout());
1059 writer.writeUnsigned(
1060 uint32_t(RInstruction::Recover_FromCharCodeEmptyIfNegative));
1061 return true;
1064 RFromCharCodeEmptyIfNegative::RFromCharCodeEmptyIfNegative(
1065 CompactBufferReader& reader) {}
1067 bool RFromCharCodeEmptyIfNegative::recover(JSContext* cx,
1068 SnapshotIterator& iter) const {
1069 // Int32 because |charCode| is computed from MCharCodeAtOrNegative.
1070 int32_t charCode = iter.readInt32();
1072 JSString* str;
1073 if (charCode < 0) {
1074 str = cx->emptyString();
1075 } else {
1076 str = StringFromCharCode(cx, charCode);
1077 if (!str) {
1078 return false;
1082 iter.storeInstructionResult(StringValue(str));
1083 return true;
1086 bool MPow::writeRecoverData(CompactBufferWriter& writer) const {
1087 MOZ_ASSERT(canRecoverOnBailout());
1088 writer.writeUnsigned(uint32_t(RInstruction::Recover_Pow));
1089 return true;
1092 RPow::RPow(CompactBufferReader& reader) {}
1094 bool RPow::recover(JSContext* cx, SnapshotIterator& iter) const {
1095 double base = iter.readNumber();
1096 double power = iter.readNumber();
1097 double result = ecmaPow(base, power);
1099 iter.storeInstructionResult(NumberValue(result));
1100 return true;
1103 bool MPowHalf::writeRecoverData(CompactBufferWriter& writer) const {
1104 MOZ_ASSERT(canRecoverOnBailout());
1105 writer.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf));
1106 return true;
1109 RPowHalf::RPowHalf(CompactBufferReader& reader) {}
1111 bool RPowHalf::recover(JSContext* cx, SnapshotIterator& iter) const {
1112 double base = iter.readNumber();
1113 double power = 0.5;
1114 double result = ecmaPow(base, power);
1116 iter.storeInstructionResult(NumberValue(result));
1117 return true;
1120 bool MMinMax::writeRecoverData(CompactBufferWriter& writer) const {
1121 MOZ_ASSERT(canRecoverOnBailout());
1122 writer.writeUnsigned(uint32_t(RInstruction::Recover_MinMax));
1123 writer.writeByte(isMax_);
1124 return true;
1127 RMinMax::RMinMax(CompactBufferReader& reader) { isMax_ = reader.readByte(); }
1129 bool RMinMax::recover(JSContext* cx, SnapshotIterator& iter) const {
1130 double x = iter.readNumber();
1131 double y = iter.readNumber();
1133 double result;
1134 if (isMax_) {
1135 result = js::math_max_impl(x, y);
1136 } else {
1137 result = js::math_min_impl(x, y);
1140 iter.storeInstructionResult(NumberValue(result));
1141 return true;
1144 bool MAbs::writeRecoverData(CompactBufferWriter& writer) const {
1145 MOZ_ASSERT(canRecoverOnBailout());
1146 writer.writeUnsigned(uint32_t(RInstruction::Recover_Abs));
1147 return true;
1150 RAbs::RAbs(CompactBufferReader& reader) {}
1152 bool RAbs::recover(JSContext* cx, SnapshotIterator& iter) const {
1153 double num = iter.readNumber();
1154 double result = js::math_abs_impl(num);
1156 iter.storeInstructionResult(NumberValue(result));
1157 return true;
1160 bool MSqrt::writeRecoverData(CompactBufferWriter& writer) const {
1161 MOZ_ASSERT(canRecoverOnBailout());
1162 writer.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt));
1163 writer.writeByte(type() == MIRType::Float32);
1164 return true;
1167 RSqrt::RSqrt(CompactBufferReader& reader) {
1168 isFloatOperation_ = reader.readByte();
1171 bool RSqrt::recover(JSContext* cx, SnapshotIterator& iter) const {
1172 double num = iter.readNumber();
1173 double result = js::math_sqrt_impl(num);
1175 // MIRType::Float32 is a specialization embedding the fact that the result is
1176 // rounded to a Float32.
1177 if (isFloatOperation_) {
1178 result = js::RoundFloat32(result);
1181 iter.storeInstructionResult(DoubleValue(result));
1182 return true;
1185 bool MAtan2::writeRecoverData(CompactBufferWriter& writer) const {
1186 MOZ_ASSERT(canRecoverOnBailout());
1187 writer.writeUnsigned(uint32_t(RInstruction::Recover_Atan2));
1188 return true;
1191 RAtan2::RAtan2(CompactBufferReader& reader) {}
1193 bool RAtan2::recover(JSContext* cx, SnapshotIterator& iter) const {
1194 double y = iter.readNumber();
1195 double x = iter.readNumber();
1196 double result = js::ecmaAtan2(y, x);
1198 iter.storeInstructionResult(DoubleValue(result));
1199 return true;
1202 bool MHypot::writeRecoverData(CompactBufferWriter& writer) const {
1203 MOZ_ASSERT(canRecoverOnBailout());
1204 writer.writeUnsigned(uint32_t(RInstruction::Recover_Hypot));
1205 writer.writeUnsigned(uint32_t(numOperands()));
1206 return true;
1209 RHypot::RHypot(CompactBufferReader& reader)
1210 : numOperands_(reader.readUnsigned()) {}
1212 bool RHypot::recover(JSContext* cx, SnapshotIterator& iter) const {
1213 JS::RootedValueVector vec(cx);
1215 if (!vec.reserve(numOperands_)) {
1216 return false;
1219 for (uint32_t i = 0; i < numOperands_; ++i) {
1220 vec.infallibleAppend(NumberValue(iter.readNumber()));
1223 RootedValue result(cx);
1225 if (!js::math_hypot_handle(cx, vec, &result)) {
1226 return false;
1229 iter.storeInstructionResult(result);
1230 return true;
1233 bool MNearbyInt::writeRecoverData(CompactBufferWriter& writer) const {
1234 MOZ_ASSERT(canRecoverOnBailout());
1235 switch (roundingMode_) {
1236 case RoundingMode::Up:
1237 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
1238 return true;
1239 case RoundingMode::Down:
1240 writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
1241 return true;
1242 case RoundingMode::TowardsZero:
1243 writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc));
1244 return true;
1245 default:
1246 MOZ_CRASH("Unsupported rounding mode.");
1250 RNearbyInt::RNearbyInt(CompactBufferReader& reader) {
1251 roundingMode_ = reader.readByte();
1254 bool RNearbyInt::recover(JSContext* cx, SnapshotIterator& iter) const {
1255 MOZ_CRASH("Unsupported rounding mode.");
1258 bool MSign::writeRecoverData(CompactBufferWriter& writer) const {
1259 MOZ_ASSERT(canRecoverOnBailout());
1260 writer.writeUnsigned(uint32_t(RInstruction::Recover_Sign));
1261 return true;
1264 RSign::RSign(CompactBufferReader& reader) {}
1266 bool RSign::recover(JSContext* cx, SnapshotIterator& iter) const {
1267 double num = iter.readNumber();
1268 double result = js::math_sign_impl(num);
1270 iter.storeInstructionResult(NumberValue(result));
1271 return true;
1274 bool MMathFunction::writeRecoverData(CompactBufferWriter& writer) const {
1275 MOZ_ASSERT(canRecoverOnBailout());
1276 switch (function_) {
1277 case UnaryMathFunction::Ceil:
1278 writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
1279 return true;
1280 case UnaryMathFunction::Floor:
1281 writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
1282 return true;
1283 case UnaryMathFunction::Round:
1284 writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
1285 return true;
1286 case UnaryMathFunction::Trunc:
1287 writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc));
1288 return true;
1289 case UnaryMathFunction::SinNative:
1290 case UnaryMathFunction::SinFdlibm:
1291 case UnaryMathFunction::CosNative:
1292 case UnaryMathFunction::CosFdlibm:
1293 case UnaryMathFunction::TanNative:
1294 case UnaryMathFunction::TanFdlibm:
1295 case UnaryMathFunction::Log:
1296 case UnaryMathFunction::Exp:
1297 case UnaryMathFunction::ACos:
1298 case UnaryMathFunction::ASin:
1299 case UnaryMathFunction::ATan:
1300 case UnaryMathFunction::Log10:
1301 case UnaryMathFunction::Log2:
1302 case UnaryMathFunction::Log1P:
1303 case UnaryMathFunction::ExpM1:
1304 case UnaryMathFunction::CosH:
1305 case UnaryMathFunction::SinH:
1306 case UnaryMathFunction::TanH:
1307 case UnaryMathFunction::ACosH:
1308 case UnaryMathFunction::ASinH:
1309 case UnaryMathFunction::ATanH:
1310 case UnaryMathFunction::Cbrt:
1311 static_assert(sizeof(UnaryMathFunction) == sizeof(uint8_t));
1312 writer.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction));
1313 writer.writeByte(uint8_t(function_));
1314 return true;
1316 MOZ_CRASH("Unknown math function.");
1319 RMathFunction::RMathFunction(CompactBufferReader& reader) {
1320 function_ = UnaryMathFunction(reader.readByte());
1323 bool RMathFunction::recover(JSContext* cx, SnapshotIterator& iter) const {
1324 double num = iter.readNumber();
1326 double result;
1327 switch (function_) {
1328 case UnaryMathFunction::SinNative:
1329 result = js::math_sin_native_impl(num);
1330 break;
1331 case UnaryMathFunction::SinFdlibm:
1332 result = js::math_sin_fdlibm_impl(num);
1333 break;
1334 case UnaryMathFunction::CosNative:
1335 result = js::math_cos_native_impl(num);
1336 break;
1337 case UnaryMathFunction::CosFdlibm:
1338 result = js::math_cos_fdlibm_impl(num);
1339 break;
1340 case UnaryMathFunction::TanNative:
1341 result = js::math_tan_native_impl(num);
1342 break;
1343 case UnaryMathFunction::TanFdlibm:
1344 result = js::math_tan_fdlibm_impl(num);
1345 break;
1346 case UnaryMathFunction::Log:
1347 result = js::math_log_impl(num);
1348 break;
1349 case UnaryMathFunction::Exp:
1350 result = js::math_exp_impl(num);
1351 break;
1352 case UnaryMathFunction::ACos:
1353 result = js::math_acos_impl(num);
1354 break;
1355 case UnaryMathFunction::ASin:
1356 result = js::math_asin_impl(num);
1357 break;
1358 case UnaryMathFunction::ATan:
1359 result = js::math_atan_impl(num);
1360 break;
1361 case UnaryMathFunction::Log10:
1362 result = js::math_log10_impl(num);
1363 break;
1364 case UnaryMathFunction::Log2:
1365 result = js::math_log2_impl(num);
1366 break;
1367 case UnaryMathFunction::Log1P:
1368 result = js::math_log1p_impl(num);
1369 break;
1370 case UnaryMathFunction::ExpM1:
1371 result = js::math_expm1_impl(num);
1372 break;
1373 case UnaryMathFunction::CosH:
1374 result = js::math_cosh_impl(num);
1375 break;
1376 case UnaryMathFunction::SinH:
1377 result = js::math_sinh_impl(num);
1378 break;
1379 case UnaryMathFunction::TanH:
1380 result = js::math_tanh_impl(num);
1381 break;
1382 case UnaryMathFunction::ACosH:
1383 result = js::math_acosh_impl(num);
1384 break;
1385 case UnaryMathFunction::ASinH:
1386 result = js::math_asinh_impl(num);
1387 break;
1388 case UnaryMathFunction::ATanH:
1389 result = js::math_atanh_impl(num);
1390 break;
1391 case UnaryMathFunction::Cbrt:
1392 result = js::math_cbrt_impl(num);
1393 break;
1395 case UnaryMathFunction::Trunc:
1396 case UnaryMathFunction::Floor:
1397 case UnaryMathFunction::Ceil:
1398 case UnaryMathFunction::Round:
1399 // These have their own recover instructions.
1400 MOZ_CRASH("Unexpected rounding math function.");
1403 iter.storeInstructionResult(DoubleValue(result));
1404 return true;
1407 bool MRandom::writeRecoverData(CompactBufferWriter& writer) const {
1408 MOZ_ASSERT(this->canRecoverOnBailout());
1409 writer.writeUnsigned(uint32_t(RInstruction::Recover_Random));
1410 return true;
1413 bool MRandom::canRecoverOnBailout() const {
1414 return !js::SupportDifferentialTesting();
1417 RRandom::RRandom(CompactBufferReader& reader) {}
1419 bool RRandom::recover(JSContext* cx, SnapshotIterator& iter) const {
1420 iter.storeInstructionResult(DoubleValue(math_random_impl(cx)));
1421 return true;
1424 bool MStringSplit::writeRecoverData(CompactBufferWriter& writer) const {
1425 MOZ_ASSERT(canRecoverOnBailout());
1426 writer.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit));
1427 return true;
1430 RStringSplit::RStringSplit(CompactBufferReader& reader) {}
1432 bool RStringSplit::recover(JSContext* cx, SnapshotIterator& iter) const {
1433 RootedString str(cx, iter.read().toString());
1434 RootedString sep(cx, iter.read().toString());
1436 JSObject* res = StringSplitString(cx, str, sep, INT32_MAX);
1437 if (!res) {
1438 return false;
1441 iter.storeInstructionResult(ObjectValue(*res));
1442 return true;
1445 bool MNaNToZero::writeRecoverData(CompactBufferWriter& writer) const {
1446 MOZ_ASSERT(canRecoverOnBailout());
1447 writer.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero));
1448 return true;
1451 RNaNToZero::RNaNToZero(CompactBufferReader& reader) {}
1453 bool RNaNToZero::recover(JSContext* cx, SnapshotIterator& iter) const {
1454 double v = iter.readNumber();
1455 if (std::isnan(v) || mozilla::IsNegativeZero(v)) {
1456 v = 0.0;
1459 iter.storeInstructionResult(DoubleValue(v));
1460 return true;
1463 bool MRegExpMatcher::writeRecoverData(CompactBufferWriter& writer) const {
1464 MOZ_ASSERT(canRecoverOnBailout());
1465 writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpMatcher));
1466 return true;
1469 RRegExpMatcher::RRegExpMatcher(CompactBufferReader& reader) {}
1471 bool RRegExpMatcher::recover(JSContext* cx, SnapshotIterator& iter) const {
1472 RootedObject regexp(cx, &iter.read().toObject());
1473 RootedString input(cx, iter.read().toString());
1475 // Int32 because |lastIndex| is computed from transpiled self-hosted call.
1476 int32_t lastIndex = iter.readInt32();
1478 RootedValue result(cx);
1479 if (!RegExpMatcherRaw(cx, regexp, input, lastIndex, nullptr, &result)) {
1480 return false;
1483 iter.storeInstructionResult(result);
1484 return true;
1487 bool MTypeOf::writeRecoverData(CompactBufferWriter& writer) const {
1488 MOZ_ASSERT(canRecoverOnBailout());
1489 writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf));
1490 return true;
1493 RTypeOf::RTypeOf(CompactBufferReader& reader) {}
1495 bool RTypeOf::recover(JSContext* cx, SnapshotIterator& iter) const {
1496 JS::Value v = iter.read();
1498 iter.storeInstructionResult(Int32Value(TypeOfValue(v)));
1499 return true;
1502 bool MTypeOfName::writeRecoverData(CompactBufferWriter& writer) const {
1503 MOZ_ASSERT(canRecoverOnBailout());
1504 writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOfName));
1505 return true;
1508 RTypeOfName::RTypeOfName(CompactBufferReader& reader) {}
1510 bool RTypeOfName::recover(JSContext* cx, SnapshotIterator& iter) const {
1511 // Int32 because |type| is computed from MTypeOf.
1512 int32_t type = iter.readInt32();
1513 MOZ_ASSERT(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT);
1515 JSString* name = TypeName(JSType(type), *cx->runtime()->commonNames);
1516 iter.storeInstructionResult(StringValue(name));
1517 return true;
1520 bool MToDouble::writeRecoverData(CompactBufferWriter& writer) const {
1521 MOZ_ASSERT(canRecoverOnBailout());
1522 writer.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble));
1523 return true;
1526 RToDouble::RToDouble(CompactBufferReader& reader) {}
1528 bool RToDouble::recover(JSContext* cx, SnapshotIterator& iter) const {
1529 RootedValue v(cx, iter.read());
1531 MOZ_ASSERT(!v.isObject());
1532 MOZ_ASSERT(!v.isSymbol());
1533 MOZ_ASSERT(!v.isBigInt());
1535 double dbl;
1536 if (!ToNumber(cx, v, &dbl)) {
1537 return false;
1540 iter.storeInstructionResult(DoubleValue(dbl));
1541 return true;
1544 bool MToFloat32::writeRecoverData(CompactBufferWriter& writer) const {
1545 MOZ_ASSERT(canRecoverOnBailout());
1546 writer.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32));
1547 return true;
1550 RToFloat32::RToFloat32(CompactBufferReader& reader) {}
1552 bool RToFloat32::recover(JSContext* cx, SnapshotIterator& iter) const {
1553 double num = iter.readNumber();
1554 double result = js::RoundFloat32(num);
1556 iter.storeInstructionResult(DoubleValue(result));
1557 return true;
1560 bool MTruncateToInt32::writeRecoverData(CompactBufferWriter& writer) const {
1561 MOZ_ASSERT(canRecoverOnBailout());
1562 writer.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32));
1563 return true;
1566 RTruncateToInt32::RTruncateToInt32(CompactBufferReader& reader) {}
1568 bool RTruncateToInt32::recover(JSContext* cx, SnapshotIterator& iter) const {
1569 RootedValue value(cx, iter.read());
1571 int32_t trunc;
1572 if (!JS::ToInt32(cx, value, &trunc)) {
1573 return false;
1576 iter.storeInstructionResult(Int32Value(trunc));
1577 return true;
1580 bool MNewObject::writeRecoverData(CompactBufferWriter& writer) const {
1581 MOZ_ASSERT(canRecoverOnBailout());
1583 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewObject));
1585 // Recover instructions are only supported if we have a template object.
1586 MOZ_ASSERT(mode_ == MNewObject::ObjectCreate);
1587 return true;
1590 RNewObject::RNewObject(CompactBufferReader& reader) {}
1592 bool RNewObject::recover(JSContext* cx, SnapshotIterator& iter) const {
1593 RootedObject templateObject(cx, &iter.read().toObject());
1595 // See CodeGenerator::visitNewObjectVMCall.
1596 // Note that recover instructions are only used if mode == ObjectCreate.
1597 JSObject* resultObject =
1598 ObjectCreateWithTemplate(cx, templateObject.as<PlainObject>());
1599 if (!resultObject) {
1600 return false;
1603 iter.storeInstructionResult(ObjectValue(*resultObject));
1604 return true;
1607 bool MNewPlainObject::writeRecoverData(CompactBufferWriter& writer) const {
1608 MOZ_ASSERT(canRecoverOnBailout());
1609 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewPlainObject));
1611 MOZ_ASSERT(gc::AllocKind(uint8_t(allocKind_)) == allocKind_);
1612 writer.writeByte(uint8_t(allocKind_));
1613 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_)) == initialHeap_);
1614 writer.writeByte(uint8_t(initialHeap_));
1615 return true;
1618 RNewPlainObject::RNewPlainObject(CompactBufferReader& reader) {
1619 allocKind_ = gc::AllocKind(reader.readByte());
1620 MOZ_ASSERT(gc::IsValidAllocKind(allocKind_));
1621 initialHeap_ = gc::Heap(reader.readByte());
1622 MOZ_ASSERT(initialHeap_ == gc::Heap::Default ||
1623 initialHeap_ == gc::Heap::Tenured);
1626 bool RNewPlainObject::recover(JSContext* cx, SnapshotIterator& iter) const {
1627 Rooted<SharedShape*> shape(cx,
1628 &iter.read().toGCCellPtr().as<Shape>().asShared());
1630 // See CodeGenerator::visitNewPlainObject.
1631 JSObject* resultObject =
1632 NewPlainObjectOptimizedFallback(cx, shape, allocKind_, initialHeap_);
1633 if (!resultObject) {
1634 return false;
1637 iter.storeInstructionResult(ObjectValue(*resultObject));
1638 return true;
1641 bool MNewArrayObject::writeRecoverData(CompactBufferWriter& writer) const {
1642 MOZ_ASSERT(canRecoverOnBailout());
1643 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayObject));
1645 writer.writeUnsigned(length_);
1646 MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_)) == initialHeap_);
1647 writer.writeByte(uint8_t(initialHeap_));
1648 return true;
1651 RNewArrayObject::RNewArrayObject(CompactBufferReader& reader) {
1652 length_ = reader.readUnsigned();
1653 initialHeap_ = gc::Heap(reader.readByte());
1654 MOZ_ASSERT(initialHeap_ == gc::Heap::Default ||
1655 initialHeap_ == gc::Heap::Tenured);
1658 bool RNewArrayObject::recover(JSContext* cx, SnapshotIterator& iter) const {
1659 iter.read(); // Skip unused shape field.
1661 NewObjectKind kind =
1662 initialHeap_ == gc::Heap::Tenured ? TenuredObject : GenericObject;
1663 JSObject* array = NewArrayOperation(cx, length_, kind);
1664 if (!array) {
1665 return false;
1668 iter.storeInstructionResult(ObjectValue(*array));
1669 return true;
1672 bool MNewTypedArray::writeRecoverData(CompactBufferWriter& writer) const {
1673 MOZ_ASSERT(canRecoverOnBailout());
1674 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray));
1675 return true;
1678 RNewTypedArray::RNewTypedArray(CompactBufferReader& reader) {}
1680 bool RNewTypedArray::recover(JSContext* cx, SnapshotIterator& iter) const {
1681 RootedObject templateObject(cx, &iter.read().toObject());
1683 size_t length = templateObject.as<FixedLengthTypedArrayObject>()->length();
1684 MOZ_ASSERT(length <= INT32_MAX,
1685 "Template objects are only created for int32 lengths");
1687 JSObject* resultObject =
1688 NewTypedArrayWithTemplateAndLength(cx, templateObject, length);
1689 if (!resultObject) {
1690 return false;
1693 iter.storeInstructionResult(ObjectValue(*resultObject));
1694 return true;
1697 bool MNewArray::writeRecoverData(CompactBufferWriter& writer) const {
1698 MOZ_ASSERT(canRecoverOnBailout());
1699 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray));
1700 writer.writeUnsigned(length());
1701 return true;
1704 RNewArray::RNewArray(CompactBufferReader& reader) {
1705 count_ = reader.readUnsigned();
1708 bool RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const {
1709 RootedObject templateObject(cx, &iter.read().toObject());
1710 Rooted<Shape*> shape(cx, templateObject->shape());
1712 ArrayObject* resultObject = NewArrayWithShape(cx, count_, shape);
1713 if (!resultObject) {
1714 return false;
1717 iter.storeInstructionResult(ObjectValue(*resultObject));
1718 return true;
1721 bool MNewIterator::writeRecoverData(CompactBufferWriter& writer) const {
1722 MOZ_ASSERT(canRecoverOnBailout());
1723 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator));
1724 writer.writeByte(type_);
1725 return true;
1728 RNewIterator::RNewIterator(CompactBufferReader& reader) {
1729 type_ = reader.readByte();
1732 bool RNewIterator::recover(JSContext* cx, SnapshotIterator& iter) const {
1733 RootedObject templateObject(cx, &iter.read().toObject());
1735 JSObject* resultObject = nullptr;
1736 switch (MNewIterator::Type(type_)) {
1737 case MNewIterator::ArrayIterator:
1738 resultObject = NewArrayIterator(cx);
1739 break;
1740 case MNewIterator::StringIterator:
1741 resultObject = NewStringIterator(cx);
1742 break;
1743 case MNewIterator::RegExpStringIterator:
1744 resultObject = NewRegExpStringIterator(cx);
1745 break;
1748 if (!resultObject) {
1749 return false;
1752 iter.storeInstructionResult(ObjectValue(*resultObject));
1753 return true;
1756 bool MLambda::writeRecoverData(CompactBufferWriter& writer) const {
1757 MOZ_ASSERT(canRecoverOnBailout());
1758 writer.writeUnsigned(uint32_t(RInstruction::Recover_Lambda));
1759 return true;
1762 RLambda::RLambda(CompactBufferReader& reader) {}
1764 bool RLambda::recover(JSContext* cx, SnapshotIterator& iter) const {
1765 RootedObject scopeChain(cx, &iter.read().toObject());
1766 RootedFunction fun(cx, &iter.read().toObject().as<JSFunction>());
1768 JSObject* resultObject = js::Lambda(cx, fun, scopeChain);
1769 if (!resultObject) {
1770 return false;
1773 iter.storeInstructionResult(ObjectValue(*resultObject));
1774 return true;
1777 bool MFunctionWithProto::writeRecoverData(CompactBufferWriter& writer) const {
1778 MOZ_ASSERT(canRecoverOnBailout());
1779 writer.writeUnsigned(uint32_t(RInstruction::Recover_FunctionWithProto));
1780 return true;
1783 RFunctionWithProto::RFunctionWithProto(CompactBufferReader& reader) {}
1785 bool RFunctionWithProto::recover(JSContext* cx, SnapshotIterator& iter) const {
1786 RootedObject scopeChain(cx, &iter.read().toObject());
1787 RootedObject prototype(cx, &iter.read().toObject());
1788 RootedFunction fun(cx, &iter.read().toObject().as<JSFunction>());
1790 JSObject* resultObject =
1791 js::FunWithProtoOperation(cx, fun, scopeChain, prototype);
1792 if (!resultObject) {
1793 return false;
1796 iter.storeInstructionResult(ObjectValue(*resultObject));
1797 return true;
1800 bool MNewCallObject::writeRecoverData(CompactBufferWriter& writer) const {
1801 MOZ_ASSERT(canRecoverOnBailout());
1802 writer.writeUnsigned(uint32_t(RInstruction::Recover_NewCallObject));
1803 return true;
1806 RNewCallObject::RNewCallObject(CompactBufferReader& reader) {}
1808 bool RNewCallObject::recover(JSContext* cx, SnapshotIterator& iter) const {
1809 Rooted<CallObject*> templateObj(cx, &iter.read().toObject().as<CallObject>());
1811 Rooted<SharedShape*> shape(cx, templateObj->sharedShape());
1813 JSObject* resultObject = CallObject::createWithShape(cx, shape);
1814 if (!resultObject) {
1815 return false;
1818 iter.storeInstructionResult(ObjectValue(*resultObject));
1819 return true;
1822 bool MObjectKeys::canRecoverOnBailout() const {
1823 // Only claim that this operation can be recovered on bailout if some other
1824 // optimization already marked it as such.
1825 return isRecoveredOnBailout();
1828 bool MObjectKeys::writeRecoverData(CompactBufferWriter& writer) const {
1829 MOZ_ASSERT(canRecoverOnBailout());
1830 writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectKeys));
1831 return true;
1834 RObjectKeys::RObjectKeys(CompactBufferReader& reader) {}
1836 bool RObjectKeys::recover(JSContext* cx, SnapshotIterator& iter) const {
1837 Rooted<JSObject*> obj(cx, &iter.read().toObject());
1839 JSObject* resultKeys = ObjectKeys(cx, obj);
1840 if (!resultKeys) {
1841 return false;
1844 iter.storeInstructionResult(ObjectValue(*resultKeys));
1845 return true;
1848 bool MObjectState::writeRecoverData(CompactBufferWriter& writer) const {
1849 MOZ_ASSERT(canRecoverOnBailout());
1850 writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState));
1851 writer.writeUnsigned(numSlots());
1852 return true;
1855 RObjectState::RObjectState(CompactBufferReader& reader) {
1856 numSlots_ = reader.readUnsigned();
1859 bool RObjectState::recover(JSContext* cx, SnapshotIterator& iter) const {
1860 RootedObject object(cx, &iter.read().toObject());
1861 Handle<NativeObject*> nativeObject = object.as<NativeObject>();
1862 MOZ_ASSERT(!Watchtower::watchesPropertyModification(nativeObject));
1863 MOZ_ASSERT(nativeObject->slotSpan() == numSlots());
1865 for (size_t i = 0; i < numSlots(); i++) {
1866 Value val = iter.read();
1867 nativeObject->setSlot(i, val);
1870 iter.storeInstructionResult(ObjectValue(*object));
1871 return true;
1874 bool MArrayState::writeRecoverData(CompactBufferWriter& writer) const {
1875 MOZ_ASSERT(canRecoverOnBailout());
1876 writer.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState));
1877 writer.writeUnsigned(numElements());
1878 return true;
1881 RArrayState::RArrayState(CompactBufferReader& reader) {
1882 numElements_ = reader.readUnsigned();
1885 bool RArrayState::recover(JSContext* cx, SnapshotIterator& iter) const {
1886 ArrayObject* object = &iter.read().toObject().as<ArrayObject>();
1888 // Int32 because |initLength| is computed from MConstant.
1889 uint32_t initLength = iter.readInt32();
1891 MOZ_ASSERT(object->getDenseInitializedLength() == 0,
1892 "initDenseElement call below relies on this");
1893 object->setDenseInitializedLength(initLength);
1895 for (size_t index = 0; index < numElements(); index++) {
1896 Value val = iter.read();
1898 if (index >= initLength) {
1899 MOZ_ASSERT(val.isUndefined());
1900 continue;
1903 object->initDenseElement(index, val);
1906 iter.storeInstructionResult(ObjectValue(*object));
1907 return true;
1910 bool MSetArrayLength::writeRecoverData(CompactBufferWriter& writer) const {
1911 MOZ_ASSERT(canRecoverOnBailout());
1912 // For simplicity, we capture directly the object instead of the elements
1913 // pointer.
1914 MOZ_ASSERT(elements()->type() != MIRType::Elements);
1915 writer.writeUnsigned(uint32_t(RInstruction::Recover_SetArrayLength));
1916 return true;
1919 bool MSetArrayLength::canRecoverOnBailout() const {
1920 return isRecoveredOnBailout();
1923 RSetArrayLength::RSetArrayLength(CompactBufferReader& reader) {}
1925 bool RSetArrayLength::recover(JSContext* cx, SnapshotIterator& iter) const {
1926 Rooted<ArrayObject*> obj(cx, &iter.read().toObject().as<ArrayObject>());
1927 RootedValue len(cx, iter.read());
1929 RootedId id(cx, NameToId(cx->names().length));
1930 Rooted<PropertyDescriptor> desc(
1931 cx, PropertyDescriptor::Data(len, JS::PropertyAttribute::Writable));
1932 ObjectOpResult error;
1933 if (!ArraySetLength(cx, obj, id, desc, error)) {
1934 return false;
1937 iter.storeInstructionResult(ObjectValue(*obj));
1938 return true;
1941 bool MAssertRecoveredOnBailout::writeRecoverData(
1942 CompactBufferWriter& writer) const {
1943 MOZ_ASSERT(canRecoverOnBailout());
1944 MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout() == mustBeRecovered_,
1945 "assertRecoveredOnBailout failed during compilation");
1946 writer.writeUnsigned(
1947 uint32_t(RInstruction::Recover_AssertRecoveredOnBailout));
1948 return true;
1951 RAssertRecoveredOnBailout::RAssertRecoveredOnBailout(
1952 CompactBufferReader& reader) {}
1954 bool RAssertRecoveredOnBailout::recover(JSContext* cx,
1955 SnapshotIterator& iter) const {
1956 iter.read(); // skip the unused operand.
1957 iter.storeInstructionResult(UndefinedValue());
1958 return true;
1961 bool MStringReplace::writeRecoverData(CompactBufferWriter& writer) const {
1962 MOZ_ASSERT(canRecoverOnBailout());
1963 writer.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace));
1964 writer.writeByte(isFlatReplacement_);
1965 return true;
1968 RStringReplace::RStringReplace(CompactBufferReader& reader) {
1969 isFlatReplacement_ = reader.readByte();
1972 bool RStringReplace::recover(JSContext* cx, SnapshotIterator& iter) const {
1973 RootedString string(cx, iter.read().toString());
1974 RootedString pattern(cx, iter.read().toString());
1975 RootedString replace(cx, iter.read().toString());
1977 JSString* result =
1978 isFlatReplacement_
1979 ? js::StringFlatReplaceString(cx, string, pattern, replace)
1980 : js::str_replace_string_raw(cx, string, pattern, replace);
1982 if (!result) {
1983 return false;
1986 iter.storeInstructionResult(StringValue(result));
1987 return true;
1990 bool MSubstr::writeRecoverData(CompactBufferWriter& writer) const {
1991 MOZ_ASSERT(canRecoverOnBailout());
1992 writer.writeUnsigned(uint32_t(RInstruction::Recover_Substr));
1993 return true;
1996 RSubstr::RSubstr(CompactBufferReader& reader) {}
1998 bool RSubstr::recover(JSContext* cx, SnapshotIterator& iter) const {
1999 RootedString str(cx, iter.read().toString());
2002 // Int32 because |begin| is computed from MStringTrimStartIndex, MConstant,
2003 // or CallSubstringKernelResult.
2004 int32_t begin = iter.readInt32();
2006 // Int32 because |length| is computed from MSub(truncated),
2007 // MStringTrimEndIndex, or CallSubstringKernelResult.
2008 int32_t length = iter.readInt32();
2010 JSString* result = SubstringKernel(cx, str, begin, length);
2011 if (!result) {
2012 return false;
2015 iter.storeInstructionResult(StringValue(result));
2016 return true;
2019 bool MAtomicIsLockFree::writeRecoverData(CompactBufferWriter& writer) const {
2020 MOZ_ASSERT(canRecoverOnBailout());
2021 writer.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree));
2022 return true;
2025 RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader& reader) {}
2027 bool RAtomicIsLockFree::recover(JSContext* cx, SnapshotIterator& iter) const {
2028 double dsize = JS::ToInteger(iter.readNumber());
2030 int32_t size;
2031 bool result = mozilla::NumberEqualsInt32(dsize, &size) &&
2032 AtomicOperations::isLockfreeJS(size);
2033 iter.storeInstructionResult(BooleanValue(result));
2034 return true;
2037 bool MBigIntAsIntN::writeRecoverData(CompactBufferWriter& writer) const {
2038 MOZ_ASSERT(canRecoverOnBailout());
2039 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsIntN));
2040 return true;
2043 RBigIntAsIntN::RBigIntAsIntN(CompactBufferReader& reader) {}
2045 bool RBigIntAsIntN::recover(JSContext* cx, SnapshotIterator& iter) const {
2046 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2047 int32_t bits = iter.readInt32();
2048 MOZ_ASSERT(bits >= 0);
2050 RootedBigInt input(cx, iter.read().toBigInt());
2052 BigInt* result = BigInt::asIntN(cx, input, bits);
2053 if (!result) {
2054 return false;
2057 iter.storeInstructionResult(JS::BigIntValue(result));
2058 return true;
2061 bool MBigIntAsUintN::writeRecoverData(CompactBufferWriter& writer) const {
2062 MOZ_ASSERT(canRecoverOnBailout());
2063 writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsUintN));
2064 return true;
2067 RBigIntAsUintN::RBigIntAsUintN(CompactBufferReader& reader) {}
2069 bool RBigIntAsUintN::recover(JSContext* cx, SnapshotIterator& iter) const {
2070 // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
2071 int32_t bits = iter.readInt32();
2072 MOZ_ASSERT(bits >= 0);
2074 RootedBigInt input(cx, iter.read().toBigInt());
2076 BigInt* result = BigInt::asUintN(cx, input, bits);
2077 if (!result) {
2078 return false;
2081 iter.storeInstructionResult(JS::BigIntValue(result));
2082 return true;
2085 bool MCreateArgumentsObject::writeRecoverData(
2086 CompactBufferWriter& writer) const {
2087 MOZ_ASSERT(canRecoverOnBailout());
2088 writer.writeUnsigned(uint32_t(RInstruction::Recover_CreateArgumentsObject));
2089 return true;
2092 RCreateArgumentsObject::RCreateArgumentsObject(CompactBufferReader& reader) {}
2094 bool RCreateArgumentsObject::recover(JSContext* cx,
2095 SnapshotIterator& iter) const {
2096 RootedObject callObject(cx, &iter.read().toObject());
2097 RootedObject result(
2098 cx, ArgumentsObject::createForIon(cx, iter.frame(), callObject));
2099 if (!result) {
2100 return false;
2103 iter.storeInstructionResult(JS::ObjectValue(*result));
2104 return true;
2107 bool MCreateInlinedArgumentsObject::writeRecoverData(
2108 CompactBufferWriter& writer) const {
2109 MOZ_ASSERT(canRecoverOnBailout());
2110 writer.writeUnsigned(
2111 uint32_t(RInstruction::Recover_CreateInlinedArgumentsObject));
2112 writer.writeUnsigned(numActuals());
2113 return true;
2116 RCreateInlinedArgumentsObject::RCreateInlinedArgumentsObject(
2117 CompactBufferReader& reader) {
2118 numActuals_ = reader.readUnsigned();
2121 bool RCreateInlinedArgumentsObject::recover(JSContext* cx,
2122 SnapshotIterator& iter) const {
2123 RootedObject callObject(cx, &iter.read().toObject());
2124 RootedFunction callee(cx, &iter.read().toObject().as<JSFunction>());
2126 JS::RootedValueArray<ArgumentsObject::MaxInlinedArgs> argsArray(cx);
2127 for (uint32_t i = 0; i < numActuals_; i++) {
2128 argsArray[i].set(iter.read());
2131 ArgumentsObject* result = ArgumentsObject::createFromValueArray(
2132 cx, argsArray, callee, callObject, numActuals_);
2133 if (!result) {
2134 return false;
2137 iter.storeInstructionResult(JS::ObjectValue(*result));
2138 return true;
2141 bool MRest::writeRecoverData(CompactBufferWriter& writer) const {
2142 MOZ_ASSERT(canRecoverOnBailout());
2143 writer.writeUnsigned(uint32_t(RInstruction::Recover_Rest));
2144 writer.writeUnsigned(numFormals());
2145 return true;
2148 RRest::RRest(CompactBufferReader& reader) {
2149 numFormals_ = reader.readUnsigned();
2152 bool RRest::recover(JSContext* cx, SnapshotIterator& iter) const {
2153 JitFrameLayout* frame = iter.frame();
2155 // Int32 because |numActuals| is computed from MArgumentsLength.
2156 uint32_t numActuals = iter.readInt32();
2157 MOZ_ASSERT(numActuals == frame->numActualArgs());
2159 uint32_t numFormals = numFormals_;
2161 uint32_t length = std::max(numActuals, numFormals) - numFormals;
2162 Value* src = frame->actualArgs() + numFormals;
2163 JSObject* rest = jit::InitRestParameter(cx, length, src, nullptr);
2164 if (!rest) {
2165 return false;
2168 iter.storeInstructionResult(ObjectValue(*rest));
2169 return true;