#include "frontend/DoWhileEmitter.h"
#include "frontend/BytecodeEmitter.h"
#include "frontend/SourceNotes.h"
#include "vm/Opcodes.h"
using namespace js;
using namespace js::frontend;
using mozilla::Maybe;
using mozilla::Nothing;
DoWhileEmitter::DoWhileEmitter(BytecodeEmitter* bce) : bce_(bce) {}
bool DoWhileEmitter::emitBody(const Maybe<uint32_t>& doPos,
const Maybe<uint32_t>& bodyPos) {
MOZ_ASSERT(state_ == State::Start);
if (doPos) {
if (!bce_->updateSourceCoordNotes(*doPos)) {
return false;
}
}
if (!bce_->emit1(JSOP_NOP)) {
return false;
}
if (!bce_->newSrcNote3(SRC_DO_WHILE, 0, 0, ¬eIndex_)) {
return false;
}
loopInfo_.emplace(bce_, StatementKind::DoLoop);
if (!loopInfo_->emitLoopHead(bce_, bodyPos)) {
return false;
}
if (!loopInfo_->emitLoopEntry(bce_, Nothing())) {
return false;
}
#ifdef DEBUG
state_ = State::Body;
#endif
return true;
}
bool DoWhileEmitter::emitCond() {
MOZ_ASSERT(state_ == State::Body);
if (!loopInfo_->emitContinueTarget(bce_)) {
return false;
}
#ifdef DEBUG
state_ = State::Cond;
#endif
return true;
}
bool DoWhileEmitter::emitEnd() {
MOZ_ASSERT(state_ == State::Cond);
if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFNE)) {
return false;
}
if (!bce_->addTryNote(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
loopInfo_->breakTargetOffset())) {
return false;
}
if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::DoWhile::CondOffset,
loopInfo_->continueTargetOffsetFromLoopHead())) {
return false;
}
if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::DoWhile::BackJumpOffset,
loopInfo_->loopEndOffsetFromLoopHead())) {
return false;
}
if (!loopInfo_->patchBreaksAndContinues(bce_)) {
return false;
}
loopInfo_.reset();
#ifdef DEBUG
state_ = State::End;
#endif
return true;
}