Bug 718786: Make the shell exit with EXITCODE_RUNTIME_ERROR when code is terminated. r=jorendorff
authorJim Blandy <jimb@mozilla.com>
Sat, 28 Jan 2012 16:24:03 -0800
changeset 86903 ab3edf81a46f7beebd5c01cdd254df9e16945346
parent 86899 7d6ce43efe5edec5352f4c2bfb9608b4d30c9e5c
child 86904 3a6ece55c68c69dca745889e96707dd0b64d6447
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs718786
milestone12.0a1
Bug 718786: Make the shell exit with EXITCODE_RUNTIME_ERROR when code is terminated. r=jorendorff In js/src/jit-test/jit_test.py, add an 'exitstatus' jit-test cookie attribute (and rename test.error to test.expect_error). Mark tests that terminate with their expected termination code. Clean up TMFLAGS comments.
js/src/jit-test/README
js/src/jit-test/jit_test.py
js/src/jit-test/tests/basic/terminate.js
js/src/shell/js.cpp
--- a/js/src/jit-test/README
+++ b/js/src/jit-test/README
@@ -50,27 +50,27 @@ The general format in EBNF is:
 
     metaline  ::= cookie { item ";" }
     cookie    ::= "|jit-test|"
     item      ::= flag | attribute
 
     flag      ::= "slow" | "allow-oom" | "valgrind" | "mjitalways" | "debug"
 
     attribute ::= name ":" value
-    name      ::= "TMFLAGS" | "error"
+    name      ::= "error" | "exitstatus"
     value     ::= <string>
 
 The metaline may appear anywhere in the first line of the file: this allows it
 to be placed inside any kind of comment.
 
 The meaning of the items:
 
     slow         Test runs slowly. Do not run if the --no-slow option is given.
     allow-oom    If the test runs out of memory, it counts as passing.
     valgrind     Run test under valgrind.
     mjitalways   Run js with -a, whether --jitflags says to or not
     debug        Run js with -d, whether --jitflags says to or not
 
     error        The test should be considered to pass iff it throws the
                  given JS exception.
-    TMFLAGS      Set the environment variable TMFLAGS to the given value.
+    exitstatus   The test should exit with the given status value (an integer).
 
 * END
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -45,25 +45,27 @@ os.path.relpath = _relpath
 class Test:
     def __init__(self, path):
         self.path = path       # path to test file
         
         self.jitflags = []     # jit flags to enable
         self.slow = False      # True means the test is slow-running
         self.allow_oom = False # True means that OOM is not considered a failure
         self.valgrind = False  # True means run under valgrind
-        self.error = ''        # Errors to expect and consider passing
+        self.expect_error = '' # Errors to expect and consider passing
+        self.expect_status = 0 # Exit status to expect from shell
 
     def copy(self):
         t = Test(self.path)
         t.jitflags = self.jitflags[:]
         t.slow = self.slow
         t.allow_oom = self.allow_oom
         t.valgrind = self.valgrind
-        t.error = self.error
+        t.expect_error = self.expect_error
+        t.expect_status = self.expect_status
         return t
 
     COOKIE = '|jit-test|'
 
     @classmethod
     def from_file(cls, path, options):
         test = cls(path)
 
@@ -75,17 +77,22 @@ class Test:
             for part in parts:
                 part = part.strip()
                 if not part:
                     continue
                 name, _, value = part.partition(':')
                 if value:
                     value = value.strip()
                     if name == 'error':
-                        test.error = value
+                        test.expect_error = value
+                    elif name == 'exitstatus':
+                        try:
+                            test.expect_status = int(value, 0);
+                        except ValueError:
+                            print("warning: couldn't parse exit status %s"%value)
                     else:
                         print('warning: unrecognized |jit-test| attribute %s'%part)
                 else:
                     if name == 'slow':
                         test.slow = True
                     elif name == 'allow-oom':
                         test.allow_oom = True
                     elif name == 'valgrind':
@@ -221,35 +228,35 @@ def run_test(test, lib_dir, shell_args):
     out, err, code, timed_out = run(cmd, os.environ, OPTIONS.timeout)
 
     if OPTIONS.show_output:
         sys.stdout.write(out)
         sys.stdout.write(err)
         sys.stdout.write('Exit code: %s\n' % code)
     if test.valgrind:
         sys.stdout.write(err)
-    return (check_output(out, err, code, test.allow_oom, test.error), 
+    return (check_output(out, err, code, test),
             out, err, code, timed_out)
 
-def check_output(out, err, rc, allow_oom, expectedError):
-    if expectedError:
-        return expectedError in err
+def check_output(out, err, rc, test):
+    if test.expect_error:
+        return test.expect_error in err
 
     for line in out.split('\n'):
         if line.startswith('Trace stats check failed'):
             return False
 
     for line in err.split('\n'):
         if 'Assertion failed:' in line:
             return False
 
-    if rc != 0:
+    if rc != test.expect_status:
         # Allow a non-zero exit code if we want to allow OOM, but only if we
         # actually got OOM.
-        return allow_oom and ': out of memory' in err
+        return test.allow_oom and ': out of memory' in err
 
     return True
 
 def print_tinderbox(label, test, message=None):
     jitflags = " ".join(test.jitflags)
     result = "%s | jit_test.py %-15s| %s" % (label, jitflags, test.path)
     if message:
         result += ": " + message
--- a/js/src/jit-test/tests/basic/terminate.js
+++ b/js/src/jit-test/tests/basic/terminate.js
@@ -1,8 +1,9 @@
+// |jit-test| exitstatus: 3
 try {
     terminate();
     assertEq("execution continued", "execution should not continue");
 } catch (x) {
     assertEq("caught exception", "uncatchable");
 } finally {
     assertEq("'finally' clause ran", "'finally' clause should not run");
 }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -470,17 +470,20 @@ Process(JSContext *cx, JSObject *obj, co
         ungetc(ch, file);
 
         int64_t t1 = PRMJ_Now();
         oldopts = JS_GetOptions(cx);
         JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
         script = JS_CompileUTF8FileHandle(cx, obj, filename, file);
         JS_SetOptions(cx, oldopts);
         if (script && !compileOnly) {
-            (void) JS_ExecuteScript(cx, obj, script, NULL);
+            if (!JS_ExecuteScript(cx, obj, script, NULL)) {
+                if (!gQuitting && !gCanceled)
+                    gExitCode = EXITCODE_RUNTIME_ERROR;
+            }
             int64_t t2 = PRMJ_Now() - t1;
             if (printTiming)
                 printf("runtime = %.3f ms\n", double(t2) / PRMJ_USEC_PER_MSEC);
         }
 
         goto cleanup;
     }