IfEmitter.cpp (7300B)
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/IfEmitter.h" 8 9 #include "frontend/BytecodeEmitter.h" 10 #include "vm/Opcodes.h" 11 12 using namespace js; 13 using namespace js::frontend; 14 15 using mozilla::Maybe; 16 17 BranchEmitterBase::BranchEmitterBase(BytecodeEmitter* bce, 18 LexicalKind lexicalKind) 19 : bce_(bce), lexicalKind_(lexicalKind) {} 20 21 IfEmitter::IfEmitter(BytecodeEmitter* bce, LexicalKind lexicalKind) 22 : BranchEmitterBase(bce, lexicalKind) {} 23 24 IfEmitter::IfEmitter(BytecodeEmitter* bce) 25 : IfEmitter(bce, LexicalKind::MayContainLexicalAccessInBranch) {} 26 27 bool BranchEmitterBase::emitThenInternal(ConditionKind conditionKind) { 28 // The end of TDZCheckCache for cond for else-if. 29 if (lexicalKind_ == LexicalKind::MayContainLexicalAccessInBranch) { 30 tdzCache_.reset(); 31 } 32 33 // Emit a jump around the then part. 34 JSOp op = conditionKind == ConditionKind::Positive ? JSOp::JumpIfFalse 35 : JSOp::JumpIfTrue; 36 if (!bce_->emitJump(op, &jumpAroundThen_)) { 37 return false; 38 } 39 40 // To restore stack depth in else part (if present), save depth of the then 41 // part. 42 thenDepth_ = bce_->bytecodeSection().stackDepth(); 43 44 // Enclose then-branch with TDZCheckCache. 45 if (lexicalKind_ == LexicalKind::MayContainLexicalAccessInBranch) { 46 tdzCache_.emplace(bce_); 47 } 48 49 return true; 50 } 51 52 void BranchEmitterBase::calculateOrCheckPushed() { 53 #ifdef DEBUG 54 if (!calculatedPushed_) { 55 pushed_ = bce_->bytecodeSection().stackDepth() - thenDepth_; 56 calculatedPushed_ = true; 57 } else { 58 MOZ_ASSERT(pushed_ == bce_->bytecodeSection().stackDepth() - thenDepth_); 59 } 60 #endif 61 } 62 63 bool BranchEmitterBase::emitElseInternal() { 64 calculateOrCheckPushed(); 65 66 // The end of TDZCheckCache for then-clause. 67 if (lexicalKind_ == LexicalKind::MayContainLexicalAccessInBranch) { 68 MOZ_ASSERT(tdzCache_.isSome()); 69 tdzCache_.reset(); 70 } 71 72 // Emit a jump from the end of our then part around the else part. The 73 // patchJumpsToTarget call at the bottom of this function will fix up 74 // the offset with jumpsAroundElse value. 75 if (!bce_->emitJump(JSOp::Goto, &jumpsAroundElse_)) { 76 return false; 77 } 78 79 // Ensure the branch-if-false comes here, then emit the else. 80 if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_)) { 81 return false; 82 } 83 84 // Clear jumpAroundThen_ offset, to tell emitEnd there was an else part. 85 jumpAroundThen_ = JumpList(); 86 87 // Restore stack depth of the then part. 88 bce_->bytecodeSection().setStackDepth(thenDepth_); 89 90 // Enclose else-branch with TDZCheckCache. 91 if (lexicalKind_ == LexicalKind::MayContainLexicalAccessInBranch) { 92 tdzCache_.emplace(bce_); 93 } 94 95 return true; 96 } 97 98 bool BranchEmitterBase::emitEndInternal() { 99 // The end of TDZCheckCache for then or else-clause. 100 if (lexicalKind_ == LexicalKind::MayContainLexicalAccessInBranch) { 101 MOZ_ASSERT(tdzCache_.isSome()); 102 tdzCache_.reset(); 103 } 104 105 calculateOrCheckPushed(); 106 107 if (jumpAroundThen_.offset.valid()) { 108 // No else part for the last branch, fixup the branch-if-false to 109 // come here. 110 if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_)) { 111 return false; 112 } 113 } 114 115 // Patch all the jumps around else parts. 116 if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_)) { 117 return false; 118 } 119 120 return true; 121 } 122 123 bool IfEmitter::emitIf(const Maybe<uint32_t>& ifPos) { 124 MOZ_ASSERT(state_ == State::Start); 125 126 if (ifPos) { 127 // Make sure this code is attributed to the "if" so that it gets a 128 // useful column number, instead of the default 0 value. 129 if (!bce_->updateSourceCoordNotes(*ifPos)) { 130 return false; 131 } 132 } 133 134 #ifdef DEBUG 135 state_ = State::If; 136 #endif 137 return true; 138 } 139 140 bool IfEmitter::emitThen( 141 ConditionKind conditionKind /* = ConditionKind::Positive */) { 142 MOZ_ASSERT(state_ == State::If || state_ == State::ElseIf); 143 144 if (lexicalKind_ == LexicalKind::MayContainLexicalAccessInBranch) { 145 MOZ_ASSERT_IF(state_ == State::ElseIf, tdzCache_.isSome()); 146 MOZ_ASSERT_IF(state_ != State::ElseIf, tdzCache_.isNothing()); 147 } 148 149 if (!emitThenInternal(conditionKind)) { 150 return false; 151 } 152 153 #ifdef DEBUG 154 state_ = State::Then; 155 #endif 156 return true; 157 } 158 159 bool IfEmitter::emitThenElse( 160 ConditionKind conditionKind /* = ConditionKind::Positive */) { 161 MOZ_ASSERT(state_ == State::If || state_ == State::ElseIf); 162 163 if (lexicalKind_ == LexicalKind::MayContainLexicalAccessInBranch) { 164 MOZ_ASSERT_IF(state_ == State::ElseIf, tdzCache_.isSome()); 165 MOZ_ASSERT_IF(state_ != State::ElseIf, tdzCache_.isNothing()); 166 } 167 168 if (!emitThenInternal(conditionKind)) { 169 return false; 170 } 171 172 #ifdef DEBUG 173 state_ = State::ThenElse; 174 #endif 175 return true; 176 } 177 178 bool IfEmitter::emitElseIf(const Maybe<uint32_t>& ifPos) { 179 MOZ_ASSERT(state_ == State::ThenElse); 180 181 if (!emitElseInternal()) { 182 return false; 183 } 184 185 if (ifPos) { 186 // Make sure this code is attributed to the "if" so that it gets a 187 // useful column number, instead of the default 0 value. 188 if (!bce_->updateSourceCoordNotes(*ifPos)) { 189 return false; 190 } 191 } 192 193 #ifdef DEBUG 194 state_ = State::ElseIf; 195 #endif 196 return true; 197 } 198 199 bool IfEmitter::emitElse() { 200 MOZ_ASSERT(state_ == State::ThenElse); 201 202 if (!emitElseInternal()) { 203 return false; 204 } 205 206 #ifdef DEBUG 207 state_ = State::Else; 208 #endif 209 return true; 210 } 211 212 bool IfEmitter::emitEnd() { 213 MOZ_ASSERT(state_ == State::Then || state_ == State::Else); 214 // If there was an else part for the last branch, jumpAroundThen_ is 215 // already fixed up when emitting the else part. 216 MOZ_ASSERT_IF(state_ == State::Then, jumpAroundThen_.offset.valid()); 217 MOZ_ASSERT_IF(state_ == State::Else, !jumpAroundThen_.offset.valid()); 218 219 if (!emitEndInternal()) { 220 return false; 221 } 222 223 #ifdef DEBUG 224 state_ = State::End; 225 #endif 226 return true; 227 } 228 229 InternalIfEmitter::InternalIfEmitter(BytecodeEmitter* bce, 230 LexicalKind lexicalKind) 231 : IfEmitter(bce, lexicalKind) { 232 #ifdef DEBUG 233 // Skip emitIf (see the comment above InternalIfEmitter declaration). 234 state_ = State::If; 235 #endif 236 } 237 238 CondEmitter::CondEmitter(BytecodeEmitter* bce) 239 : BranchEmitterBase(bce, LexicalKind::MayContainLexicalAccessInBranch) {} 240 241 bool CondEmitter::emitCond() { 242 MOZ_ASSERT(state_ == State::Start); 243 #ifdef DEBUG 244 state_ = State::Cond; 245 #endif 246 return true; 247 } 248 249 bool CondEmitter::emitThenElse( 250 ConditionKind conditionKind /* = ConditionKind::Positive */) { 251 MOZ_ASSERT(state_ == State::Cond); 252 if (!emitThenInternal(conditionKind)) { 253 return false; 254 } 255 256 #ifdef DEBUG 257 state_ = State::ThenElse; 258 #endif 259 return true; 260 } 261 262 bool CondEmitter::emitElse() { 263 MOZ_ASSERT(state_ == State::ThenElse); 264 265 if (!emitElseInternal()) { 266 return false; 267 } 268 269 #ifdef DEBUG 270 state_ = State::Else; 271 #endif 272 return true; 273 } 274 275 bool CondEmitter::emitEnd() { 276 MOZ_ASSERT(state_ == State::Else); 277 MOZ_ASSERT(!jumpAroundThen_.offset.valid()); 278 279 if (!emitEndInternal()) { 280 return false; 281 } 282 283 #ifdef DEBUG 284 state_ = State::End; 285 #endif 286 return true; 287 }