summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/AsyncEmitter.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/AsyncEmitter.h')
-rw-r--r--js/src/frontend/AsyncEmitter.h174
1 files changed, 174 insertions, 0 deletions
diff --git a/js/src/frontend/AsyncEmitter.h b/js/src/frontend/AsyncEmitter.h
new file mode 100644
index 0000000000..778f708c4f
--- /dev/null
+++ b/js/src/frontend/AsyncEmitter.h
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef frontend_AsyncEmitter_h
+#define frontend_AsyncEmitter_h
+
+#include "mozilla/Attributes.h" // MOZ_STACK_CLASS
+
+#include "frontend/TryEmitter.h" // TryEmitter
+
+namespace js {
+namespace frontend {
+
+struct BytecodeEmitter;
+
+// Class for emitting Bytecode associated with the AsyncFunctionGenerator.
+//
+// Usage:
+//
+// For an async function, the params have to be handled separately,
+// because the body may have pushed an additional var environment, changing
+// the number of hops required to reach the |.generator| variable. In order
+// to handle this, we can't reuse the same TryCatch emitter.
+//
+// Simple case - For a function without expression or destructuring
+// parameters:
+// `async function f(<params>) {<body>}`,
+// AsyncEmitter ae(this);
+//
+// ae.prepareForParamsWithoutExpressionOrDestructuring();
+// // Emit Params.
+// ...
+// ae.paramsEpilogue(); // We need to emit the epilogue before the extra
+// VarScope emitExtraBodyVarScope();
+//
+// // Emit new scope
+// ae.prepareForBody();
+//
+// // Emit body of the Function.
+// ...
+//
+// ae.emitEndFunction();
+//
+// Complex case - For a function with expression or destructuring parameters:
+// `async function f(<expression>) {<body>}`,
+// AsyncEmitter ae(this);
+//
+// ae.prepareForParamsWithExpressionOrDestructuring();
+//
+// // Emit Params.
+// ...
+// ae.paramsEpilogue(); // We need to emit the epilogue before the extra
+// // VarScope
+// emitExtraBodyVarScope();
+//
+// // Emit new scope
+// ae.prepareForBody();
+//
+// // Emit body of the Function.
+// ...
+//
+// // The final yield is emitted in FunctionScriptEmitter::emitEndBody().
+// ae.emitEndFunction();
+//
+//
+// Async Module case - For a module with `await` in the top level:
+// AsyncEmitter ae(this);
+// ae.prepareForModule(); // prepareForModule is used to setup the generator
+// // for the async module.
+// switchToMain();
+// ...
+//
+// // Emit new scope
+// ae.prepareForBody();
+//
+// // Emit body of the Script.
+//
+// ae.emitEndModule();
+//
+
+class MOZ_STACK_CLASS AsyncEmitter {
+ private:
+ BytecodeEmitter* bce_;
+
+ // try-catch block for async function parameter and body.
+ mozilla::Maybe<TryEmitter> rejectTryCatch_;
+
+#ifdef DEBUG
+ // The state of this emitter.
+ //
+ // +-------+
+ // | Start |-+
+ // +-------+ |
+ // |
+ // +----------+
+ // |
+ // | [Parameters with Expression or Destructuring]
+ // | prepareForParamsWithExpressionOrDestructuring +------------+
+ // +----------------------------------------------------| Parameters |-->+
+ // | +------------+ |
+ // | |
+ // | [Parameters Without Expression or Destructuring] |
+ // | prepareForParamsWithoutExpressionOrDestructuring +------------+ |
+ // +----------------------------------------------------| Parameters |-->+
+ // | +------------+ |
+ // | [Modules] |
+ // | prepareForModule +----------------+ |
+ // +-------------------->| ModulePrologue |--+ |
+ // +----------------+ | |
+ // | |
+ // | |
+ // +-----------------------------------------+ |
+ // | |
+ // | |
+ // V +------------+ paramsEpilogue |
+ // +<--------------------| PostParams |<---------------------------------+
+ // | +------------+
+ // |
+ // | [Script body]
+ // | prepareForBody +---------+
+ // +-------------------->| Body |--------+
+ // +---------+ | <emit script body>
+ // +----------------------------------------+
+ // |
+ // | [Functions]
+ // | emitEndFunction +-----+
+ // +--------------------->| End |
+ // | +-----+
+ // |
+ // | [Modules]
+ // | emitEndModule +-----+
+ // +--------------------->| End |
+ // +-----+
+
+ enum class State {
+ // The initial state.
+ Start,
+
+ Parameters,
+
+ ModulePrologue,
+
+ PostParams,
+
+ Body,
+
+ End,
+ };
+
+ State state_ = State::Start;
+#endif
+
+ [[nodiscard]] bool emitRejectCatch();
+ [[nodiscard]] bool emitFinalYield();
+
+ public:
+ explicit AsyncEmitter(BytecodeEmitter* bce) : bce_(bce){};
+
+ [[nodiscard]] bool prepareForParamsWithoutExpressionOrDestructuring();
+ [[nodiscard]] bool prepareForParamsWithExpressionOrDestructuring();
+ [[nodiscard]] bool prepareForModule();
+ [[nodiscard]] bool emitParamsEpilogue();
+ [[nodiscard]] bool prepareForBody();
+ [[nodiscard]] bool emitEndFunction();
+ [[nodiscard]] bool emitEndModule();
+};
+
+} /* namespace frontend */
+} /* namespace js */
+
+#endif /* frontend_AsyncEmitter_h */