зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1505150 - Move implementations of ParseContext and SharedContext to their own files. r=jorendorff
Differential Revision: https://phabricator.services.mozilla.com/D11098 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
a3dbcdcdf6
Коммит
45ee1152af
|
@ -25,6 +25,7 @@
|
|||
#include "vm/RegExpObject.h"
|
||||
|
||||
#include "frontend/ParseContext-inl.h"
|
||||
#include "frontend/SharedContext-inl.h"
|
||||
#include "vm/JSContext-inl.h"
|
||||
|
||||
// # About compliance with EcmaScript
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#define frontend_ParseContext_inl_h
|
||||
|
||||
#include "frontend/ParseContext.h"
|
||||
#include "frontend/Parser.h"
|
||||
#include "vm/JSContext.h"
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
@ -26,6 +28,53 @@ ParseContext::Statement::is<ParseContext::ClassStatement>() const
|
|||
return kind_ == StatementKind::Class;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T&
|
||||
ParseContext::Statement::as()
|
||||
{
|
||||
MOZ_ASSERT(is<T>());
|
||||
return static_cast<T&>(*this);
|
||||
}
|
||||
|
||||
inline ParseContext::Scope::BindingIter
|
||||
ParseContext::Scope::bindings(ParseContext* pc)
|
||||
{
|
||||
// In function scopes with parameter expressions, function special names
|
||||
// (like '.this') are declared as vars in the function scope, despite its
|
||||
// not being the var scope.
|
||||
return BindingIter(*this, pc->varScope_ == this || pc->functionScope_.ptrOr(nullptr) == this);
|
||||
}
|
||||
|
||||
inline
|
||||
ParseContext::Scope::Scope(ParserBase* parser)
|
||||
: Nestable<Scope>(&parser->pc->innermostScope_),
|
||||
declared_(parser->context->frontendCollectionPool()),
|
||||
possibleAnnexBFunctionBoxes_(parser->context->frontendCollectionPool()),
|
||||
id_(parser->usedNames.nextScopeId())
|
||||
{ }
|
||||
|
||||
inline
|
||||
ParseContext::Scope::Scope(JSContext* cx, ParseContext* pc, UsedNameTracker& usedNames)
|
||||
: Nestable<Scope>(&pc->innermostScope_),
|
||||
declared_(cx->frontendCollectionPool()),
|
||||
possibleAnnexBFunctionBoxes_(cx->frontendCollectionPool()),
|
||||
id_(usedNames.nextScopeId())
|
||||
{ }
|
||||
|
||||
inline
|
||||
ParseContext::VarScope::VarScope(ParserBase* parser)
|
||||
: Scope(parser)
|
||||
{
|
||||
useAsVarScope(parser->pc);
|
||||
}
|
||||
|
||||
inline
|
||||
ParseContext::VarScope::VarScope(JSContext* cx, ParseContext* pc, UsedNameTracker& usedNames)
|
||||
: Scope(cx, pc, usedNames)
|
||||
{
|
||||
useAsVarScope(pc);
|
||||
}
|
||||
|
||||
inline JS::Result<Ok, ParseContext::BreakStatementError>
|
||||
ParseContext::checkBreakStatement(PropertyName* label)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,546 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#include "frontend/ParseContext-inl.h"
|
||||
#include "vm/EnvironmentObject-inl.h"
|
||||
|
||||
using mozilla::Maybe;
|
||||
using mozilla::Some;
|
||||
using mozilla::Nothing;
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
|
||||
|
||||
const char*
|
||||
DeclarationKindString(DeclarationKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case DeclarationKind::PositionalFormalParameter:
|
||||
case DeclarationKind::FormalParameter:
|
||||
return "formal parameter";
|
||||
case DeclarationKind::CoverArrowParameter:
|
||||
return "cover arrow parameter";
|
||||
case DeclarationKind::Var:
|
||||
return "var";
|
||||
case DeclarationKind::Let:
|
||||
return "let";
|
||||
case DeclarationKind::Const:
|
||||
return "const";
|
||||
case DeclarationKind::Class:
|
||||
return "class";
|
||||
case DeclarationKind::Import:
|
||||
return "import";
|
||||
case DeclarationKind::BodyLevelFunction:
|
||||
case DeclarationKind::ModuleBodyLevelFunction:
|
||||
case DeclarationKind::LexicalFunction:
|
||||
case DeclarationKind::SloppyLexicalFunction:
|
||||
return "function";
|
||||
case DeclarationKind::VarForAnnexBLexicalFunction:
|
||||
return "annex b var";
|
||||
case DeclarationKind::ForOfVar:
|
||||
return "var in for-of";
|
||||
case DeclarationKind::SimpleCatchParameter:
|
||||
case DeclarationKind::CatchParameter:
|
||||
return "catch parameter";
|
||||
}
|
||||
|
||||
MOZ_CRASH("Bad DeclarationKind");
|
||||
}
|
||||
|
||||
bool
|
||||
DeclarationKindIsVar(DeclarationKind kind)
|
||||
{
|
||||
return kind == DeclarationKind::Var ||
|
||||
kind == DeclarationKind::BodyLevelFunction ||
|
||||
kind == DeclarationKind::VarForAnnexBLexicalFunction ||
|
||||
kind == DeclarationKind::ForOfVar;
|
||||
}
|
||||
|
||||
bool
|
||||
DeclarationKindIsParameter(DeclarationKind kind)
|
||||
{
|
||||
return kind == DeclarationKind::PositionalFormalParameter ||
|
||||
kind == DeclarationKind::FormalParameter;
|
||||
}
|
||||
|
||||
bool
|
||||
UsedNameTracker::noteUse(JSContext* cx, JSAtom* name, uint32_t scriptId, uint32_t scopeId)
|
||||
{
|
||||
if (UsedNameMap::AddPtr p = map_.lookupForAdd(name)) {
|
||||
if (!p || !p->value().noteUsedInScope(scriptId, scopeId)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
UsedNameInfo info(cx);
|
||||
if (!info.noteUsedInScope(scriptId, scopeId)) {
|
||||
return false;
|
||||
}
|
||||
if (!map_.add(p, name, std::move(info))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
UsedNameTracker::UsedNameInfo::resetToScope(uint32_t scriptId, uint32_t scopeId)
|
||||
{
|
||||
while (!uses_.empty()) {
|
||||
Use& innermost = uses_.back();
|
||||
if (innermost.scopeId < scopeId) {
|
||||
break;
|
||||
}
|
||||
MOZ_ASSERT(innermost.scriptId >= scriptId);
|
||||
uses_.popBack();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UsedNameTracker::rewind(RewindToken token)
|
||||
{
|
||||
scriptCounter_ = token.scriptId;
|
||||
scopeCounter_ = token.scopeId;
|
||||
|
||||
for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
|
||||
r.front().value().resetToScope(token.scriptId, token.scopeId);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParseContext::Scope::dump(ParseContext* pc)
|
||||
{
|
||||
JSContext* cx = pc->sc()->context;
|
||||
|
||||
fprintf(stdout, "ParseScope %p", this);
|
||||
|
||||
fprintf(stdout, "\n decls:\n");
|
||||
for (DeclaredNameMap::Range r = declared_->all(); !r.empty(); r.popFront()) {
|
||||
UniqueChars bytes = AtomToPrintableString(cx, r.front().key());
|
||||
if (!bytes) {
|
||||
return;
|
||||
}
|
||||
DeclaredNameInfo& info = r.front().value().wrapped;
|
||||
fprintf(stdout, " %s %s%s\n",
|
||||
DeclarationKindString(info.kind()),
|
||||
bytes.get(),
|
||||
info.closedOver() ? " (closed over)" : "");
|
||||
}
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc, FunctionBox* funbox)
|
||||
{
|
||||
if (!possibleAnnexBFunctionBoxes_) {
|
||||
if (!possibleAnnexBFunctionBoxes_.acquire(pc->sc()->context)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return maybeReportOOM(pc, possibleAnnexBFunctionBoxes_->append(funbox));
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::Scope::propagateAndMarkAnnexBFunctionBoxes(ParseContext* pc)
|
||||
{
|
||||
// Strict mode doesn't have wack Annex B function semantics.
|
||||
if (pc->sc()->strict() ||
|
||||
!possibleAnnexBFunctionBoxes_ ||
|
||||
possibleAnnexBFunctionBoxes_->empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this == &pc->varScope()) {
|
||||
// Base case: actually declare the Annex B vars and mark applicable
|
||||
// function boxes as Annex B.
|
||||
RootedPropertyName name(pc->sc()->context);
|
||||
Maybe<DeclarationKind> redeclaredKind;
|
||||
uint32_t unused;
|
||||
for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
|
||||
if (pc->annexBAppliesToLexicalFunctionInInnermostScope(funbox)) {
|
||||
name = funbox->function()->explicitName()->asPropertyName();
|
||||
if (!pc->tryDeclareVar(name,
|
||||
DeclarationKind::VarForAnnexBLexicalFunction,
|
||||
DeclaredNameInfo::npos, &redeclaredKind, &unused))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!redeclaredKind);
|
||||
funbox->isAnnexB = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Inner scope case: propagate still applicable function boxes to the
|
||||
// enclosing scope.
|
||||
for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
|
||||
if (pc->annexBAppliesToLexicalFunctionInInnermostScope(funbox)) {
|
||||
if (!enclosing()->addPossibleAnnexBFunctionBox(pc, funbox)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DeclarationKindIsCatchParameter(DeclarationKind kind)
|
||||
{
|
||||
return kind == DeclarationKind::SimpleCatchParameter ||
|
||||
kind == DeclarationKind::CatchParameter;
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::Scope::addCatchParameters(ParseContext* pc, Scope& catchParamScope)
|
||||
{
|
||||
if (pc->useAsmOrInsideUseAsm()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) {
|
||||
DeclarationKind kind = r.front().value()->kind();
|
||||
uint32_t pos = r.front().value()->pos();
|
||||
MOZ_ASSERT(DeclarationKindIsCatchParameter(kind));
|
||||
JSAtom* name = r.front().key();
|
||||
AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name);
|
||||
MOZ_ASSERT(!p);
|
||||
if (!addDeclaredName(pc, p, name, kind, pos)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ParseContext::Scope::removeCatchParameters(ParseContext* pc, Scope& catchParamScope)
|
||||
{
|
||||
if (pc->useAsmOrInsideUseAsm()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) {
|
||||
DeclaredNamePtr p = declared_->lookup(r.front().key());
|
||||
MOZ_ASSERT(p);
|
||||
|
||||
// This check is needed because the catch body could have declared
|
||||
// vars, which would have been added to catchParamScope.
|
||||
if (DeclarationKindIsCatchParameter(r.front().value()->kind())) {
|
||||
declared_->remove(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParseContext::ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc,
|
||||
ErrorReporter& errorReporter, class UsedNameTracker& usedNames,
|
||||
Directives* newDirectives, bool isFull)
|
||||
: Nestable<ParseContext>(&parent),
|
||||
traceLog_(sc->context,
|
||||
isFull
|
||||
? TraceLogger_ParsingFull
|
||||
: TraceLogger_ParsingSyntax,
|
||||
errorReporter),
|
||||
sc_(sc),
|
||||
errorReporter_(errorReporter),
|
||||
innermostStatement_(nullptr),
|
||||
innermostScope_(nullptr),
|
||||
varScope_(nullptr),
|
||||
positionalFormalParameterNames_(cx->frontendCollectionPool()),
|
||||
closedOverBindingsForLazy_(cx->frontendCollectionPool()),
|
||||
innerFunctionsForLazy(cx, GCVector<JSFunction*, 8>(cx)),
|
||||
newDirectives(newDirectives),
|
||||
lastYieldOffset(NoYieldOffset),
|
||||
lastAwaitOffset(NoAwaitOffset),
|
||||
scriptId_(usedNames.nextScriptId()),
|
||||
isStandaloneFunctionBody_(false),
|
||||
superScopeNeedsHomeObject_(false)
|
||||
{
|
||||
if (isFunctionBox()) {
|
||||
if (functionBox()->function()->isNamedLambda()) {
|
||||
namedLambdaScope_.emplace(cx, parent, usedNames);
|
||||
}
|
||||
functionScope_.emplace(cx, parent, usedNames);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::init()
|
||||
{
|
||||
if (scriptId_ == UINT32_MAX) {
|
||||
errorReporter_.reportErrorNoOffset(JSMSG_NEED_DIET, js_script_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSContext* cx = sc()->context;
|
||||
|
||||
if (isFunctionBox()) {
|
||||
// Named lambdas always need a binding for their own name. If this
|
||||
// binding is closed over when we finish parsing the function in
|
||||
// finishExtraFunctionScopes, the function box needs to be marked as
|
||||
// needing a dynamic DeclEnv object.
|
||||
RootedFunction fun(cx, functionBox()->function());
|
||||
if (fun->isNamedLambda()) {
|
||||
if (!namedLambdaScope_->init(this)) {
|
||||
return false;
|
||||
}
|
||||
AddDeclaredNamePtr p =
|
||||
namedLambdaScope_->lookupDeclaredNameForAdd(fun->explicitName());
|
||||
MOZ_ASSERT(!p);
|
||||
if (!namedLambdaScope_->addDeclaredName(this, p, fun->explicitName(),
|
||||
DeclarationKind::Const,
|
||||
DeclaredNameInfo::npos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!functionScope_->init(this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!positionalFormalParameterNames_.acquire(cx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!closedOverBindingsForLazy_.acquire(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ParseContext::annexBAppliesToLexicalFunctionInInnermostScope(FunctionBox* funbox)
|
||||
{
|
||||
MOZ_ASSERT(!sc()->strict());
|
||||
|
||||
RootedPropertyName name(sc()->context, funbox->function()->explicitName()->asPropertyName());
|
||||
Maybe<DeclarationKind> redeclaredKind =
|
||||
isVarRedeclaredInInnermostScope(name, DeclarationKind::VarForAnnexBLexicalFunction);
|
||||
|
||||
if (!redeclaredKind && isFunctionBox()) {
|
||||
Scope& funScope = functionScope();
|
||||
if (&funScope != &varScope()) {
|
||||
// Annex B.3.3.1 disallows redeclaring parameter names. In the
|
||||
// presence of parameter expressions, parameter names are on the
|
||||
// function scope, which encloses the var scope. This means the
|
||||
// isVarRedeclaredInInnermostScope call above would not catch this
|
||||
// case, so test it manually.
|
||||
if (AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(name)) {
|
||||
DeclarationKind declaredKind = p->value()->kind();
|
||||
if (DeclarationKindIsParameter(declaredKind)) {
|
||||
redeclaredKind = Some(declaredKind);
|
||||
} else {
|
||||
MOZ_ASSERT(FunctionScope::isSpecialName(sc()->context, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If an early error would have occurred already, this function should not
|
||||
// exhibit Annex B.3.3 semantics.
|
||||
return !redeclaredKind;
|
||||
}
|
||||
|
||||
Maybe<DeclarationKind>
|
||||
ParseContext::isVarRedeclaredInInnermostScope(HandlePropertyName name, DeclarationKind kind)
|
||||
{
|
||||
Maybe<DeclarationKind> redeclaredKind;
|
||||
uint32_t unused;
|
||||
MOZ_ALWAYS_TRUE(tryDeclareVarHelper<DryRunInnermostScopeOnly>(name, kind,
|
||||
DeclaredNameInfo::npos,
|
||||
&redeclaredKind, &unused));
|
||||
return redeclaredKind;
|
||||
}
|
||||
|
||||
Maybe<DeclarationKind>
|
||||
ParseContext::isVarRedeclaredInEval(HandlePropertyName name, DeclarationKind kind)
|
||||
{
|
||||
MOZ_ASSERT(DeclarationKindIsVar(kind));
|
||||
MOZ_ASSERT(sc()->isEvalContext());
|
||||
|
||||
// In the case of eval, we also need to check enclosing VM scopes to see
|
||||
// if the var declaration is allowed in the context.
|
||||
//
|
||||
// This check is necessary in addition to
|
||||
// js::CheckEvalDeclarationConflicts because we only know during parsing
|
||||
// if a var is bound by for-of.
|
||||
js::Scope* enclosingScope = sc()->compilationEnclosingScope();
|
||||
js::Scope* varScope = EvalScope::nearestVarScopeForDirectEval(enclosingScope);
|
||||
MOZ_ASSERT(varScope);
|
||||
for (ScopeIter si(enclosingScope); si; si++) {
|
||||
for (js::BindingIter bi(si.scope()); bi; bi++) {
|
||||
if (bi.name() != name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (bi.kind()) {
|
||||
case BindingKind::Let: {
|
||||
// Annex B.3.5 allows redeclaring simple (non-destructured)
|
||||
// catch parameters with var declarations, except when it
|
||||
// appears in a for-of.
|
||||
bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch &&
|
||||
kind != DeclarationKind::ForOfVar;
|
||||
if (!annexB35Allowance) {
|
||||
return Some(ScopeKindIsCatch(si.kind())
|
||||
? DeclarationKind::CatchParameter
|
||||
: DeclarationKind::Let);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingKind::Const:
|
||||
return Some(DeclarationKind::Const);
|
||||
|
||||
case BindingKind::Import:
|
||||
case BindingKind::FormalParameter:
|
||||
case BindingKind::Var:
|
||||
case BindingKind::NamedLambdaCallee:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (si.scope() == varScope) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::tryDeclareVar(HandlePropertyName name, DeclarationKind kind,
|
||||
uint32_t beginPos, Maybe<DeclarationKind>* redeclaredKind,
|
||||
uint32_t* prevPos)
|
||||
{
|
||||
return tryDeclareVarHelper<NotDryRun>(name, kind, beginPos, redeclaredKind, prevPos);
|
||||
}
|
||||
|
||||
template <ParseContext::DryRunOption dryRunOption>
|
||||
bool
|
||||
ParseContext::tryDeclareVarHelper(HandlePropertyName name, DeclarationKind kind,
|
||||
uint32_t beginPos, Maybe<DeclarationKind>* redeclaredKind,
|
||||
uint32_t* prevPos)
|
||||
{
|
||||
MOZ_ASSERT(DeclarationKindIsVar(kind));
|
||||
|
||||
// It is an early error if a 'var' declaration appears inside a
|
||||
// scope contour that has a lexical declaration of the same name. For
|
||||
// example, the following are early errors:
|
||||
//
|
||||
// { let x; var x; }
|
||||
// { { var x; } let x; }
|
||||
//
|
||||
// And the following are not:
|
||||
//
|
||||
// { var x; var x; }
|
||||
// { { let x; } var x; }
|
||||
|
||||
for (ParseContext::Scope* scope = innermostScope();
|
||||
scope != varScope().enclosing();
|
||||
scope = scope->enclosing())
|
||||
{
|
||||
if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
|
||||
DeclarationKind declaredKind = p->value()->kind();
|
||||
if (DeclarationKindIsVar(declaredKind)) {
|
||||
// Any vars that are redeclared as body-level functions must
|
||||
// be recorded as body-level functions.
|
||||
//
|
||||
// In the case of global and eval scripts, GlobalDeclaration-
|
||||
// Instantiation [1] and EvalDeclarationInstantiation [2]
|
||||
// check for the declarability of global var and function
|
||||
// bindings via CanDeclareVar [3] and CanDeclareGlobal-
|
||||
// Function [4]. CanDeclareGlobalFunction is strictly more
|
||||
// restrictive than CanDeclareGlobalVar, so record the more
|
||||
// restrictive kind. These semantics are implemented in
|
||||
// CheckCanDeclareGlobalBinding.
|
||||
//
|
||||
// For a var previously declared as ForOfVar, this previous
|
||||
// DeclarationKind is used only to check for if the
|
||||
// 'arguments' binding should be declared. Since body-level
|
||||
// functions shadow 'arguments' [5], it is correct to alter
|
||||
// the kind to BodyLevelFunction. See
|
||||
// declareFunctionArgumentsObject.
|
||||
//
|
||||
// VarForAnnexBLexicalFunction declarations are declared when
|
||||
// the var scope exits. It is not possible for a var to be
|
||||
// previously declared as VarForAnnexBLexicalFunction and
|
||||
// checked for redeclaration.
|
||||
//
|
||||
// [1] ES 15.1.11
|
||||
// [2] ES 18.2.1.3
|
||||
// [3] ES 8.1.1.4.15
|
||||
// [4] ES 8.1.1.4.16
|
||||
// [5] ES 9.2.12
|
||||
if (dryRunOption == NotDryRun && kind == DeclarationKind::BodyLevelFunction) {
|
||||
MOZ_ASSERT(declaredKind != DeclarationKind::VarForAnnexBLexicalFunction);
|
||||
p->value()->alterKind(kind);
|
||||
}
|
||||
} else if (!DeclarationKindIsParameter(declaredKind)) {
|
||||
// Annex B.3.5 allows redeclaring simple (non-destructured)
|
||||
// catch parameters with var declarations, except when it
|
||||
// appears in a for-of.
|
||||
bool annexB35Allowance = declaredKind == DeclarationKind::SimpleCatchParameter &&
|
||||
kind != DeclarationKind::ForOfVar;
|
||||
|
||||
// Annex B.3.3 allows redeclaring functions in the same block.
|
||||
bool annexB33Allowance = declaredKind == DeclarationKind::SloppyLexicalFunction &&
|
||||
kind == DeclarationKind::VarForAnnexBLexicalFunction &&
|
||||
scope == innermostScope();
|
||||
|
||||
if (!annexB35Allowance && !annexB33Allowance) {
|
||||
*redeclaredKind = Some(declaredKind);
|
||||
*prevPos = p->value()->pos();
|
||||
return true;
|
||||
}
|
||||
} else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) {
|
||||
MOZ_ASSERT(DeclarationKindIsParameter(declaredKind));
|
||||
|
||||
// Annex B.3.3.1 disallows redeclaring parameter names.
|
||||
// We don't need to set *prevPos here since this case is not
|
||||
// an error.
|
||||
*redeclaredKind = Some(declaredKind);
|
||||
return true;
|
||||
}
|
||||
} else if (dryRunOption == NotDryRun) {
|
||||
if (!scope->addDeclaredName(this, p, name, kind, beginPos)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// DryRunOption is used for propagating Annex B functions: we don't
|
||||
// want to declare the synthesized Annex B vars until we exit the var
|
||||
// scope and know that no early errors would have occurred. In order
|
||||
// to avoid quadratic search, we only check for var redeclarations in
|
||||
// the innermost scope when doing a dry run.
|
||||
if (dryRunOption == DryRunInnermostScopeOnly) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sc()->strict() && sc()->isEvalContext() &&
|
||||
(dryRunOption == NotDryRun || innermostScope() == &varScope()))
|
||||
{
|
||||
*redeclaredKind = isVarRedeclaredInEval(name, kind);
|
||||
// We don't have position information at runtime.
|
||||
*prevPos = DeclaredNameInfo::npos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace frontend
|
||||
|
||||
} // namespace js
|
|
@ -19,6 +19,16 @@ namespace frontend {
|
|||
|
||||
class ParserBase;
|
||||
|
||||
const char*
|
||||
DeclarationKindString(DeclarationKind kind);
|
||||
|
||||
// Returns true if the declaration is `var` or equivalent.
|
||||
bool
|
||||
DeclarationKindIsVar(DeclarationKind kind);
|
||||
|
||||
bool
|
||||
DeclarationKindIsParameter(DeclarationKind kind);
|
||||
|
||||
// A data structure for tracking used names per parsing session in order to
|
||||
// compute which bindings are closed over. Scripts and scopes are numbered
|
||||
// monotonically in textual order and name uses are tracked by lists of
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "wasm/AsmJS.h"
|
||||
|
||||
#include "frontend/ParseContext-inl.h"
|
||||
#include "frontend/SharedContext-inl.h"
|
||||
#include "vm/EnvironmentObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -128,42 +129,6 @@ PropagateTransitiveParseFlags(const T* inner, U* outer)
|
|||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
DeclarationKindString(DeclarationKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case DeclarationKind::PositionalFormalParameter:
|
||||
case DeclarationKind::FormalParameter:
|
||||
return "formal parameter";
|
||||
case DeclarationKind::CoverArrowParameter:
|
||||
return "cover arrow parameter";
|
||||
case DeclarationKind::Var:
|
||||
return "var";
|
||||
case DeclarationKind::Let:
|
||||
return "let";
|
||||
case DeclarationKind::Const:
|
||||
return "const";
|
||||
case DeclarationKind::Class:
|
||||
return "class";
|
||||
case DeclarationKind::Import:
|
||||
return "import";
|
||||
case DeclarationKind::BodyLevelFunction:
|
||||
case DeclarationKind::ModuleBodyLevelFunction:
|
||||
case DeclarationKind::LexicalFunction:
|
||||
case DeclarationKind::SloppyLexicalFunction:
|
||||
return "function";
|
||||
case DeclarationKind::VarForAnnexBLexicalFunction:
|
||||
return "annex b var";
|
||||
case DeclarationKind::ForOfVar:
|
||||
return "var in for-of";
|
||||
case DeclarationKind::SimpleCatchParameter:
|
||||
case DeclarationKind::CatchParameter:
|
||||
return "catch parameter";
|
||||
}
|
||||
|
||||
MOZ_CRASH("Bad DeclarationKind");
|
||||
}
|
||||
|
||||
static bool
|
||||
StatementKindIsBraced(StatementKind kind)
|
||||
{
|
||||
|
@ -175,530 +140,6 @@ StatementKindIsBraced(StatementKind kind)
|
|||
kind == StatementKind::Class;
|
||||
}
|
||||
|
||||
void
|
||||
ParseContext::Scope::dump(ParseContext* pc)
|
||||
{
|
||||
JSContext* cx = pc->sc()->context;
|
||||
|
||||
fprintf(stdout, "ParseScope %p", this);
|
||||
|
||||
fprintf(stdout, "\n decls:\n");
|
||||
for (DeclaredNameMap::Range r = declared_->all(); !r.empty(); r.popFront()) {
|
||||
UniqueChars bytes = AtomToPrintableString(cx, r.front().key());
|
||||
if (!bytes) {
|
||||
return;
|
||||
}
|
||||
DeclaredNameInfo& info = r.front().value().wrapped;
|
||||
fprintf(stdout, " %s %s%s\n",
|
||||
DeclarationKindString(info.kind()),
|
||||
bytes.get(),
|
||||
info.closedOver() ? " (closed over)" : "");
|
||||
}
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc, FunctionBox* funbox)
|
||||
{
|
||||
if (!possibleAnnexBFunctionBoxes_) {
|
||||
if (!possibleAnnexBFunctionBoxes_.acquire(pc->sc()->context)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return maybeReportOOM(pc, possibleAnnexBFunctionBoxes_->append(funbox));
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::Scope::propagateAndMarkAnnexBFunctionBoxes(ParseContext* pc)
|
||||
{
|
||||
// Strict mode doesn't have wack Annex B function semantics.
|
||||
if (pc->sc()->strict() ||
|
||||
!possibleAnnexBFunctionBoxes_ ||
|
||||
possibleAnnexBFunctionBoxes_->empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this == &pc->varScope()) {
|
||||
// Base case: actually declare the Annex B vars and mark applicable
|
||||
// function boxes as Annex B.
|
||||
RootedPropertyName name(pc->sc()->context);
|
||||
Maybe<DeclarationKind> redeclaredKind;
|
||||
uint32_t unused;
|
||||
for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
|
||||
if (pc->annexBAppliesToLexicalFunctionInInnermostScope(funbox)) {
|
||||
name = funbox->function()->explicitName()->asPropertyName();
|
||||
if (!pc->tryDeclareVar(name,
|
||||
DeclarationKind::VarForAnnexBLexicalFunction,
|
||||
DeclaredNameInfo::npos, &redeclaredKind, &unused))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!redeclaredKind);
|
||||
funbox->isAnnexB = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Inner scope case: propagate still applicable function boxes to the
|
||||
// enclosing scope.
|
||||
for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
|
||||
if (pc->annexBAppliesToLexicalFunctionInInnermostScope(funbox)) {
|
||||
if (!enclosing()->addPossibleAnnexBFunctionBox(pc, funbox)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DeclarationKindIsCatchParameter(DeclarationKind kind)
|
||||
{
|
||||
return kind == DeclarationKind::SimpleCatchParameter ||
|
||||
kind == DeclarationKind::CatchParameter;
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::Scope::addCatchParameters(ParseContext* pc, Scope& catchParamScope)
|
||||
{
|
||||
if (pc->useAsmOrInsideUseAsm()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) {
|
||||
DeclarationKind kind = r.front().value()->kind();
|
||||
uint32_t pos = r.front().value()->pos();
|
||||
MOZ_ASSERT(DeclarationKindIsCatchParameter(kind));
|
||||
JSAtom* name = r.front().key();
|
||||
AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name);
|
||||
MOZ_ASSERT(!p);
|
||||
if (!addDeclaredName(pc, p, name, kind, pos)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ParseContext::Scope::removeCatchParameters(ParseContext* pc, Scope& catchParamScope)
|
||||
{
|
||||
if (pc->useAsmOrInsideUseAsm()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) {
|
||||
DeclaredNamePtr p = declared_->lookup(r.front().key());
|
||||
MOZ_ASSERT(p);
|
||||
|
||||
// This check is needed because the catch body could have declared
|
||||
// vars, which would have been added to catchParamScope.
|
||||
if (DeclarationKindIsCatchParameter(r.front().value()->kind())) {
|
||||
declared_->remove(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SharedContext::computeAllowSyntax(Scope* scope)
|
||||
{
|
||||
for (ScopeIter si(scope); si; si++) {
|
||||
if (si.kind() == ScopeKind::Function) {
|
||||
JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
|
||||
if (fun->isArrow()) {
|
||||
continue;
|
||||
}
|
||||
allowNewTarget_ = true;
|
||||
allowSuperProperty_ = fun->allowSuperProperty();
|
||||
allowSuperCall_ = fun->isDerivedClassConstructor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SharedContext::computeThisBinding(Scope* scope)
|
||||
{
|
||||
for (ScopeIter si(scope); si; si++) {
|
||||
if (si.kind() == ScopeKind::Module) {
|
||||
thisBinding_ = ThisBinding::Module;
|
||||
return;
|
||||
}
|
||||
|
||||
if (si.kind() == ScopeKind::Function) {
|
||||
JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
|
||||
|
||||
// Arrow functions don't have their own `this` binding.
|
||||
if (fun->isArrow()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Derived class constructors (including nested arrow functions and
|
||||
// eval) need TDZ checks when accessing |this|.
|
||||
if (fun->isDerivedClassConstructor()) {
|
||||
needsThisTDZChecks_ = true;
|
||||
}
|
||||
|
||||
thisBinding_ = ThisBinding::Function;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
thisBinding_ = ThisBinding::Global;
|
||||
}
|
||||
|
||||
void
|
||||
SharedContext::computeInWith(Scope* scope)
|
||||
{
|
||||
for (ScopeIter si(scope); si; si++) {
|
||||
if (si.kind() == ScopeKind::With) {
|
||||
inWith_ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EvalSharedContext::EvalSharedContext(JSContext* cx, JSObject* enclosingEnv,
|
||||
Scope* enclosingScope, Directives directives,
|
||||
bool extraWarnings)
|
||||
: SharedContext(cx, Kind::Eval, directives, extraWarnings),
|
||||
enclosingScope_(cx, enclosingScope),
|
||||
bindings(cx)
|
||||
{
|
||||
computeAllowSyntax(enclosingScope);
|
||||
computeInWith(enclosingScope);
|
||||
computeThisBinding(enclosingScope);
|
||||
|
||||
// If this eval is in response to Debugger.Frame.eval, we may have been
|
||||
// passed an incomplete scope chain. In order to better determine the 'this'
|
||||
// binding type, we traverse the environment chain, looking for a CallObject
|
||||
// and recompute the binding type based on its body scope.
|
||||
//
|
||||
// NOTE: A non-debug eval in a non-syntactic environment will also trigger
|
||||
// this code. In that case, we should still compute the same binding type.
|
||||
if (enclosingEnv && enclosingScope->hasOnChain(ScopeKind::NonSyntactic)) {
|
||||
JSObject* env = enclosingEnv;
|
||||
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();
|
||||
}
|
||||
|
||||
if (unwrapped->is<CallObject>()) {
|
||||
JSFunction* callee = &unwrapped->as<CallObject>().callee();
|
||||
computeThisBinding(callee->nonLazyScript()->bodyScope());
|
||||
break;
|
||||
}
|
||||
|
||||
env = env->enclosingEnvironment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParseContext::ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc,
|
||||
ErrorReporter& errorReporter, class UsedNameTracker& usedNames,
|
||||
Directives* newDirectives, bool isFull)
|
||||
: Nestable<ParseContext>(&parent),
|
||||
traceLog_(sc->context,
|
||||
isFull
|
||||
? TraceLogger_ParsingFull
|
||||
: TraceLogger_ParsingSyntax,
|
||||
errorReporter),
|
||||
sc_(sc),
|
||||
errorReporter_(errorReporter),
|
||||
innermostStatement_(nullptr),
|
||||
innermostScope_(nullptr),
|
||||
varScope_(nullptr),
|
||||
positionalFormalParameterNames_(cx->frontendCollectionPool()),
|
||||
closedOverBindingsForLazy_(cx->frontendCollectionPool()),
|
||||
innerFunctionsForLazy(cx, GCVector<JSFunction*, 8>(cx)),
|
||||
newDirectives(newDirectives),
|
||||
lastYieldOffset(NoYieldOffset),
|
||||
lastAwaitOffset(NoAwaitOffset),
|
||||
scriptId_(usedNames.nextScriptId()),
|
||||
isStandaloneFunctionBody_(false),
|
||||
superScopeNeedsHomeObject_(false)
|
||||
{
|
||||
if (isFunctionBox()) {
|
||||
if (functionBox()->function()->isNamedLambda()) {
|
||||
namedLambdaScope_.emplace(cx, parent, usedNames);
|
||||
}
|
||||
functionScope_.emplace(cx, parent, usedNames);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::init()
|
||||
{
|
||||
if (scriptId_ == UINT32_MAX) {
|
||||
errorReporter_.reportErrorNoOffset(JSMSG_NEED_DIET, js_script_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSContext* cx = sc()->context;
|
||||
|
||||
if (isFunctionBox()) {
|
||||
// Named lambdas always need a binding for their own name. If this
|
||||
// binding is closed over when we finish parsing the function in
|
||||
// finishExtraFunctionScopes, the function box needs to be marked as
|
||||
// needing a dynamic DeclEnv object.
|
||||
RootedFunction fun(cx, functionBox()->function());
|
||||
if (fun->isNamedLambda()) {
|
||||
if (!namedLambdaScope_->init(this)) {
|
||||
return false;
|
||||
}
|
||||
AddDeclaredNamePtr p =
|
||||
namedLambdaScope_->lookupDeclaredNameForAdd(fun->explicitName());
|
||||
MOZ_ASSERT(!p);
|
||||
if (!namedLambdaScope_->addDeclaredName(this, p, fun->explicitName(),
|
||||
DeclarationKind::Const,
|
||||
DeclaredNameInfo::npos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!functionScope_->init(this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!positionalFormalParameterNames_.acquire(cx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!closedOverBindingsForLazy_.acquire(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
UsedNameTracker::noteUse(JSContext* cx, JSAtom* name, uint32_t scriptId, uint32_t scopeId)
|
||||
{
|
||||
if (UsedNameMap::AddPtr p = map_.lookupForAdd(name)) {
|
||||
if (!p || !p->value().noteUsedInScope(scriptId, scopeId)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
UsedNameInfo info(cx);
|
||||
if (!info.noteUsedInScope(scriptId, scopeId)) {
|
||||
return false;
|
||||
}
|
||||
if (!map_.add(p, name, std::move(info))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
UsedNameTracker::UsedNameInfo::resetToScope(uint32_t scriptId, uint32_t scopeId)
|
||||
{
|
||||
while (!uses_.empty()) {
|
||||
Use& innermost = uses_.back();
|
||||
if (innermost.scopeId < scopeId) {
|
||||
break;
|
||||
}
|
||||
MOZ_ASSERT(innermost.scriptId >= scriptId);
|
||||
uses_.popBack();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UsedNameTracker::rewind(RewindToken token)
|
||||
{
|
||||
scriptCounter_ = token.scriptId;
|
||||
scopeCounter_ = token.scopeId;
|
||||
|
||||
for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
|
||||
r.front().value().resetToScope(token.scriptId, token.scopeId);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
FunctionBox::atomsAreKept()
|
||||
{
|
||||
return context->zone()->hasKeptAtoms();
|
||||
}
|
||||
#endif
|
||||
|
||||
FunctionBox::FunctionBox(JSContext* cx, ObjectBox* traceListHead,
|
||||
JSFunction* fun, uint32_t toStringStart,
|
||||
Directives directives, bool extraWarnings,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
|
||||
: ObjectBox(fun, traceListHead),
|
||||
SharedContext(cx, Kind::FunctionBox, directives, extraWarnings),
|
||||
enclosingScope_(nullptr),
|
||||
namedLambdaBindings_(nullptr),
|
||||
functionScopeBindings_(nullptr),
|
||||
extraVarScopeBindings_(nullptr),
|
||||
functionNode(nullptr),
|
||||
bufStart(0),
|
||||
bufEnd(0),
|
||||
startLine(1),
|
||||
startColumn(0),
|
||||
toStringStart(toStringStart),
|
||||
toStringEnd(0),
|
||||
length(0),
|
||||
isGenerator_(generatorKind == GeneratorKind::Generator),
|
||||
isAsync_(asyncKind == FunctionAsyncKind::AsyncFunction),
|
||||
hasDestructuringArgs(false),
|
||||
hasParameterExprs(false),
|
||||
hasDirectEvalInParameterExpr(false),
|
||||
hasDuplicateParameters(false),
|
||||
useAsm(false),
|
||||
isAnnexB(false),
|
||||
wasEmitted(false),
|
||||
declaredArguments(false),
|
||||
usesArguments(false),
|
||||
usesApply(false),
|
||||
usesThis(false),
|
||||
usesReturn(false),
|
||||
hasRest_(false),
|
||||
hasExprBody_(false),
|
||||
hasExtensibleScope_(false),
|
||||
argumentsHasLocalBinding_(false),
|
||||
definitelyNeedsArgsObj_(false),
|
||||
needsHomeObject_(false),
|
||||
isDerivedClassConstructor_(false),
|
||||
hasThisBinding_(false),
|
||||
hasInnerFunctions_(false)
|
||||
{
|
||||
// Functions created at parse time may be set singleton after parsing and
|
||||
// baked into JIT code, so they must be allocated tenured. They are held by
|
||||
// the JSScript so cannot be collected during a minor GC anyway.
|
||||
MOZ_ASSERT(fun->isTenured());
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::initFromLazyFunction()
|
||||
{
|
||||
JSFunction* fun = function();
|
||||
if (fun->lazyScript()->isDerivedClassConstructor()) {
|
||||
setDerivedClassConstructor();
|
||||
}
|
||||
if (fun->lazyScript()->needsHomeObject()) {
|
||||
setNeedsHomeObject();
|
||||
}
|
||||
if (fun->lazyScript()->hasEnclosingScope()) {
|
||||
enclosingScope_ = fun->lazyScript()->enclosingScope();
|
||||
} else {
|
||||
enclosingScope_ = nullptr;
|
||||
}
|
||||
initWithEnclosingScope(enclosingScope_);
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::initStandaloneFunction(Scope* enclosingScope)
|
||||
{
|
||||
// Standalone functions are Function or Generator constructors and are
|
||||
// always scoped to the global.
|
||||
MOZ_ASSERT(enclosingScope->is<GlobalScope>());
|
||||
enclosingScope_ = enclosingScope;
|
||||
allowNewTarget_ = true;
|
||||
thisBinding_ = ThisBinding::Function;
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind)
|
||||
{
|
||||
SharedContext* sc = enclosing->sc();
|
||||
useAsm = sc->isFunctionBox() && sc->asFunctionBox()->useAsmOrInsideUseAsm();
|
||||
|
||||
JSFunction* fun = function();
|
||||
|
||||
// Arrow functions don't have their own `this` binding.
|
||||
if (fun->isArrow()) {
|
||||
allowNewTarget_ = sc->allowNewTarget();
|
||||
allowSuperProperty_ = sc->allowSuperProperty();
|
||||
allowSuperCall_ = sc->allowSuperCall();
|
||||
needsThisTDZChecks_ = sc->needsThisTDZChecks();
|
||||
thisBinding_ = sc->thisBinding();
|
||||
} else {
|
||||
allowNewTarget_ = true;
|
||||
allowSuperProperty_ = fun->allowSuperProperty();
|
||||
|
||||
if (IsConstructorKind(kind)) {
|
||||
auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
|
||||
MOZ_ASSERT(stmt);
|
||||
stmt->constructorBox = this;
|
||||
|
||||
if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
|
||||
setDerivedClassConstructor();
|
||||
allowSuperCall_ = true;
|
||||
needsThisTDZChecks_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
thisBinding_ = ThisBinding::Function;
|
||||
}
|
||||
|
||||
if (sc->inWith()) {
|
||||
inWith_ = true;
|
||||
} else {
|
||||
auto isWith = [](ParseContext::Statement* stmt) {
|
||||
return stmt->kind() == StatementKind::With;
|
||||
};
|
||||
|
||||
inWith_ = enclosing->findInnermostStatement(isWith);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
|
||||
{
|
||||
if (!function()->isArrow()) {
|
||||
allowNewTarget_ = true;
|
||||
allowSuperProperty_ = function()->allowSuperProperty();
|
||||
|
||||
if (isDerivedClassConstructor()) {
|
||||
setDerivedClassConstructor();
|
||||
allowSuperCall_ = true;
|
||||
needsThisTDZChecks_ = true;
|
||||
}
|
||||
|
||||
thisBinding_ = ThisBinding::Function;
|
||||
} else {
|
||||
computeAllowSyntax(enclosingScope);
|
||||
computeThisBinding(enclosingScope);
|
||||
}
|
||||
|
||||
computeInWith(enclosingScope);
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::setEnclosingScopeForInnerLazyFunction(Scope* enclosingScope)
|
||||
{
|
||||
MOZ_ASSERT(isLazyFunctionWithoutEnclosingScope());
|
||||
|
||||
// For lazy functions inside a function which is being compiled, we cache
|
||||
// the incomplete scope object while compiling, and store it to the
|
||||
// LazyScript once the enclosing script successfully finishes compilation
|
||||
// in FunctionBox::finish.
|
||||
enclosingScope_ = enclosingScope;
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::finish()
|
||||
{
|
||||
if (!isLazyFunctionWithoutEnclosingScope()) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(enclosingScope_);
|
||||
function()->lazyScript()->setEnclosingScope(enclosingScope_);
|
||||
}
|
||||
|
||||
template <class ParseHandler, typename Unit>
|
||||
inline typename GeneralParser<ParseHandler, Unit>::FinalParser*
|
||||
GeneralParser<ParseHandler, Unit>::asFinalParser()
|
||||
|
@ -1094,17 +535,6 @@ PerHandlerParser<ParseHandler>::newFunctionBox(CodeNodeType funNode, JSFunction*
|
|||
return funbox;
|
||||
}
|
||||
|
||||
ModuleSharedContext::ModuleSharedContext(JSContext* cx, ModuleObject* module,
|
||||
Scope* enclosingScope, ModuleBuilder& builder)
|
||||
: SharedContext(cx, Kind::Module, Directives(true), false),
|
||||
module_(cx, module),
|
||||
enclosingScope_(cx, enclosingScope),
|
||||
bindings(cx),
|
||||
builder(builder)
|
||||
{
|
||||
thisBinding_ = ThisBinding::Module;
|
||||
}
|
||||
|
||||
void
|
||||
ParserBase::trace(JSTracer* trc)
|
||||
{
|
||||
|
@ -1397,242 +827,6 @@ PerHandlerParser<ParseHandler>::noteDestructuredPositionalFormalParameter(CodeNo
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DeclarationKindIsVar(DeclarationKind kind)
|
||||
{
|
||||
return kind == DeclarationKind::Var ||
|
||||
kind == DeclarationKind::BodyLevelFunction ||
|
||||
kind == DeclarationKind::VarForAnnexBLexicalFunction ||
|
||||
kind == DeclarationKind::ForOfVar;
|
||||
}
|
||||
|
||||
Maybe<DeclarationKind>
|
||||
ParseContext::isVarRedeclaredInEval(HandlePropertyName name, DeclarationKind kind)
|
||||
{
|
||||
MOZ_ASSERT(DeclarationKindIsVar(kind));
|
||||
MOZ_ASSERT(sc()->isEvalContext());
|
||||
|
||||
// In the case of eval, we also need to check enclosing VM scopes to see
|
||||
// if the var declaration is allowed in the context.
|
||||
//
|
||||
// This check is necessary in addition to
|
||||
// js::CheckEvalDeclarationConflicts because we only know during parsing
|
||||
// if a var is bound by for-of.
|
||||
js::Scope* enclosingScope = sc()->compilationEnclosingScope();
|
||||
js::Scope* varScope = EvalScope::nearestVarScopeForDirectEval(enclosingScope);
|
||||
MOZ_ASSERT(varScope);
|
||||
for (ScopeIter si(enclosingScope); si; si++) {
|
||||
for (js::BindingIter bi(si.scope()); bi; bi++) {
|
||||
if (bi.name() != name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (bi.kind()) {
|
||||
case BindingKind::Let: {
|
||||
// Annex B.3.5 allows redeclaring simple (non-destructured)
|
||||
// catch parameters with var declarations, except when it
|
||||
// appears in a for-of.
|
||||
bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch &&
|
||||
kind != DeclarationKind::ForOfVar;
|
||||
if (!annexB35Allowance) {
|
||||
return Some(ScopeKindIsCatch(si.kind())
|
||||
? DeclarationKind::CatchParameter
|
||||
: DeclarationKind::Let);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingKind::Const:
|
||||
return Some(DeclarationKind::Const);
|
||||
|
||||
case BindingKind::Import:
|
||||
case BindingKind::FormalParameter:
|
||||
case BindingKind::Var:
|
||||
case BindingKind::NamedLambdaCallee:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (si.scope() == varScope) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
Maybe<DeclarationKind>
|
||||
ParseContext::isVarRedeclaredInInnermostScope(HandlePropertyName name, DeclarationKind kind)
|
||||
{
|
||||
Maybe<DeclarationKind> redeclaredKind;
|
||||
uint32_t unused;
|
||||
MOZ_ALWAYS_TRUE(tryDeclareVarHelper<DryRunInnermostScopeOnly>(name, kind,
|
||||
DeclaredNameInfo::npos,
|
||||
&redeclaredKind, &unused));
|
||||
return redeclaredKind;
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::tryDeclareVar(HandlePropertyName name, DeclarationKind kind,
|
||||
uint32_t beginPos, Maybe<DeclarationKind>* redeclaredKind,
|
||||
uint32_t* prevPos)
|
||||
{
|
||||
return tryDeclareVarHelper<NotDryRun>(name, kind, beginPos, redeclaredKind, prevPos);
|
||||
}
|
||||
|
||||
static bool
|
||||
DeclarationKindIsParameter(DeclarationKind kind)
|
||||
{
|
||||
return kind == DeclarationKind::PositionalFormalParameter ||
|
||||
kind == DeclarationKind::FormalParameter;
|
||||
}
|
||||
|
||||
template <ParseContext::DryRunOption dryRunOption>
|
||||
bool
|
||||
ParseContext::tryDeclareVarHelper(HandlePropertyName name, DeclarationKind kind,
|
||||
uint32_t beginPos, Maybe<DeclarationKind>* redeclaredKind,
|
||||
uint32_t* prevPos)
|
||||
{
|
||||
MOZ_ASSERT(DeclarationKindIsVar(kind));
|
||||
|
||||
// It is an early error if a 'var' declaration appears inside a
|
||||
// scope contour that has a lexical declaration of the same name. For
|
||||
// example, the following are early errors:
|
||||
//
|
||||
// { let x; var x; }
|
||||
// { { var x; } let x; }
|
||||
//
|
||||
// And the following are not:
|
||||
//
|
||||
// { var x; var x; }
|
||||
// { { let x; } var x; }
|
||||
|
||||
for (ParseContext::Scope* scope = innermostScope();
|
||||
scope != varScope().enclosing();
|
||||
scope = scope->enclosing())
|
||||
{
|
||||
if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
|
||||
DeclarationKind declaredKind = p->value()->kind();
|
||||
if (DeclarationKindIsVar(declaredKind)) {
|
||||
// Any vars that are redeclared as body-level functions must
|
||||
// be recorded as body-level functions.
|
||||
//
|
||||
// In the case of global and eval scripts, GlobalDeclaration-
|
||||
// Instantiation [1] and EvalDeclarationInstantiation [2]
|
||||
// check for the declarability of global var and function
|
||||
// bindings via CanDeclareVar [3] and CanDeclareGlobal-
|
||||
// Function [4]. CanDeclareGlobalFunction is strictly more
|
||||
// restrictive than CanDeclareGlobalVar, so record the more
|
||||
// restrictive kind. These semantics are implemented in
|
||||
// CheckCanDeclareGlobalBinding.
|
||||
//
|
||||
// For a var previously declared as ForOfVar, this previous
|
||||
// DeclarationKind is used only to check for if the
|
||||
// 'arguments' binding should be declared. Since body-level
|
||||
// functions shadow 'arguments' [5], it is correct to alter
|
||||
// the kind to BodyLevelFunction. See
|
||||
// declareFunctionArgumentsObject.
|
||||
//
|
||||
// VarForAnnexBLexicalFunction declarations are declared when
|
||||
// the var scope exits. It is not possible for a var to be
|
||||
// previously declared as VarForAnnexBLexicalFunction and
|
||||
// checked for redeclaration.
|
||||
//
|
||||
// [1] ES 15.1.11
|
||||
// [2] ES 18.2.1.3
|
||||
// [3] ES 8.1.1.4.15
|
||||
// [4] ES 8.1.1.4.16
|
||||
// [5] ES 9.2.12
|
||||
if (dryRunOption == NotDryRun && kind == DeclarationKind::BodyLevelFunction) {
|
||||
MOZ_ASSERT(declaredKind != DeclarationKind::VarForAnnexBLexicalFunction);
|
||||
p->value()->alterKind(kind);
|
||||
}
|
||||
} else if (!DeclarationKindIsParameter(declaredKind)) {
|
||||
// Annex B.3.5 allows redeclaring simple (non-destructured)
|
||||
// catch parameters with var declarations, except when it
|
||||
// appears in a for-of.
|
||||
bool annexB35Allowance = declaredKind == DeclarationKind::SimpleCatchParameter &&
|
||||
kind != DeclarationKind::ForOfVar;
|
||||
|
||||
// Annex B.3.3 allows redeclaring functions in the same block.
|
||||
bool annexB33Allowance = declaredKind == DeclarationKind::SloppyLexicalFunction &&
|
||||
kind == DeclarationKind::VarForAnnexBLexicalFunction &&
|
||||
scope == innermostScope();
|
||||
|
||||
if (!annexB35Allowance && !annexB33Allowance) {
|
||||
*redeclaredKind = Some(declaredKind);
|
||||
*prevPos = p->value()->pos();
|
||||
return true;
|
||||
}
|
||||
} else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) {
|
||||
MOZ_ASSERT(DeclarationKindIsParameter(declaredKind));
|
||||
|
||||
// Annex B.3.3.1 disallows redeclaring parameter names.
|
||||
// We don't need to set *prevPos here since this case is not
|
||||
// an error.
|
||||
*redeclaredKind = Some(declaredKind);
|
||||
return true;
|
||||
}
|
||||
} else if (dryRunOption == NotDryRun) {
|
||||
if (!scope->addDeclaredName(this, p, name, kind, beginPos)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// DryRunOption is used for propagating Annex B functions: we don't
|
||||
// want to declare the synthesized Annex B vars until we exit the var
|
||||
// scope and know that no early errors would have occurred. In order
|
||||
// to avoid quadratic search, we only check for var redeclarations in
|
||||
// the innermost scope when doing a dry run.
|
||||
if (dryRunOption == DryRunInnermostScopeOnly) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sc()->strict() && sc()->isEvalContext() &&
|
||||
(dryRunOption == NotDryRun || innermostScope() == &varScope()))
|
||||
{
|
||||
*redeclaredKind = isVarRedeclaredInEval(name, kind);
|
||||
// We don't have position information at runtime.
|
||||
*prevPos = DeclaredNameInfo::npos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ParseContext::annexBAppliesToLexicalFunctionInInnermostScope(FunctionBox* funbox)
|
||||
{
|
||||
MOZ_ASSERT(!sc()->strict());
|
||||
|
||||
RootedPropertyName name(sc()->context, funbox->function()->explicitName()->asPropertyName());
|
||||
Maybe<DeclarationKind> redeclaredKind =
|
||||
isVarRedeclaredInInnermostScope(name, DeclarationKind::VarForAnnexBLexicalFunction);
|
||||
|
||||
if (!redeclaredKind && isFunctionBox()) {
|
||||
Scope& funScope = functionScope();
|
||||
if (&funScope != &varScope()) {
|
||||
// Annex B.3.3.1 disallows redeclaring parameter names. In the
|
||||
// presence of parameter expressions, parameter names are on the
|
||||
// function scope, which encloses the var scope. This means the
|
||||
// isVarRedeclaredInInnermostScope call above would not catch this
|
||||
// case, so test it manually.
|
||||
if (AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(name)) {
|
||||
DeclarationKind declaredKind = p->value()->kind();
|
||||
if (DeclarationKindIsParameter(declaredKind)) {
|
||||
redeclaredKind = Some(declaredKind);
|
||||
} else {
|
||||
MOZ_ASSERT(FunctionScope::isSpecialName(sc()->context, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If an early error would have occurred already, this function should not
|
||||
// exhibit Annex B.3.3 semantics.
|
||||
return !redeclaredKind;
|
||||
}
|
||||
|
||||
template <class ParseHandler, typename Unit>
|
||||
bool
|
||||
GeneralParser<ParseHandler, Unit>::checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt,
|
||||
|
|
|
@ -204,29 +204,6 @@ public:
|
|||
{ }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline T&
|
||||
ParseContext::Statement::as()
|
||||
{
|
||||
MOZ_ASSERT(is<T>());
|
||||
return static_cast<T&>(*this);
|
||||
}
|
||||
|
||||
inline ParseContext::Scope::BindingIter
|
||||
ParseContext::Scope::bindings(ParseContext* pc)
|
||||
{
|
||||
// In function scopes with parameter expressions, function special names
|
||||
// (like '.this') are declared as vars in the function scope, despite its
|
||||
// not being the var scope.
|
||||
return BindingIter(*this, pc->varScope_ == this || pc->functionScope_.ptrOr(nullptr) == this);
|
||||
}
|
||||
|
||||
inline
|
||||
Directives::Directives(ParseContext* parent)
|
||||
: strict_(parent->sc()->strict()),
|
||||
asmJS_(parent->useAsmOrInsideUseAsm())
|
||||
{}
|
||||
|
||||
enum VarContext { HoistVars, DontHoistVars };
|
||||
enum PropListType { ObjectLiteral, ClassBody, DerivedClassBody };
|
||||
enum class PropertyType {
|
||||
|
@ -418,36 +395,6 @@ class MOZ_STACK_CLASS ParserBase
|
|||
MOZ_MUST_USE bool setSourceMapInfo();
|
||||
};
|
||||
|
||||
inline
|
||||
ParseContext::Scope::Scope(ParserBase* parser)
|
||||
: Nestable<Scope>(&parser->pc->innermostScope_),
|
||||
declared_(parser->context->frontendCollectionPool()),
|
||||
possibleAnnexBFunctionBoxes_(parser->context->frontendCollectionPool()),
|
||||
id_(parser->usedNames.nextScopeId())
|
||||
{ }
|
||||
|
||||
inline
|
||||
ParseContext::Scope::Scope(JSContext* cx, ParseContext* pc, UsedNameTracker& usedNames)
|
||||
: Nestable<Scope>(&pc->innermostScope_),
|
||||
declared_(cx->frontendCollectionPool()),
|
||||
possibleAnnexBFunctionBoxes_(cx->frontendCollectionPool()),
|
||||
id_(usedNames.nextScopeId())
|
||||
{ }
|
||||
|
||||
inline
|
||||
ParseContext::VarScope::VarScope(ParserBase* parser)
|
||||
: Scope(parser)
|
||||
{
|
||||
useAsVarScope(parser->pc);
|
||||
}
|
||||
|
||||
inline
|
||||
ParseContext::VarScope::VarScope(JSContext* cx, ParseContext* pc, UsedNameTracker& usedNames)
|
||||
: Scope(cx, pc, usedNames)
|
||||
{
|
||||
useAsVarScope(pc);
|
||||
}
|
||||
|
||||
enum FunctionCallBehavior {
|
||||
PermitAssignmentToFunctionCalls,
|
||||
ForbidAssignmentToFunctionCalls
|
||||
|
@ -1703,10 +1650,6 @@ JSFunction*
|
|||
AllocNewFunction(JSContext* cx, HandleAtom atom, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
HandleObject proto, bool isSelfHosting = false, bool inFunctionBox = false);
|
||||
|
||||
// Returns true if the declaration is `var` or equivalent.
|
||||
bool
|
||||
DeclarationKindIsVar(DeclarationKind kind);
|
||||
|
||||
} /* namespace frontend */
|
||||
} /* namespace js */
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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_SharedContext_inl_h
|
||||
#define frontend_SharedContext_inl_h
|
||||
|
||||
#include "frontend/SharedContext.h"
|
||||
#include "frontend/ParseContext.h"
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
inline
|
||||
Directives::Directives(ParseContext* parent)
|
||||
: strict_(parent->sc()->strict()),
|
||||
asmJS_(parent->useAsmOrInsideUseAsm())
|
||||
{}
|
||||
|
||||
} // namespace frontend
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // frontend_SharedContext_inl_h
|
|
@ -0,0 +1,300 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#include "frontend/SharedContext.h"
|
||||
#include "frontend/ParseContext-inl.h"
|
||||
#include "vm/EnvironmentObject-inl.h"
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
void
|
||||
SharedContext::computeAllowSyntax(Scope* scope)
|
||||
{
|
||||
for (ScopeIter si(scope); si; si++) {
|
||||
if (si.kind() == ScopeKind::Function) {
|
||||
JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
|
||||
if (fun->isArrow()) {
|
||||
continue;
|
||||
}
|
||||
allowNewTarget_ = true;
|
||||
allowSuperProperty_ = fun->allowSuperProperty();
|
||||
allowSuperCall_ = fun->isDerivedClassConstructor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SharedContext::computeThisBinding(Scope* scope)
|
||||
{
|
||||
for (ScopeIter si(scope); si; si++) {
|
||||
if (si.kind() == ScopeKind::Module) {
|
||||
thisBinding_ = ThisBinding::Module;
|
||||
return;
|
||||
}
|
||||
|
||||
if (si.kind() == ScopeKind::Function) {
|
||||
JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
|
||||
|
||||
// Arrow functions don't have their own `this` binding.
|
||||
if (fun->isArrow()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Derived class constructors (including nested arrow functions and
|
||||
// eval) need TDZ checks when accessing |this|.
|
||||
if (fun->isDerivedClassConstructor()) {
|
||||
needsThisTDZChecks_ = true;
|
||||
}
|
||||
|
||||
thisBinding_ = ThisBinding::Function;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
thisBinding_ = ThisBinding::Global;
|
||||
}
|
||||
|
||||
void
|
||||
SharedContext::computeInWith(Scope* scope)
|
||||
{
|
||||
for (ScopeIter si(scope); si; si++) {
|
||||
if (si.kind() == ScopeKind::With) {
|
||||
inWith_ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EvalSharedContext::EvalSharedContext(JSContext* cx, JSObject* enclosingEnv,
|
||||
Scope* enclosingScope, Directives directives,
|
||||
bool extraWarnings)
|
||||
: SharedContext(cx, Kind::Eval, directives, extraWarnings),
|
||||
enclosingScope_(cx, enclosingScope),
|
||||
bindings(cx)
|
||||
{
|
||||
computeAllowSyntax(enclosingScope);
|
||||
computeInWith(enclosingScope);
|
||||
computeThisBinding(enclosingScope);
|
||||
|
||||
// If this eval is in response to Debugger.Frame.eval, we may have been
|
||||
// passed an incomplete scope chain. In order to better determine the 'this'
|
||||
// binding type, we traverse the environment chain, looking for a CallObject
|
||||
// and recompute the binding type based on its body scope.
|
||||
//
|
||||
// NOTE: A non-debug eval in a non-syntactic environment will also trigger
|
||||
// this code. In that case, we should still compute the same binding type.
|
||||
if (enclosingEnv && enclosingScope->hasOnChain(ScopeKind::NonSyntactic)) {
|
||||
JSObject* env = enclosingEnv;
|
||||
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();
|
||||
}
|
||||
|
||||
if (unwrapped->is<CallObject>()) {
|
||||
JSFunction* callee = &unwrapped->as<CallObject>().callee();
|
||||
computeThisBinding(callee->nonLazyScript()->bodyScope());
|
||||
break;
|
||||
}
|
||||
|
||||
env = env->enclosingEnvironment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
FunctionBox::atomsAreKept()
|
||||
{
|
||||
return context->zone()->hasKeptAtoms();
|
||||
}
|
||||
#endif
|
||||
|
||||
FunctionBox::FunctionBox(JSContext* cx, ObjectBox* traceListHead,
|
||||
JSFunction* fun, uint32_t toStringStart,
|
||||
Directives directives, bool extraWarnings,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
|
||||
: ObjectBox(fun, traceListHead),
|
||||
SharedContext(cx, Kind::FunctionBox, directives, extraWarnings),
|
||||
enclosingScope_(nullptr),
|
||||
namedLambdaBindings_(nullptr),
|
||||
functionScopeBindings_(nullptr),
|
||||
extraVarScopeBindings_(nullptr),
|
||||
functionNode(nullptr),
|
||||
bufStart(0),
|
||||
bufEnd(0),
|
||||
startLine(1),
|
||||
startColumn(0),
|
||||
toStringStart(toStringStart),
|
||||
toStringEnd(0),
|
||||
length(0),
|
||||
isGenerator_(generatorKind == GeneratorKind::Generator),
|
||||
isAsync_(asyncKind == FunctionAsyncKind::AsyncFunction),
|
||||
hasDestructuringArgs(false),
|
||||
hasParameterExprs(false),
|
||||
hasDirectEvalInParameterExpr(false),
|
||||
hasDuplicateParameters(false),
|
||||
useAsm(false),
|
||||
isAnnexB(false),
|
||||
wasEmitted(false),
|
||||
declaredArguments(false),
|
||||
usesArguments(false),
|
||||
usesApply(false),
|
||||
usesThis(false),
|
||||
usesReturn(false),
|
||||
hasRest_(false),
|
||||
hasExprBody_(false),
|
||||
hasExtensibleScope_(false),
|
||||
argumentsHasLocalBinding_(false),
|
||||
definitelyNeedsArgsObj_(false),
|
||||
needsHomeObject_(false),
|
||||
isDerivedClassConstructor_(false),
|
||||
hasThisBinding_(false),
|
||||
hasInnerFunctions_(false)
|
||||
{
|
||||
// Functions created at parse time may be set singleton after parsing and
|
||||
// baked into JIT code, so they must be allocated tenured. They are held by
|
||||
// the JSScript so cannot be collected during a minor GC anyway.
|
||||
MOZ_ASSERT(fun->isTenured());
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::initFromLazyFunction()
|
||||
{
|
||||
JSFunction* fun = function();
|
||||
if (fun->lazyScript()->isDerivedClassConstructor()) {
|
||||
setDerivedClassConstructor();
|
||||
}
|
||||
if (fun->lazyScript()->needsHomeObject()) {
|
||||
setNeedsHomeObject();
|
||||
}
|
||||
if (fun->lazyScript()->hasEnclosingScope()) {
|
||||
enclosingScope_ = fun->lazyScript()->enclosingScope();
|
||||
} else {
|
||||
enclosingScope_ = nullptr;
|
||||
}
|
||||
initWithEnclosingScope(enclosingScope_);
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::initStandaloneFunction(Scope* enclosingScope)
|
||||
{
|
||||
// Standalone functions are Function or Generator constructors and are
|
||||
// always scoped to the global.
|
||||
MOZ_ASSERT(enclosingScope->is<GlobalScope>());
|
||||
enclosingScope_ = enclosingScope;
|
||||
allowNewTarget_ = true;
|
||||
thisBinding_ = ThisBinding::Function;
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind)
|
||||
{
|
||||
SharedContext* sc = enclosing->sc();
|
||||
useAsm = sc->isFunctionBox() && sc->asFunctionBox()->useAsmOrInsideUseAsm();
|
||||
|
||||
JSFunction* fun = function();
|
||||
|
||||
// Arrow functions don't have their own `this` binding.
|
||||
if (fun->isArrow()) {
|
||||
allowNewTarget_ = sc->allowNewTarget();
|
||||
allowSuperProperty_ = sc->allowSuperProperty();
|
||||
allowSuperCall_ = sc->allowSuperCall();
|
||||
needsThisTDZChecks_ = sc->needsThisTDZChecks();
|
||||
thisBinding_ = sc->thisBinding();
|
||||
} else {
|
||||
allowNewTarget_ = true;
|
||||
allowSuperProperty_ = fun->allowSuperProperty();
|
||||
|
||||
if (IsConstructorKind(kind)) {
|
||||
auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
|
||||
MOZ_ASSERT(stmt);
|
||||
stmt->constructorBox = this;
|
||||
|
||||
if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
|
||||
setDerivedClassConstructor();
|
||||
allowSuperCall_ = true;
|
||||
needsThisTDZChecks_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
thisBinding_ = ThisBinding::Function;
|
||||
}
|
||||
|
||||
if (sc->inWith()) {
|
||||
inWith_ = true;
|
||||
} else {
|
||||
auto isWith = [](ParseContext::Statement* stmt) {
|
||||
return stmt->kind() == StatementKind::With;
|
||||
};
|
||||
|
||||
inWith_ = enclosing->findInnermostStatement(isWith);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
|
||||
{
|
||||
if (!function()->isArrow()) {
|
||||
allowNewTarget_ = true;
|
||||
allowSuperProperty_ = function()->allowSuperProperty();
|
||||
|
||||
if (isDerivedClassConstructor()) {
|
||||
setDerivedClassConstructor();
|
||||
allowSuperCall_ = true;
|
||||
needsThisTDZChecks_ = true;
|
||||
}
|
||||
|
||||
thisBinding_ = ThisBinding::Function;
|
||||
} else {
|
||||
computeAllowSyntax(enclosingScope);
|
||||
computeThisBinding(enclosingScope);
|
||||
}
|
||||
|
||||
computeInWith(enclosingScope);
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::setEnclosingScopeForInnerLazyFunction(Scope* enclosingScope)
|
||||
{
|
||||
MOZ_ASSERT(isLazyFunctionWithoutEnclosingScope());
|
||||
|
||||
// For lazy functions inside a function which is being compiled, we cache
|
||||
// the incomplete scope object while compiling, and store it to the
|
||||
// LazyScript once the enclosing script successfully finishes compilation
|
||||
// in FunctionBox::finish.
|
||||
enclosingScope_ = enclosingScope;
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::finish()
|
||||
{
|
||||
if (!isLazyFunctionWithoutEnclosingScope()) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(enclosingScope_);
|
||||
function()->lazyScript()->setEnclosingScope(enclosingScope_);
|
||||
}
|
||||
|
||||
ModuleSharedContext::ModuleSharedContext(JSContext* cx, ModuleObject* module,
|
||||
Scope* enclosingScope, ModuleBuilder& builder)
|
||||
: SharedContext(cx, Kind::Module, Directives(true), false),
|
||||
module_(cx, module),
|
||||
enclosingScope_(cx, enclosingScope),
|
||||
bindings(cx),
|
||||
builder(builder)
|
||||
{
|
||||
thisBinding_ = ThisBinding::Module;
|
||||
}
|
||||
|
||||
} // namespace frontend
|
||||
|
||||
} // namespace js
|
|
@ -43,8 +43,10 @@ UNIFIED_SOURCES += [
|
|||
'JumpList.cpp',
|
||||
'NameFunctions.cpp',
|
||||
'NameOpEmitter.cpp',
|
||||
'ParseContext.cpp',
|
||||
'ParseNode.cpp',
|
||||
'PropOpEmitter.cpp',
|
||||
'SharedContext.cpp',
|
||||
'SwitchEmitter.cpp',
|
||||
'TDZCheckCache.cpp',
|
||||
'TokenStream.cpp',
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "wasm/WasmSerialize.h"
|
||||
#include "wasm/WasmValidate.h"
|
||||
|
||||
#include "frontend/SharedContext-inl.h"
|
||||
#include "vm/ArrayBufferObject-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче