summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/AbstractScopePtr.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/AbstractScopePtr.h')
-rw-r--r--js/src/frontend/AbstractScopePtr.h143
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