author | Tooru Fujisawa <arai_a@mac.com> |
Thu, 11 Jun 2015 13:14:13 +0900 | |
changeset 248199 | 6e36d0a459997873cf57c015ca1b99c448eebf03 |
parent 248198 | 76a74dc6ccc9555294a8918e23101577502fc099 |
child 248200 | dcb1893ec57928420ad86e5302c48b468ff6c778 |
push id | 60900 |
push user | arai_a@mac.com |
push date | Thu, 11 Jun 2015 04:17:04 +0000 |
treeherder | mozilla-inbound@53a469d71606 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 1170716 |
milestone | 41.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
|
js/src/shell/js.cpp | file | annotate | diff | comparison | revisions | |
js/src/tests/shell/warning.js | file | annotate | diff | comparison | revisions |
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -121,16 +121,19 @@ static size_t gMaxStackSize = 128 * size * Limit the timeout to 30 minutes to prevent an overflow on platfoms * that represent the time internally in microseconds using 32-bit int. */ static double MAX_TIMEOUT_INTERVAL = 1800.0; static double gTimeoutInterval = -1.0; static volatile bool gServiceInterrupt = false; static JS::PersistentRootedValue gInterruptFunc; +static bool gLastWarningEnabled = false; +static JS::PersistentRootedValue gLastWarning; + static bool enableDisassemblyDumps = false; static bool offthreadCompilation = false; static bool enableBaseline = false; static bool enableIon = false; static bool enableAsmJS = false; static bool enableNativeRegExp = false; static bool enableUnboxedArrays = false; #ifdef JS_GC_ZEAL @@ -3032,16 +3035,73 @@ SetInterruptCallback(JSContext* cx, unsi return false; } gInterruptFunc = value; args.rval().setUndefined(); return true; } +static bool +EnableLastWarning(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + gLastWarningEnabled = true; + gLastWarning.setNull(); + + args.rval().setUndefined(); + return true; +} + +static bool +DisableLastWarning(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + gLastWarningEnabled = false; + gLastWarning.setNull(); + + args.rval().setUndefined(); + return true; +} + +static bool +GetLastWarning(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (!gLastWarningEnabled) { + JS_ReportError(cx, "Call enableLastWarning first."); + return false; + } + + if (!JS_WrapValue(cx, &gLastWarning)) + return false; + + args.rval().set(gLastWarning); + return true; +} + +static bool +ClearLastWarning(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (!gLastWarningEnabled) { + JS_ReportError(cx, "Call enableLastWarning first."); + return false; + } + + gLastWarning.setNull(); + + args.rval().setUndefined(); + return true; +} + #ifdef DEBUG static bool StackDump(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); bool showArgs = ToBoolean(args.get(0)); bool showLocals = ToBoolean(args.get(1)); @@ -4701,16 +4761,32 @@ static const JSFunctionSpecWithHelp shel " be called. Before returning, fun is called with the return value of the\n" " interrupt handler."), JS_FN_HELP("setInterruptCallback", SetInterruptCallback, 1, 0, "setInterruptCallback(func)", " Sets func as the interrupt callback function.\n" " Calling this function will replace any callback set by |timeout|.\n"), + JS_FN_HELP("enableLastWarning", EnableLastWarning, 0, 0, +"enableLastWarning()", +" Enable storing the last warning."), + + JS_FN_HELP("disableLastWarning", DisableLastWarning, 0, 0, +"disableLastWarning()", +" Disable storing the last warning."), + + JS_FN_HELP("getLastWarning", GetLastWarning, 0, 0, +"getLastWarning()", +" Returns an object that represents the last warning."), + + JS_FN_HELP("clearLastWarning", ClearLastWarning, 0, 0, +"clearLastWarning()", +" Clear the last warning."), + JS_FN_HELP("elapsed", Elapsed, 0, 0, "elapsed()", " Execution time elapsed for the current context."), JS_FN_HELP("decompileFunction", DecompileFunction, 1, 0, "decompileFunction(func)", " Decompile a function."), @@ -5021,19 +5097,65 @@ const JSErrorFormatString* js::shell::my_GetErrorMessage(void* userRef, const unsigned errorNumber) { if (errorNumber == 0 || errorNumber >= JSShellErr_Limit) return nullptr; return &jsShell_ErrorFormatString[errorNumber]; } +static bool +CreateLastWarningObject(JSContext* cx, JSErrorReport* report) +{ + RootedObject warningObj(cx, JS_NewObject(cx, nullptr)); + if (!warningObj) + return false; + + RootedString nameStr(cx); + if (report->exnType == JSEXN_NONE) + nameStr = JS_NewStringCopyZ(cx, "None"); + else + nameStr = GetErrorTypeName(cx->runtime(), report->exnType); + if (!nameStr) + return false; + RootedValue nameVal(cx, StringValue(nameStr)); + if (!DefineProperty(cx, warningObj, cx->names().name, nameVal)) + return false; + + RootedString messageStr(cx, JS_NewUCStringCopyZ(cx, report->ucmessage)); + if (!messageStr) + return false; + RootedValue messageVal(cx, StringValue(messageStr)); + if (!DefineProperty(cx, warningObj, cx->names().message, messageVal)) + return false; + + RootedValue linenoVal(cx, Int32Value(report->lineno)); + if (!DefineProperty(cx, warningObj, cx->names().lineNumber, linenoVal)) + return false; + + RootedValue columnVal(cx, Int32Value(report->column)); + if (!DefineProperty(cx, warningObj, cx->names().columnNumber, columnVal)) + return false; + + gLastWarning.setObject(*warningObj); + return true; +} + void js::shell::my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report) { + if (report && JSREPORT_IS_WARNING(report->flags) && gLastWarningEnabled) { + JS::AutoSaveExceptionState savedExc(cx); + if (!CreateLastWarningObject(cx, report)) { + fputs("Unhandled error happened while creating last warning object.\n", gOutFile); + fflush(gOutFile); + } + savedExc.restore(); + } + gGotError = PrintError(cx, gErrFile, message, report, reportWarnings); if (report->exnType != JSEXN_NONE && !JSREPORT_IS_WARNING(report->flags)) { if (report->errorNumber == JSMSG_OUT_OF_MEMORY) { gExitCode = EXITCODE_OUT_OF_MEMORY; } else { gExitCode = EXITCODE_RUNTIME_ERROR; } } @@ -6300,16 +6422,17 @@ main(int argc, char** argv, char** envp) return 1; JS_SetErrorReporter(rt, my_ErrorReporter); JS::SetOutOfMemoryCallback(rt, my_OOMCallback, nullptr); if (!SetRuntimeOptions(rt, op)) return 1; gInterruptFunc.init(rt, NullValue()); + gLastWarning.init(rt, NullValue()); JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff); size_t availMem = op.getIntOption("available-memory"); if (availMem > 0) JS_SetGCParametersBasedOnAvailableMemory(rt, availMem); JS_SetTrustedPrincipals(rt, &ShellPrincipals::fullyTrusted);
new file mode 100644 --- /dev/null +++ b/js/src/tests/shell/warning.js @@ -0,0 +1,52 @@ +// |reftest| skip-if(!xulRuntime.shell) + +var BUGNUMBER = 1170716; +var summary = 'Add js shell functions to get last warning'; + +print(BUGNUMBER + ": " + summary); + +// Warning with JSEXN_NONE. + +enableLastWarning(); + +eval(`({}).__proto__ = {};`); + +var warning = getLastWarning(); +assertEq(warning !== null, true); +assertEq(warning.name, "None"); +assertEq(warning.message.includes("mutating"), true); +assertEq(warning.lineNumber, 1); +assertEq(warning.columnNumber, 1); + +// Clear last warning. + +clearLastWarning(); +warning = getLastWarning(); +assertEq(warning, null); + +// Warning with JSEXN_SYNTAXERR. + +options("strict"); +eval(`var a; if (a=0) {}`); + +warning = getLastWarning(); +assertEq(warning !== null, true); +assertEq(warning.name, "SyntaxError"); +assertEq(warning.message.includes("equality"), true); +assertEq(warning.lineNumber, 1); +assertEq(warning.columnNumber, 14); + +// Disabled. + +disableLastWarning(); + +eval(`var a; if (a=0) {}`); + +enableLastWarning(); +warning = getLastWarning(); +assertEq(warning, null); + +disableLastWarning(); + +if (typeof reportCompare === "function") + reportCompare(true, true);