Bug 1185106 - Part 1: Add AsyncFunction flag in FunctionBox, JSScript, and LazyScript. r=efaust,till draft
authorMariusz Kierski <mkierski@mozilla.com>
Sun, 28 Aug 2016 20:42:39 +0900
changeset 430922 5d3dbb908bfad2adbbc3d3dfcb99099e11f68a02
parent 430921 d1ec57e1c6f0fdbb374b6eae36c1c710faecfd1b
child 430923 9de8902519a4b6e22b20e887f147d796421f398f
push id33945
push userarai_a@mac.com
push dateFri, 28 Oct 2016 11:34:02 +0000
reviewersefaust, till
bugs1185106
milestone52.0a1
Bug 1185106 - Part 1: Add AsyncFunction flag in FunctionBox, JSScript, and LazyScript. r=efaust,till MozReview-Commit-ID: 6nOsJO3doV9
js/src/asmjs/AsmJS.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SharedContext.h
js/src/jsfun.h
js/src/jsscript.cpp
js/src/jsscript.h
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -7063,17 +7063,17 @@ ParseFunction(ModuleValidator& m, ParseN
 
     RootedFunction& fun = m.dummyFunction();
     fun->setAtom(name);
     fun->setArgCount(0);
 
     ParseContext* outerpc = m.parser().pc;
     Directives directives(outerpc);
     FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, directives, NotGenerator,
-                                                    /* tryAnnexB = */ false);
+                                                    SyncFunction, /* tryAnnexB = */ false);
     if (!funbox)
         return false;
     funbox->initWithEnclosingParseContext(outerpc, frontend::Statement);
 
     Directives newDirectives = directives;
     ParseContext funpc(&m.parser(), funbox, &newDirectives);
     if (!funpc.init())
         return false;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -431,30 +431,31 @@ UsedNameTracker::rewind(RewindToken toke
     scopeCounter_ = token.scopeId;
 
     for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront())
         r.front().value().resetToScope(token.scriptId, token.scopeId);
 }
 
 FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead,
                          JSFunction* fun, Directives directives, bool extraWarnings,
-                         GeneratorKind generatorKind)
+                         GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
   : ObjectBox(fun, traceListHead),
     SharedContext(cx, Kind::ObjectBox, directives, extraWarnings),
     enclosingScope_(nullptr),
     namedLambdaBindings_(nullptr),
     functionScopeBindings_(nullptr),
     extraVarScopeBindings_(nullptr),
     functionNode(nullptr),
     bufStart(0),
     bufEnd(0),
     startLine(1),
     startColumn(0),
     length(0),
     generatorKindBits_(GeneratorKindAsBits(generatorKind)),
+    asyncKindBits_(AsyncKindAsBits(asyncKind)),
     isGenexpLambda(false),
     hasDestructuringArgs(false),
     hasParameterExprs(false),
     hasDirectEvalInParameterExpr(false),
     hasDuplicateParameters(false),
     useAsm(false),
     insideUseAsm(false),
     isAnnexB(false),
@@ -729,31 +730,32 @@ Parser<ParseHandler>::newObjectBox(JSObj
     traceListHead = objbox;
 
     return objbox;
 }
 
 template <typename ParseHandler>
 FunctionBox*
 Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheritedDirectives,
-                                     GeneratorKind generatorKind, bool tryAnnexB)
+                                     GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+                                     bool tryAnnexB)
 {
     MOZ_ASSERT(fun);
     MOZ_ASSERT_IF(tryAnnexB, !pc->sc()->strict());
 
     /*
      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
      * arenas containing the entries must be alive until we are done with
      * scanning, parsing and code generation for the whole script or top-level
      * function.
      */
     FunctionBox* funbox =
         alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, inheritedDirectives,
-                                options().extraWarningsOption, generatorKind);
+                                options().extraWarningsOption, generatorKind, asyncKind);
     if (!funbox) {
         ReportOutOfMemory(context);
         return nullptr;
     }
 
     traceListHead = funbox;
     if (fn)
         handler.setFunctionBox(fn, funbox);
@@ -2190,16 +2192,17 @@ Parser<SyntaxParseHandler>::finishFuncti
     if (!lazy)
         return false;
 
     // Flags that need to be copied into the JSScript when we do the full
     // parse.
     if (pc->sc()->strict())
         lazy->setStrict();
     lazy->setGeneratorKind(funbox->generatorKind());
+    lazy->setAsyncKind(funbox->asyncKind());
     if (funbox->isLikelyConstructorWrapper())
         lazy->setLikelyConstructorWrapper();
     if (funbox->isDerivedClassConstructor())
         lazy->setIsDerivedClassConstructor();
     if (funbox->needsHomeObject())
         lazy->setNeedsHomeObject();
     if (funbox->declaredArguments)
         lazy->setShouldDeclareArguments();
@@ -2230,17 +2233,17 @@ Parser<FullParseHandler>::standaloneFunc
         return null();
 
     ParseNode* argsbody = handler.newList(PNK_PARAMSBODY);
     if (!argsbody)
         return null();
     fn->pn_body = argsbody;
 
     FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind,
-                                         /* tryAnnexB = */ false);
+                                         SyncFunction, /* tryAnnexB = */ false);
     if (!funbox)
         return null();
     funbox->initStandaloneFunction(enclosingScope);
 
     ParseContext funpc(this, funbox, newDirectives);
     if (!funpc.init())
         return null();
     funpc.setIsStandaloneFunctionBody();
@@ -2916,17 +2919,17 @@ Parser<FullParseHandler>::skipLazyInnerF
     // When a lazily-parsed function is called, we only fully parse (and emit)
     // that function, not any of its nested children. The initial syntax-only
     // parse recorded the free variables of nested functions and their extents,
     // so we can skip over them after accounting for their free variables.
 
     RootedFunction fun(context, handler.nextLazyInnerFunction());
     MOZ_ASSERT(!fun->isLegacyGenerator());
     FunctionBox* funbox = newFunctionBox(pn, fun, Directives(/* strict = */ false),
-                                         fun->generatorKind(), tryAnnexB);
+                                         fun->generatorKind(), fun->asyncKind(), tryAnnexB);
     if (!funbox)
         return false;
 
     LazyScript* lazy = fun->lazyScript();
     if (lazy->needsHomeObject())
         funbox->setNeedsHomeObject();
 
     PropagateTransitiveParseFlags(lazy, pc->sc());
@@ -3138,17 +3141,17 @@ Parser<FullParseHandler>::trySyntaxParse
         tokenStream.tell(&position);
         if (!parser->tokenStream.seek(position, tokenStream))
             return false;
 
         // Make a FunctionBox before we enter the syntax parser, because |pn|
         // still expects a FunctionBox to be attached to it during BCE, and
         // the syntax parser cannot attach one to it.
         FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind,
-                                             tryAnnexB);
+                                             SyncFunction, tryAnnexB);
         if (!funbox)
             return false;
         funbox->initWithEnclosingParseContext(pc, kind);
 
         if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, inHandling,
                                    yieldHandling, kind, inheritedDirectives, newDirectives))
         {
             if (parser->hadAbortedSyntaxParse()) {
@@ -3226,17 +3229,18 @@ Parser<ParseHandler>::innerFunction(Node
                                     bool tryAnnexB, Directives inheritedDirectives,
                                     Directives* newDirectives)
 {
     // Note that it is possible for outerpc != this->pc, as we may be
     // attempting to syntax parse an inner function from an outer full
     // parser. In that case, outerpc is a ParseContext from the full parser
     // instead of the current top of the stack of the syntax parser.
 
-    FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, tryAnnexB);
+    FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind,
+                                         SyncFunction, tryAnnexB);
     if (!funbox)
         return false;
     funbox->initWithEnclosingParseContext(outerpc, kind);
 
     return innerFunction(pn, outerpc, funbox, inHandling, yieldHandling, kind, inheritedDirectives,
                          newDirectives);
 }
 
@@ -3266,17 +3270,17 @@ Parser<FullParseHandler>::standaloneLazy
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     Node pn = handler.newFunctionDefinition();
     if (!pn)
         return null();
 
     Directives directives(strict);
-    FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind,
+    FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, SyncFunction,
                                          /* tryAnnexB = */ false);
     if (!funbox)
         return null();
     funbox->initFromLazyFunction();
 
     Directives newDirectives = directives;
     ParseContext funpc(this, funbox, &newDirectives);
     if (!funpc.init())
@@ -7812,17 +7816,17 @@ Parser<ParseHandler>::generatorComprehen
 
     RootedFunction fun(context, newFunction(/* atom = */ nullptr, Expression,
                                             StarGenerator, proto));
     if (!fun)
         return null();
 
     // Create box for fun->object early to root it.
     Directives directives(/* strict = */ outerpc->sc()->strict());
-    FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator,
+    FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator, SyncFunction,
                                             /* tryAnnexB = */ false);
     if (!genFunbox)
         return null();
     genFunbox->isGenexpLambda = true;
     genFunbox->initWithEnclosingParseContext(outerpc, Expression);
 
     ParseContext genpc(this, genFunbox, /* newDirectives = */ nullptr);
     if (!genpc.init())
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -493,16 +493,20 @@ class ParseContext : public Nestable<Par
     bool isLegacyGenerator() const {
         return generatorKind() == LegacyGenerator;
     }
 
     bool isStarGenerator() const {
         return generatorKind() == StarGenerator;
     }
 
+    bool isAsync() const {
+        return sc_->isFunctionBox() && sc_->asFunctionBox()->isAsync();
+    }
+
     bool isArrowFunction() const {
         return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isArrow();
     }
 
     bool isMethod() const {
         return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isMethod();
     }
 
@@ -935,17 +939,18 @@ class Parser final : private JS::AutoGCR
     Node parse();
 
     /*
      * Allocate a new parsed object or function container from
      * cx->tempLifoAlloc.
      */
     ObjectBox* newObjectBox(JSObject* obj);
     FunctionBox* newFunctionBox(Node fn, JSFunction* fun, Directives directives,
-                                GeneratorKind generatorKind, bool tryAnnexB);
+                                GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+                                bool tryAnnexB);
 
     /*
      * Create a new function object given a name (which is optional if this is
      * a function expression).
      */
     JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind, GeneratorKind generatorKind,
                             HandleObject proto);
 
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -448,16 +448,18 @@ class FunctionBox : public ObjectBox, pu
     ParseNode*      functionNode;           /* back pointer used by asm.js for error messages */
     uint32_t        bufStart;
     uint32_t        bufEnd;
     uint32_t        startLine;
     uint32_t        startColumn;
     uint16_t        length;
 
     uint8_t         generatorKindBits_;     /* The GeneratorKind of this function. */
+    uint8_t         asyncKindBits_;         /* The FunctionAsyncKing of this function. */
+
     bool            isGenexpLambda:1;       /* lambda from generator expression */
     bool            hasDestructuringArgs:1; /* parameter list contains destructuring expression */
     bool            hasParameterExprs:1;    /* parameter list contains expressions */
     bool            hasDirectEvalInParameterExpr:1; /* parameter list contains direct eval */
     bool            hasDuplicateParameters:1; /* parameter list contains duplicate names */
     bool            useAsm:1;               /* see useAsmOrInsideUseAsm */
     bool            insideUseAsm:1;         /* see useAsmOrInsideUseAsm */
     bool            isAnnexB:1;             /* need to emit a synthesized Annex B assignment */
@@ -468,17 +470,18 @@ class FunctionBox : public ObjectBox, pu
     bool            usesArguments:1;        /* contains a free use of 'arguments' */
     bool            usesApply:1;            /* contains an f.apply() call */
     bool            usesThis:1;             /* contains 'this' */
     bool            usesReturn:1;           /* contains a 'return' statement */
 
     FunctionContextFlags funCxFlags;
 
     FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
-                Directives directives, bool extraWarnings, GeneratorKind generatorKind);
+                Directives directives, bool extraWarnings, GeneratorKind generatorKind,
+                FunctionAsyncKind asyncKind);
 
     MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
         MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms());
         return MutableHandle<LexicalScope::Data*>::fromMarkedLocation(&namedLambdaBindings_);
     }
 
     MutableHandle<FunctionScope::Data*> functionScopeBindings() {
         MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms());
@@ -527,16 +530,18 @@ class FunctionBox : public ObjectBox, pu
     bool isLikelyConstructorWrapper() const {
         return usesArguments && usesApply && usesThis && !usesReturn;
     }
 
     GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
     bool isGenerator() const { return generatorKind() != NotGenerator; }
     bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
     bool isStarGenerator() const { return generatorKind() == StarGenerator; }
+    FunctionAsyncKind asyncKind() const { return AsyncKindFromBits(asyncKindBits_); }
+    bool isAsync() const { return asyncKind() == AsyncFunction; }
     bool isArrow() const { return function()->isArrow(); }
 
     void setGeneratorKind(GeneratorKind kind) {
         // A generator kind can be set at initialization, or when "yield" is
         // first seen.  In both cases the transition can only happen from
         // NotGenerator.
         MOZ_ASSERT(!isGenerator());
         generatorKindBits_ = GeneratorKindAsBits(kind);
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -296,16 +296,23 @@ class JSFunction : public js::NativeObje
     void setResolvedLength() {
         flags_ |= RESOLVED_LENGTH;
     }
 
     void setResolvedName() {
         flags_ |= RESOLVED_NAME;
     }
 
+    void setAsyncKind(js::FunctionAsyncKind asyncKind) {
+        if (isInterpretedLazy())
+            lazyScript()->setAsyncKind(asyncKind);
+        else
+            nonLazyScript()->setAsyncKind(asyncKind);
+    }
+
     bool getUnresolvedLength(JSContext* cx, js::MutableHandleValue v);
 
     JSAtom* getUnresolvedName(JSContext* cx);
 
     JSAtom* name() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
 
     // Because display names (see Debugger.Object.displayName) are already stored
     // on functions and will always contain a valid es6 function name, as described
@@ -464,16 +471,28 @@ class JSFunction : public js::NativeObje
     }
 
     bool isGenerator() const { return generatorKind() != js::NotGenerator; }
 
     bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
 
     bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
 
+    js::FunctionAsyncKind asyncKind() const {
+        return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind();
+    }
+
+    bool isAsync() const {
+        if (isInterpretedLazy())
+            return lazyScript()->asyncKind() == js::AsyncFunction;
+        if (hasScript())
+            return nonLazyScript()->asyncKind() == js::AsyncFunction;
+        return false;
+    }
+
     void setScript(JSScript* script_) {
         mutableScript() = script_;
     }
 
     void initScript(JSScript* script_) {
         mutableScript().init(script_);
     }
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2610,16 +2610,17 @@ JSScript::initFromFunctionBox(ExclusiveC
 
     script->functionHasThisBinding_ = funbox->hasThisBinding();
     script->functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
 
     script->funLength_ = funbox->length;
 
     script->isGeneratorExp_ = funbox->isGenexpLambda;
     script->setGeneratorKind(funbox->generatorKind());
+    script->setAsyncKind(funbox->asyncKind());
 
     PositionalFormalParameterIter fi(script);
     while (fi && !fi.closedOver())
         fi++;
     script->funHasAnyAliasedFormal_ = !!fi;
 
     script->setHasInnerFunctions(funbox->hasInnerFunctions());
 }
@@ -3267,16 +3268,17 @@ js::detail::CopyScript(JSContext* cx, Ha
     dst->hasSingletons_ = src->hasSingletons();
     dst->treatAsRunOnce_ = src->treatAsRunOnce();
     dst->hasInnerFunctions_ = src->hasInnerFunctions();
     dst->isGeneratorExp_ = src->isGeneratorExp();
     dst->setGeneratorKind(src->generatorKind());
     dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
     dst->needsHomeObject_ = src->needsHomeObject();
     dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
+    dst->isAsync_ = src->asyncKind() == AsyncFunction;
 
     if (nconsts != 0) {
         GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
         dst->consts()->vector = vector;
         for (unsigned i = 0; i < nconsts; ++i)
             MOZ_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom());
     }
     if (nobjects != 0) {
@@ -3999,16 +4001,17 @@ LazyScript::Create(ExclusiveContext* cx,
     union {
         PackedView p;
         uint64_t packedFields;
     };
 
     p.version = version;
     p.shouldDeclareArguments = false;
     p.hasThisBinding = false;
+    p.isAsync = false;
     p.numClosedOverBindings = closedOverBindings.length();
     p.numInnerFunctions = innerFunctions.length();
     p.generatorKindBits = GeneratorKindAsBits(NotGenerator);
     p.strict = false;
     p.bindingsAccessedDynamically = false;
     p.hasDebuggerStatement = false;
     p.hasDirectEval = false;
     p.isLikelyConstructorWrapper = false;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -635,28 +635,40 @@ class ScriptSourceObject : public Native
     static const uint32_t SOURCE_SLOT = 0;
     static const uint32_t ELEMENT_SLOT = 1;
     static const uint32_t ELEMENT_PROPERTY_SLOT = 2;
     static const uint32_t INTRODUCTION_SCRIPT_SLOT = 3;
     static const uint32_t RESERVED_SLOTS = 4;
 };
 
 enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };
+enum FunctionAsyncKind { SyncFunction, AsyncFunction };
 
 static inline unsigned
 GeneratorKindAsBits(GeneratorKind generatorKind) {
     return static_cast<unsigned>(generatorKind);
 }
 
 static inline GeneratorKind
 GeneratorKindFromBits(unsigned val) {
     MOZ_ASSERT(val <= StarGenerator);
     return static_cast<GeneratorKind>(val);
 }
 
+static inline unsigned
+AsyncKindAsBits(FunctionAsyncKind asyncKind) {
+    return static_cast<unsigned>(asyncKind);
+}
+
+static inline FunctionAsyncKind
+AsyncKindFromBits(unsigned val) {
+    MOZ_ASSERT(val <= AsyncFunction);
+    return static_cast<FunctionAsyncKind>(val);
+}
+
 /*
  * NB: after a successful XDR_DECODE, XDRScript callers must do any required
  * subsequent set-up of owning function or script object and then call
  * CallNewScriptHook.
  */
 template<XDRMode mode>
 bool
 XDRScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript enclosingScript,
@@ -983,16 +995,18 @@ class JSScript : public js::gc::TenuredC
     // script.
     bool hasInnerFunctions_:1;
 
     bool needsHomeObject_:1;
 
     bool isDerivedClassConstructor_:1;
     bool isDefaultClassConstructor_:1;
 
+    bool isAsync_:1;
+
     // Add padding so JSScript is gc::Cell aligned. Make padding protected
     // instead of private to suppress -Wunused-private-field compiler warnings.
   protected:
 #if JS_BITS_PER_WORD == 32
     // Currently no padding is needed.
 #endif
 
     //
@@ -1271,16 +1285,24 @@ class JSScript : public js::gc::TenuredC
     bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
     void setGeneratorKind(js::GeneratorKind kind) {
         // A script only gets its generator kind set as part of initialization,
         // so it can only transition from not being a generator.
         MOZ_ASSERT(!isGenerator());
         generatorKindBits_ = GeneratorKindAsBits(kind);
     }
 
+    js::FunctionAsyncKind asyncKind() const {
+        return isAsync_ ? js::AsyncFunction : js::SyncFunction;
+    }
+
+    void setAsyncKind(js::FunctionAsyncKind kind) {
+        isAsync_ = kind == js::AsyncFunction;
+    }
+
     void setNeedsHomeObject() {
         needsHomeObject_ = true;
     }
     bool needsHomeObject() const {
         return needsHomeObject_;
     }
 
     bool isDerivedClassConstructor() const {
@@ -1882,17 +1904,18 @@ class LazyScript : public gc::TenuredCel
 
   private:
     struct PackedView {
         // Assorted bits that should really be in ScriptSourceObject.
         uint32_t version : 8;
 
         uint32_t shouldDeclareArguments : 1;
         uint32_t hasThisBinding : 1;
-        uint32_t numClosedOverBindings : 22;
+        uint32_t isAsync : 1;
+        uint32_t numClosedOverBindings : 21;
         uint32_t numInnerFunctions : 20;
 
         uint32_t generatorKindBits : 2;
 
         // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
         // If you add another boolean here, make sure to initialze it in
         // LazyScript::CreateRaw().
         uint32_t strict : 1;
@@ -2019,16 +2042,24 @@ class LazyScript : public gc::TenuredCel
         // A script only gets its generator kind set as part of initialization,
         // so it can only transition from NotGenerator.
         MOZ_ASSERT(!isGenerator());
         // Legacy generators cannot currently be lazy.
         MOZ_ASSERT(kind != LegacyGenerator);
         p_.generatorKindBits = GeneratorKindAsBits(kind);
     }
 
+    FunctionAsyncKind asyncKind() const {
+        return p_.isAsync ? AsyncFunction : SyncFunction;
+    }
+
+    void setAsyncKind(FunctionAsyncKind kind) {
+        p_.isAsync = kind == AsyncFunction;
+    }
+
     bool strict() const {
         return p_.strict;
     }
     void setStrict() {
         p_.strict = true;
     }
 
     bool bindingsAccessedDynamically() const {