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:
Ashley Hauck 2018-11-06 22:51:40 +00:00
Родитель a3dbcdcdf6
Коммит 45ee1152af
10 изменённых файлов: 936 добавлений и 864 удалений

Просмотреть файл

@ -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"