1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "frontend/ParseContext-inl.h"
8
9 #include "frontend/CompilationStencil.h" // ScopeContext
10 #include "frontend/Parser.h" // ParserBase
11 #include "js/friend/ErrorMessages.h" // JSMSG_*
12 #include "vm/WellKnownAtom.h" // js_*_str
13
14 #include "vm/EnvironmentObject-inl.h"
15
16 using mozilla::Maybe;
17 using mozilla::Nothing;
18 using mozilla::Some;
19
20 namespace js {
21 namespace frontend {
22
23 using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
24 using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
25
DeclarationKindString(DeclarationKind kind)26 const char* DeclarationKindString(DeclarationKind kind) {
27 switch (kind) {
28 case DeclarationKind::PositionalFormalParameter:
29 case DeclarationKind::FormalParameter:
30 return "formal parameter";
31 case DeclarationKind::CoverArrowParameter:
32 return "cover arrow parameter";
33 case DeclarationKind::Var:
34 return "var";
35 case DeclarationKind::Let:
36 return "let";
37 case DeclarationKind::Const:
38 return "const";
39 case DeclarationKind::Class:
40 return "class";
41 case DeclarationKind::Import:
42 return "import";
43 case DeclarationKind::BodyLevelFunction:
44 case DeclarationKind::ModuleBodyLevelFunction:
45 case DeclarationKind::LexicalFunction:
46 case DeclarationKind::SloppyLexicalFunction:
47 return "function";
48 case DeclarationKind::VarForAnnexBLexicalFunction:
49 return "annex b var";
50 case DeclarationKind::SimpleCatchParameter:
51 case DeclarationKind::CatchParameter:
52 return "catch parameter";
53 case DeclarationKind::PrivateName:
54 return "private name";
55 case DeclarationKind::Synthetic:
56 return "synthetic";
57 case DeclarationKind::PrivateMethod:
58 return "private method";
59 }
60
61 MOZ_CRASH("Bad DeclarationKind");
62 }
63
DeclarationKindIsVar(DeclarationKind kind)64 bool DeclarationKindIsVar(DeclarationKind kind) {
65 return kind == DeclarationKind::Var ||
66 kind == DeclarationKind::BodyLevelFunction ||
67 kind == DeclarationKind::VarForAnnexBLexicalFunction;
68 }
69
DeclarationKindIsParameter(DeclarationKind kind)70 bool DeclarationKindIsParameter(DeclarationKind kind) {
71 return kind == DeclarationKind::PositionalFormalParameter ||
72 kind == DeclarationKind::FormalParameter;
73 }
74
noteUse(JSContext * cx,TaggedParserAtomIndex name,NameVisibility visibility,uint32_t scriptId,uint32_t scopeId,mozilla::Maybe<TokenPos> tokenPosition)75 bool UsedNameTracker::noteUse(JSContext* cx, TaggedParserAtomIndex name,
76 NameVisibility visibility, uint32_t scriptId,
77 uint32_t scopeId,
78 mozilla::Maybe<TokenPos> tokenPosition) {
79 if (UsedNameMap::AddPtr p = map_.lookupForAdd(name)) {
80 if (!p->value().noteUsedInScope(scriptId, scopeId)) {
81 return false;
82 }
83 } else {
84 // We need a token position precisely where we have private visibility.
85 MOZ_ASSERT(tokenPosition.isSome() ==
86 (visibility == NameVisibility::Private));
87
88 if (visibility == NameVisibility::Private) {
89 // We have seen at least one private name
90 hasPrivateNames_ = true;
91 }
92
93 UsedNameInfo info(cx, visibility, tokenPosition);
94
95 if (!info.noteUsedInScope(scriptId, scopeId)) {
96 return false;
97 }
98 if (!map_.add(p, name, std::move(info))) {
99 return false;
100 }
101 }
102
103 return true;
104 }
105
getUnboundPrivateNames(Vector<UnboundPrivateName,8> & unboundPrivateNames)106 bool UsedNameTracker::getUnboundPrivateNames(
107 Vector<UnboundPrivateName, 8>& unboundPrivateNames) {
108 // We never saw any private names, so can just return early
109 if (!hasPrivateNames_) {
110 return true;
111 }
112
113 for (auto iter = map_.iter(); !iter.done(); iter.next()) {
114 // Don't care about public;
115 if (iter.get().value().isPublic()) {
116 continue;
117 }
118
119 // empty list means all bound
120 if (iter.get().value().empty()) {
121 continue;
122 }
123
124 if (!unboundPrivateNames.emplaceBack(iter.get().key(),
125 *iter.get().value().pos())) {
126 return false;
127 }
128 }
129
130 // Return a sorted list in ascendng order of position.
131 auto comparePosition = [](const auto& a, const auto& b) {
132 return a.position < b.position;
133 };
134 std::sort(unboundPrivateNames.begin(), unboundPrivateNames.end(),
135 comparePosition);
136
137 return true;
138 }
139
hasUnboundPrivateNames(JSContext * cx,mozilla::Maybe<UnboundPrivateName> & maybeUnboundName)140 bool UsedNameTracker::hasUnboundPrivateNames(
141 JSContext* cx, mozilla::Maybe<UnboundPrivateName>& maybeUnboundName) {
142 // We never saw any private names, so can just return early
143 if (!hasPrivateNames_) {
144 return true;
145 }
146
147 Vector<UnboundPrivateName, 8> unboundPrivateNames(cx);
148 if (!getUnboundPrivateNames(unboundPrivateNames)) {
149 return false;
150 }
151
152 if (unboundPrivateNames.empty()) {
153 return true;
154 }
155
156 // GetUnboundPrivateNames returns the list sorted.
157 maybeUnboundName.emplace(unboundPrivateNames[0]);
158 return true;
159 }
160
resetToScope(uint32_t scriptId,uint32_t scopeId)161 void UsedNameTracker::UsedNameInfo::resetToScope(uint32_t scriptId,
162 uint32_t scopeId) {
163 while (!uses_.empty()) {
164 Use& innermost = uses_.back();
165 if (innermost.scopeId < scopeId) {
166 break;
167 }
168 MOZ_ASSERT(innermost.scriptId >= scriptId);
169 uses_.popBack();
170 }
171 }
172
rewind(RewindToken token)173 void UsedNameTracker::rewind(RewindToken token) {
174 scriptCounter_ = token.scriptId;
175 scopeCounter_ = token.scopeId;
176
177 for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
178 r.front().value().resetToScope(token.scriptId, token.scopeId);
179 }
180 }
181
dump(ParseContext * pc,ParserBase * parser)182 void ParseContext::Scope::dump(ParseContext* pc, ParserBase* parser) {
183 JSContext* cx = pc->sc()->cx_;
184
185 fprintf(stdout, "ParseScope %p", this);
186
187 fprintf(stdout, "\n decls:\n");
188 for (DeclaredNameMap::Range r = declared_->all(); !r.empty(); r.popFront()) {
189 auto index = r.front().key();
190 UniqueChars bytes = parser->parserAtoms().toPrintableString(cx, index);
191 if (!bytes) {
192 return;
193 }
194 DeclaredNameInfo& info = r.front().value().wrapped;
195 fprintf(stdout, " %s %s%s\n", DeclarationKindString(info.kind()),
196 bytes.get(), info.closedOver() ? " (closed over)" : "");
197 }
198
199 fprintf(stdout, "\n");
200 }
201
addPossibleAnnexBFunctionBox(ParseContext * pc,FunctionBox * funbox)202 bool ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc,
203 FunctionBox* funbox) {
204 if (!possibleAnnexBFunctionBoxes_) {
205 if (!possibleAnnexBFunctionBoxes_.acquire(pc->sc()->cx_)) {
206 return false;
207 }
208 }
209
210 return maybeReportOOM(pc, possibleAnnexBFunctionBoxes_->append(funbox));
211 }
212
propagateAndMarkAnnexBFunctionBoxes(ParseContext * pc,ParserBase * parser)213 bool ParseContext::Scope::propagateAndMarkAnnexBFunctionBoxes(
214 ParseContext* pc, ParserBase* parser) {
215 // Strict mode doesn't have wack Annex B function semantics.
216 if (pc->sc()->strict() || !possibleAnnexBFunctionBoxes_ ||
217 possibleAnnexBFunctionBoxes_->empty()) {
218 return true;
219 }
220
221 if (this == &pc->varScope()) {
222 // Base case: actually declare the Annex B vars and mark applicable
223 // function boxes as Annex B.
224 Maybe<DeclarationKind> redeclaredKind;
225 uint32_t unused;
226 for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
227 bool annexBApplies;
228 if (!pc->computeAnnexBAppliesToLexicalFunctionInInnermostScope(
229 funbox, parser, &annexBApplies)) {
230 return false;
231 }
232 if (annexBApplies) {
233 if (!pc->tryDeclareVar(funbox->explicitName(), parser,
234 DeclarationKind::VarForAnnexBLexicalFunction,
235 DeclaredNameInfo::npos, &redeclaredKind,
236 &unused)) {
237 return false;
238 }
239
240 MOZ_ASSERT(!redeclaredKind);
241 funbox->isAnnexB = true;
242 }
243 }
244 } else {
245 // Inner scope case: propagate still applicable function boxes to the
246 // enclosing scope.
247 for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
248 bool annexBApplies;
249 if (!pc->computeAnnexBAppliesToLexicalFunctionInInnermostScope(
250 funbox, parser, &annexBApplies)) {
251 return false;
252 }
253 if (annexBApplies) {
254 if (!enclosing()->addPossibleAnnexBFunctionBox(pc, funbox)) {
255 return false;
256 }
257 }
258 }
259 }
260
261 return true;
262 }
263
DeclarationKindIsCatchParameter(DeclarationKind kind)264 static bool DeclarationKindIsCatchParameter(DeclarationKind kind) {
265 return kind == DeclarationKind::SimpleCatchParameter ||
266 kind == DeclarationKind::CatchParameter;
267 }
268
addCatchParameters(ParseContext * pc,Scope & catchParamScope)269 bool ParseContext::Scope::addCatchParameters(ParseContext* pc,
270 Scope& catchParamScope) {
271 if (pc->useAsmOrInsideUseAsm()) {
272 return true;
273 }
274
275 for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
276 r.popFront()) {
277 DeclarationKind kind = r.front().value()->kind();
278 uint32_t pos = r.front().value()->pos();
279 MOZ_ASSERT(DeclarationKindIsCatchParameter(kind));
280 auto name = r.front().key();
281 AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name);
282 MOZ_ASSERT(!p);
283 if (!addDeclaredName(pc, p, name, kind, pos)) {
284 return false;
285 }
286 }
287
288 return true;
289 }
290
removeCatchParameters(ParseContext * pc,Scope & catchParamScope)291 void ParseContext::Scope::removeCatchParameters(ParseContext* pc,
292 Scope& catchParamScope) {
293 if (pc->useAsmOrInsideUseAsm()) {
294 return;
295 }
296
297 for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
298 r.popFront()) {
299 auto name = r.front().key();
300 DeclaredNamePtr p = declared_->lookup(name);
301 MOZ_ASSERT(p);
302
303 // This check is needed because the catch body could have declared
304 // vars, which would have been added to catchParamScope.
305 if (DeclarationKindIsCatchParameter(r.front().value()->kind())) {
306 declared_->remove(p);
307 }
308 }
309 }
310
ParseContext(JSContext * cx,ParseContext * & parent,SharedContext * sc,ErrorReporter & errorReporter,CompilationState & compilationState,Directives * newDirectives,bool isFull)311 ParseContext::ParseContext(JSContext* cx, ParseContext*& parent,
312 SharedContext* sc, ErrorReporter& errorReporter,
313 CompilationState& compilationState,
314 Directives* newDirectives, bool isFull)
315 : Nestable<ParseContext>(&parent),
316 traceLog_(sc->cx_,
317 isFull ? TraceLogger_ParsingFull : TraceLogger_ParsingSyntax,
318 errorReporter),
319 sc_(sc),
320 errorReporter_(errorReporter),
321 innermostStatement_(nullptr),
322 innermostScope_(nullptr),
323 varScope_(nullptr),
324 positionalFormalParameterNames_(cx->frontendCollectionPool()),
325 closedOverBindingsForLazy_(cx->frontendCollectionPool()),
326 innerFunctionIndexesForLazy(cx),
327 newDirectives(newDirectives),
328 lastYieldOffset(NoYieldOffset),
329 lastAwaitOffset(NoAwaitOffset),
330 scriptId_(compilationState.usedNames.nextScriptId()),
331 superScopeNeedsHomeObject_(false) {
332 if (isFunctionBox()) {
333 if (functionBox()->isNamedLambda()) {
334 namedLambdaScope_.emplace(cx, parent, compilationState.usedNames);
335 }
336 functionScope_.emplace(cx, parent, compilationState.usedNames);
337 }
338 }
339
init()340 bool ParseContext::init() {
341 if (scriptId_ == UINT32_MAX) {
342 errorReporter_.errorNoOffset(JSMSG_NEED_DIET, js_script_str);
343 return false;
344 }
345
346 JSContext* cx = sc()->cx_;
347
348 if (isFunctionBox()) {
349 // Named lambdas always need a binding for their own name. If this
350 // binding is closed over when we finish parsing the function in
351 // finishFunctionScopes, the function box needs to be marked as
352 // needing a dynamic DeclEnv object.
353 if (functionBox()->isNamedLambda()) {
354 if (!namedLambdaScope_->init(this)) {
355 return false;
356 }
357 AddDeclaredNamePtr p = namedLambdaScope_->lookupDeclaredNameForAdd(
358 functionBox()->explicitName());
359 MOZ_ASSERT(!p);
360 if (!namedLambdaScope_->addDeclaredName(
361 this, p, functionBox()->explicitName(), DeclarationKind::Const,
362 DeclaredNameInfo::npos)) {
363 return false;
364 }
365 }
366
367 if (!functionScope_->init(this)) {
368 return false;
369 }
370
371 if (!positionalFormalParameterNames_.acquire(cx)) {
372 return false;
373 }
374 }
375
376 if (!closedOverBindingsForLazy_.acquire(cx)) {
377 return false;
378 }
379
380 return true;
381 }
382
computeAnnexBAppliesToLexicalFunctionInInnermostScope(FunctionBox * funbox,ParserBase * parser,bool * annexBApplies)383 bool ParseContext::computeAnnexBAppliesToLexicalFunctionInInnermostScope(
384 FunctionBox* funbox, ParserBase* parser, bool* annexBApplies) {
385 MOZ_ASSERT(!sc()->strict());
386
387 TaggedParserAtomIndex name = funbox->explicitName();
388 Maybe<DeclarationKind> redeclaredKind;
389 if (!isVarRedeclaredInInnermostScope(
390 name, parser, DeclarationKind::VarForAnnexBLexicalFunction,
391 &redeclaredKind)) {
392 return false;
393 }
394
395 if (!redeclaredKind && isFunctionBox()) {
396 Scope& funScope = functionScope();
397 if (&funScope != &varScope()) {
398 // Annex B.3.3.1 disallows redeclaring parameter names. In the
399 // presence of parameter expressions, parameter names are on the
400 // function scope, which encloses the var scope. This means the
401 // isVarRedeclaredInInnermostScope call above would not catch this
402 // case, so test it manually.
403 if (DeclaredNamePtr p = funScope.lookupDeclaredName(name)) {
404 DeclarationKind declaredKind = p->value()->kind();
405 if (DeclarationKindIsParameter(declaredKind)) {
406 redeclaredKind = Some(declaredKind);
407 } else {
408 MOZ_ASSERT(FunctionScope::isSpecialName(sc()->cx_, name));
409 }
410 }
411 }
412 }
413
414 // If an early error would have occurred already, this function should not
415 // exhibit Annex B.3.3 semantics.
416 *annexBApplies = !redeclaredKind;
417 return true;
418 }
419
isVarRedeclaredInInnermostScope(TaggedParserAtomIndex name,ParserBase * parser,DeclarationKind kind,mozilla::Maybe<DeclarationKind> * out)420 bool ParseContext::isVarRedeclaredInInnermostScope(
421 TaggedParserAtomIndex name, ParserBase* parser, DeclarationKind kind,
422 mozilla::Maybe<DeclarationKind>* out) {
423 uint32_t unused;
424 return tryDeclareVarHelper<DryRunInnermostScopeOnly>(
425 name, parser, kind, DeclaredNameInfo::npos, out, &unused);
426 }
427
isVarRedeclaredInEval(TaggedParserAtomIndex name,ParserBase * parser,DeclarationKind kind,Maybe<DeclarationKind> * out)428 bool ParseContext::isVarRedeclaredInEval(TaggedParserAtomIndex name,
429 ParserBase* parser,
430 DeclarationKind kind,
431 Maybe<DeclarationKind>* out) {
432 auto maybeKind = parser->getCompilationState()
433 .scopeContext.lookupLexicalBindingInEnclosingScope(name);
434 if (!maybeKind) {
435 *out = Nothing();
436 return true;
437 }
438
439 switch (*maybeKind) {
440 case ScopeContext::EnclosingLexicalBindingKind::Let:
441 *out = Some(DeclarationKind::Let);
442 break;
443 case ScopeContext::EnclosingLexicalBindingKind::Const:
444 *out = Some(DeclarationKind::Const);
445 break;
446 case ScopeContext::EnclosingLexicalBindingKind::CatchParameter:
447 *out = Some(DeclarationKind::CatchParameter);
448 break;
449 case ScopeContext::EnclosingLexicalBindingKind::Synthetic:
450 *out = Some(DeclarationKind::Synthetic);
451 break;
452 case ScopeContext::EnclosingLexicalBindingKind::PrivateMethod:
453 *out = Some(DeclarationKind::PrivateMethod);
454 break;
455 }
456 return true;
457 }
458
tryDeclareVar(TaggedParserAtomIndex name,ParserBase * parser,DeclarationKind kind,uint32_t beginPos,Maybe<DeclarationKind> * redeclaredKind,uint32_t * prevPos)459 bool ParseContext::tryDeclareVar(TaggedParserAtomIndex name, ParserBase* parser,
460 DeclarationKind kind, uint32_t beginPos,
461 Maybe<DeclarationKind>* redeclaredKind,
462 uint32_t* prevPos) {
463 return tryDeclareVarHelper<NotDryRun>(name, parser, kind, beginPos,
464 redeclaredKind, prevPos);
465 }
466
467 template <ParseContext::DryRunOption dryRunOption>
tryDeclareVarHelper(TaggedParserAtomIndex name,ParserBase * parser,DeclarationKind kind,uint32_t beginPos,Maybe<DeclarationKind> * redeclaredKind,uint32_t * prevPos)468 bool ParseContext::tryDeclareVarHelper(TaggedParserAtomIndex name,
469 ParserBase* parser, DeclarationKind kind,
470 uint32_t beginPos,
471 Maybe<DeclarationKind>* redeclaredKind,
472 uint32_t* prevPos) {
473 MOZ_ASSERT(DeclarationKindIsVar(kind));
474
475 // It is an early error if a 'var' declaration appears inside a
476 // scope contour that has a lexical declaration of the same name. For
477 // example, the following are early errors:
478 //
479 // { let x; var x; }
480 // { { var x; } let x; }
481 //
482 // And the following are not:
483 //
484 // { var x; var x; }
485 // { { let x; } var x; }
486
487 for (ParseContext::Scope* scope = innermostScope();
488 scope != varScope().enclosing(); scope = scope->enclosing()) {
489 if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
490 DeclarationKind declaredKind = p->value()->kind();
491 if (DeclarationKindIsVar(declaredKind)) {
492 if (dryRunOption == NotDryRun) {
493 RedeclareVar(p, kind);
494 }
495 } else if (!DeclarationKindIsParameter(declaredKind)) {
496 // Annex B.3.5 allows redeclaring simple (non-destructured)
497 // catch parameters with var declarations.
498 bool annexB35Allowance =
499 declaredKind == DeclarationKind::SimpleCatchParameter;
500
501 // Annex B.3.3 allows redeclaring functions in the same block.
502 bool annexB33Allowance =
503 declaredKind == DeclarationKind::SloppyLexicalFunction &&
504 kind == DeclarationKind::VarForAnnexBLexicalFunction &&
505 scope == innermostScope();
506
507 if (!annexB35Allowance && !annexB33Allowance) {
508 *redeclaredKind = Some(declaredKind);
509 *prevPos = p->value()->pos();
510 return true;
511 }
512 } else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) {
513 MOZ_ASSERT(DeclarationKindIsParameter(declaredKind));
514
515 // Annex B.3.3.1 disallows redeclaring parameter names.
516 // We don't need to set *prevPos here since this case is not
517 // an error.
518 *redeclaredKind = Some(declaredKind);
519 return true;
520 }
521 } else if (dryRunOption == NotDryRun) {
522 if (!scope->addDeclaredName(this, p, name, kind, beginPos)) {
523 return false;
524 }
525 }
526
527 // DryRunOption is used for propagating Annex B functions: we don't
528 // want to declare the synthesized Annex B vars until we exit the var
529 // scope and know that no early errors would have occurred. In order
530 // to avoid quadratic search, we only check for var redeclarations in
531 // the innermost scope when doing a dry run.
532 if (dryRunOption == DryRunInnermostScopeOnly) {
533 break;
534 }
535 }
536
537 if (!sc()->strict() && sc()->isEvalContext() &&
538 (dryRunOption == NotDryRun || innermostScope() == &varScope())) {
539 if (!isVarRedeclaredInEval(name, parser, kind, redeclaredKind)) {
540 return false;
541 }
542 // We don't have position information at runtime.
543 *prevPos = DeclaredNameInfo::npos;
544 }
545
546 return true;
547 }
548
hasUsedName(const UsedNameTracker & usedNames,TaggedParserAtomIndex name)549 bool ParseContext::hasUsedName(const UsedNameTracker& usedNames,
550 TaggedParserAtomIndex name) {
551 if (auto p = usedNames.lookup(name)) {
552 return p->value().isUsedInScript(scriptId());
553 }
554 return false;
555 }
556
hasUsedFunctionSpecialName(const UsedNameTracker & usedNames,TaggedParserAtomIndex name)557 bool ParseContext::hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
558 TaggedParserAtomIndex name) {
559 MOZ_ASSERT(name == TaggedParserAtomIndex::WellKnown::arguments() ||
560 name == TaggedParserAtomIndex::WellKnown::dotThis());
561 return hasUsedName(usedNames, name) ||
562 functionBox()->bindingsAccessedDynamically();
563 }
564
declareFunctionThis(const UsedNameTracker & usedNames,bool canSkipLazyClosedOverBindings)565 bool ParseContext::declareFunctionThis(const UsedNameTracker& usedNames,
566 bool canSkipLazyClosedOverBindings) {
567 // The asm.js validator does all its own symbol-table management so, as an
568 // optimization, avoid doing any work here.
569 if (useAsmOrInsideUseAsm()) {
570 return true;
571 }
572
573 // Derived class constructors emit JSOp::CheckReturn, which requires
574 // '.this' to be bound.
575 FunctionBox* funbox = functionBox();
576 auto dotThis = TaggedParserAtomIndex::WellKnown::dotThis();
577
578 bool declareThis;
579 if (canSkipLazyClosedOverBindings) {
580 declareThis = funbox->functionHasThisBinding();
581 } else {
582 declareThis = hasUsedFunctionSpecialName(usedNames, dotThis) ||
583 funbox->isClassConstructor();
584 }
585
586 if (declareThis) {
587 ParseContext::Scope& funScope = functionScope();
588 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis);
589 MOZ_ASSERT(!p);
590 if (!funScope.addDeclaredName(this, p, dotThis, DeclarationKind::Var,
591 DeclaredNameInfo::npos)) {
592 return false;
593 }
594 funbox->setFunctionHasThisBinding();
595 }
596
597 return true;
598 }
599
declareFunctionArgumentsObject(const UsedNameTracker & usedNames,bool canSkipLazyClosedOverBindings)600 bool ParseContext::declareFunctionArgumentsObject(
601 const UsedNameTracker& usedNames, bool canSkipLazyClosedOverBindings) {
602 FunctionBox* funbox = functionBox();
603 ParseContext::Scope& funScope = functionScope();
604 ParseContext::Scope& _varScope = varScope();
605
606 bool usesArguments = false;
607 bool hasExtraBodyVarScope = &funScope != &_varScope;
608
609 // Time to implement the odd semantics of 'arguments'.
610 auto argumentsName = TaggedParserAtomIndex::WellKnown::arguments();
611
612 bool tryDeclareArguments;
613 if (canSkipLazyClosedOverBindings) {
614 tryDeclareArguments = funbox->shouldDeclareArguments();
615 } else {
616 tryDeclareArguments = hasUsedFunctionSpecialName(usedNames, argumentsName);
617 }
618
619 // ES 9.2.12 steps 19 and 20 say formal parameters, lexical bindings,
620 // and body-level functions named 'arguments' shadow the arguments
621 // object.
622 //
623 // So even if there wasn't a free use of 'arguments' but there is a var
624 // binding of 'arguments', we still might need the arguments object.
625 //
626 // If we have an extra var scope due to parameter expressions and the body
627 // declared 'var arguments', we still need to declare 'arguments' in the
628 // function scope.
629 DeclaredNamePtr p = _varScope.lookupDeclaredName(argumentsName);
630 if (p && p->value()->kind() == DeclarationKind::Var) {
631 if (hasExtraBodyVarScope) {
632 tryDeclareArguments = true;
633 } else {
634 usesArguments = true;
635 }
636 }
637
638 if (tryDeclareArguments) {
639 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName);
640 if (!p) {
641 if (!funScope.addDeclaredName(this, p, argumentsName,
642 DeclarationKind::Var,
643 DeclaredNameInfo::npos)) {
644 return false;
645 }
646 funbox->setShouldDeclareArguments();
647 usesArguments = true;
648 } else if (hasExtraBodyVarScope) {
649 // Formal parameters shadow the arguments object.
650 return true;
651 }
652 }
653
654 if (usesArguments) {
655 funbox->setNeedsArgsObj();
656 }
657
658 return true;
659 }
660
declareDotGeneratorName()661 bool ParseContext::declareDotGeneratorName() {
662 // The special '.generator' binding must be on the function scope, and must
663 // be marked closed-over, as generators expect to find it on the CallObject.
664 ParseContext::Scope& funScope = functionScope();
665 auto dotGenerator = TaggedParserAtomIndex::WellKnown::dotGenerator();
666 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator);
667 if (!p) {
668 if (!funScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
669 DeclaredNameInfo::npos, ClosedOver::Yes)) {
670 return false;
671 }
672 }
673 return true;
674 }
675
declareTopLevelDotGeneratorName()676 bool ParseContext::declareTopLevelDotGeneratorName() {
677 // Provide a .generator binding on the module scope for compatibility with
678 // generator code, which expect to find it on the CallObject for normal
679 // generators.
680 MOZ_ASSERT(
681 sc()->isModuleContext(),
682 "Tried to declare top level dot generator in a non-module context.");
683 ParseContext::Scope& modScope = varScope();
684 auto dotGenerator = TaggedParserAtomIndex::WellKnown::dotGenerator();
685 AddDeclaredNamePtr p = modScope.lookupDeclaredNameForAdd(dotGenerator);
686 return p ||
687 modScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
688 DeclaredNameInfo::npos, ClosedOver::Yes);
689 }
690
691 } // namespace frontend
692
693 } // namespace js
694