From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- js/src/frontend/CallOrNewEmitter.h | 352 +++++++++++++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 js/src/frontend/CallOrNewEmitter.h (limited to 'js/src/frontend/CallOrNewEmitter.h') 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 + +#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 ifNotOptimizable_; + + mozilla::Maybe poe_; + mozilla::Maybe eoe_; + mozilla::Maybe 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 */ -- cgit v1.2.3