summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/CallOrNewEmitter.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/frontend/CallOrNewEmitter.h
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/frontend/CallOrNewEmitter.h')
-rw-r--r--js/src/frontend/CallOrNewEmitter.h352
1 files changed, 352 insertions, 0 deletions
diff --git a/js/src/frontend/CallOrNewEmitter.h b/js/src/frontend/CallOrNewEmitter.h
new file mode 100644
index 0000000000..5abf644b70
--- /dev/null
+++ b/js/src/frontend/CallOrNewEmitter.h
@@ -0,0 +1,352 @@
+/* -*- 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_CallOrNewEmitter_h
+#define frontend_CallOrNewEmitter_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Maybe.h"
+
+#include <stdint.h>
+
+#include "frontend/ElemOpEmitter.h"
+#include "frontend/IfEmitter.h"
+#include "frontend/PrivateOpEmitter.h"
+#include "frontend/PropOpEmitter.h"
+#include "frontend/ValueUsage.h"
+#include "vm/BytecodeUtil.h"
+#include "vm/Opcodes.h"
+
+namespace js {
+namespace frontend {
+
+struct BytecodeEmitter;
+class TaggedParserAtomIndex;
+
+// Class for emitting bytecode for call or new expression.
+//
+// Usage: (check for the return value is omitted for simplicity)
+//
+// `print(arg);`
+// CallOrNewEmitter cone(this, JSOp::Call,
+// CallOrNewEmitter::ArgumentsKind::Other,
+// ValueUsage::WantValue);
+// cone.emitNameCallee(print);
+// cone.emitThis();
+// cone.prepareForNonSpreadArguments();
+// emit(arg);
+// cone.emitEnd(1, offset_of_callee);
+//
+// `callee.prop(arg1, arg2);`
+// CallOrNewEmitter cone(this, JSOp::Call,
+// CallOrNewEmitter::ArgumentsKind::Other,
+// ValueUsage::WantValue);
+// PropOpEmitter& poe = cone.prepareForPropCallee(false);
+// ... emit `callee.prop` with `poe` here...
+// cone.emitThis();
+// cone.prepareForNonSpreadArguments();
+// emit(arg1);
+// emit(arg2);
+// cone.emitEnd(2, offset_of_callee);
+//
+// `callee[key](arg);`
+// CallOrNewEmitter cone(this, JSOp::Call,
+// CallOrNewEmitter::ArgumentsKind::Other,
+// ValueUsage::WantValue);
+// ElemOpEmitter& eoe = cone.prepareForElemCallee(false);
+// ... emit `callee[key]` with `eoe` here...
+// cone.emitThis();
+// cone.prepareForNonSpreadArguments();
+// emit(arg);
+// cone.emitEnd(1, offset_of_callee);
+//
+// `callee.#method(arg);`
+// CallOrNewEmitter cone(this, JSOp::Call,
+// CallOrNewEmitter::ArgumentsKind::Other,
+// ValueUsage::WantValue);
+// PrivateOpEmitter& xoe = cone.prepareForPrivateCallee();
+// ... emit `callee.#method` with `xoe` here...
+// cone.prepareForNonSpreadArguments();
+// emit(arg);
+// cone.emitEnd(1, offset_of_callee);
+//
+// `(function() { ... })(arg);`
+// CallOrNewEmitter cone(this, JSOp::Call,
+// CallOrNewEmitter::ArgumentsKind::Other,
+// ValueUsage::WantValue);
+// cone.prepareForFunctionCallee();
+// emit(function);
+// cone.emitThis();
+// cone.prepareForNonSpreadArguments();
+// emit(arg);
+// cone.emitEnd(1, offset_of_callee);
+//
+// `super(arg);`
+// CallOrNewEmitter cone(this, JSOp::Call,
+// CallOrNewEmitter::ArgumentsKind::Other,
+// ValueUsage::WantValue);
+// cone.emitSuperCallee();
+// cone.emitThis();
+// cone.prepareForNonSpreadArguments();
+// emit(arg);
+// cone.emitEnd(1, offset_of_callee);
+//
+// `(some_other_expression)(arg);`
+// CallOrNewEmitter cone(this, JSOp::Call,
+// CallOrNewEmitter::ArgumentsKind::Other,
+// ValueUsage::WantValue);
+// cone.prepareForOtherCallee();
+// emit(some_other_expression);
+// cone.emitThis();
+// cone.prepareForNonSpreadArguments();
+// emit(arg);
+// cone.emitEnd(1, offset_of_callee);
+//
+// `print(...arg);`
+// CallOrNewEmitter cone(this, JSOp::SpreadCall,
+// CallOrNewEmitter::ArgumentsKind::SingleSpread,
+// ValueUsage::WantValue);
+// cone.emitNameCallee(print);
+// cone.emitThis();
+// if (cone.wantSpreadOperand()) {
+// emit(arg)
+// }
+// cone.emitSpreadArgumentsTest();
+// emit([...arg]);
+// cone.emitEnd(1, offset_of_callee);
+//
+// `new f(arg);`
+// CallOrNewEmitter cone(this, JSOp::New,
+// CallOrNewEmitter::ArgumentsKind::Other,
+// ValueUsage::WantValue);
+// cone.emitNameCallee(f);
+// cone.emitThis();
+// cone.prepareForNonSpreadArguments();
+// emit(arg);
+// cone.emitEnd(1, offset_of_callee);
+//
+class MOZ_STACK_CLASS CallOrNewEmitter {
+ public:
+ enum class ArgumentsKind {
+ Other,
+
+ // Specify this for the following case:
+ //
+ // g(...input);
+ //
+ // This enables optimization to avoid allocating an intermediate array
+ // for spread operation.
+ //
+ // wantSpreadOperand() returns true when this is specified.
+ SingleSpread,
+
+ // Used for default derived class constructors:
+ //
+ // constructor(...args) {
+ // super(...args);
+ // }
+ //
+ // The rest-parameter is directly passed through to the `super` call without
+ // using the iteration protocol.
+ PassthroughRest,
+ };
+
+ private:
+ BytecodeEmitter* bce_;
+
+ // The opcode for the call or new.
+ JSOp op_;
+
+ // Whether the call is a spread call with single parameter or not.
+ // See the comment in emitSpreadArgumentsTest for more details.
+ ArgumentsKind argumentsKind_;
+
+ // The branch for spread call optimization.
+ mozilla::Maybe<InternalIfEmitter> ifNotOptimizable_;
+
+ mozilla::Maybe<PropOpEmitter> poe_;
+ mozilla::Maybe<ElemOpEmitter> eoe_;
+ mozilla::Maybe<PrivateOpEmitter> xoe_;
+
+ // The state of this emitter.
+ //
+ // +-------+ emitNameCallee +------------+
+ // | Start |-+------------------------->| NameCallee |------+
+ // +-------+ | +------------+ |
+ // | |
+ // | prepareForPropCallee +------------+ v
+ // +------------------------->| PropCallee |----->+
+ // | +------------+ |
+ // | |
+ // | prepareForElemCallee +------------+ v
+ // +------------------------->| ElemCallee |----->+
+ // | +------------+ |
+ // | |
+ // | prepareForPrivateCallee +---------------+ v
+ // +------------------------->| PrivateCallee |-->+
+ // | +---------------+ |
+ // | |
+ // | prepareForFunctionCallee +----------------+ v
+ // +------------------------->| FunctionCallee |->+
+ // | +----------------+ |
+ // | |
+ // | emitSuperCallee +-------------+ v
+ // +------------------------->| SuperCallee |---->+
+ // | +-------------+ |
+ // | |
+ // | prepareForOtherCallee +-------------+ v
+ // +------------------------->| OtherCallee |---->+
+ // +-------------+ |
+ // |
+ // +--------------------------------------------------------+
+ // |
+ // | emitThis +------+
+ // +--------->| This |-+
+ // +------+ |
+ // |
+ // +-------------------+
+ // |
+ // | [!isSpread]
+ // | prepareForNonSpreadArguments +-----------+ emitEnd +-----+
+ // +------------------------------->+->| Arguments |-------->| End |
+ // | ^ +-----------+ +-----+
+ // | |
+ // | +<------------------------------------+
+ // | | |
+ // | | emitSpreadArgumentsTestEnd |
+ // | | |
+ // | | +-----------------+ |
+ // | +---------| SpreadIteration |------+ |
+ // | +-----------------+ | |
+ // | +----------------------------------+ |
+ // | | |
+ // | | wantSpreadIteration |
+ // | | |
+ // | | +---------------------+ |
+ // | +---------| SpreadArgumentsTest |--+ |
+ // | +---------------------+ | |
+ // | [isSpread] | |
+ // | wantSpreadOperand +-------------------+ emitSpreadArgumentsTest | |
+ // +-------------------->| WantSpreadOperand |-------------------------+ |
+ // | +-------------------+ |
+ // | |
+ // | |
+ // | |
+ // | [isSpread] |
+ // | prepareForSpreadArguments |
+ // +----------------------------------------------------------------------+
+ enum class State {
+ // The initial state.
+ Start,
+
+ // After calling emitNameCallee.
+ NameCallee,
+
+ // After calling prepareForPropCallee.
+ PropCallee,
+
+ // After calling prepareForElemCallee.
+ ElemCallee,
+
+ // After calling prepareForPrivateCallee.
+ PrivateCallee,
+
+ // After calling prepareForFunctionCallee.
+ FunctionCallee,
+
+ // After calling emitSuperCallee.
+ SuperCallee,
+
+ // After calling prepareForOtherCallee.
+ OtherCallee,
+
+ // After calling emitThis.
+ This,
+
+ // After calling wantSpreadOperand.
+ WantSpreadOperand,
+
+ // After calling emitSpreadArgumentsTest.
+ SpreadArgumentsTest,
+
+ // After calling wantSpreadIteration.
+ SpreadIteration,
+
+ // After calling prepareForNonSpreadArguments.
+ Arguments,
+
+ // After calling emitEnd.
+ End
+ };
+ State state_ = State::Start;
+
+ public:
+ CallOrNewEmitter(BytecodeEmitter* bce, JSOp op, ArgumentsKind argumentsKind,
+ ValueUsage valueUsage);
+
+ private:
+ [[nodiscard]] bool isCall() const {
+ return op_ == JSOp::Call || op_ == JSOp::CallIgnoresRv ||
+ op_ == JSOp::SpreadCall || isEval();
+ }
+
+ [[nodiscard]] bool isNew() const {
+ return op_ == JSOp::New || op_ == JSOp::SpreadNew;
+ }
+
+ [[nodiscard]] bool isSuperCall() const {
+ return op_ == JSOp::SuperCall || op_ == JSOp::SpreadSuperCall;
+ }
+
+ [[nodiscard]] bool isEval() const {
+ return op_ == JSOp::Eval || op_ == JSOp::StrictEval ||
+ op_ == JSOp::SpreadEval || op_ == JSOp::StrictSpreadEval;
+ }
+
+ [[nodiscard]] bool isSpread() const { return IsSpreadOp(op_); }
+
+ [[nodiscard]] bool isSingleSpread() const {
+ return argumentsKind_ == ArgumentsKind::SingleSpread;
+ }
+
+ [[nodiscard]] bool isPassthroughRest() const {
+ return argumentsKind_ == ArgumentsKind::PassthroughRest;
+ }
+
+ public:
+ [[nodiscard]] bool emitNameCallee(TaggedParserAtomIndex name);
+ [[nodiscard]] PropOpEmitter& prepareForPropCallee(bool isSuperProp);
+ [[nodiscard]] ElemOpEmitter& prepareForElemCallee(bool isSuperElem);
+ [[nodiscard]] PrivateOpEmitter& prepareForPrivateCallee(
+ TaggedParserAtomIndex privateName);
+ [[nodiscard]] bool prepareForFunctionCallee();
+ [[nodiscard]] bool emitSuperCallee();
+ [[nodiscard]] bool prepareForOtherCallee();
+
+ [[nodiscard]] bool emitThis();
+
+ [[nodiscard]] bool prepareForNonSpreadArguments();
+ [[nodiscard]] bool prepareForSpreadArguments();
+
+ // See the usage in the comment at the top of the class.
+ [[nodiscard]] bool wantSpreadOperand();
+ [[nodiscard]] bool emitSpreadArgumentsTest();
+ [[nodiscard]] bool emitSpreadArgumentsTestEnd();
+ [[nodiscard]] bool wantSpreadIteration();
+
+ // Parameters are the offset in the source code for each character below:
+ //
+ // callee(arg);
+ // ^
+ // |
+ // beginPos
+ [[nodiscard]] bool emitEnd(uint32_t argc, uint32_t beginPos);
+};
+
+} /* namespace frontend */
+} /* namespace js */
+
+#endif /* frontend_CallOrNewEmitter_h */