/* -*- 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/. */
// These 2 functions are used to write the same code with lambda using auto // arguments. The auto argument type is set by the Variant.match function of the // InputScope variant. Thus dispatching to either a Scope* or to a // ScopeStencilRef. This function can then be used as a way to specialize the // code within the lambda without duplicating the code. // // Identically, an InputName is constructed using the scope type and the // matching binding name type. This way, functions which are called by this // lambda can manipulate an InputName and do not have to be duplicated. // // for (InputScopeIter si(...); si; si++) { // si.scope().match([](auto& scope) { // for (auto bi = InputBindingIter(scope); bi; bi++) { // InputName name(scope, bi.name()); // } // }); // } static js::BindingIter InputBindingIter(Scope* ptr) { return js::BindingIter(ptr);
}
// JSAtom variant is used only on the main thread delazification, // where JSContext is always available.
JSContext* cx = fc->maybeCurrentJSContext();
MOZ_ASSERT(cx);
if (!*otherCached) { // TODO-Stencil: // Here, we convert our name into a JSAtom*, and hard-crash on failure // to allocate. This conversion should not be required as we should be // able to iterate up snapshotted scope chains that use parser atoms. // // This will be fixed when the enclosing scopes are snapshotted. // // See bug 1690277.
AutoEnterOOMUnsafeRegion oomUnsafe;
*otherCached = parserAtoms.toJSAtom(cx, fc, other, atomCache); if (!*otherCached) {
oomUnsafe.crash("InputName::isEqualTo");
}
} else {
MOZ_ASSERT(atomCache.getExistingAtomAt(cx, other) == *otherCached);
} return ptr == *otherCached;
},
[&](const NameStencilRef& ref) -> bool { return parserAtoms.isEqualToExternalParserAtomIndex(other, ref.context_,
ref.atomIndex_);
});
}
bool GenericAtom::operator==(const GenericAtom& other) const { return ref.match(
[&other](const EmitterName& name) -> bool { return other.ref.match(
[&name](const EmitterName& other) -> bool { // We never have multiple Emitter context at the same time.
MOZ_ASSERT(name.fc == other.fc);
MOZ_ASSERT(&name.parserAtoms == &other.parserAtoms);
MOZ_ASSERT(&name.atomCache == &other.atomCache); return name.index == other.index;
},
[&name](const StencilName& other) -> bool { return name.parserAtoms.isEqualToExternalParserAtomIndex(
name.index, other.stencil, other.index);
},
[&name](JSAtom* other) -> bool { // JSAtom variant is used only on the main thread delazification, // where JSContext is always available.
JSContext* cx = name.fc->maybeCurrentJSContext();
MOZ_ASSERT(cx);
AutoEnterOOMUnsafeRegion oomUnsafe;
JSAtom* namePtr = name.parserAtoms.toJSAtom(
cx, name.fc, name.index, name.atomCache); if (!namePtr) {
oomUnsafe.crash("GenericAtom(EmitterName == JSAtom*)");
} return namePtr == other;
});
},
[&other](const StencilName& name) -> bool { return other.ref.match(
[&name](const EmitterName& other) -> bool { return other.parserAtoms.isEqualToExternalParserAtomIndex(
other.index, name.stencil, name.index);
},
[&name](const StencilName& other) -> bool { // Technically it is possible to have multiple stencils, but in // this particular case let's assume we never encounter a case // where we are comparing names from different stencils. // // The reason this assumption is safe today is that we are only // using this in the context of a stencil-delazification, where // the only StencilNames are coming from the CompilationStencil // provided to CompilationInput::initFromStencil.
MOZ_ASSERT(&name.stencil == &other.stencil); return name.index == other.index;
},
[](JSAtom* other) -> bool {
MOZ_CRASH("Never used."); returnfalse;
});
},
[&other](JSAtom* name) -> bool { return other.ref.match(
[&name](const EmitterName& other) -> bool { // JSAtom variant is used only on the main thread delazification, // where JSContext is always available.
JSContext* cx = other.fc->maybeCurrentJSContext();
MOZ_ASSERT(cx);
AutoEnterOOMUnsafeRegion oomUnsafe;
JSAtom* otherPtr = other.parserAtoms.toJSAtom(
cx, other.fc, other.index, other.atomCache); if (!otherPtr) {
oomUnsafe.crash("GenericAtom(JSAtom* == EmitterName)");
} return name == otherPtr;
},
[](const StencilName& other) -> bool {
MOZ_CRASH("Never used."); returnfalse;
},
[&name](JSAtom* other) -> bool { return name == other; });
});
}
bool ScopeContext::init(FrontendContext* fc, CompilationInput& input,
ParserAtomsTable& parserAtoms,
ScopeBindingCache* scopeCache, InheritThis inheritThis,
JSObject* enclosingEnv) { // Record the scopeCache to be used while looking up NameLocation bindings.
this->scopeCache = scopeCache;
scopeCacheGen = scopeCache->getCurrentGeneration();
// If this eval is in response to Debugger.Frame.eval, we may have an // incomplete scope chain. In order to provide a better debugging experience, // we inspect the (optional) environment chain to determine it's enclosing // FunctionScope if there is one. If there is no such scope, we use the // orignal scope provided. // // NOTE: This is used to compute the ThisBinding kind and to allow access to // private fields and methods, while other contextual information only // uses the actual scope passed to the compile. auto effectiveScope =
determineEffectiveScope(maybeNonDefaultEnclosingScope, enclosingEnv);
if (inheritThis == InheritThis::Yes) {
computeThisBinding(effectiveScope);
computeThisEnvironment(maybeNonDefaultEnclosingScope);
}
computeInScope(maybeNonDefaultEnclosingScope);
cacheEnclosingScope(input.enclosingScope);
if (input.target == CompilationInput::CompilationTarget::Eval) { if (!cacheEnclosingScopeBindingForEval(fc, input, parserAtoms)) { returnfalse;
} if (!cachePrivateFieldsForEval(fc, input, enclosingEnv, effectiveScope,
parserAtoms)) { returnfalse;
}
}
returntrue;
}
void ScopeContext::computeThisEnvironment(const InputScope& enclosingScope) {
uint32_t envCount = 0; for (InputScopeIter si(enclosingScope); si; si++) { if (si.kind() == ScopeKind::Function) { // Arrow function inherit the "this" environment of the enclosing script, // so continue ignore them. if (!si.scope().isArrow()) {
allowNewTarget = true;
if (si.scope().allowSuperProperty()) {
allowSuperProperty = true;
enclosingThisEnvironmentHops = envCount;
}
// This computes a general answer for the query "does the enclosing scope // have a function scope that needs a home object?", but it's only asserted // if the parser parses eval body that contains `super` that needs a home // object. for (InputScopeIter si(enclosingScope); si; si++) { if (si.kind() == ScopeKind::Function) { if (si.scope().isArrow()) { continue;
} if (si.scope().allowSuperProperty() && si.scope().needsHomeObject()) {
hasFunctionNeedsHomeObjectOnChain = true;
} break;
}
} #endif
// Pre-fill the scope cache by iterating over all the names. Stop iterating // as soon as we find a scope which already has a filled scope cache.
AutoEnterOOMUnsafeRegion oomUnsafe; for (InputScopeIter si(enclosingScope); si; si++) { // If the current scope already exists, then there is no need to go deeper // as the scope which are encoded after this one should already be present // in the cache. bool hasScopeCache = si.scope().match([&](auto& scope_ref) -> bool {
MOZ_ASSERT(scopeCache->canCacheFor(scope_ref)); return scopeCache->lookupScope(scope_ref, scopeCacheGen);
}); if (hasScopeCache) { return;
}
bool hasEnv = si.hasSyntacticEnvironment(); auto setCatchAll = [&](NameLocation loc) { return si.scope().match([&](auto& scope_ref) { using BindingMapPtr = decltype(scopeCache->createCacheFor(scope_ref));
BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref); if (!bindingMapPtr) {
oomUnsafe.crash( "ScopeContext::cacheEnclosingScope: scopeCache->createCacheFor"); return;
}
bindingMapPtr->catchAll.emplace(loc);
});
}; auto createEmpty = [&]() { return si.scope().match([&](auto& scope_ref) { using BindingMapPtr = decltype(scopeCache->createCacheFor(scope_ref));
BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref); if (!bindingMapPtr) {
oomUnsafe.crash( "ScopeContext::cacheEnclosingScope: scopeCache->createCacheFor"); return;
}
});
};
switch (si.kind()) { case ScopeKind::Function: if (hasEnv) { if (si.scope().funHasExtensibleScope()) {
setCatchAll(NameLocation::Dynamic()); return;
}
si.scope().match([&](auto& scope_ref) { using BindingMapPtr =
decltype(scopeCache->createCacheFor(scope_ref)); using Lookup = typename std::remove_pointer_t<BindingMapPtr>::Lookup;
BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref); if (!bindingMapPtr) {
oomUnsafe.crash( "ScopeContext::cacheEnclosingScope: " "scopeCache->createCacheFor"); return;
}
for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
NameLocation loc = bi.nameLocation(); if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate) { continue;
} auto ctxFreeKey = bi.name();
GenericAtom ctxKey(scope_ref, ctxFreeKey);
Lookup ctxLookup(scope_ref, ctxKey); if (!bindingMapPtr->hashMap.put(ctxLookup, ctxFreeKey, loc)) {
oomUnsafe.crash( "ScopeContext::cacheEnclosingScope: bindingMapPtr->put"); return;
}
}
});
} else {
createEmpty();
} break;
case ScopeKind::StrictEval: case ScopeKind::FunctionBodyVar: case ScopeKind::Lexical: case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: case ScopeKind::SimpleCatch: case ScopeKind::Catch: case ScopeKind::FunctionLexical: case ScopeKind::ClassBody: if (hasEnv) {
si.scope().match([&](auto& scope_ref) { using BindingMapPtr =
decltype(scopeCache->createCacheFor(scope_ref)); using Lookup = typename std::remove_pointer_t<BindingMapPtr>::Lookup;
BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref); if (!bindingMapPtr) {
oomUnsafe.crash( "ScopeContext::cacheEnclosingScope: " "scopeCache->createCacheFor"); return;
}
for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
NameLocation loc = bi.nameLocation(); if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate) { continue;
} auto ctxFreeKey = bi.name();
GenericAtom ctxKey(scope_ref, ctxFreeKey);
Lookup ctxLookup(scope_ref, ctxKey); if (!bindingMapPtr->hashMap.putNew(ctxLookup, ctxFreeKey, loc)) {
oomUnsafe.crash( "ScopeContext::cacheEnclosingScope: bindingMapPtr->put"); return;
}
}
});
} else {
createEmpty();
} break;
case ScopeKind::Module: // This case is used only when delazifying a function inside // module. // Initial compilation of module doesn't have enlcosing scope. if (hasEnv) {
si.scope().match([&](auto& scope_ref) { using BindingMapPtr =
decltype(scopeCache->createCacheFor(scope_ref)); using Lookup = typename std::remove_pointer_t<BindingMapPtr>::Lookup;
BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref); if (!bindingMapPtr) {
oomUnsafe.crash( "ScopeContext::cacheEnclosingScope: " "scopeCache->createCacheFor"); return;
}
for (auto bi = InputBindingIter(scope_ref); bi; bi++) { // Imports are on the environment but are indirect // bindings and must be accessed dynamically instead of // using an EnvironmentCoordinate.
NameLocation loc = bi.nameLocation(); if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate &&
loc.kind() != NameLocation::Kind::Import) { continue;
} auto ctxFreeKey = bi.name();
GenericAtom ctxKey(scope_ref, ctxFreeKey);
Lookup ctxLookup(scope_ref, ctxKey); if (!bindingMapPtr->hashMap.putNew(ctxLookup, ctxFreeKey, loc)) {
oomUnsafe.crash( "ScopeContext::cacheEnclosingScope: bindingMapPtr->put"); return;
}
}
});
} else {
createEmpty();
} break;
case ScopeKind::Eval: // As an optimization, if the eval doesn't have its own var // environment and its immediate enclosing scope is a global // scope, all accesses are global. if (!hasEnv) {
ScopeKind kind = si.scope().enclosing().kind(); if (kind == ScopeKind::Global || kind == ScopeKind::NonSyntactic) {
setCatchAll(NameLocation::Global(BindingKind::Var)); return;
}
}
setCatchAll(NameLocation::Dynamic()); return;
case ScopeKind::Global:
setCatchAll(NameLocation::Global(BindingKind::Var)); return;
case ScopeKind::With: case ScopeKind::NonSyntactic:
setCatchAll(NameLocation::Dynamic()); return;
case ScopeKind::WasmInstance: case ScopeKind::WasmFunction:
MOZ_CRASH("No direct eval inside wasm functions");
}
}
MOZ_CRASH("Malformed scope chain");
}
// Given an input scope, possibly refine this to a more precise scope. // This is used during eval in the debugger to provide the appropriate scope and // ThisBinding kind and environment, which is key to making private field eval // work correctly. // // The trick here is that an eval may have a non-syntatic scope but nevertheless // have an 'interesting' environment which can be traversed to find the // appropriate scope the the eval to function as desired. See the diagram below. // // Eval Scope Eval Env Frame Env Frame Scope // ============ ============= ========= ============= // // NonSyntactic // | // v // null DebugEnvProxy LexicalScope // | | // v v // DebugEnvProxy --> CallObj --> FunctionScope // | | | // v v v // ... ... ... //
InputScope ScopeContext::determineEffectiveScope(InputScope& scope,
JSObject* environment) {
MOZ_ASSERT(effectiveScopeHops == 0); // If the scope-chain is non-syntactic, we may still determine a more precise // effective-scope to use instead. if (environment && scope.hasOnChain(ScopeKind::NonSyntactic)) {
JSObject* env = environment; while (env) { // Look at target of any DebugEnvironmentProxy, but be sure to use // enclosingEnvironment() of the proxy itself.
JSObject* unwrapped = env; if (env->is<DebugEnvironmentProxy>()) {
unwrapped = &env->as<DebugEnvironmentProxy>().environment(); #ifdef DEBUG
enclosingEnvironmentIsDebugProxy_ = true; #endif
}
if (unwrapped->is<CallObject>()) {
JSFunction* callee = &unwrapped->as<CallObject>().callee(); return InputScope(callee->nonLazyScript()->bodyScope());
}
uint32_t varScopeDepth =
DepthOfNearestVarScopeForDirectEval(input.enclosingScope);
uint32_t depth = 0; for (InputScopeIter si(input.enclosingScope); si; si++) { bool success = si.scope().match([&](auto& scope_ref) { for (auto bi = InputBindingIter(scope_ref); bi; bi++) { switch (bi.kind()) { case BindingKind::Let: { // Annex B.3.5 allows redeclaring simple (non-destructured) // catch parameters with var declarations. bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch; if (!annexB35Allowance) { auto kind = ScopeKindIsCatch(si.kind())
? EnclosingLexicalBindingKind::CatchParameter
: EnclosingLexicalBindingKind::Let;
InputName binding(scope_ref, bi.name()); if (!addToEnclosingLexicalBindingCache(
fc, parserAtoms, input.atomCache, binding, kind)) { returnfalse;
}
} break;
}
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT // TODO: Optimize cache population for `using` bindings. (Bug 1899502) case BindingKind::Using: break; #endif case BindingKind::Const: {
InputName binding(scope_ref, bi.name()); if (!addToEnclosingLexicalBindingCache(
fc, parserAtoms, input.atomCache, binding,
EnclosingLexicalBindingKind::Const)) { returnfalse;
} break;
}
case BindingKind::Synthetic: {
InputName binding(scope_ref, bi.name()); if (!addToEnclosingLexicalBindingCache(
fc, parserAtoms, input.atomCache, binding,
EnclosingLexicalBindingKind::Synthetic)) { returnfalse;
} break;
}
case BindingKind::PrivateMethod: {
InputName binding(scope_ref, bi.name()); if (!addToEnclosingLexicalBindingCache(
fc, parserAtoms, input.atomCache, binding,
EnclosingLexicalBindingKind::PrivateMethod)) { returnfalse;
} break;
}
case BindingKind::Import: case BindingKind::FormalParameter: case BindingKind::Var: case BindingKind::NamedLambdaCallee: break;
}
} returntrue;
}); if (!success) { returnfalse;
}
// Same lexical binding can appear multiple times across scopes. // // enclosingLexicalBindingCache_ map is used for detecting conflicting // `var` binding, and inner binding should be reported in the error. // // cacheEnclosingScopeBindingForEval iterates from inner scope, and // inner-most binding is added to the map first. // // Do not overwrite the value with outer bindings. auto p = enclosingLexicalBindingCache_->lookupForAdd(parserName); if (!p) { if (!enclosingLexicalBindingCache_->add(p, parserName, kind)) {
ReportOutOfMemory(fc); returnfalse;
}
}
#ifdef DEBUG if (atom.isWellKnownAtomId()) { constauto& info = GetWellKnownAtomInfo(atom.toWellKnownAtomId()); // #constructor is a well-known term, but it is invalid private name.
MOZ_ASSERT(!(info.length > 1 && info.content[0] == '#'));
} elseif (atom.isLength2StaticParserString()) { char content[2];
ParserAtomsTable::getLength2Content(atom.toLength2StaticParserString(),
content); // # character is not part of the allowed character of static strings.
MOZ_ASSERT(content[0] != '#');
} #endif
// We compute an environment coordinate relative to the effective scope // environment. In order to safely consume these environment coordinates, // we re-map them to include the hops to get the to the effective scope: // see EmitterScope::lookupPrivate
uint32_t hops = effectiveScopeHops; for (InputScopeIter si(effectiveScope); si; si++) { if (si.scope().kind() == ScopeKind::ClassBody) {
uint32_t slots = 0; bool success = si.scope().match([&](auto& scope_ref) { for (auto bi = InputBindingIter(scope_ref); bi; bi++) { if (bi.kind() == BindingKind::PrivateMethod ||
(bi.kind() == BindingKind::Synthetic &&
IsPrivateField(scope_ref, bi.name()))) {
InputName binding(scope_ref, bi.name()); auto parserName =
binding.internInto(fc, parserAtoms, input.atomCache); if (!parserName) { returnfalse;
}
NameLocation loc = NameLocation::DebugEnvironmentCoordinate(
bi.kind(), hops, slots);
if (!effectiveScopePrivateFieldCache_->put(parserName, loc)) {
ReportOutOfMemory(fc); returnfalse;
}
}
slots++;
} returntrue;
}); if (!success) { returnfalse;
}
}
// Hops is only consumed by GetAliasedDebugVar, which uses this to // traverse the debug environment chain. See the [SMDOC] for Debug // Environment Chain, which explains why we don't check for // isEnvironment when computing hops here (basically, debug proxies // pretend all scopes have environments, even if they were actually // optimized out).
hops++;
}
returntrue;
}
#ifdef DEBUG staticbool NameIsOnEnvironment(FrontendContext* fc,
ParserAtomsTable& parserAtoms,
CompilationAtomCache& atomCache,
InputScope& scope, TaggedParserAtomIndex name) {
JSAtom* jsname = nullptr; return scope.match([&](auto& scope_ref) { if (std::is_same_v<decltype(scope_ref), FakeStencilGlobalScope&>) { // This condition is added to handle the FakeStencilGlobalScope which is // used to emulate the global object when delazifying while executing, and // which is not provided by the Stencil. returntrue;
} for (auto bi = InputBindingIter(scope_ref); bi; bi++) { // If found, the name must already be on the environment or an import, // or else there is a bug in the closed-over name analysis in the // Parser.
InputName binding(scope_ref, bi.name()); if (binding.isEqualTo(fc, parserAtoms, atomCache, name, &jsname)) {
BindingLocation::Kind kind = bi.location().kind();
if (bi.hasArgumentSlot()) { // The following is equivalent to // functionScope.script()->functionAllowsParameterRedeclaration() if (scope.hasMappedArgsObj()) { // Check for duplicate positional formal parameters. using InputBindingIter = decltype(bi); for (InputBindingIter bi2(bi); bi2 && bi2.hasArgumentSlot();
bi2++) {
InputName binding2(scope_ref, bi2.name()); if (binding2.isEqualTo(fc, parserAtoms, atomCache, name,
&jsname)) {
kind = bi2.location().kind();
}
}
}
}
#ifdef DEBUG // Catch assertion failures in the NoCache variant before looking at the // cached content.
NameLocation expect =
searchInEnclosingScopeNoCache(fc, input, parserAtoms, name); #endif
// If the result happens to be in the cached content of the scope that we // are iterating over, then return it.
si.scope().match([&](auto& scope_ref) { using BindingMapPtr =
decltype(scopeCache->lookupScope(scope_ref, scopeCacheGen));
BindingMapPtr bindingMapPtr =
scopeCache->lookupScope(scope_ref, scopeCacheGen);
MOZ_ASSERT(bindingMapPtr);
auto& bindingMap = *bindingMapPtr; if (bindingMap.catchAll.isSome()) {
found = bindingMap.catchAll; return;
}
// The scope_ref is given as argument to know where to lookup the key // index of the hash table if the names have to be compared. using Lookup = typename std::remove_pointer_t<BindingMapPtr>::Lookup;
Lookup ctxName(scope_ref, genName); auto ptr = bindingMap.hashMap.lookup(ctxName); if (!ptr) { return;
}
found.emplace(ptr->value());
});
if (found.isSome()) { // Cached entries do not store the number of hops, as it might be reused // by multiple inner functions, which might different number of hops.
found = found.map([&hops](NameLocation loc) { if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate) { return loc;
} return loc.addHops(hops);
}); return found.value();
}
case ScopeKind::StrictEval: case ScopeKind::FunctionBodyVar: case ScopeKind::Lexical: case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: case ScopeKind::SimpleCatch: case ScopeKind::Catch: case ScopeKind::FunctionLexical: case ScopeKind::ClassBody: if (hasEnv) {
si.scope().match([&](auto& scope_ref) { for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
InputName binding(scope_ref, bi.name()); if (!binding.isEqualTo(fc, parserAtoms, input.atomCache, name,
&jsname)) { continue;
}
// The name must already have been marked as closed // over. If this assertion is hit, there is a bug in the // name analysis.
BindingLocation bindLoc = bi.location();
MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
result.emplace(NameLocation::EnvironmentCoordinate(
bi.kind(), hops, bindLoc.slot())); return;
}
});
} break;
case ScopeKind::Module: // This case is used only when delazifying a function inside // module. // Initial compilation of module doesn't have enlcosing scope. if (hasEnv) {
si.scope().match([&](auto& scope_ref) { for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
InputName binding(scope_ref, bi.name()); if (!binding.isEqualTo(fc, parserAtoms, input.atomCache, name,
&jsname)) { continue;
}
BindingLocation bindLoc = bi.location();
// Imports are on the environment but are indirect // bindings and must be accessed dynamically instead of // using an EnvironmentCoordinate. if (bindLoc.kind() == BindingLocation::Kind::Import) {
MOZ_ASSERT(si.kind() == ScopeKind::Module);
result.emplace(NameLocation::Import()); return;
}
case ScopeKind::Eval: // As an optimization, if the eval doesn't have its own var // environment and its immediate enclosing scope is a global // scope, all accesses are global. if (!hasEnv) {
ScopeKind kind = si.scope().enclosing().kind(); if (kind == ScopeKind::Global || kind == ScopeKind::NonSyntactic) { return NameLocation::Global(BindingKind::Var);
}
} return NameLocation::Dynamic();
case ScopeKind::Global: return NameLocation::Global(BindingKind::Var);
case ScopeKind::With: case ScopeKind::NonSyntactic: return NameLocation::Dynamic();
case ScopeKind::WasmInstance: case ScopeKind::WasmFunction:
MOZ_CRASH("No direct eval inside wasm functions");
}
mozilla::Maybe<ScopeContext::EnclosingLexicalBindingKind>
ScopeContext::lookupLexicalBindingInEnclosingScope(TaggedParserAtomIndex name) { auto p = enclosingLexicalBindingCache_->lookup(name); if (!p) { return mozilla::Nothing();
}
mozilla::Maybe<NameLocation> ScopeContext::getPrivateFieldLocation(
TaggedParserAtomIndex name) { // The locations returned by this method are only valid for // traversing debug environments. // // See the comment in cachePrivateFieldsForEval
MOZ_ASSERT(enclosingEnvironmentIsDebugProxy_); auto p = effectiveScopePrivateFieldCache_->lookup(name); if (!p) { return mozilla::Nothing();
} return mozilla::Some(p->value());
}
auto gcthings = lazy->gcthings();
size_t length = gcthings.Length(); if (length == 0) { returntrue;
}
// Reduce the length to the first element which is not a function. for (size_t i = 0; i < length; i++) {
gc::Cell* cell = gcthings[i].asCell(); if (!cell || !cell->is<JSObject>()) {
length = i; break;
}
MOZ_ASSERT(cell->as<JSObject>()->is<JSFunction>());
}
for (size_t i = 0; i < length; i++) {
gc::Cell* cell = gcthings[i].asCell();
JSFunction* fun = &cell->as<JSObject>()->as<JSFunction>();
gcThingsData[i] = TaggedScriptThingIndex(ScriptIndex(i)); new (mozilla::KnownNotNull, &scriptData[i]) ScriptStencil();
ScriptStencil& data = scriptData[i]; new (mozilla::KnownNotNull, &scriptExtra[i]) ScriptStencilExtra();
ScriptStencilExtra& extra = scriptExtra[i];
// Info derived from parent compilation should not be set yet for our inner // lazy functions. Instead that info will be updated when we finish our // compilation.
MOZ_ASSERT(lazy->hasEnclosingScript());
}
// Reduce the length to the first element which is not a function. for (size_t i = offset; i < offset + length; i++) { if (!lazy.context_.gcThingData[i].isFunction()) {
length = i - offset; break;
}
}
for (size_t i = 0; i < length; i++) {
ScriptStencilRef inner{lazy.context_,
lazy.context_.gcThingData[i + offset].toFunction()};
gcThingsData[i] = TaggedScriptThingIndex(ScriptIndex(i)); new (mozilla::KnownNotNull, &scriptData[i]) ScriptStencil();
ScriptStencil& data = scriptData[i];
ScriptStencilExtra& extra = scriptExtra[i];
InputName name{inner, inner.scriptData().functionAtom}; if (!name.isNull()) { auto displayAtom = name.internInto(fc, parseAtoms, atomCache); if (!displayAtom) { returnfalse;
}
data.functionAtom = displayAtom;
}
data.functionFlags = inner.scriptData().functionFlags;
// The gcthings() array contains the inner function list followed by the // closed-over bindings data. Skip the inner function list, as it is already // cached in cachedGCThings_. See also: BaseScript::CreateLazy.
size_t start = cachedGCThings_.Length(); auto gcthings = lazy->gcthings();
size_t length = gcthings.Length();
MOZ_ASSERT(start <= length); if (length - start == 0) { returntrue;
}
// The gcthings array contains the inner function list followed by the // closed-over bindings data. Skip the inner function list, as it is already // cached in cachedGCThings_. See also: BaseScript::CreateLazy.
size_t offset = lazy.scriptData().gcThingsOffset.index;
size_t length = lazy.scriptData().gcThingsLength;
size_t start = cachedGCThings_.Length();
MOZ_ASSERT(start <= length); if (length - start == 0) { returntrue;
}
length -= start;
start += offset;
// Atoms from the lazy.context (CompilationStencil) are not registered in the // the parseAtoms table. Thus we create a new span which will contain all the // interned atoms.
TaggedParserAtomIndex* closedOverBindings =
alloc.newArrayUninitialized<TaggedParserAtomIndex>(length); if (!closedOverBindings) {
ReportOutOfMemory(fc); returnfalse;
}
for (size_t i = 0; i < length; i++) { auto gcThing = lazy.context_.gcThingData[i + start]; if (gcThing.isNull()) {
closedOverBindings[i] = TaggedParserAtomIndex::null(); continue;
}
MOZ_ASSERT(gcThing.isAtom());
InputName name(lazy, gcThing.toAtom()); auto parserAtom = name.internInto(fc, parseAtoms, atomCache); if (!parserAtom) { returnfalse;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.