Bug 634800 - Clean up reportCompileErrorNumberVA(). r=jwalden.
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 13 Jun 2012 23:23:01 -0700
changeset 106445 a977ac53a195ee750973025594a945e9c37d65a9
parent 106444 000eb13cb3bafedfc910025e90abf2d0f5a74ad8
child 106446 b3820743259201b5eadc2fdfbda4cb14e2a80a59
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherdermozilla-central@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs634800
milestone16.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 634800 - Clean up reportCompileErrorNumberVA(). r=jwalden.
content/base/src/nsINode.cpp
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -390,55 +390,73 @@ TokenStream::TokenBuf::findEOLMax(const 
         n++;
     }
     return p;
 }
 
 bool
 TokenStream::reportCompileErrorNumberVA(ParseNode *pn, unsigned flags, unsigned errorNumber, va_list ap)
 {
-    JSErrorReport report;
-    char *message;
-    jschar *windowChars;
-    char *windowBytes;
-    bool warning;
-    JSBool ok;
-    const TokenPos *tp;
-    unsigned i;
+    class ReportManager
+    {
+        JSContext *cx;
+        JSErrorReport *report;
+        bool hasCharArgs;
+
+      public:
+        char *message;
+
+        ReportManager(JSContext *cx, JSErrorReport *report, bool hasCharArgs)
+          : cx(cx), report(report), hasCharArgs(hasCharArgs), message(NULL)
+        {}
+
+        ~ReportManager() {
+            cx->free_((void*)report->uclinebuf);
+            cx->free_((void*)report->linebuf);
+            cx->free_(message);
+            cx->free_((void*)report->ucmessage);
+
+            if (report->messageArgs) {
+                if (hasCharArgs) {
+                    unsigned i = 0;
+                    while (report->messageArgs[i])
+                        cx->free_((void *)report->messageArgs[i++]);
+                }
+                cx->free_((void *)report->messageArgs);
+            }
+        }
+    };
 
     if (JSREPORT_IS_STRICT(flags) && !cx->hasStrictOption())
         return true;
 
-    warning = JSREPORT_IS_WARNING(flags);
+    bool warning = JSREPORT_IS_WARNING(flags);
     if (warning && cx->hasWErrorOption()) {
         flags &= ~JSREPORT_WARNING;
         warning = false;
     }
 
+    const TokenPos *const tp = pn ? &pn->pn_pos : &currentToken().pos;
+
+    JSErrorReport report;
     PodZero(&report);
     report.flags = flags;
     report.errorNumber = errorNumber;
-    message = NULL;
-    windowChars = NULL;
-    windowBytes = NULL;
-
-    MUST_FLOW_THROUGH("out");
-    ok = js_ExpandErrorArguments(cx, js_GetErrorMessage, NULL,
-                                 errorNumber, &message, &report,
-                                 !(flags & JSREPORT_UC), ap);
-    if (!ok) {
-        warning = false;
-        goto out;
-    }
-
     report.filename = filename;
     report.originPrincipals = originPrincipals;
+    report.lineno = tp->begin.lineno;
 
-    tp = pn ? &pn->pn_pos : &currentToken().pos;
-    report.lineno = tp->begin.lineno;
+    bool hasCharArgs = !(flags & JSREPORT_UC);
+
+    ReportManager mgr(cx, &report, hasCharArgs);
+
+    if (!js_ExpandErrorArguments(cx, js_GetErrorMessage, NULL, errorNumber, &mgr.message, &report,
+                                 hasCharArgs, ap)) {
+        return false;
+    }
 
     /*
      * Given a token, T, that we want to complain about: if T's (starting)
      * lineno doesn't match TokenStream's lineno, that means we've scanned past
      * the line that T starts on, which makes it hard to print some or all of
      * T's (starting) line for context.
      *
      * So we don't even try, leaving report.linebuf and friends zeroed.  This
@@ -464,35 +482,27 @@ TokenStream::reportCompileErrorNumberVA(
 
         // Find EOL, or truncate at the back if necessary.
         const jschar *windowLimit = userbuf.findEOLMax(tokptr, windowRadius);
         size_t windowLength = windowLimit - windowBase;
         JS_ASSERT(windowLength <= windowRadius * 2);
 
         // Create the windowed strings.
         StringBuffer windowBuf(cx);
-        if (!windowBuf.append(windowBase, windowLength) || !windowBuf.append((jschar)0)) {
-            warning = false;
-            goto out;
-        }
-        windowChars = windowBuf.extractWellSized();
-        if (!windowChars) {
-            warning = false;
-            goto out;
-        }
-        windowBytes = DeflateString(cx, windowChars, windowLength);
-        if (!windowBytes) {
-            warning = false;
-            goto out;
-        }
+        if (!windowBuf.append(windowBase, windowLength) || !windowBuf.append((jschar)0))
+            return false;
 
         // Unicode and char versions of the window into the offending source
         // line, without final \n.
-        report.linebuf = windowBytes;
-        report.uclinebuf = windowChars;
+        report.uclinebuf = windowBuf.extractWellSized();
+        if (!report.uclinebuf)
+            return false;
+        report.linebuf = DeflateString(cx, report.uclinebuf, windowLength);
+        if (!report.linebuf)
+            return false;
 
         // The lineno check above means we should only see single-line tokens here.
         JS_ASSERT(tp->begin.lineno == tp->end.lineno);
         report.tokenptr = report.linebuf + windowIndex;
         report.uctokenptr = report.uclinebuf + windowIndex;
     }
 
     /*
@@ -503,47 +513,30 @@ TokenStream::reportCompileErrorNumberVA(
      * If an exception is thrown but not caught, the JSREPORT_EXCEPTION
      * flag will be set in report.flags.  Proper behavior for an error
      * reporter is to ignore a report with this flag for all but top-level
      * compilation errors.  The exception will remain pending, and so long
      * as the non-top-level "load", "eval", or "compile" native function
      * returns false, the top-level reporter will eventually receive the
      * uncaught exception report.
      */
-    if (!js_ErrorToException(cx, message, &report, NULL, NULL)) {
+    if (!js_ErrorToException(cx, mgr.message, &report, NULL, NULL)) {
         /*
          * If debugErrorHook is present then we give it a chance to veto
          * sending the error on to the regular error reporter.
          */
         bool reportError = true;
-        if (JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook)
-            reportError = hook(cx, message, &report, cx->runtime->debugHooks.debugErrorHookData);
+        if (JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook) {
+            reportError = hook(cx, mgr.message, &report,
+                               cx->runtime->debugHooks.debugErrorHookData);
+        }
 
         /* Report the error */
         if (reportError && cx->errorReporter)
-            cx->errorReporter(cx, message, &report);
-    }
-
-  out:
-    if (windowBytes)
-        cx->free_(windowBytes);
-    if (windowChars)
-        cx->free_(windowChars);
-    if (message)
-        cx->free_(message);
-    if (report.ucmessage)
-        cx->free_((void *)report.ucmessage);
-
-    if (report.messageArgs) {
-        if (!(flags & JSREPORT_UC)) {
-            i = 0;
-            while (report.messageArgs[i])
-                cx->free_((void *)report.messageArgs[i++]);
-        }
-        cx->free_((void *)report.messageArgs);
+            cx->errorReporter(cx, mgr.message, &report);
     }
 
     return warning;
 }
 
 bool
 js::ReportStrictModeError(JSContext *cx, TokenStream *ts, ParseNode *pn, unsigned errorNumber, ...)
 {
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -495,17 +495,20 @@ class TokenStream
 
     bool isStrictMode() const { return strictModeGetter ? strictModeGetter->get() : false; }
     bool isXMLTagMode() const { return !!(flags & TSF_XMLTAGMODE); }
     bool isXMLOnlyMode() const { return !!(flags & TSF_XMLONLYMODE); }
     bool isUnexpectedEOF() const { return !!(flags & TSF_UNEXPECTED_EOF); }
     bool isEOF() const { return !!(flags & TSF_EOF); }
     bool hasOctalCharacterEscape() const { return flags & TSF_OCTAL_CHAR; }
 
-    bool reportCompileErrorNumberVA(ParseNode *pn, unsigned flags, unsigned errorNumber, va_list ap);
+    // Return false if we should stop compiling, either because (a) we issued
+    // an error message, or (b) something went wrong, such as an OOM.
+    bool reportCompileErrorNumberVA(ParseNode *pn, unsigned flags, unsigned errorNumber,
+                                    va_list ap);
 
   private:
     static JSAtom *atomize(JSContext *cx, CharBuffer &cb);
     bool putIdentInTokenbuf(const jschar *identStart);
 
     /*
      * Enables flags in the associated tokenstream for the object lifetime.
      * Useful for lexically-scoped flag toggles.