diff options
Diffstat (limited to 'js/src/jit/Recover.cpp')
-rw-r--r-- | js/src/jit/Recover.cpp | 1694 |
1 files changed, 1694 insertions, 0 deletions
diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp new file mode 100644 index 000000000..13bf9224b --- /dev/null +++ b/js/src/jit/Recover.cpp @@ -0,0 +1,1694 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/Recover.h" + +#include "mozilla/SizePrintfMacros.h" + +#include "jsapi.h" +#include "jscntxt.h" +#include "jsmath.h" +#include "jsobj.h" +#include "jsstr.h" + +#include "builtin/RegExp.h" +#include "builtin/SIMD.h" +#include "builtin/TypedObject.h" + +#include "gc/Heap.h" + +#include "jit/JitFrameIterator.h" +#include "jit/JitSpewer.h" +#include "jit/MIR.h" +#include "jit/MIRGraph.h" +#include "jit/VMFunctions.h" +#include "vm/Interpreter.h" +#include "vm/String.h" + +#include "vm/Interpreter-inl.h" +#include "vm/NativeObject-inl.h" + +using namespace js; +using namespace js::jit; + +bool +MNode::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_CRASH("This instruction is not serializable"); +} + +void +RInstruction::readRecoverData(CompactBufferReader& reader, RInstructionStorage* raw) +{ + uint32_t op = reader.readUnsigned(); + switch (Opcode(op)) { +# define MATCH_OPCODES_(op) \ + case Recover_##op: \ + static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \ + "Storage space is too small to decode R" #op " instructions."); \ + new (raw->addr()) R##op(reader); \ + break; + + RECOVER_OPCODE_LIST(MATCH_OPCODES_) +# undef MATCH_OPCODES_ + + case Recover_Invalid: + default: + MOZ_CRASH("Bad decoding of the previous instruction?"); + } +} + +bool +MResumePoint::writeRecoverData(CompactBufferWriter& writer) const +{ + writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint)); + + MBasicBlock* bb = block(); + JSFunction* fun = bb->info().funMaybeLazy(); + JSScript* script = bb->info().script(); + uint32_t exprStack = stackDepth() - bb->info().ninvoke(); + +#ifdef DEBUG + // Ensure that all snapshot which are encoded can safely be used for + // bailouts. + if (GetJitContext()->cx) { + uint32_t stackDepth; + bool reachablePC; + jsbytecode* bailPC = pc(); + + if (mode() == MResumePoint::ResumeAfter) + bailPC = GetNextPc(pc()); + + if (!ReconstructStackDepth(GetJitContext()->cx, script, + bailPC, &stackDepth, &reachablePC)) + { + return false; + } + + if (reachablePC) { + if (JSOp(*bailPC) == JSOP_FUNCALL) { + // For fun.call(this, ...); the reconstructStackDepth will + // include the this. When inlining that is not included. So the + // exprStackSlots will be one less. + MOZ_ASSERT(stackDepth - exprStack <= 1); + } else if (JSOp(*bailPC) != JSOP_FUNAPPLY && + !IsGetPropPC(bailPC) && !IsSetPropPC(bailPC)) + { + // For fun.apply({}, arguments) the reconstructStackDepth will + // have stackdepth 4, but it could be that we inlined the + // funapply. In that case exprStackSlots, will have the real + // arguments in the slots and not be 4. + + // With accessors, we have different stack depths depending on + // whether or not we inlined the accessor, as the inlined stack + // contains a callee function that should never have been there + // and we might just be capturing an uneventful property site, + // in which case there won't have been any violence. + MOZ_ASSERT(exprStack == stackDepth); + } + } + } +#endif + + // Test if we honor the maximum of arguments at all times. This is a sanity + // check and not an algorithm limit. So check might be a bit too loose. +4 + // to account for scope chain, return value, this value and maybe + // arguments_object. + MOZ_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4); + +#ifdef JS_JITSPEW + uint32_t implicit = StartArgSlot(script); +#endif + uint32_t formalArgs = CountArgSlots(script, fun); + uint32_t nallocs = formalArgs + script->nfixed() + exprStack; + + JitSpew(JitSpew_IonSnapshots, "Starting frame; implicit %u, formals %u, fixed %" PRIuSIZE ", exprs %u", + implicit, formalArgs - implicit, script->nfixed(), exprStack); + + uint32_t pcoff = script->pcToOffset(pc()); + JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs); + writer.writeUnsigned(pcoff); + writer.writeUnsigned(nallocs); + return true; +} + +RResumePoint::RResumePoint(CompactBufferReader& reader) +{ + pcOffset_ = reader.readUnsigned(); + numOperands_ = reader.readUnsigned(); + JitSpew(JitSpew_IonSnapshots, "Read RResumePoint (pc offset %u, nslots %u)", + pcOffset_, numOperands_); +} + +bool +RResumePoint::recover(JSContext* cx, SnapshotIterator& iter) const +{ + MOZ_CRASH("This instruction is not recoverable."); +} + +bool +MBitNot::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_BitNot)); + return true; +} + +RBitNot::RBitNot(CompactBufferReader& reader) +{ } + +bool +RBitNot::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue operand(cx, iter.read()); + + int32_t result; + if (!js::BitNot(cx, operand, &result)) + return false; + + RootedValue rootedResult(cx, js::Int32Value(result)); + iter.storeInstructionResult(rootedResult); + return true; +} + +bool +MBitAnd::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd)); + return true; +} + +RBitAnd::RBitAnd(CompactBufferReader& reader) +{ } + +bool +RBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + int32_t result; + MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); + + if (!js::BitAnd(cx, lhs, rhs, &result)) + return false; + + RootedValue rootedResult(cx, js::Int32Value(result)); + iter.storeInstructionResult(rootedResult); + return true; +} + +bool +MBitOr::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_BitOr)); + return true; +} + +RBitOr::RBitOr(CompactBufferReader& reader) +{} + +bool +RBitOr::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + int32_t result; + MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); + + if (!js::BitOr(cx, lhs, rhs, &result)) + return false; + + RootedValue asValue(cx, js::Int32Value(result)); + iter.storeInstructionResult(asValue); + return true; +} + +bool +MBitXor::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_BitXor)); + return true; +} + +RBitXor::RBitXor(CompactBufferReader& reader) +{ } + +bool +RBitXor::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + + int32_t result; + if (!js::BitXor(cx, lhs, rhs, &result)) + return false; + + RootedValue rootedResult(cx, js::Int32Value(result)); + iter.storeInstructionResult(rootedResult); + return true; +} + +bool +MLsh::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Lsh)); + return true; +} + +RLsh::RLsh(CompactBufferReader& reader) +{} + +bool +RLsh::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + int32_t result; + MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); + + if (!js::BitLsh(cx, lhs, rhs, &result)) + return false; + + RootedValue asValue(cx, js::Int32Value(result)); + iter.storeInstructionResult(asValue); + return true; +} + +bool +MRsh::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Rsh)); + return true; +} + +RRsh::RRsh(CompactBufferReader& reader) +{ } + +bool +RRsh::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); + + int32_t result; + if (!js::BitRsh(cx, lhs, rhs, &result)) + return false; + + RootedValue rootedResult(cx, js::Int32Value(result)); + iter.storeInstructionResult(rootedResult); + return true; +} + +bool +MUrsh::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Ursh)); + return true; +} + +RUrsh::RUrsh(CompactBufferReader& reader) +{ } + +bool +RUrsh::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); + + RootedValue result(cx); + if (!js::UrshOperation(cx, lhs, rhs, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MSignExtend::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtend)); + MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_); + writer.writeByte(uint8_t(mode_)); + return true; +} + +RSignExtend::RSignExtend(CompactBufferReader& reader) +{ + mode_ = reader.readByte(); +} + +bool +RSignExtend::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue operand(cx, iter.read()); + + int32_t result; + switch (MSignExtend::Mode(mode_)) { + case MSignExtend::Byte: + if (!js::SignExtendOperation<int8_t>(cx, operand, &result)) + return false; + break; + case MSignExtend::Half: + if (!js::SignExtendOperation<int16_t>(cx, operand, &result)) + return false; + break; + } + + RootedValue rootedResult(cx, js::Int32Value(result)); + iter.storeInstructionResult(rootedResult); + return true; +} + +bool +MAdd::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Add)); + writer.writeByte(specialization_ == MIRType::Float32); + return true; +} + +RAdd::RAdd(CompactBufferReader& reader) +{ + isFloatOperation_ = reader.readByte(); +} + +bool +RAdd::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); + if (!js::AddValues(cx, &lhs, &rhs, &result)) + return false; + + // MIRType::Float32 is a specialization embedding the fact that the result is + // rounded to a Float32. + if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MSub::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Sub)); + writer.writeByte(specialization_ == MIRType::Float32); + return true; +} + +RSub::RSub(CompactBufferReader& reader) +{ + isFloatOperation_ = reader.readByte(); +} + +bool +RSub::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); + if (!js::SubValues(cx, &lhs, &rhs, &result)) + return false; + + // MIRType::Float32 is a specialization embedding the fact that the result is + // rounded to a Float32. + if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MMul::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Mul)); + writer.writeByte(specialization_ == MIRType::Float32); + MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_); + writer.writeByte(uint8_t(mode_)); + return true; +} + +RMul::RMul(CompactBufferReader& reader) +{ + isFloatOperation_ = reader.readByte(); + mode_ = reader.readByte(); +} + +bool +RMul::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + RootedValue result(cx); + + if (MMul::Mode(mode_) == MMul::Normal) { + if (!js::MulValues(cx, &lhs, &rhs, &result)) + return false; + + // MIRType::Float32 is a specialization embedding the fact that the + // result is rounded to a Float32. + if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) + return false; + } else { + MOZ_ASSERT(MMul::Mode(mode_) == MMul::Integer); + if (!js::math_imul_handle(cx, lhs, rhs, &result)) + return false; + } + + iter.storeInstructionResult(result); + return true; +} + +bool +MDiv::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Div)); + writer.writeByte(specialization_ == MIRType::Float32); + return true; +} + +RDiv::RDiv(CompactBufferReader& reader) +{ + isFloatOperation_ = reader.readByte(); +} + +bool +RDiv::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + RootedValue result(cx); + + if (!js::DivValues(cx, &lhs, &rhs, &result)) + return false; + + // MIRType::Float32 is a specialization embedding the fact that the result is + // rounded to a Float32. + if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MMod::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Mod)); + return true; +} + +RMod::RMod(CompactBufferReader& reader) +{ } + +bool +RMod::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); + if (!js::ModValues(cx, &lhs, &rhs, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MNot::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Not)); + return true; +} + +RNot::RNot(CompactBufferReader& reader) +{ } + +bool +RNot::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue v(cx, iter.read()); + RootedValue result(cx); + + result.setBoolean(!ToBoolean(v)); + + iter.storeInstructionResult(result); + return true; +} + +bool +MConcat::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Concat)); + return true; +} + +RConcat::RConcat(CompactBufferReader& reader) +{} + +bool +RConcat::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue lhs(cx, iter.read()); + RootedValue rhs(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(!lhs.isObject() && !rhs.isObject()); + if (!js::AddValues(cx, &lhs, &rhs, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +RStringLength::RStringLength(CompactBufferReader& reader) +{} + +bool +RStringLength::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue operand(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(!operand.isObject()); + if (!js::GetLengthProperty(operand, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MStringLength::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_StringLength)); + return true; +} + +bool +MArgumentsLength::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength)); + return true; +} + +RArgumentsLength::RArgumentsLength(CompactBufferReader& reader) +{ } + +bool +RArgumentsLength::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue result(cx); + + result.setInt32(iter.readOuterNumActualArgs()); + + iter.storeInstructionResult(result); + return true; +} + +bool +MFloor::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor)); + return true; +} + +RFloor::RFloor(CompactBufferReader& reader) +{ } + +bool RFloor::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue v(cx, iter.read()); + RootedValue result(cx); + + if (!js::math_floor_handle(cx, v, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MCeil::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil)); + return true; +} + +RCeil::RCeil(CompactBufferReader& reader) +{ } + + +bool +RCeil::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue v(cx, iter.read()); + RootedValue result(cx); + + if (!js::math_ceil_handle(cx, v, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MRound::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Round)); + return true; +} + +RRound::RRound(CompactBufferReader& reader) +{} + +bool +RRound::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue arg(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(!arg.isObject()); + if(!js::math_round_handle(cx, arg, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MCharCodeAt::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt)); + return true; +} + +RCharCodeAt::RCharCodeAt(CompactBufferReader& reader) +{} + +bool +RCharCodeAt::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedString lhs(cx, iter.read().toString()); + RootedValue rhs(cx, iter.read()); + RootedValue result(cx); + + if (!js::str_charCodeAt_impl(cx, lhs, rhs, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MFromCharCode::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode)); + return true; +} + +RFromCharCode::RFromCharCode(CompactBufferReader& reader) +{} + +bool +RFromCharCode::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue operand(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(!operand.isObject()); + if (!js::str_fromCharCode_one_arg(cx, operand, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MPow::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Pow)); + return true; +} + +RPow::RPow(CompactBufferReader& reader) +{ } + +bool +RPow::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue base(cx, iter.read()); + RootedValue power(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(base.isNumber() && power.isNumber()); + if (!js::math_pow_handle(cx, base, power, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MPowHalf::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf)); + return true; +} + +RPowHalf::RPowHalf(CompactBufferReader& reader) +{ } + +bool +RPowHalf::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue base(cx, iter.read()); + RootedValue power(cx); + RootedValue result(cx); + power.setNumber(0.5); + + MOZ_ASSERT(base.isNumber()); + if (!js::math_pow_handle(cx, base, power, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MMinMax::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_MinMax)); + writer.writeByte(isMax_); + return true; +} + +RMinMax::RMinMax(CompactBufferReader& reader) +{ + isMax_ = reader.readByte(); +} + +bool +RMinMax::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue a(cx, iter.read()); + RootedValue b(cx, iter.read()); + RootedValue result(cx); + + if (!js::minmax_impl(cx, isMax_, a, b, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MAbs::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Abs)); + return true; +} + +RAbs::RAbs(CompactBufferReader& reader) +{ } + +bool +RAbs::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue v(cx, iter.read()); + RootedValue result(cx); + + if (!js::math_abs_handle(cx, v, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MSqrt::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt)); + writer.writeByte(type() == MIRType::Float32); + return true; +} + +RSqrt::RSqrt(CompactBufferReader& reader) +{ + isFloatOperation_ = reader.readByte(); +} + +bool +RSqrt::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue num(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(num.isNumber()); + if (!math_sqrt_handle(cx, num, &result)) + return false; + + // MIRType::Float32 is a specialization embedding the fact that the result is + // rounded to a Float32. + if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MAtan2::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Atan2)); + return true; +} + +RAtan2::RAtan2(CompactBufferReader& reader) +{ } + +bool +RAtan2::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue y(cx, iter.read()); + RootedValue x(cx, iter.read()); + RootedValue result(cx); + + if(!math_atan2_handle(cx, y, x, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MHypot::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Hypot)); + writer.writeUnsigned(uint32_t(numOperands())); + return true; +} + +RHypot::RHypot(CompactBufferReader& reader) + : numOperands_(reader.readUnsigned()) +{ } + +bool +RHypot::recover(JSContext* cx, SnapshotIterator& iter) const +{ + JS::AutoValueVector vec(cx); + + if (!vec.reserve(numOperands_)) + return false; + + for (uint32_t i = 0 ; i < numOperands_ ; ++i) + vec.infallibleAppend(iter.read()); + + RootedValue result(cx); + + if(!js::math_hypot_handle(cx, vec, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MMathFunction::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + switch (function_) { + case Round: + writer.writeUnsigned(uint32_t(RInstruction::Recover_Round)); + return true; + case Sin: + case Log: + writer.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction)); + writer.writeByte(function_); + return true; + default: + MOZ_CRASH("Unknown math function."); + } +} + +RMathFunction::RMathFunction(CompactBufferReader& reader) +{ + function_ = reader.readByte(); +} + +bool +RMathFunction::recover(JSContext* cx, SnapshotIterator& iter) const +{ + switch (function_) { + case MMathFunction::Sin: { + RootedValue arg(cx, iter.read()); + RootedValue result(cx); + + if (!js::math_sin_handle(cx, arg, &result)) + return false; + + iter.storeInstructionResult(result); + return true; + } + case MMathFunction::Log: { + RootedValue arg(cx, iter.read()); + RootedValue result(cx); + + if (!js::math_log_handle(cx, arg, &result)) + return false; + + iter.storeInstructionResult(result); + return true; + } + default: + MOZ_CRASH("Unknown math function."); + } +} + +bool +MRandom::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(this->canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Random)); + return true; +} + +RRandom::RRandom(CompactBufferReader& reader) +{} + +bool +RRandom::recover(JSContext* cx, SnapshotIterator& iter) const +{ + iter.storeInstructionResult(DoubleValue(math_random_impl(cx))); + return true; +} + +bool +MStringSplit::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit)); + return true; +} + +RStringSplit::RStringSplit(CompactBufferReader& reader) +{} + +bool +RStringSplit::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedString str(cx, iter.read().toString()); + RootedString sep(cx, iter.read().toString()); + RootedObjectGroup group(cx, iter.read().toObject().group()); + RootedValue result(cx); + + JSObject* res = str_split_string(cx, group, str, sep, INT32_MAX); + if (!res) + return false; + + result.setObject(*res); + iter.storeInstructionResult(result); + return true; +} + +bool +MNaNToZero::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero)); + return true; +} + +RNaNToZero::RNaNToZero(CompactBufferReader& reader) +{ } + + +bool +RNaNToZero::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue v(cx, iter.read()); + RootedValue result(cx); + MOZ_ASSERT(v.isDouble() || v.isInt32()); + + // x ? x : 0.0 + if (ToBoolean(v)) + result = v; + else + result.setDouble(0.0); + + iter.storeInstructionResult(result); + return true; +} + +bool +MRegExpMatcher::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpMatcher)); + return true; +} + +RRegExpMatcher::RRegExpMatcher(CompactBufferReader& reader) +{} + +bool +RRegExpMatcher::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedObject regexp(cx, &iter.read().toObject()); + RootedString input(cx, iter.read().toString()); + int32_t lastIndex = iter.read().toInt32(); + + RootedValue result(cx); + if (!RegExpMatcherRaw(cx, regexp, input, lastIndex, nullptr, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MRegExpSearcher::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpSearcher)); + return true; +} + +RRegExpSearcher::RRegExpSearcher(CompactBufferReader& reader) +{} + +bool +RRegExpSearcher::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedObject regexp(cx, &iter.read().toObject()); + RootedString input(cx, iter.read().toString()); + int32_t lastIndex = iter.read().toInt32(); + + int32_t result; + if (!RegExpSearcherRaw(cx, regexp, input, lastIndex, nullptr, &result)) + return false; + + RootedValue resultVal(cx); + resultVal.setInt32(result); + iter.storeInstructionResult(resultVal); + return true; +} + +bool +MRegExpTester::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpTester)); + return true; +} + +RRegExpTester::RRegExpTester(CompactBufferReader& reader) +{ } + +bool +RRegExpTester::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedString string(cx, iter.read().toString()); + RootedObject regexp(cx, &iter.read().toObject()); + int32_t lastIndex = iter.read().toInt32(); + int32_t endIndex; + + if (!js::RegExpTesterRaw(cx, regexp, string, lastIndex, &endIndex)) + return false; + + RootedValue result(cx); + result.setInt32(endIndex); + iter.storeInstructionResult(result); + return true; +} + +bool +MTypeOf::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf)); + return true; +} + +RTypeOf::RTypeOf(CompactBufferReader& reader) +{ } + +bool +RTypeOf::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue v(cx, iter.read()); + + RootedValue result(cx, StringValue(TypeOfOperation(v, cx->runtime()))); + iter.storeInstructionResult(result); + return true; +} + +bool +MToDouble::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble)); + return true; +} + +RToDouble::RToDouble(CompactBufferReader& reader) +{ } + +bool +RToDouble::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue v(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(!v.isObject()); + MOZ_ASSERT(!v.isSymbol()); + + double dbl; + if (!ToNumber(cx, v, &dbl)) + return false; + + result.setDouble(dbl); + iter.storeInstructionResult(result); + return true; +} + +bool +MToFloat32::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32)); + return true; +} + +RToFloat32::RToFloat32(CompactBufferReader& reader) +{ } + +bool +RToFloat32::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue v(cx, iter.read()); + RootedValue result(cx); + + MOZ_ASSERT(!v.isObject()); + if (!RoundFloat32(cx, v, &result)) + return false; + + iter.storeInstructionResult(result); + return true; +} + +bool +MTruncateToInt32::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32)); + return true; +} + +RTruncateToInt32::RTruncateToInt32(CompactBufferReader& reader) +{ } + +bool +RTruncateToInt32::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue value(cx, iter.read()); + RootedValue result(cx); + + int32_t trunc; + if (!JS::ToInt32(cx, value, &trunc)) + return false; + + result.setInt32(trunc); + iter.storeInstructionResult(result); + return true; +} + +bool +MNewObject::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_NewObject)); + MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_); + writer.writeByte(uint8_t(mode_)); + return true; +} + +RNewObject::RNewObject(CompactBufferReader& reader) +{ + mode_ = MNewObject::Mode(reader.readByte()); +} + +bool +RNewObject::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedObject templateObject(cx, &iter.read().toObject()); + RootedValue result(cx); + JSObject* resultObject = nullptr; + + // See CodeGenerator::visitNewObjectVMCall + switch (mode_) { + case MNewObject::ObjectLiteral: + resultObject = NewObjectOperationWithTemplate(cx, templateObject); + break; + case MNewObject::ObjectCreate: + resultObject = ObjectCreateWithTemplate(cx, templateObject.as<PlainObject>()); + break; + } + + if (!resultObject) + return false; + + result.setObject(*resultObject); + iter.storeInstructionResult(result); + return true; +} + +bool +MNewTypedArray::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray)); + return true; +} + +RNewTypedArray::RNewTypedArray(CompactBufferReader& reader) +{ +} + +bool +RNewTypedArray::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedObject templateObject(cx, &iter.read().toObject()); + RootedValue result(cx); + + uint32_t length = templateObject.as<TypedArrayObject>()->length(); + JSObject* resultObject = TypedArrayCreateWithTemplate(cx, templateObject, length); + if (!resultObject) + return false; + + result.setObject(*resultObject); + iter.storeInstructionResult(result); + return true; +} + +bool +MNewArray::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray)); + writer.writeUnsigned(length()); + return true; +} + +RNewArray::RNewArray(CompactBufferReader& reader) +{ + count_ = reader.readUnsigned(); +} + +bool +RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedObject templateObject(cx, &iter.read().toObject()); + RootedValue result(cx); + RootedObjectGroup group(cx, templateObject->group()); + + JSObject* resultObject = NewFullyAllocatedArrayTryUseGroup(cx, group, count_); + if (!resultObject) + return false; + + result.setObject(*resultObject); + iter.storeInstructionResult(result); + return true; +} + +bool +MNewDerivedTypedObject::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_NewDerivedTypedObject)); + return true; +} + +RNewDerivedTypedObject::RNewDerivedTypedObject(CompactBufferReader& reader) +{ } + +bool +RNewDerivedTypedObject::recover(JSContext* cx, SnapshotIterator& iter) const +{ + Rooted<TypeDescr*> descr(cx, &iter.read().toObject().as<TypeDescr>()); + Rooted<TypedObject*> owner(cx, &iter.read().toObject().as<TypedObject>()); + int32_t offset = iter.read().toInt32(); + + JSObject* obj = OutlineTypedObject::createDerived(cx, descr, owner, offset); + if (!obj) + return false; + + RootedValue result(cx, ObjectValue(*obj)); + iter.storeInstructionResult(result); + return true; +} + +bool +MCreateThisWithTemplate::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_CreateThisWithTemplate)); + return true; +} + +RCreateThisWithTemplate::RCreateThisWithTemplate(CompactBufferReader& reader) +{ +} + +bool +RCreateThisWithTemplate::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedObject templateObject(cx, &iter.read().toObject()); + + // See CodeGenerator::visitCreateThisWithTemplate + JSObject* resultObject = NewObjectOperationWithTemplate(cx, templateObject); + if (!resultObject) + return false; + + RootedValue result(cx); + result.setObject(*resultObject); + iter.storeInstructionResult(result); + return true; +} + +bool +MLambda::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_Lambda)); + return true; +} + +RLambda::RLambda(CompactBufferReader& reader) +{ +} + +bool +RLambda::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedObject scopeChain(cx, &iter.read().toObject()); + RootedFunction fun(cx, &iter.read().toObject().as<JSFunction>()); + + JSObject* resultObject = js::Lambda(cx, fun, scopeChain); + if (!resultObject) + return false; + + RootedValue result(cx); + result.setObject(*resultObject); + iter.storeInstructionResult(result); + return true; +} + +bool +MSimdBox::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_SimdBox)); + static_assert(unsigned(SimdType::Count) < 0x100, "assuming SimdType fits in 8 bits"); + writer.writeByte(uint8_t(simdType())); + return true; +} + +RSimdBox::RSimdBox(CompactBufferReader& reader) +{ + type_ = reader.readByte(); +} + +bool +RSimdBox::recover(JSContext* cx, SnapshotIterator& iter) const +{ + JSObject* resultObject = nullptr; + RValueAllocation a = iter.readAllocation(); + MOZ_ASSERT(iter.allocationReadable(a)); + MOZ_ASSERT_IF(a.mode() == RValueAllocation::ANY_FLOAT_REG, a.fpuReg().isSimd128()); + const FloatRegisters::RegisterContent* raw = iter.floatAllocationPointer(a); + switch (SimdType(type_)) { + case SimdType::Bool8x16: + resultObject = js::CreateSimd<Bool8x16>(cx, (const Bool8x16::Elem*) raw); + break; + case SimdType::Int8x16: + resultObject = js::CreateSimd<Int8x16>(cx, (const Int8x16::Elem*) raw); + break; + case SimdType::Uint8x16: + resultObject = js::CreateSimd<Uint8x16>(cx, (const Uint8x16::Elem*) raw); + break; + case SimdType::Bool16x8: + resultObject = js::CreateSimd<Bool16x8>(cx, (const Bool16x8::Elem*) raw); + break; + case SimdType::Int16x8: + resultObject = js::CreateSimd<Int16x8>(cx, (const Int16x8::Elem*) raw); + break; + case SimdType::Uint16x8: + resultObject = js::CreateSimd<Uint16x8>(cx, (const Uint16x8::Elem*) raw); + break; + case SimdType::Bool32x4: + resultObject = js::CreateSimd<Bool32x4>(cx, (const Bool32x4::Elem*) raw); + break; + case SimdType::Int32x4: + resultObject = js::CreateSimd<Int32x4>(cx, (const Int32x4::Elem*) raw); + break; + case SimdType::Uint32x4: + resultObject = js::CreateSimd<Uint32x4>(cx, (const Uint32x4::Elem*) raw); + break; + case SimdType::Float32x4: + resultObject = js::CreateSimd<Float32x4>(cx, (const Float32x4::Elem*) raw); + break; + case SimdType::Float64x2: + MOZ_CRASH("NYI, RSimdBox of Float64x2"); + break; + case SimdType::Bool64x2: + MOZ_CRASH("NYI, RSimdBox of Bool64x2"); + break; + case SimdType::Count: + MOZ_CRASH("RSimdBox of Count is unreachable"); + } + + if (!resultObject) + return false; + + RootedValue result(cx); + result.setObject(*resultObject); + iter.storeInstructionResult(result); + return true; +} + +bool +MObjectState::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState)); + writer.writeUnsigned(numSlots()); + return true; +} + +RObjectState::RObjectState(CompactBufferReader& reader) +{ + numSlots_ = reader.readUnsigned(); +} + +bool +RObjectState::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedObject object(cx, &iter.read().toObject()); + RootedValue val(cx); + + if (object->is<UnboxedPlainObject>()) { + const UnboxedLayout& layout = object->as<UnboxedPlainObject>().layout(); + + RootedId id(cx); + RootedValue receiver(cx, ObjectValue(*object)); + const UnboxedLayout::PropertyVector& properties = layout.properties(); + for (size_t i = 0; i < properties.length(); i++) { + val = iter.read(); + + // This is the default placeholder value of MObjectState, when no + // properties are defined yet. + if (val.isUndefined()) + continue; + + id = NameToId(properties[i].name); + ObjectOpResult result; + + // SetProperty can only fail due to OOM. + if (!SetProperty(cx, object, id, val, receiver, result)) + return false; + if (!result) + return result.reportError(cx, object, id); + } + } else { + RootedNativeObject nativeObject(cx, &object->as<NativeObject>()); + MOZ_ASSERT(nativeObject->slotSpan() == numSlots()); + + for (size_t i = 0; i < numSlots(); i++) { + val = iter.read(); + nativeObject->setSlot(i, val); + } + } + + val.setObject(*object); + iter.storeInstructionResult(val); + return true; +} + +bool +MArrayState::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState)); + writer.writeUnsigned(numElements()); + return true; +} + +RArrayState::RArrayState(CompactBufferReader& reader) +{ + numElements_ = reader.readUnsigned(); +} + +bool +RArrayState::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue result(cx); + ArrayObject* object = &iter.read().toObject().as<ArrayObject>(); + uint32_t initLength = iter.read().toInt32(); + + object->setDenseInitializedLength(initLength); + for (size_t index = 0; index < numElements(); index++) { + Value val = iter.read(); + + if (index >= initLength) { + MOZ_ASSERT(val.isUndefined()); + continue; + } + + object->initDenseElement(index, val); + } + + result.setObject(*object); + iter.storeInstructionResult(result); + return true; +} + +bool +MAssertRecoveredOnBailout::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout() == mustBeRecovered_, + "assertRecoveredOnBailout failed during compilation"); + writer.writeUnsigned(uint32_t(RInstruction::Recover_AssertRecoveredOnBailout)); + return true; +} + +RAssertRecoveredOnBailout::RAssertRecoveredOnBailout(CompactBufferReader& reader) +{ } + +bool RAssertRecoveredOnBailout::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue result(cx); + iter.read(); // skip the unused operand. + result.setUndefined(); + iter.storeInstructionResult(result); + return true; +} + +bool +MStringReplace::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace)); + writer.writeByte(isFlatReplacement_); + return true; +} + +RStringReplace::RStringReplace(CompactBufferReader& reader) +{ + isFlatReplacement_ = reader.readByte(); +} + +bool RStringReplace::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedString string(cx, iter.read().toString()); + RootedString pattern(cx, iter.read().toString()); + RootedString replace(cx, iter.read().toString()); + + JSString* result = isFlatReplacement_ ? js::str_flat_replace_string(cx, string, pattern, replace) : + js::str_replace_string_raw(cx, string, pattern, replace); + + if (!result) + return false; + + iter.storeInstructionResult(StringValue(result)); + return true; +} + +bool +MAtomicIsLockFree::writeRecoverData(CompactBufferWriter& writer) const +{ + MOZ_ASSERT(canRecoverOnBailout()); + writer.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree)); + return true; +} + +RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader& reader) +{ } + +bool +RAtomicIsLockFree::recover(JSContext* cx, SnapshotIterator& iter) const +{ + RootedValue operand(cx, iter.read()); + MOZ_ASSERT(operand.isInt32()); + + int32_t result; + if (!js::AtomicIsLockFree(cx, operand, &result)) + return false; + + RootedValue rootedResult(cx, js::Int32Value(result)); + iter.storeInstructionResult(rootedResult); + return true; +} |