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