Bug 1130123 - Part 1: Move deprecated JS telemetry from Parser to JSCompartment. r=jandem
authorChris Peterson <cpeterson@mozilla.com>
Tue, 10 Feb 2015 23:17:43 -0800
changeset 228810 cb6cc119ceddc20798a42847f3b026eb3fd75fbe
parent 228809 07479758ab6870988d3165990e8d4b468628aeba
child 228811 c8356c3884b2d254b9939827b6771d21141d86d4
push id28271
push usercbook@mozilla.com
push dateThu, 12 Feb 2015 14:33:39 +0000
treeherdermozilla-central@81f979b17fbd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1130123
milestone38.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 1130123 - Part 1: Move deprecated JS telemetry from Parser to JSCompartment. r=jandem
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/xpconnect/src/XPCJSRuntime.cpp
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -505,22 +505,16 @@ Parser<ParseHandler>::Parser(ExclusiveCo
     ss(nullptr),
     keepAtoms(cx->perThreadData),
     foldConstants(foldConstants),
 #ifdef DEBUG
     checkOptionsCalled(false),
 #endif
     abortedSyntaxParse(false),
     isUnexpectedEOF_(false),
-    sawDeprecatedForEach(false),
-    sawDeprecatedDestructuringForIn(false),
-    sawDeprecatedLegacyGenerator(false),
-    sawDeprecatedExpressionClosure(false),
-    sawDeprecatedLetBlock(false),
-    sawDeprecatedLetExpression(false),
     handler(cx, *alloc, tokenStream, syntaxParser, lazyOuterFunction)
 {
     {
         AutoLockForExclusiveAccess lock(cx);
         cx->perThreadData->addActiveCompilation();
     }
 
     // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings
@@ -546,18 +540,16 @@ Parser<ParseHandler>::checkOptions()
     return true;
 }
 
 template <typename ParseHandler>
 Parser<ParseHandler>::~Parser()
 {
     MOZ_ASSERT(checkOptionsCalled);
 
-    accumulateTelemetry();
-
     alloc.release(tempPoolMark);
 
     /*
      * The parser can allocate enormous amounts of memory for large functions.
      * Eagerly free the memory now (which otherwise won't be freed until the
      * next GC) to avoid unnecessary OOMs.
      */
     alloc.freeAllIfHugeAndUnused();
@@ -2539,17 +2531,17 @@ Parser<ParseHandler>::functionArgsAndBod
     if (tt != TOK_LC) {
         if (funbox->isStarGenerator()) {
             report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY);
             return false;
         }
 
         if (kind != Arrow) {
 #if JS_HAS_EXPR_CLOSURES
-            sawDeprecatedExpressionClosure = true;
+            addTelemetry(JSCompartment::DeprecatedExpressionClosure);
 #else
             report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY);
             return false;
 #endif
         }
 
         tokenStream.ungetToken();
         bodyType = ExpressionBody;
@@ -3685,26 +3677,26 @@ Parser<ParseHandler>::deprecatedLetBlock
 
     Node expr;
     if (letContext == LetStatement) {
         expr = statements();
         if (!expr)
             return null();
         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
 
-        sawDeprecatedLetBlock = true;
+        addTelemetry(JSCompartment::DeprecatedLetBlock);
         if (!report(ParseWarning, pc->sc->strict, expr, JSMSG_DEPRECATED_LET_BLOCK))
             return null();
     } else {
         MOZ_ASSERT(letContext == LetExpression);
         expr = assignExpr();
         if (!expr)
             return null();
 
-        sawDeprecatedLetExpression = true;
+        addTelemetry(JSCompartment::DeprecatedLetExpression);
         if (!report(ParseWarning, pc->sc->strict, expr, JSMSG_DEPRECATED_LET_EXPRESSION))
             return null();
     }
     handler.setLexicalScopeBody(block, expr);
     PopStatementPC(tokenStream, pc);
 
     TokenPos letPos(begin, pos().end);
 
@@ -4616,17 +4608,17 @@ Parser<FullParseHandler>::forStatement()
 
     if (allowsForEachIn()) {
         bool matched;
         if (!tokenStream.matchContextualKeyword(&matched, context->names().each))
             return null();
         if (matched) {
             iflags = JSITER_FOREACH;
             isForEach = true;
-            sawDeprecatedForEach = true;
+            addTelemetry(JSCompartment::DeprecatedForEach);
             if (versionNumber() < JSVERSION_LATEST) {
                 if (!report(ParseWarning, pc->sc->strict, null(), JSMSG_DEPRECATED_FOR_EACH))
                     return null();
             }
         }
     }
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
@@ -4851,17 +4843,17 @@ Parser<FullParseHandler>::forStatement()
           case PNK_OBJECT:
             if (versionNumber() == JSVERSION_1_7) {
                 /*
                  * Destructuring for-in requires [key, value] enumeration
                  * in JS1.7.
                  */
                 if (!isForEach && headKind == PNK_FORIN) {
                     iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
-                    sawDeprecatedDestructuringForIn = true;
+                    addTelemetry(JSCompartment::DeprecatedDestructuringForIn);
                 }
             }
             break;
 
           default:;
         }
     } else {
         if (isForEach) {
@@ -5417,17 +5409,17 @@ Parser<ParseHandler>::yieldExpression()
             return null();
 
         if (!pc->sc->isFunctionBox()) {
             report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
             return null();
         }
 
         pc->sc->asFunctionBox()->setGeneratorKind(LegacyGenerator);
-        sawDeprecatedLegacyGenerator = true;
+        addTelemetry(JSCompartment::DeprecatedLegacyGenerator);
 
         if (pc->funHasReturnExpr) {
             /* As in Python (see PEP-255), disallow return v; in generators. */
             reportBadReturn(null(), ParseError, JSMSG_BAD_GENERATOR_RETURN,
                             JSMSG_BAD_ANON_GENERATOR_RETURN);
             return null();
         }
         // Fall through.
@@ -6814,17 +6806,17 @@ Parser<FullParseHandler>::legacyComprehe
 
         pn2->pn_iflags = JSITER_ENUMERATE;
         if (allowsForEachIn()) {
             bool matched;
             if (!tokenStream.matchContextualKeyword(&matched, context->names().each))
                 return null();
             if (matched) {
                 pn2->pn_iflags |= JSITER_FOREACH;
-                sawDeprecatedForEach = true;
+                addTelemetry(JSCompartment::DeprecatedForEach);
                 if (versionNumber() < JSVERSION_LATEST) {
                     if (!report(ParseWarning, pc->sc->strict, pn2, JSMSG_DEPRECATED_FOR_EACH))
                         return null();
                 }
             }
         }
         MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
 
@@ -8379,57 +8371,21 @@ Parser<ParseHandler>::exprInParens()
     }
 #endif /* JS_HAS_GENERATOR_EXPRS */
 
     return pn;
 }
 
 template <typename ParseHandler>
 void
-Parser<ParseHandler>::accumulateTelemetry()
+Parser<ParseHandler>::addTelemetry(JSCompartment::DeprecatedLanguageExtension e)
 {
     JSContext* cx = context->maybeJSContext();
     if (!cx)
         return;
-    const char* filename = getFilename();
-    if (!filename)
-        return;
-
-    bool isAddon = !!cx->compartment()->addonId;
-    bool isHTTP = strncmp(filename, "http://", 7) == 0 || strncmp(filename, "https://", 8) == 0;
-
-    // Only report telemetry for web content, not add-ons or chrome JS.
-    if (isAddon || !isHTTP)
-        return;
-
-    enum DeprecatedLanguageExtensions {
-        DeprecatedForEach = 0,            // JS 1.6+
-        DeprecatedDestructuringForIn = 1, // JS 1.7 only
-        DeprecatedLegacyGenerator = 2,    // JS 1.7+
-        DeprecatedExpressionClosure = 3,  // Added in JS 1.8, but not version-gated
-        DeprecatedLetBlock = 4,           // Added in JS 1.7, but not version-gated
-        DeprecatedLetExpression = 5,      // Added in JS 1.7, but not version-gated
-    };
-
-    // Hazard analysis can't tell that the telemetry callbacks don't GC.
-    JS::AutoSuppressGCAnalysis nogc;
-
-    // Call back into Firefox's Telemetry reporter.
-    int id = JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT;
-    if (sawDeprecatedForEach)
-         cx->runtime()->addTelemetry(id, DeprecatedForEach);
-    if (sawDeprecatedDestructuringForIn)
-         cx->runtime()->addTelemetry(id, DeprecatedDestructuringForIn);
-    if (sawDeprecatedLegacyGenerator)
-        cx->runtime()->addTelemetry(id, DeprecatedLegacyGenerator);
-    if (sawDeprecatedExpressionClosure)
-         cx->runtime()->addTelemetry(id, DeprecatedExpressionClosure);
-    if (sawDeprecatedLetBlock)
-         cx->runtime()->addTelemetry(id, DeprecatedLetBlock);
-    if (sawDeprecatedLetExpression)
-         cx->runtime()->addTelemetry(id, DeprecatedLetExpression);
+    cx->compartment()->addTelemetry(e);
 }
 
 template class Parser<FullParseHandler>;
 template class Parser<SyntaxParseHandler>;
 
 } /* namespace frontend */
 } /* namespace js */
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -367,24 +367,16 @@ class Parser : private JS::AutoGCRooter,
      * is not known whether the parse succeeds or fails, this bit is set and
      * the parse will return false.
      */
     bool abortedSyntaxParse:1;
 
     /* Unexpected end of input, i.e. TOK_EOF not at top-level. */
     bool isUnexpectedEOF_:1;
 
-    /* Used for collecting telemetry on SpiderMonkey's deprecated language extensions. */
-    bool sawDeprecatedForEach:1;
-    bool sawDeprecatedDestructuringForIn:1;
-    bool sawDeprecatedLegacyGenerator:1;
-    bool sawDeprecatedExpressionClosure:1;
-    bool sawDeprecatedLetBlock:1;
-    bool sawDeprecatedLetExpression:1;
-
     typedef typename ParseHandler::Node Node;
     typedef typename ParseHandler::DefinitionNode DefinitionNode;
 
   public:
     /* State specific to the kind of parse being performed. */
     ParseHandler handler;
 
   private:
@@ -699,17 +691,17 @@ class Parser : private JS::AutoGCRooter,
 
     bool leaveFunction(Node fn, ParseContext<ParseHandler> *outerpc,
                        FunctionSyntaxKind kind = Expression);
 
     TokenPos pos() const { return tokenStream.currentToken().pos; }
 
     bool asmJS(Node list);
 
-    void accumulateTelemetry();
+    void addTelemetry(JSCompartment::DeprecatedLanguageExtension e);
 
     friend class LegacyCompExprTransplanter;
     friend struct BindData<ParseHandler>;
 };
 
 /* Declare some required template specializations. */
 
 template <>
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -70,22 +70,25 @@ JSCompartment::JSCompartment(Zone *zone,
     debugScriptMap(nullptr),
     debugScopes(nullptr),
     enumerators(nullptr),
     compartmentStats(nullptr),
     scheduledForDestruction(false),
     maybeAlive(true),
     jitCompartment_(nullptr)
 {
+    PodArrayZero(sawDeprecatedLanguageExtension);
     runtime_->numCompartments++;
     MOZ_ASSERT_IF(options.mergeable(), options.invisibleToDebugger());
 }
 
 JSCompartment::~JSCompartment()
 {
+    reportTelemetry();
+
     js_delete(jitCompartment_);
     js_delete(watchpointMap);
     js_delete(scriptCountsMap);
     js_delete(debugScriptMap);
     js_delete(debugScopes);
     js_delete(lazyArrayBuffers);
     js_free(enumerators);
 
@@ -809,8 +812,25 @@ JSCompartment::addSizeOfIncludingThis(mo
                         + initialShapes.sizeOfExcludingThis(mallocSizeOf);
     *innerViewsArg += innerViews.sizeOfExcludingThis(mallocSizeOf);
     if (lazyArrayBuffers)
         *lazyArrayBuffersArg += lazyArrayBuffers->sizeOfIncludingThis(mallocSizeOf);
     *crossCompartmentWrappersArg += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf);
     *regexpCompartment += regExps.sizeOfExcludingThis(mallocSizeOf);
     *savedStacksSet += savedStacks_.sizeOfExcludingThis(mallocSizeOf);
 }
+
+void
+JSCompartment::reportTelemetry()
+{
+    // Only report telemetry for web content, not add-ons or chrome JS.
+    if (addonId || isSystem)
+        return;
+
+    // Hazard analysis can't tell that the telemetry callbacks don't GC.
+    JS::AutoSuppressGCAnalysis nogc;
+
+    // Call back into Firefox's Telemetry reporter.
+    for (size_t i = 0; i < DeprecatedLanguageExtensionCount; i++) {
+        if (sawDeprecatedLanguageExtension[i])
+            runtime_->addTelemetry(JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT, i);
+    }
+}
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -514,16 +514,37 @@ struct JSCompartment
   private:
     js::jit::JitCompartment *jitCompartment_;
 
   public:
     bool ensureJitCompartmentExists(JSContext *cx);
     js::jit::JitCompartment *jitCompartment() {
         return jitCompartment_;
     }
+
+    enum DeprecatedLanguageExtension {
+        DeprecatedForEach = 0,              // JS 1.6+
+        DeprecatedDestructuringForIn = 1,   // JS 1.7 only
+        DeprecatedLegacyGenerator = 2,      // JS 1.7+
+        DeprecatedExpressionClosure = 3,    // Added in JS 1.8
+        DeprecatedLetBlock = 4,             // Added in JS 1.7
+        DeprecatedLetExpression = 5,        // Added in JS 1.7
+        DeprecatedLanguageExtensionCount
+    };
+
+  private:
+    // Used for collecting telemetry on SpiderMonkey's deprecated language extensions.
+    bool sawDeprecatedLanguageExtension[DeprecatedLanguageExtensionCount];
+
+    void reportTelemetry();
+
+  public:
+    void addTelemetry(DeprecatedLanguageExtension e) {
+        sawDeprecatedLanguageExtension[e] = true;
+    }
 };
 
 inline bool
 JSRuntime::isAtomsZone(JS::Zone *zone)
 {
     return zone == atomsCompartment_->zone();
 }
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -3034,17 +3034,16 @@ AccumulateTelemetryCallback(int id, uint
         break;
       case JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS:
         Telemetry::Accumulate(Telemetry::GC_SCC_SWEEP_TOTAL_MS, sample);
         break;
       case JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS:
         Telemetry::Accumulate(Telemetry::GC_SCC_SWEEP_MAX_PAUSE_MS, sample);
         break;
       case JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT:
-        MOZ_ASSERT(sample <= 5);
         Telemetry::Accumulate(Telemetry::JS_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT, sample);
         break;
       case JS_TELEMETRY_ADDON_EXCEPTIONS:
         Telemetry::Accumulate(Telemetry::JS_TELEMETRY_ADDON_EXCEPTIONS, nsDependentCString(key), sample);
         break;
       default:
         MOZ_ASSERT_UNREACHABLE("Unexpected JS_TELEMETRY id");
     }