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
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);
43 // se.prepareForCaseValue();
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);
61 // se.prepareForCaseValue();
65 // se.prepareForCaseValue();
75 // se.emitDefaultBody();
80 // `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body; }`
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);
98 // se.emitCaseBody(c2_expr_value, tableGen);
103 // `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body;
104 // default: def_body; }`
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);
122 // se.emitCaseBody(c2_expr_value, tableGen);
125 // se.emitDefaultBody();
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);
142 // se.prepareForCaseValue();
144 // se.emitCaseJump();
146 // se.emitCaseBody();
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);
164 // se.prepareForCaseValue();
166 // se.emitCaseJump();
168 // se.emitCaseBody();
173 class MOZ_STACK_CLASS SwitchEmitter
{
174 // Bytecode for each case.
176 // Cond Switch (uses an equality comparison for each case)
189 // JSOp::Default default
207 // JSOp::TableSwitch c1, c2, ...
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.
247 bool finished_
= false;
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
);
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_
);
277 // Returns the higher bound of the numbers.
278 int32_t high() const {
279 MOZ_ASSERT(finished_
);
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;
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`.
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;
331 // Offset of each JSOp::Case.
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 // +-------+ +--------------+ |
342 // +-------------------------------------------+
344 // | validateCaseCount +-----------+
345 // +->+------------------------>+------------------>| CaseCount |-+
346 // | ^ +-----------+ |
347 // | emitLexical +---------+ | |
348 // +------------>| Lexical |-+ |
351 // +--------------------------------------------------------------+
353 // | emitTable +-------+
354 // +---------->| Table |----------------------------------->+-+
357 // | emitCond +------+ | |
358 // +---------->| Cond |-+------------------------------->+->+ |
361 // +------------------+ | |
363 // |prepareForCaseValue +-----------+ | |
364 // +----------+--------->| CaseValue | | |
365 // ^ +-----------+ | |
367 // | | emitCaseJump +------+ | |
368 // | +------------->| Case |->+-+ |
371 // +--------------------------------------+ |
373 // +----------------------------------------------------------+
376 // +-+----------------------------------------->+-------->| End |
378 // | emitCaseBody +----------+ |
379 // +->+-+---------------->| CaseBody |--->+-+-+
380 // ^ | +----------+ ^ |
382 // | | emitDefaultBody +-------------+ | |
383 // | +---------------->| DefaultBody |-+ |
384 // | +-------------+ |
386 // +-------------------------------------+
390 // The initial state.
393 // After calling emitDiscriminant.
396 // After calling validateCaseCount.
399 // After calling emitLexical.
402 // After calling emitCond.
405 // After calling emitTable.
408 // After calling prepareForCaseValue.
411 // After calling emitCaseJump.
414 // After calling emitCaseBody.
417 // After calling emitDefaultBody.
420 // After calling emitEnd.
423 State state_
= State::Start
;
426 explicit SwitchEmitter(BytecodeEmitter
* bce
);
428 // `switchPos` is the offset in the source code for the character below:
430 // switch ( cond ) { ... }
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();
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
{
468 explicit InternalSwitchEmitter(BytecodeEmitter
* bce
);
471 } /* namespace frontend */
474 #endif /* frontend_SwitchEmitter_h */