WhileEmitter.cpp (2674B)
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/. */ 6 7 #include "frontend/WhileEmitter.h" 8 9 #include "frontend/BytecodeEmitter.h" 10 #include "vm/Opcodes.h" 11 #include "vm/StencilEnums.h" // TryNoteKind 12 13 using namespace js; 14 using namespace js::frontend; 15 16 WhileEmitter::WhileEmitter(BytecodeEmitter* bce) : bce_(bce) {} 17 18 bool WhileEmitter::emitCond(uint32_t whilePos, uint32_t condPos, 19 uint32_t endPos) { 20 MOZ_ASSERT(state_ == State::Start); 21 22 // If we have a single-line while, like "while (x) ;", we want to emit the 23 // line note before the loop, so that the debugger sees a single entry point. 24 // This way, if there is a breakpoint on the line, it will only fire once; and 25 // "next"ing will skip the whole loop. However, for the multi-line case we 26 // want to emit the line note for the JSOp::LoopHead, so that "cont" stops on 27 // each iteration -- but without a stop before the first iteration. 28 if (bce_->errorReporter().lineAt(whilePos) == 29 bce_->errorReporter().lineAt(endPos)) { 30 if (!bce_->updateSourceCoordNotes(whilePos)) { 31 return false; 32 } 33 // Emit a Nop to ensure the source position is not part of the loop. 34 if (!bce_->emit1(JSOp::Nop)) { 35 return false; 36 } 37 } 38 39 loopInfo_.emplace(bce_, StatementKind::WhileLoop); 40 41 if (!loopInfo_->emitLoopHead(bce_, mozilla::Some(condPos))) { 42 return false; 43 } 44 45 #ifdef DEBUG 46 state_ = State::Cond; 47 #endif 48 return true; 49 } 50 51 bool WhileEmitter::emitBody() { 52 MOZ_ASSERT(state_ == State::Cond); 53 54 if (!bce_->emitJump(JSOp::JumpIfFalse, &loopInfo_->breaks)) { 55 return false; 56 } 57 58 tdzCacheForBody_.emplace(bce_); 59 60 #ifdef DEBUG 61 state_ = State::Body; 62 #endif 63 return true; 64 } 65 66 bool WhileEmitter::emitEnd() { 67 MOZ_ASSERT(state_ == State::Body); 68 69 tdzCacheForBody_.reset(); 70 71 if (!loopInfo_->emitContinueTarget(bce_)) { 72 return false; 73 } 74 75 if (!loopInfo_->emitLoopEnd(bce_, JSOp::Goto, TryNoteKind::Loop)) { 76 return false; 77 } 78 79 loopInfo_.reset(); 80 81 #ifdef DEBUG 82 state_ = State::End; 83 #endif 84 return true; 85 } 86 87 #if defined(ENABLE_DECORATORS) || defined(ENABLE_EXPLICIT_RESOURCE_MANAGEMENT) 88 bool InternalWhileEmitter::emitCond() { 89 MOZ_ASSERT(state_ == State::Start); 90 91 loopInfo_.emplace(bce_, StatementKind::WhileLoop); 92 93 if (!loopInfo_->emitLoopHead(bce_, mozilla::Nothing())) { 94 return false; 95 } 96 97 # ifdef DEBUG 98 state_ = State::Cond; 99 # endif 100 return true; 101 } 102 #endif