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 #ifndef frontend_IfEmitter_h 8 #define frontend_IfEmitter_h 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/Maybe.h" 12 13 #include <stdint.h> 14 15 #include "frontend/JumpList.h" 16 #include "frontend/SourceNotes.h" 17 #include "frontend/TDZCheckCache.h" 18 19 namespace js { 20 namespace frontend { 21 22 struct BytecodeEmitter; 23 24 class MOZ_STACK_CLASS BranchEmitterBase { 25 protected: 26 BytecodeEmitter* bce_; 27 28 // Jump around the then clause, to the beginning of the else clause. 29 JumpList jumpAroundThen_; 30 31 // Jump around the else clause, to the end of the entire branch. 32 JumpList jumpsAroundElse_; 33 34 // The stack depth before emitting the then block. 35 // Used for restoring stack depth before emitting the else block. 36 // Also used for assertion to make sure then and else blocks pushed the 37 // same number of values. 38 int32_t thenDepth_ = 0; 39 40 // Whether the then-clause, the else-clause, or else-if condition may 41 // contain declaration or access to lexical variables, which means they 42 // should have their own TDZCheckCache. Basically TDZCheckCache should be 43 // created for each basic block, which then-clause, else-clause, and 44 // else-if condition are, but for internally used branches which are 45 // known not to touch lexical variables we can skip creating TDZCheckCache 46 // for them. 47 // 48 // See the comment for TDZCheckCache class for more details. 49 enum class Kind { 50 // For syntactic branches (if, if-else, and conditional expression), 51 // which basically may contain declaration or accesses to lexical 52 // variables inside then-clause, else-clause, and else-if condition. 53 MayContainLexicalAccessInBranch, 54 55 // For internally used branches which don't touch lexical variables 56 // inside then-clause, else-clause, nor else-if condition. 57 NoLexicalAccessInBranch 58 }; 59 Kind kind_; 60 61 mozilla::Maybe<TDZCheckCache> tdzCache_; 62 63 #ifdef DEBUG 64 // The number of values pushed in the then and else blocks. 65 int32_t pushed_ = 0; 66 bool calculatedPushed_ = false; 67 #endif 68 69 protected: 70 BranchEmitterBase(BytecodeEmitter* bce, Kind kind); 71 72 MOZ_MUST_USE bool emitThenInternal(); 73 void calculateOrCheckPushed(); 74 MOZ_MUST_USE bool emitElseInternal(); 75 MOZ_MUST_USE bool emitEndInternal(); 76 77 public: 78 #ifdef DEBUG 79 // Returns the number of values pushed onto the value stack inside 80 // `then_block` and `else_block`. 81 // Can be used in assertion after emitting if-then-else. pushed()82 int32_t pushed() const { return pushed_; } 83 84 // Returns the number of values popped onto the value stack inside 85 // `then_block` and `else_block`. 86 // Can be used in assertion after emitting if-then-else. popped()87 int32_t popped() const { return -pushed_; } 88 #endif 89 }; 90 91 // Class for emitting bytecode for blocks like if-then-else. 92 // 93 // This class can be used to emit single if-then-else block, or cascading 94 // else-if blocks. 95 // 96 // Usage: (check for the return value is omitted for simplicity) 97 // 98 // `if (cond) then_block` 99 // IfEmitter ifThen(this); 100 // ifThen.emitIf(Some(offset_of_if)); 101 // emit(cond); 102 // ifThen.emitThen(); 103 // emit(then_block); 104 // ifThen.emitEnd(); 105 // 106 // `if (cond) then_block else else_block` 107 // IfEmitter ifThenElse(this); 108 // ifThen.emitIf(Some(offset_of_if)); 109 // emit(cond); 110 // ifThenElse.emitThenElse(); 111 // emit(then_block); 112 // ifThenElse.emitElse(); 113 // emit(else_block); 114 // ifThenElse.emitEnd(); 115 // 116 // `if (c1) b1 else if (c2) b2 else if (c3) b3 else b4` 117 // IfEmitter ifThenElse(this); 118 // ifThen.emitIf(Some(offset_of_if)); 119 // emit(c1); 120 // ifThenElse.emitThenElse(); 121 // emit(b1); 122 // ifThenElse.emitElseIf(Some(offset_of_if)); 123 // emit(c2); 124 // ifThenElse.emitThenElse(); 125 // emit(b2); 126 // ifThenElse.emitElseIf(Some(offset_of_if)); 127 // emit(c3); 128 // ifThenElse.emitThenElse(); 129 // emit(b3); 130 // ifThenElse.emitElse(); 131 // emit(b4); 132 // ifThenElse.emitEnd(); 133 // 134 class MOZ_STACK_CLASS IfEmitter : public BranchEmitterBase { 135 protected: 136 #ifdef DEBUG 137 // The state of this emitter. 138 // 139 // +-------+ emitIf +----+ 140 // | Start |------->| If |-+ 141 // +-------+ +----+ | 142 // | 143 // +--------------------+ 144 // | 145 // v emitThen +------+ emitEnd +-----+ 146 // +->+--------->| Then |---------------------------->+-------->| End | 147 // ^ | +------+ ^ +-----+ 148 // | | | 149 // | | | 150 // | | | 151 // | | emitThenElse +----------+ emitElse +------+ | 152 // | +------------->| ThenElse |-+--------->| Else |-+ 153 // | +----------+ | +------+ 154 // | | 155 // | | emitElseIf +--------+ 156 // | +----------->| ElseIf |-+ 157 // | +--------+ | 158 // | | 159 // +------------------------------------------------------+ 160 enum class State { 161 // The initial state. 162 Start, 163 164 // After calling emitIf. 165 If, 166 167 // After calling emitThen. 168 Then, 169 170 // After calling emitThenElse. 171 ThenElse, 172 173 // After calling emitElse. 174 Else, 175 176 // After calling emitElseIf. 177 ElseIf, 178 179 // After calling emitEnd. 180 End 181 }; 182 State state_ = State::Start; 183 #endif 184 185 protected: 186 // For InternalIfEmitter. 187 IfEmitter(BytecodeEmitter* bce, Kind kind); 188 189 public: 190 explicit IfEmitter(BytecodeEmitter* bce); 191 192 // `ifPos` is the offset in the source code for the character below: 193 // 194 // if ( cond ) { ... } else if ( cond2 ) { ... } 195 // ^ ^ 196 // | | 197 // | ifPos for emitElseIf 198 // | 199 // ifPos for emitIf 200 // 201 // Can be Nothing() if not available. 202 MOZ_MUST_USE bool emitIf(const mozilla::Maybe<uint32_t>& ifPos); 203 204 MOZ_MUST_USE bool emitThen(); 205 MOZ_MUST_USE bool emitThenElse(); 206 207 MOZ_MUST_USE bool emitElseIf(const mozilla::Maybe<uint32_t>& ifPos); 208 MOZ_MUST_USE bool emitElse(); 209 210 MOZ_MUST_USE bool emitEnd(); 211 }; 212 213 // Class for emitting bytecode for blocks like if-then-else which doesn't touch 214 // lexical variables. 215 // 216 // See the comments above NoLexicalAccessInBranch for more details when to use 217 // this instead of IfEmitter. 218 // Compared to IfEmitter, this class doesn't have emitIf method, given that 219 // it doesn't have syntactic `if`, and also the `cond` value can be already 220 // on the stack. 221 // 222 // Usage: (check for the return value is omitted for simplicity) 223 // 224 // `if (cond) then_block else else_block` (effectively) 225 // emit(cond); 226 // InternalIfEmitter ifThenElse(this); 227 // ifThenElse.emitThenElse(); 228 // emit(then_block); 229 // ifThenElse.emitElse(); 230 // emit(else_block); 231 // ifThenElse.emitEnd(); 232 // 233 class MOZ_STACK_CLASS InternalIfEmitter : public IfEmitter { 234 public: 235 explicit InternalIfEmitter(BytecodeEmitter* bce); 236 }; 237 238 // Class for emitting bytecode for conditional expression. 239 // 240 // Usage: (check for the return value is omitted for simplicity) 241 // 242 // `cond ? then_expr : else_expr` 243 // CondEmitter condElse(this); 244 // condElse.emitCond(); 245 // emit(cond); 246 // condElse.emitThenElse(); 247 // emit(then_expr); 248 // condElse.emitElse(); 249 // emit(else_expr); 250 // condElse.emitEnd(); 251 // 252 class MOZ_STACK_CLASS CondEmitter : public BranchEmitterBase { 253 #ifdef DEBUG 254 // The state of this emitter. 255 // 256 // +-------+ emitCond +------+ emitThenElse +----------+ 257 // | Start |--------->| Cond |------------->| ThenElse |-+ 258 // +-------+ +------+ +----------+ | 259 // | 260 // +-----------------+ 261 // | 262 // | emitElse +------+ emitEnd +-----+ 263 // +--------->| Else |-------->| End | 264 // +------+ +-----+ 265 enum class State { 266 // The initial state. 267 Start, 268 269 // After calling emitCond. 270 Cond, 271 272 // After calling emitThenElse. 273 ThenElse, 274 275 // After calling emitElse. 276 Else, 277 278 // After calling emitEnd. 279 End 280 }; 281 State state_ = State::Start; 282 #endif 283 284 public: 285 explicit CondEmitter(BytecodeEmitter* bce); 286 287 MOZ_MUST_USE bool emitCond(); 288 MOZ_MUST_USE bool emitThenElse(); 289 MOZ_MUST_USE bool emitElse(); 290 MOZ_MUST_USE bool emitEnd(); 291 }; 292 293 } /* namespace frontend */ 294 } /* namespace js */ 295 296 #endif /* frontend_IfEmitter_h */ 297