Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / SwitchEmitter.h
blob59d45fc71c0f1a0f2b3ea3ac35b256eda1a48890
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/. */
7 #ifndef frontend_SwitchEmitter_h
8 #define frontend_SwitchEmitter_h
10 #include "mozilla/Assertions.h" // MOZ_ASSERT
11 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS
12 #include "mozilla/Maybe.h" // mozilla::Maybe
14 #include <stddef.h> // size_t
15 #include <stdint.h> // int32_t, uint32_t
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
26 namespace js {
27 namespace frontend {
29 struct BytecodeEmitter;
31 // Class for emitting bytecode for switch-case-default block.
33 // Usage: (check for the return value is omitted for simplicity)
35 // `switch (discriminant) { case c1_expr: c1_body; }`
36 // SwitchEmitter se(this);
37 // se.emitDiscriminant(offset_of_switch);
38 // emit(discriminant);
40 // se.validateCaseCount(1);
41 // se.emitCond();
43 // se.prepareForCaseValue();
44 // emit(c1_expr);
45 // se.emitCaseJump();
47 // se.emitCaseBody();
48 // emit(c1_body);
50 // se.emitEnd();
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);
58 // se.validateCaseCount(2);
59 // se.emitCond();
61 // se.prepareForCaseValue();
62 // emit(c1_expr);
63 // se.emitCaseJump();
65 // se.prepareForCaseValue();
66 // emit(c2_expr);
67 // se.emitCaseJump();
69 // se.emitCaseBody();
70 // emit(c1_body);
72 // se.emitCaseBody();
73 // emit(c2_body);
75 // se.emitDefaultBody();
76 // emit(def_body);
78 // se.emitEnd();
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);
87 // // If `!tableGen.isValid()` here, `emitCond` should be used instead.
89 // SwitchEmitter se(this);
90 // se.emitDiscriminant(offset_of_switch);
91 // emit(discriminant);
92 // se.validateCaseCount(2);
93 // se.emitTable(tableGen);
95 // se.emitCaseBody(c1_expr_value, tableGen);
96 // emit(c1_body);
98 // se.emitCaseBody(c2_expr_value, tableGen);
99 // emit(c2_body);
101 // se.emitEnd();
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);
111 // // If `!tableGen.isValid()` here, `emitCond` should be used instead.
113 // SwitchEmitter se(this);
114 // se.emitDiscriminant(offset_of_switch);
115 // emit(discriminant);
116 // se.validateCaseCount(2);
117 // se.emitTable(tableGen);
119 // se.emitCaseBody(c1_expr_value, tableGen);
120 // emit(c1_body);
122 // se.emitCaseBody(c2_expr_value, tableGen);
123 // emit(c2_body);
125 // se.emitDefaultBody();
126 // emit(def_body);
128 // se.emitEnd();
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);
136 // se.validateCaseCount(1);
138 // se.emitLexical(bindings);
140 // se.emitCond();
142 // se.prepareForCaseValue();
143 // emit(c1_expr);
144 // se.emitCaseJump();
146 // se.emitCaseBody();
147 // emit(c1_body);
149 // se.emitEnd();
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);
157 // se.validateCaseCount(1);
159 // se.emitLexical(bindings);
160 // emit(hosted functions);
162 // se.emitCond();
164 // se.prepareForCaseValue();
165 // emit(c1_expr);
166 // se.emitCaseJump();
168 // se.emitCaseBody();
169 // emit(c1_body);
171 // se.emitEnd();
173 class MOZ_STACK_CLASS SwitchEmitter {
174 // Bytecode for each case.
176 // Cond Switch (uses an equality comparison for each case)
177 // {discriminant}
179 // {c1_expr}
180 // JSOp::Case c1
182 // JSOp::JumpTarget
183 // {c2_expr}
184 // JSOp::Case c2
186 // ...
188 // JSOp::JumpTarget
189 // JSOp::Default default
191 // c1:
192 // JSOp::JumpTarget
193 // {c1_body}
194 // JSOp::Goto end
196 // c2:
197 // JSOp::JumpTarget
198 // {c2_body}
199 // JSOp::Goto end
201 // default:
202 // end:
203 // JSOp::JumpTarget
205 // Table Switch
206 // {discriminant}
207 // JSOp::TableSwitch c1, c2, ...
209 // c1:
210 // JSOp::JumpTarget
211 // {c1_body}
212 // JSOp::Goto end
214 // c2:
215 // JSOp::JumpTarget
216 // {c2_body}
217 // JSOp::Goto end
219 // ...
221 // end:
222 // JSOp::JumpTarget
224 public:
225 enum class Kind { Table, Cond };
227 // Class for generating optimized table switch data.
228 class MOZ_STACK_CLASS TableGenerator {
229 BytecodeEmitter* bce_;
231 // Bit array for given numbers.
232 mozilla::Maybe<js::Vector<size_t, 128, SystemAllocPolicy>> intmap_;
234 // The length of the intmap_.
235 int32_t intmapBitLength_ = 0;
237 // The length of the table.
238 uint32_t tableLength_ = 0;
240 // The lower and higher bounds of the table.
241 int32_t low_ = JSVAL_INT_MAX, high_ = JSVAL_INT_MIN;
243 // Whether the table is still valid.
244 bool valid_ = true;
246 #ifdef DEBUG
247 bool finished_ = false;
248 #endif
250 public:
251 explicit TableGenerator(BytecodeEmitter* bce) : bce_(bce) {}
253 void setInvalid() { valid_ = false; }
254 [[nodiscard]] bool isValid() const { return valid_; }
255 [[nodiscard]] bool isInvalid() const { return !valid_; }
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);
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);
266 private:
267 friend SwitchEmitter;
269 // The following methods can be used only after calling `finish`.
271 // Returns the lower bound of the added numbers.
272 int32_t low() const {
273 MOZ_ASSERT(finished_);
274 return low_;
277 // Returns the higher bound of the numbers.
278 int32_t high() const {
279 MOZ_ASSERT(finished_);
280 return high_;
283 // Returns the index in SwitchEmitter.caseOffsets_ for table switch.
284 uint32_t toCaseIndex(int32_t caseValue) const;
286 // Returns the length of the table.
287 // This method can be called only if `isValid()` is true.
288 uint32_t tableLength() const;
291 private:
292 BytecodeEmitter* bce_;
294 // `kind_` should be set to the correct value in emitCond/emitTable.
295 Kind kind_ = Kind::Cond;
297 // True if there's explicit default case.
298 bool hasDefault_ = false;
300 // The number of cases in the switch statement, excluding the default case.
301 uint32_t caseCount_ = 0;
303 // Internal index for case jump and case body, used by cond switch.
304 uint32_t caseIndex_ = 0;
306 // Bytecode offset after emitting `discriminant`.
307 BytecodeOffset top_;
309 // Bytecode offset of the previous JSOp::Case.
310 BytecodeOffset lastCaseOffset_;
312 // Bytecode offset of the JSOp::JumpTarget for default body.
313 JumpTarget defaultJumpTargetOffset_;
315 // Bytecode offset of the JSOp::Default.
316 JumpList condSwitchDefaultOffset_;
318 // Instantiated when there's lexical scope for entire switch.
319 mozilla::Maybe<TDZCheckCache> tdzCacheLexical_;
320 mozilla::Maybe<EmitterScope> emitterScope_;
322 // Instantiated while emitting case expression and case/default body.
323 mozilla::Maybe<TDZCheckCache> tdzCacheCaseAndBody_;
325 // Control for switch.
326 mozilla::Maybe<BreakableControl> controlInfo_;
328 uint32_t switchPos_ = 0;
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_;
336 // The state of this emitter.
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 // +-------------------------------------+
388 protected:
389 enum class State {
390 // The initial state.
391 Start,
393 // After calling emitDiscriminant.
394 Discriminant,
396 // After calling validateCaseCount.
397 CaseCount,
399 // After calling emitLexical.
400 Lexical,
402 // After calling emitCond.
403 Cond,
405 // After calling emitTable.
406 Table,
408 // After calling prepareForCaseValue.
409 CaseValue,
411 // After calling emitCaseJump.
412 Case,
414 // After calling emitCaseBody.
415 CaseBody,
417 // After calling emitDefaultBody.
418 DefaultBody,
420 // After calling emitEnd.
423 State state_ = State::Start;
425 public:
426 explicit SwitchEmitter(BytecodeEmitter* bce);
428 // `switchPos` is the offset in the source code for the character below:
430 // switch ( cond ) { ... }
431 // ^
432 // |
433 // switchPos
434 [[nodiscard]] bool emitDiscriminant(uint32_t switchPos);
436 // `caseCount` should be the number of cases in the switch statement,
437 // excluding the default case.
438 [[nodiscard]] bool validateCaseCount(uint32_t caseCount);
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);
444 [[nodiscard]] bool emitCond();
445 [[nodiscard]] bool emitTable(const TableGenerator& tableGen);
447 [[nodiscard]] bool prepareForCaseValue();
448 [[nodiscard]] bool emitCaseJump();
450 [[nodiscard]] bool emitCaseBody();
451 [[nodiscard]] bool emitCaseBody(int32_t caseValue,
452 const TableGenerator& tableGen);
453 [[nodiscard]] bool emitDefaultBody();
454 [[nodiscard]] bool emitEnd();
456 private:
457 [[nodiscard]] bool emitCaseOrDefaultJump(uint32_t caseIndex, bool isDefault);
458 [[nodiscard]] bool emitImplicitDefault();
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);
471 } /* namespace frontend */
472 } /* namespace js */
474 #endif /* frontend_SwitchEmitter_h */