michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "jit/Recover.h" michael@0: michael@0: #include "jit/IonSpewer.h" michael@0: #include "jit/MIR.h" michael@0: #include "jit/MIRGraph.h" michael@0: michael@0: using namespace js; michael@0: using namespace js::jit; michael@0: michael@0: void michael@0: RInstruction::readRecoverData(CompactBufferReader &reader, RInstructionStorage *raw) michael@0: { michael@0: uint32_t op = reader.readUnsigned(); michael@0: switch (Opcode(op)) { michael@0: case Recover_ResumePoint: michael@0: new (raw->addr()) RResumePoint(reader); michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("Bad decoding of the previous instruction?"); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: MResumePoint::writeRecoverData(CompactBufferWriter &writer) const michael@0: { michael@0: writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint)); michael@0: michael@0: MBasicBlock *bb = block(); michael@0: JSFunction *fun = bb->info().funMaybeLazy(); michael@0: JSScript *script = bb->info().script(); michael@0: uint32_t exprStack = stackDepth() - bb->info().ninvoke(); michael@0: michael@0: #ifdef DEBUG michael@0: // Ensure that all snapshot which are encoded can safely be used for michael@0: // bailouts. michael@0: if (GetIonContext()->cx) { michael@0: uint32_t stackDepth; michael@0: bool reachablePC; michael@0: jsbytecode *bailPC = pc(); michael@0: michael@0: if (mode() == MResumePoint::ResumeAfter) michael@0: bailPC = GetNextPc(pc()); michael@0: michael@0: if (!ReconstructStackDepth(GetIonContext()->cx, script, michael@0: bailPC, &stackDepth, &reachablePC)) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (reachablePC) { michael@0: if (JSOp(*bailPC) == JSOP_FUNCALL) { michael@0: // For fun.call(this, ...); the reconstructStackDepth will michael@0: // include the this. When inlining that is not included. So the michael@0: // exprStackSlots will be one less. michael@0: MOZ_ASSERT(stackDepth - exprStack <= 1); michael@0: } else if (JSOp(*bailPC) != JSOP_FUNAPPLY && michael@0: !IsGetPropPC(bailPC) && !IsSetPropPC(bailPC)) michael@0: { michael@0: // For fun.apply({}, arguments) the reconstructStackDepth will michael@0: // have stackdepth 4, but it could be that we inlined the michael@0: // funapply. In that case exprStackSlots, will have the real michael@0: // arguments in the slots and not be 4. michael@0: michael@0: // With accessors, we have different stack depths depending on michael@0: // whether or not we inlined the accessor, as the inlined stack michael@0: // contains a callee function that should never have been there michael@0: // and we might just be capturing an uneventful property site, michael@0: // in which case there won't have been any violence. michael@0: MOZ_ASSERT(exprStack == stackDepth); michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: // Test if we honor the maximum of arguments at all times. This is a sanity michael@0: // check and not an algorithm limit. So check might be a bit too loose. +4 michael@0: // to account for scope chain, return value, this value and maybe michael@0: // arguments_object. michael@0: MOZ_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4); michael@0: michael@0: uint32_t implicit = StartArgSlot(script); michael@0: uint32_t formalArgs = CountArgSlots(script, fun); michael@0: uint32_t nallocs = formalArgs + script->nfixed() + exprStack; michael@0: michael@0: IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u", michael@0: implicit, formalArgs - implicit, script->nfixed(), exprStack); michael@0: michael@0: uint32_t pcoff = script->pcToOffset(pc()); michael@0: IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs); michael@0: writer.writeUnsigned(pcoff); michael@0: writer.writeUnsigned(nallocs); michael@0: return true; michael@0: } michael@0: michael@0: RResumePoint::RResumePoint(CompactBufferReader &reader) michael@0: { michael@0: static_assert(sizeof(*this) <= sizeof(RInstructionStorage), michael@0: "Storage space is too small to decode this recover instruction."); michael@0: pcOffset_ = reader.readUnsigned(); michael@0: numOperands_ = reader.readUnsigned(); michael@0: IonSpew(IonSpew_Snapshots, "Read RResumePoint (pc offset %u, nslots %u)", michael@0: pcOffset_, numOperands_); michael@0: }