SwitchEmitter.h (14106B)
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_SwitchEmitter_h 8 #define frontend_SwitchEmitter_h 9 10 #include "mozilla/Assertions.h" // MOZ_ASSERT 11 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS 12 #include "mozilla/Maybe.h" // mozilla::Maybe 13 14 #include <stddef.h> // size_t 15 #include <stdint.h> // int32_t, uint32_t 16 17 #include "frontend/BytecodeControlStructures.h" // BreakableControl 18 #include "frontend/EmitterScope.h" // EmitterScope 19 #include "frontend/JumpList.h" // JumpList, JumpTarget 20 #include "frontend/TDZCheckCache.h" // TDZCheckCache 21 #include "js/AllocPolicy.h" // SystemAllocPolicy 22 #include "js/Value.h" // JSVAL_INT_MAX, JSVAL_INT_MIN 23 #include "js/Vector.h" // Vector 24 #include "vm/Scope.h" // LexicalScope 25 26 namespace js { 27 namespace frontend { 28 29 struct BytecodeEmitter; 30 31 // Class for emitting bytecode for switch-case-default block. 32 // 33 // Usage: (check for the return value is omitted for simplicity) 34 // 35 // `switch (discriminant) { case c1_expr: c1_body; }` 36 // SwitchEmitter se(this); 37 // se.emitDiscriminant(offset_of_switch); 38 // emit(discriminant); 39 // 40 // se.validateCaseCount(1); 41 // se.emitCond(); 42 // 43 // se.prepareForCaseValue(); 44 // emit(c1_expr); 45 // se.emitCaseJump(); 46 // 47 // se.emitCaseBody(); 48 // emit(c1_body); 49 // 50 // se.emitEnd(); 51 // 52 // `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body; 53 // default: def_body; }` 54 // SwitchEmitter se(this); 55 // se.emitDiscriminant(offset_of_switch); 56 // emit(discriminant); 57 // 58 // se.validateCaseCount(2); 59 // se.emitCond(); 60 // 61 // se.prepareForCaseValue(); 62 // emit(c1_expr); 63 // se.emitCaseJump(); 64 // 65 // se.prepareForCaseValue(); 66 // emit(c2_expr); 67 // se.emitCaseJump(); 68 // 69 // se.emitCaseBody(); 70 // emit(c1_body); 71 // 72 // se.emitCaseBody(); 73 // emit(c2_body); 74 // 75 // se.emitDefaultBody(); 76 // emit(def_body); 77 // 78 // se.emitEnd(); 79 // 80 // `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body; }` 81 // with Table Switch 82 // SwitchEmitter::TableGenerator tableGen(this); 83 // tableGen.addNumber(c1_expr_value); 84 // tableGen.addNumber(c2_expr_value); 85 // tableGen.finish(2); 86 // 87 // // If `!tableGen.isValid()` here, `emitCond` should be used instead. 88 // 89 // SwitchEmitter se(this); 90 // se.emitDiscriminant(offset_of_switch); 91 // emit(discriminant); 92 // se.validateCaseCount(2); 93 // se.emitTable(tableGen); 94 // 95 // se.emitCaseBody(c1_expr_value, tableGen); 96 // emit(c1_body); 97 // 98 // se.emitCaseBody(c2_expr_value, tableGen); 99 // emit(c2_body); 100 // 101 // se.emitEnd(); 102 // 103 // `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body; 104 // default: def_body; }` 105 // with Table Switch 106 // SwitchEmitter::TableGenerator tableGen(bce); 107 // tableGen.addNumber(c1_expr_value); 108 // tableGen.addNumber(c2_expr_value); 109 // tableGen.finish(2); 110 // 111 // // If `!tableGen.isValid()` here, `emitCond` should be used instead. 112 // 113 // SwitchEmitter se(this); 114 // se.emitDiscriminant(offset_of_switch); 115 // emit(discriminant); 116 // se.validateCaseCount(2); 117 // se.emitTable(tableGen); 118 // 119 // se.emitCaseBody(c1_expr_value, tableGen); 120 // emit(c1_body); 121 // 122 // se.emitCaseBody(c2_expr_value, tableGen); 123 // emit(c2_body); 124 // 125 // se.emitDefaultBody(); 126 // emit(def_body); 127 // 128 // se.emitEnd(); 129 // 130 // `switch (discriminant) { case c1_expr: c1_body; }` 131 // in case c1_body contains lexical bindings 132 // SwitchEmitter se(this); 133 // se.emitDiscriminant(offset_of_switch); 134 // emit(discriminant); 135 // 136 // se.validateCaseCount(1); 137 // 138 // se.emitLexical(bindings); 139 // 140 // se.emitCond(); 141 // 142 // se.prepareForCaseValue(); 143 // emit(c1_expr); 144 // se.emitCaseJump(); 145 // 146 // se.emitCaseBody(); 147 // emit(c1_body); 148 // 149 // se.emitEnd(); 150 // 151 // `switch (discriminant) { case c1_expr: c1_body; }` 152 // in case c1_body contains hosted functions 153 // SwitchEmitter se(this); 154 // se.emitDiscriminant(offset_of_switch); 155 // emit(discriminant); 156 // 157 // se.validateCaseCount(1); 158 // 159 // se.emitLexical(bindings); 160 // emit(hosted functions); 161 // 162 // se.emitCond(); 163 // 164 // se.prepareForCaseValue(); 165 // emit(c1_expr); 166 // se.emitCaseJump(); 167 // 168 // se.emitCaseBody(); 169 // emit(c1_body); 170 // 171 // se.emitEnd(); 172 // 173 class MOZ_STACK_CLASS SwitchEmitter { 174 // Bytecode for each case. 175 // 176 // Cond Switch (uses an equality comparison for each case) 177 // {discriminant} 178 // 179 // {c1_expr} 180 // JSOp::Case c1 181 // 182 // JSOp::JumpTarget 183 // {c2_expr} 184 // JSOp::Case c2 185 // 186 // ... 187 // 188 // JSOp::JumpTarget 189 // JSOp::Default default 190 // 191 // c1: 192 // JSOp::JumpTarget 193 // {c1_body} 194 // JSOp::Goto end 195 // 196 // c2: 197 // JSOp::JumpTarget 198 // {c2_body} 199 // JSOp::Goto end 200 // 201 // default: 202 // end: 203 // JSOp::JumpTarget 204 // 205 // Table Switch 206 // {discriminant} 207 // JSOp::TableSwitch c1, c2, ... 208 // 209 // c1: 210 // JSOp::JumpTarget 211 // {c1_body} 212 // JSOp::Goto end 213 // 214 // c2: 215 // JSOp::JumpTarget 216 // {c2_body} 217 // JSOp::Goto end 218 // 219 // ... 220 // 221 // end: 222 // JSOp::JumpTarget 223 224 public: 225 enum class Kind { Table, Cond }; 226 227 // Class for generating optimized table switch data. 228 class MOZ_STACK_CLASS TableGenerator { 229 BytecodeEmitter* bce_; 230 231 // Bit array for given numbers. 232 mozilla::Maybe<js::Vector<size_t, 128, SystemAllocPolicy>> intmap_; 233 234 // The length of the intmap_. 235 int32_t intmapBitLength_ = 0; 236 237 // The length of the table. 238 uint32_t tableLength_ = 0; 239 240 // The lower and higher bounds of the table. 241 int32_t low_ = JSVAL_INT_MAX, high_ = JSVAL_INT_MIN; 242 243 // Whether the table is still valid. 244 bool valid_ = true; 245 246 #ifdef DEBUG 247 bool finished_ = false; 248 #endif 249 250 public: 251 explicit TableGenerator(BytecodeEmitter* bce) : bce_(bce) {} 252 253 void setInvalid() { valid_ = false; } 254 [[nodiscard]] bool isValid() const { return valid_; } 255 [[nodiscard]] bool isInvalid() const { return !valid_; } 256 257 // Add the given number to the table. The number is the value of 258 // `expr` for `case expr:` syntax. 259 [[nodiscard]] bool addNumber(int32_t caseValue); 260 261 // Finish generating the table. 262 // `caseCount` should be the number of cases in the switch statement, 263 // excluding the default case. 264 void finish(uint32_t caseCount); 265 266 private: 267 friend SwitchEmitter; 268 269 // The following methods can be used only after calling `finish`. 270 271 // Returns the lower bound of the added numbers. 272 int32_t low() const { 273 MOZ_ASSERT(finished_); 274 return low_; 275 } 276 277 // Returns the higher bound of the numbers. 278 int32_t high() const { 279 MOZ_ASSERT(finished_); 280 return high_; 281 } 282 283 // Returns the index in SwitchEmitter.caseOffsets_ for table switch. 284 uint32_t toCaseIndex(int32_t caseValue) const; 285 286 // Returns the length of the table. 287 // This method can be called only if `isValid()` is true. 288 uint32_t tableLength() const; 289 }; 290 291 private: 292 BytecodeEmitter* bce_; 293 294 // `kind_` should be set to the correct value in emitCond/emitTable. 295 Kind kind_ = Kind::Cond; 296 297 // True if there's explicit default case. 298 bool hasDefault_ = false; 299 300 // The number of cases in the switch statement, excluding the default case. 301 uint32_t caseCount_ = 0; 302 303 // Internal index for case jump and case body, used by cond switch. 304 uint32_t caseIndex_ = 0; 305 306 // Bytecode offset after emitting `discriminant`. 307 BytecodeOffset top_; 308 309 // Bytecode offset of the previous JSOp::Case. 310 BytecodeOffset lastCaseOffset_; 311 312 // Bytecode offset of the JSOp::JumpTarget for default body. 313 JumpTarget defaultJumpTargetOffset_; 314 315 // Bytecode offset of the JSOp::Default. 316 JumpList condSwitchDefaultOffset_; 317 318 // Instantiated when there's lexical scope for entire switch. 319 mozilla::Maybe<TDZCheckCache> tdzCacheLexical_; 320 mozilla::Maybe<EmitterScope> emitterScope_; 321 322 // Instantiated while emitting case expression and case/default body. 323 mozilla::Maybe<TDZCheckCache> tdzCacheCaseAndBody_; 324 325 // Control for switch. 326 mozilla::Maybe<BreakableControl> controlInfo_; 327 328 uint32_t switchPos_ = 0; 329 330 // Cond Switch: 331 // Offset of each JSOp::Case. 332 // Table Switch: 333 // Offset of each JSOp::JumpTarget for case. 334 js::Vector<BytecodeOffset, 32, SystemAllocPolicy> caseOffsets_; 335 336 // The state of this emitter. 337 // 338 // +-------+ emitDiscriminant +--------------+ 339 // | Start |----------------->| Discriminant |-+ 340 // +-------+ +--------------+ | 341 // | 342 // +-------------------------------------------+ 343 // | 344 // | validateCaseCount +-----------+ 345 // +->+------------------------>+------------------>| CaseCount |-+ 346 // | ^ +-----------+ | 347 // | emitLexical +---------+ | | 348 // +------------>| Lexical |-+ | 349 // +---------+ | 350 // | 351 // +--------------------------------------------------------------+ 352 // | 353 // | emitTable +-------+ 354 // +---------->| Table |----------------------------------->+-+ 355 // | +-------+ ^ | 356 // | | | 357 // | emitCond +------+ | | 358 // +---------->| Cond |-+------------------------------->+->+ | 359 // +------+ | ^ | 360 // | | | 361 // +------------------+ | | 362 // | | | 363 // |prepareForCaseValue +-----------+ | | 364 // +----------+--------->| CaseValue | | | 365 // ^ +-----------+ | | 366 // | | | | 367 // | | emitCaseJump +------+ | | 368 // | +------------->| Case |->+-+ | 369 // | +------+ | | 370 // | | | 371 // +--------------------------------------+ | 372 // | 373 // +----------------------------------------------------------+ 374 // | 375 // | emitEnd +-----+ 376 // +-+----------------------------------------->+-------->| End | 377 // | ^ +-----+ 378 // | emitCaseBody +----------+ | 379 // +->+-+---------------->| CaseBody |--->+-+-+ 380 // ^ | +----------+ ^ | 381 // | | | | 382 // | | emitDefaultBody +-------------+ | | 383 // | +---------------->| DefaultBody |-+ | 384 // | +-------------+ | 385 // | | 386 // +-------------------------------------+ 387 // 388 protected: 389 enum class State { 390 // The initial state. 391 Start, 392 393 // After calling emitDiscriminant. 394 Discriminant, 395 396 // After calling validateCaseCount. 397 CaseCount, 398 399 // After calling emitLexical. 400 Lexical, 401 402 // After calling emitCond. 403 Cond, 404 405 // After calling emitTable. 406 Table, 407 408 // After calling prepareForCaseValue. 409 CaseValue, 410 411 // After calling emitCaseJump. 412 Case, 413 414 // After calling emitCaseBody. 415 CaseBody, 416 417 // After calling emitDefaultBody. 418 DefaultBody, 419 420 // After calling emitEnd. 421 End 422 }; 423 State state_ = State::Start; 424 425 public: 426 explicit SwitchEmitter(BytecodeEmitter* bce); 427 428 // `switchPos` is the offset in the source code for the character below: 429 // 430 // switch ( cond ) { ... } 431 // ^ 432 // | 433 // switchPos 434 [[nodiscard]] bool emitDiscriminant(uint32_t switchPos); 435 436 // `caseCount` should be the number of cases in the switch statement, 437 // excluding the default case. 438 [[nodiscard]] bool validateCaseCount(uint32_t caseCount); 439 440 // `bindings` is a lexical scope for the entire switch, in case there's 441 // let/const effectively directly under case or default blocks. 442 [[nodiscard]] bool emitLexical(LexicalScope::ParserData* bindings); 443 444 [[nodiscard]] bool emitCond(); 445 [[nodiscard]] bool emitTable(const TableGenerator& tableGen); 446 447 [[nodiscard]] bool prepareForCaseValue(); 448 [[nodiscard]] bool emitCaseJump(); 449 450 [[nodiscard]] bool emitCaseBody(); 451 [[nodiscard]] bool emitCaseBody(int32_t caseValue, 452 const TableGenerator& tableGen); 453 [[nodiscard]] bool emitDefaultBody(); 454 [[nodiscard]] bool emitEnd(); 455 456 private: 457 [[nodiscard]] bool emitCaseOrDefaultJump(uint32_t caseIndex, bool isDefault); 458 [[nodiscard]] bool emitImplicitDefault(); 459 }; 460 461 // Class for emitting bytecode for switch-case-default block that doesn't 462 // correspond to a syntactic `switch`. 463 // Compared to SwitchEmitter, this class doesn't require `emitDiscriminant`, 464 // and the discriminant can already be on the stack. Usage is otherwise 465 // the same as SwitchEmitter. 466 class MOZ_STACK_CLASS InternalSwitchEmitter : public SwitchEmitter { 467 public: 468 explicit InternalSwitchEmitter(BytecodeEmitter* bce); 469 }; 470 471 } /* namespace frontend */ 472 } /* namespace js */ 473 474 #endif /* frontend_SwitchEmitter_h */