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/EmitterScope.h | 210 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 js/src/frontend/EmitterScope.h (limited to 'js/src/frontend/EmitterScope.h') diff --git a/js/src/frontend/EmitterScope.h b/js/src/frontend/EmitterScope.h new file mode 100644 index 0000000000..8f985faffe --- /dev/null +++ b/js/src/frontend/EmitterScope.h @@ -0,0 +1,210 @@ +/* -*- 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_EmitterScope_h +#define frontend_EmitterScope_h + +#include "mozilla/Maybe.h" + +#include + +#include "ds/Nestable.h" +#include "frontend/AbstractScopePtr.h" +#include "frontend/NameAnalysisTypes.h" +#include "frontend/NameCollections.h" +#include "frontend/Stencil.h" +#include "vm/Opcodes.h" // JSOp +#include "vm/SharedStencil.h" // GCThingIndex + +namespace js { +namespace frontend { + +struct BytecodeEmitter; +class EvalSharedContext; +class FunctionBox; +class GlobalSharedContext; +class ModuleSharedContext; +class TaggedParserAtomIndex; + +// A scope that introduces bindings. +class EmitterScope : public Nestable { + // The cache of bound names that may be looked up in the + // scope. Initially populated as the set of names this scope binds. As + // names are looked up in enclosing scopes, they are cached on the + // current scope. + PooledMapPtr nameCache_; + + // If this scope's cache does not include free names, such as the + // global scope, the NameLocation to return. + mozilla::Maybe fallbackFreeNameLocation_; + + // True if there is a corresponding EnvironmentObject on the environment + // chain, false if all bindings are stored in frame slots on the stack. + bool hasEnvironment_; + + // The number of enclosing environments. Used for error checking. + uint8_t environmentChainLength_; + + // The next usable slot on the frame for not-closed over bindings. + // + // The initial frame slot when assigning slots to bindings is the + // enclosing scope's nextFrameSlot. For the first scope in a frame, + // the initial frame slot is 0. + uint32_t nextFrameSlot_; + + // The index in the BytecodeEmitter's interned scope vector, otherwise + // ScopeNote::NoScopeIndex. + GCThingIndex scopeIndex_; + + // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's + // block scope note list. Otherwise ScopeNote::NoScopeNote. + uint32_t noteIndex_; + + [[nodiscard]] bool ensureCache(BytecodeEmitter* bce); + + [[nodiscard]] bool checkSlotLimits(BytecodeEmitter* bce, + const ParserBindingIter& bi); + + [[nodiscard]] bool checkEnvironmentChainLength(BytecodeEmitter* bce); + + void updateFrameFixedSlots(BytecodeEmitter* bce, const ParserBindingIter& bi); + + [[nodiscard]] bool putNameInCache(BytecodeEmitter* bce, + TaggedParserAtomIndex name, + NameLocation loc); + + mozilla::Maybe lookupInCache(BytecodeEmitter* bce, + TaggedParserAtomIndex name); + + EmitterScope* enclosing(BytecodeEmitter** bce) const; + + mozilla::Maybe enclosingScopeIndex(BytecodeEmitter* bce) const; + + static bool nameCanBeFree(BytecodeEmitter* bce, TaggedParserAtomIndex name); + + NameLocation searchAndCache(BytecodeEmitter* bce, TaggedParserAtomIndex name); + + [[nodiscard]] bool internEmptyGlobalScopeAsBody(BytecodeEmitter* bce); + + [[nodiscard]] bool internScopeStencil(BytecodeEmitter* bce, ScopeIndex index); + + [[nodiscard]] bool internBodyScopeStencil(BytecodeEmitter* bce, + ScopeIndex index); + [[nodiscard]] bool appendScopeNote(BytecodeEmitter* bce); + + [[nodiscard]] bool clearFrameSlotRange(BytecodeEmitter* bce, JSOp opcode, + uint32_t slotStart, + uint32_t slotEnd) const; + + [[nodiscard]] bool deadZoneFrameSlotRange(BytecodeEmitter* bce, + uint32_t slotStart, + uint32_t slotEnd) const { + return clearFrameSlotRange(bce, JSOp::Uninitialized, slotStart, slotEnd); + } + + public: + explicit EmitterScope(BytecodeEmitter* bce); + + void dump(BytecodeEmitter* bce); + + [[nodiscard]] bool enterLexical(BytecodeEmitter* bce, ScopeKind kind, + LexicalScope::ParserData* bindings); + [[nodiscard]] bool enterClassBody(BytecodeEmitter* bce, ScopeKind kind, + ClassBodyScope::ParserData* bindings); + [[nodiscard]] bool enterNamedLambda(BytecodeEmitter* bce, + FunctionBox* funbox); + [[nodiscard]] bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox); + [[nodiscard]] bool enterFunctionExtraBodyVar(BytecodeEmitter* bce, + FunctionBox* funbox); + [[nodiscard]] bool enterGlobal(BytecodeEmitter* bce, + GlobalSharedContext* globalsc); + [[nodiscard]] bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc); + [[nodiscard]] bool enterModule(BytecodeEmitter* module, + ModuleSharedContext* modulesc); + [[nodiscard]] bool enterWith(BytecodeEmitter* bce); + [[nodiscard]] bool deadZoneFrameSlots(BytecodeEmitter* bce) const; + + [[nodiscard]] bool leave(BytecodeEmitter* bce, bool nonLocal = false); + + GCThingIndex index() const { + MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex, + "Did you forget to intern a Scope?"); + return scopeIndex_; + } + + uint32_t noteIndex() const { return noteIndex_; } + + AbstractScopePtr scope(const BytecodeEmitter* bce) const; + mozilla::Maybe scopeIndex(const BytecodeEmitter* bce) const; + + bool hasEnvironment() const { return hasEnvironment_; } + + // The first frame slot used. + uint32_t frameSlotStart() const { + if (EmitterScope* inFrame = enclosingInFrame()) { + return inFrame->nextFrameSlot_; + } + return 0; + } + + // The last frame slot used + 1. + uint32_t frameSlotEnd() const { return nextFrameSlot_; } + + EmitterScope* enclosingInFrame() const { + return Nestable::enclosing(); + } + + NameLocation lookup(BytecodeEmitter* bce, TaggedParserAtomIndex name); + + // Find both the slot associated with a private name and the location of the + // corresponding `.privateBrand` binding. + // + // Simply doing two separate lookups, one for `name` and another for + // `.privateBrand`, would give the wrong answer in this case: + // + // class Outer { + // #outerMethod() { reutrn "ok"; } + // + // test() { + // class Inner { + // #innerMethod() {} + // test(outer) { + // return outer.#outerMethod(); + // } + // } + // return new Inner().test(this); + // } + // } + // + // new Outer().test(); // should return "ok" + // + // At the point in Inner.test where `#outerMethod` is called, we need to + // check for the private brand of `Outer`, not `Inner`; but both class bodies + // have `.privateBrand` bindings. In a normal `lookup`, the inner binding + // would shadow the outer one. + // + // This method instead sets `brandLoc` to the location of the `.privateBrand` + // binding in the same class body as the private name `name`, ignoring + // shadowing. If `name` refers to a name that is actually stamped onto the + // target object (anything other than a non-static private method), then + // `brandLoc` is set to Nothing. + void lookupPrivate(BytecodeEmitter* bce, TaggedParserAtomIndex name, + NameLocation& loc, mozilla::Maybe& brandLoc); + + mozilla::Maybe locationBoundInScope(TaggedParserAtomIndex name, + EmitterScope* target); + + // For a given emitter scope, return the number of enclosing environments in + // the current compilation (this excludes environments that could enclose the + // compilation, like would happen for an eval copmilation). + static uint32_t CountEnclosingCompilationEnvironments( + BytecodeEmitter* bce, EmitterScope* emitterScope); +}; + +} /* namespace frontend */ +} /* namespace js */ + +#endif /* frontend_EmitterScope_h */ -- cgit v1.2.3