diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/jit/WarpBuilderShared.h | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit/WarpBuilderShared.h')
-rw-r--r-- | js/src/jit/WarpBuilderShared.h | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/js/src/jit/WarpBuilderShared.h b/js/src/jit/WarpBuilderShared.h new file mode 100644 index 0000000000..01dcac4936 --- /dev/null +++ b/js/src/jit/WarpBuilderShared.h @@ -0,0 +1,276 @@ +/* -*- 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 jit_WarpBuilderShared_h +#define jit_WarpBuilderShared_h + +#include "mozilla/Attributes.h" + +#include "jit/MIRGraph.h" +#include "js/Value.h" + +namespace js { + +class BytecodeLocation; + +namespace jit { + +class MBasicBlock; +class MCall; +class MConstant; +class MInstruction; +class MIRGenerator; +class TempAllocator; +class WarpSnapshot; +class WrappedFunction; + +// Helper class to manage call state. +class MOZ_STACK_CLASS CallInfo { + MDefinition* callee_ = nullptr; + MDefinition* thisArg_ = nullptr; + MDefinition* newTargetArg_ = nullptr; + MDefinitionVector args_; + + bool constructing_; + + // True if the caller does not use the return value. + bool ignoresReturnValue_; + + bool inlined_ = false; + bool setter_ = false; + bool apply_; + + public: + // For some argument formats (normal calls, FunCall, FunApplyArgs in an + // inlined function) we can shuffle around definitions in the CallInfo + // and use a normal MCall. For others, we need to use a specialized call. + enum class ArgFormat { + Standard, + Array, + FunApplyArgs, + }; + + private: + ArgFormat argFormat_ = ArgFormat::Standard; + + public: + CallInfo(TempAllocator& alloc, jsbytecode* pc, bool constructing, + bool ignoresReturnValue) + : args_(alloc), + constructing_(constructing), + ignoresReturnValue_(ignoresReturnValue), + apply_(JSOp(*pc) == JSOp::FunApply) {} + + [[nodiscard]] bool init(MBasicBlock* current, uint32_t argc) { + MOZ_ASSERT(args_.empty()); + + // Get the arguments in the right order + if (!args_.reserve(argc)) { + return false; + } + + if (constructing()) { + setNewTarget(current->pop()); + } + + for (int32_t i = argc; i > 0; i--) { + args_.infallibleAppend(current->peek(-i)); + } + current->popn(argc); + + // Get |this| and |callee| + setThis(current->pop()); + setCallee(current->pop()); + + return true; + } + + void initForSpreadCall(MBasicBlock* current) { + MOZ_ASSERT(args_.empty()); + + if (constructing()) { + setNewTarget(current->pop()); + } + + // Spread calls have one argument, an Array object containing the args. + static_assert(decltype(args_)::InlineLength >= 1, + "Appending one argument should be infallible"); + MOZ_ALWAYS_TRUE(args_.append(current->pop())); + + // Get |this| and |callee| + setThis(current->pop()); + setCallee(current->pop()); + + argFormat_ = ArgFormat::Array; + } + + void initForGetterCall(MDefinition* callee, MDefinition* thisVal) { + MOZ_ASSERT(args_.empty()); + setCallee(callee); + setThis(thisVal); + } + void initForSetterCall(MDefinition* callee, MDefinition* thisVal, + MDefinition* rhs) { + MOZ_ASSERT(args_.empty()); + markAsSetter(); + setCallee(callee); + setThis(thisVal); + static_assert(decltype(args_)::InlineLength >= 1, + "Appending one argument should be infallible"); + MOZ_ALWAYS_TRUE(args_.append(rhs)); + } + + void popCallStack(MBasicBlock* current) { current->popn(numFormals()); } + + [[nodiscard]] bool pushCallStack(MBasicBlock* current) { + // Ensure sufficient space in the slots: needed for inlining from FunApply. + if (apply_) { + uint32_t depth = current->stackDepth() + numFormals(); + if (depth > current->nslots()) { + if (!current->increaseSlots(depth - current->nslots())) { + return false; + } + } + } + + current->push(callee()); + current->push(thisArg()); + + for (uint32_t i = 0; i < argc(); i++) { + current->push(getArg(i)); + } + + if (constructing()) { + current->push(getNewTarget()); + } + + return true; + } + + uint32_t argc() const { return args_.length(); } + uint32_t numFormals() const { return argc() + 2 + constructing(); } + + [[nodiscard]] bool setArgs(const MDefinitionVector& args) { + MOZ_ASSERT(args_.empty()); + return args_.appendAll(args); + } + [[nodiscard]] bool replaceArgs(const MDefinitionVector& args) { + args_.clear(); + return setArgs(args); + } + + MDefinitionVector& argv() { return args_; } + + const MDefinitionVector& argv() const { return args_; } + + MDefinition* getArg(uint32_t i) const { + MOZ_ASSERT(i < argc()); + return args_[i]; + } + + void setArg(uint32_t i, MDefinition* def) { + MOZ_ASSERT(i < argc()); + args_[i] = def; + } + + void removeArg(uint32_t i) { args_.erase(&args_[i]); } + + MDefinition* thisArg() const { + MOZ_ASSERT(thisArg_); + return thisArg_; + } + + void setThis(MDefinition* thisArg) { thisArg_ = thisArg; } + + bool constructing() const { return constructing_; } + + bool ignoresReturnValue() const { return ignoresReturnValue_; } + + void setNewTarget(MDefinition* newTarget) { + MOZ_ASSERT(constructing()); + newTargetArg_ = newTarget; + } + MDefinition* getNewTarget() const { + MOZ_ASSERT(newTargetArg_); + return newTargetArg_; + } + + bool isSetter() const { return setter_; } + void markAsSetter() { setter_ = true; } + + bool isInlined() const { return inlined_; } + void markAsInlined() { inlined_ = true; } + + MDefinition* callee() const { + MOZ_ASSERT(callee_); + return callee_; + } + + void setCallee(MDefinition* callee) { callee_ = callee; } + + template <typename Fun> + void forEachCallOperand(Fun& f) { + f(callee_); + f(thisArg_); + if (newTargetArg_) { + f(newTargetArg_); + } + for (uint32_t i = 0; i < argc(); i++) { + f(getArg(i)); + } + } + + void setImplicitlyUsedUnchecked() { + auto setFlag = [](MDefinition* def) { def->setImplicitlyUsedUnchecked(); }; + forEachCallOperand(setFlag); + } + + ArgFormat argFormat() const { return argFormat_; } + void setArgFormat(ArgFormat argFormat) { argFormat_ = argFormat; } + + MDefinition* arrayArg() const { + MOZ_ASSERT(argFormat_ == ArgFormat::Array); + MOZ_ASSERT_IF(!apply_, argc() == 1 + uint32_t(constructing_)); + MOZ_ASSERT_IF(apply_, argc() == 2 && !constructing_); + return getArg(argc() - 1 - constructing_); + } +}; + +// Base class for code sharing between WarpBuilder and WarpCacheIRTranspiler. +// Because this code is used by WarpCacheIRTranspiler we should +// generally assume that we only have access to the current basic block. +class WarpBuilderShared { + WarpSnapshot& snapshot_; + MIRGenerator& mirGen_; + TempAllocator& alloc_; + + protected: + MBasicBlock* current; + + WarpBuilderShared(WarpSnapshot& snapshot, MIRGenerator& mirGen, + MBasicBlock* current_); + + [[nodiscard]] bool resumeAfter(MInstruction* ins, BytecodeLocation loc); + + MConstant* constant(const JS::Value& v); + void pushConstant(const JS::Value& v); + + MCall* makeCall(CallInfo& callInfo, bool needsThisCheck, + WrappedFunction* target = nullptr, bool isDOMCall = false); + MInstruction* makeSpreadCall(CallInfo& callInfo, bool isSameRealm = false, + WrappedFunction* target = nullptr); + + public: + MBasicBlock* currentBlock() const { return current; } + WarpSnapshot& snapshot() const { return snapshot_; } + MIRGenerator& mirGen() { return mirGen_; } + TempAllocator& alloc() { return alloc_; } +}; + +} // namespace jit +} // namespace js + +#endif |