Bug 1451343 - Part 1: Use provided capture information. (r=Yoric)
authorEric Faust <efaustbmo@gmail.com>
Mon, 30 Apr 2018 23:37:41 -0700
changeset 472556 03130e40886bf76d8d0de4ce16b7a042fd54b4f4
parent 472518 7134ec98560255d2c6ffa8b47a1fd78f04d29851
child 472557 cf0675c2f36251c5c9871987a02efe4be1e25dc0
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersYoric
bugs1451343
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1451343 - Part 1: Use provided capture information. (r=Yoric)
js/src/frontend/BinSource-auto.cpp
js/src/frontend/BinSource.cpp
js/src/frontend/BinSource.h
js/src/frontend/BinSource.yaml
--- a/js/src/frontend/BinSource-auto.cpp
+++ b/js/src/frontend/BinSource-auto.cpp
@@ -3036,17 +3036,17 @@ BinASTParser<Tok>::parseInterfaceAsserte
 
 
 #if defined(DEBUG)
     const BinField expected_fields[3] = { BinField::LexicallyDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval };
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let));
-    MOZ_TRY(parseAndUpdateCapturedNames());
+    MOZ_TRY(parseAndUpdateCapturedNames(kind));
 
 
 
     BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
     if (hasDirectEval) {
         parseContext_->sc()->setHasDirectEval();
         parseContext_->sc()->setBindingsAccessedDynamically();
     }
@@ -3092,17 +3092,17 @@ BinASTParser<Tok>::parseInterfaceAsserte
 
 
 #if defined(DEBUG)
     const BinField expected_fields[3] = { BinField::ParameterNames, BinField::CapturedNames, BinField::HasDirectEval };
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     MOZ_TRY(parseAndUpdateScopeNames(parseContext_->functionScope(), DeclarationKind:: PositionalFormalParameter));
-    MOZ_TRY(parseAndUpdateCapturedNames());
+    MOZ_TRY(parseAndUpdateCapturedNames(kind));
 
 
 
     BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
     if (hasDirectEval) {
         parseContext_->sc()->setHasDirectEval();
         parseContext_->sc()->setBindingsAccessedDynamically();
     }
@@ -3150,17 +3150,17 @@ BinASTParser<Tok>::parseInterfaceAsserte
 
 #if defined(DEBUG)
     const BinField expected_fields[4] = { BinField::LexicallyDeclaredNames, BinField::VarDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval };
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let));
     MOZ_TRY(parseAndUpdateScopeNames(parseContext_->varScope(), DeclarationKind::Var));
-    MOZ_TRY(parseAndUpdateCapturedNames());
+    MOZ_TRY(parseAndUpdateCapturedNames(kind));
 
 
 
     BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
     if (hasDirectEval) {
         parseContext_->sc()->setHasDirectEval();
         parseContext_->sc()->setBindingsAccessedDynamically();
     }
--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -193,29 +193,60 @@ BinASTParser<Tok>::buildFunction(const s
                  NewLexicalScopeData(cx_, parseContext_->namedLambdaScope(), alloc_, parseContext_));
 
         funbox->namedLambdaBindings().set(*recursiveBinding);
     }
 
     return result;
 }
 
+// Try to mark the capture in the given scope, if the variable exists.
+// Return whether it was found in this scope and marked successfully.
+static bool TryMarkCaptureInScope(ParseContext::Scope& scope, HandleAtom atom)
+{
+    auto name = scope.lookupDeclaredName(atom);
+    if (!name)
+        return false;
+    name->value()->setClosedOver();
+    return true;
+}
+
 template<typename Tok> JS::Result<Ok>
-BinASTParser<Tok>::parseAndUpdateCapturedNames()
+BinASTParser<Tok>::parseAndUpdateCapturedNames(const BinKind kind)
 {
     // For the moment, we do not attempt to validate the list of captured names.
     AutoList guard(*tokenizer_);
     uint32_t length = 0;
 
     MOZ_TRY(tokenizer_->enterList(length, guard));
     RootedAtom name(cx_);
     for (uint32_t i = 0; i < length; ++i) {
         name = nullptr;
 
         MOZ_TRY_VAR(name, tokenizer_->readAtom());
+        if (kind == BinKind::AssertedParameterScope) {
+            MOZ_ASSERT(parseContext_->isFunctionBox());
+
+            if (parseContext_->functionBox()->function()->isNamedLambda()) {
+                if (TryMarkCaptureInScope(parseContext_->namedLambdaScope(), name))
+                    continue;
+            }
+
+            if (!TryMarkCaptureInScope(parseContext_->functionScope(), name))
+                return raiseUndeclaredCapture(name);
+            continue;
+        }
+
+        if (kind == BinKind::AssertedVarScope) {
+            if (TryMarkCaptureInScope(parseContext_->varScope(), name))
+                continue;
+        }
+
+        if (!TryMarkCaptureInScope(*parseContext_->innermostScope(), name))
+            return raiseUndeclaredCapture(name);
     }
     MOZ_TRY(guard.done());
     return Ok();
 }
 
 template<typename Tok> JS::Result<Ok>
 BinASTParser<Tok>::parseAndUpdateScopeNames(ParseContext::Scope& scope, DeclarationKind kind)
 {
@@ -282,16 +313,23 @@ BinASTParser<Tok>::appendDirectivesToBod
         result->checkListConsistency();
 #endif // defined(DEBUG)
     }
 
     return result;
 }
 
 template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
+BinASTParser<Tok>::raiseUndeclaredCapture(JSAtom* name)
+{
+    // As below, don't put the name in a message.
+    return raiseError("Captured variable undeclared in scope");
+}
+
+template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
 BinASTParser<Tok>::raiseMissingVariableInAssertedScope(JSAtom* name)
 {
     // For the moment, we don't trust inputs sufficiently to put the name
     // in an error message.
     return raiseError("Missing variable in AssertedScope");
 }
 
 template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
--- a/js/src/frontend/BinSource.h
+++ b/js/src/frontend/BinSource.h
@@ -152,16 +152,17 @@ class BinASTParser : public BinASTParser
 
   private:
     MOZ_MUST_USE JS::Result<ParseNode*> parseAux(const uint8_t* start, const size_t length);
 
     // --- Raise errors.
     //
     // These methods return a (failed) JS::Result for convenience.
 
+    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseUndeclaredCapture(JSAtom* name);
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingVariableInAssertedScope(JSAtom* name);
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingDirectEvalInAssertedScope();
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidKind(const char* superKind,
         const BinKind kind);
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidVariant(const char* kind,
         const BinVariant value);
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingField(const char* kind,
         const BinField field);
@@ -186,17 +187,17 @@ class BinASTParser : public BinASTParser
     buildFunctionBox(GeneratorKind generatorKind, FunctionAsyncKind functionAsyncKind, FunctionSyntaxKind syntax, ParseNode* name);
 
     // Parse full scope information to a specific var scope / let scope combination.
     MOZ_MUST_USE JS::Result<Ok> parseAndUpdateScope(ParseContext::Scope& varScope,
         ParseContext::Scope& letScope);
     // Parse a list of names and add it to a given scope.
     MOZ_MUST_USE JS::Result<Ok> parseAndUpdateScopeNames(ParseContext::Scope& scope,
         DeclarationKind kind);
-    MOZ_MUST_USE JS::Result<Ok> parseAndUpdateCapturedNames();
+    MOZ_MUST_USE JS::Result<Ok> parseAndUpdateCapturedNames(const BinKind kind);
     MOZ_MUST_USE JS::Result<Ok> checkBinding(JSAtom* name);
 
     // --- Utilities.
 
     MOZ_MUST_USE JS::Result<ParseNode*> appendDirectivesToBody(ParseNode* body,
         ParseNode* directives);
 
   private: // Implement ErrorReporter
--- a/js/src/frontend/BinSource.yaml
+++ b/js/src/frontend/BinSource.yaml
@@ -211,17 +211,17 @@ AssertedBlockScope:
             // add variables to the call object.
             parseContext_->functionBox()->setHasExtensibleScope();
         }
         auto result = Ok();
     fields:
         capturedNames:
             block:
                 replace: |
-                    MOZ_TRY(parseAndUpdateCapturedNames());
+                    MOZ_TRY(parseAndUpdateCapturedNames(kind));
         hasDirectEval:
             after: |
                 if (hasDirectEval) {
                     parseContext_->sc()->setHasDirectEval();
                     parseContext_->sc()->setBindingsAccessedDynamically();
                 }
         lexicallyDeclaredNames:
             block: