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/frontend/AbstractScopePtr.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/frontend/AbstractScopePtr.h')
-rw-r--r-- | js/src/frontend/AbstractScopePtr.h | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/js/src/frontend/AbstractScopePtr.h b/js/src/frontend/AbstractScopePtr.h new file mode 100644 index 0000000000..276470d5f3 --- /dev/null +++ b/js/src/frontend/AbstractScopePtr.h @@ -0,0 +1,143 @@ +/* -*- 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_AbstractScopePtr_h +#define frontend_AbstractScopePtr_h + +#include "mozilla/Maybe.h" +#include "mozilla/Variant.h" + +#include "frontend/TypedIndex.h" +#include "gc/Barrier.h" +#include "gc/Rooting.h" +#include "gc/Tracer.h" +#include "vm/Scope.h" +#include "vm/ScopeKind.h" // For ScopeKind + +namespace js { +class Scope; +class GlobalScope; +class EvalScope; +struct MemberInitializers; +class GCMarker; + +namespace frontend { +struct CompilationState; +struct CompilationGCOutput; +class ScopeStencil; +} // namespace frontend + +using ScopeIndex = frontend::TypedIndex<Scope>; +using HeapPtrScope = HeapPtr<Scope*>; + +// An interface class to support Scope queries in the frontend without requiring +// a GC Allocated scope to necessarily exist. +// +// This abstracts Scope* and a ScopeStencil type used within the frontend before +// the Scope is allocated. +// +// Because a AbstractScopePtr may hold onto a Scope, it must be rooted if a GC +// may occur to ensure that the scope is traced. +class AbstractScopePtr { + public: + // Used to hold index and the compilationState together to avoid having a + // potentially nullable compilationState. + struct Deferred { + ScopeIndex index; + frontend::CompilationState& compilationState; + }; + + // To make writing code and managing invariants easier, we require that + // any nullptr scopes be stored on the HeapPtrScope arm of the variant. + using ScopeType = mozilla::Variant<HeapPtrScope, Deferred>; + + private: + ScopeType scope_ = ScopeType(HeapPtrScope()); + + Scope* scope() const { return scope_.as<HeapPtrScope>(); } + + public: + friend class js::Scope; + + AbstractScopePtr() = default; + + explicit AbstractScopePtr(Scope* scope) : scope_(HeapPtrScope(scope)) {} + + AbstractScopePtr(frontend::CompilationState& compilationState, + ScopeIndex scope) + : scope_(Deferred{scope, compilationState}) {} + + bool isNullptr() const { + if (isScopeStencil()) { + return false; + } + return scope_.as<HeapPtrScope>() == nullptr; + } + + // Return true if this AbstractScopePtr represents a Scope, either existant + // or to be reified. This indicates that queries can be executed on this + // scope data. Returning false is the equivalent to a nullptr, and usually + // indicates the end of the scope chain. + explicit operator bool() const { return !isNullptr(); } + + bool isScopeStencil() const { return scope_.is<Deferred>(); } + + // Note: this handle is rooted in the CompilationState. + frontend::ScopeStencil& scopeData() const; + frontend::CompilationState& compilationState() const; + + // This allows us to check whether or not this provider wraps + // or otherwise would reify to a particular scope type. + template <typename T> + bool is() const { + static_assert(std::is_base_of_v<Scope, T>, + "Trying to ask about non-Scope type"); + if (isNullptr()) { + return false; + } + return kind() == T::classScopeKind_; + } + + ScopeKind kind() const; + AbstractScopePtr enclosing() const; + bool hasEnvironment() const; + // Valid iff is<FunctionScope> + bool isArrow() const; + + bool hasOnChain(ScopeKind kind) const { + for (AbstractScopePtr it = *this; it; it = it.enclosing()) { + if (it.kind() == kind) { + return true; + } + } + return false; + } + + void trace(JSTracer* trc); +}; + +// Specializations of AbstractScopePtr::is +template <> +inline bool AbstractScopePtr::is<GlobalScope>() const { + return !isNullptr() && + (kind() == ScopeKind::Global || kind() == ScopeKind::NonSyntactic); +} + +template <> +inline bool AbstractScopePtr::is<EvalScope>() const { + return !isNullptr() && + (kind() == ScopeKind::Eval || kind() == ScopeKind::StrictEval); +} + +} // namespace js + +namespace JS { +template <> +struct GCPolicy<js::AbstractScopePtr::Deferred> + : JS::IgnoreGCPolicy<js::AbstractScopePtr::Deferred> {}; +} // namespace JS + +#endif // frontend_AbstractScopePtr_h |