diff --git a/js/src/jit/AsmJS.cpp b/js/src/jit/AsmJS.cpp index 03d75992e9f6..fc188ef8fec9 100644 --- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -1231,6 +1231,7 @@ class MOZ_STACK_CLASS ModuleCompiler char * errorString_; uint32_t errorOffset_; + bool errorOverRecursed_; int64_t usecBefore_; SlowFunctionVector slowFunctions_; @@ -1260,6 +1261,7 @@ class MOZ_STACK_CLASS ModuleCompiler globalAccesses_(cx), errorString_(nullptr), errorOffset_(UINT32_MAX), + errorOverRecursed_(false), usecBefore_(PRMJ_Now()), slowFunctions_(cx), finishedFunctionBodies_(false) @@ -1275,6 +1277,8 @@ class MOZ_STACK_CLASS ModuleCompiler errorString_); js_free(errorString_); } + if (errorOverRecursed_) + js_ReportOverRecursed(cx_); // Avoid spurious Label assertions on compilation failure. if (!stackOverflowLabel_.bound()) @@ -1324,7 +1328,15 @@ class MOZ_STACK_CLASS ModuleCompiler } bool fail(ParseNode *pn, const char *str) { - return failOffset(pn ? pn->pn_pos.begin : parser_.tokenStream.peekTokenPos().begin, str); + if (pn) + return failOffset(pn->pn_pos.begin, str); + + // The exact rooting static analysis does not perform dataflow analysis, so it believes + // that unrooted things on the stack during compilation may still be accessed after this. + // Since pn is typically only null under OOM, this suppression simply forces any GC to be + // delayed until the compilation is off the stack and more memory can be freed. + gc::AutoSuppressGC nogc(cx_); + return failOffset(parser_.tokenStream.peekTokenPos().begin, str); } bool failfVA(ParseNode *pn, const char *fmt, va_list ap) { @@ -1353,6 +1365,11 @@ class MOZ_STACK_CLASS ModuleCompiler return false; } + bool failOverRecursed() { + errorOverRecursed_ = true; + return false; + } + static const unsigned SLOW_FUNCTION_THRESHOLD_MS = 250; bool maybeReportCompileTime(const Func &func) { @@ -3813,7 +3830,7 @@ CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltin static bool CheckCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition **def, Type *type) { - JS_CHECK_RECURSION(f.cx(), return false); + JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed()); ParseNode *callee = CallCallee(call); @@ -4104,7 +4121,7 @@ static bool CheckAddOrSub(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type, unsigned *numAddOrSubOut = nullptr) { - JS_CHECK_RECURSION(f.cx(), return false); + JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed()); JS_ASSERT(expr->isKind(PNK_ADD) || expr->isKind(PNK_SUB)); ParseNode *lhs = BinaryLeft(expr); @@ -4308,7 +4325,7 @@ CheckBitwise(FunctionCompiler &f, ParseNode *bitwise, MDefinition **def, Type *t static bool CheckExpr(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type) { - JS_CHECK_RECURSION(f.cx(), return false); + JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed()); if (!f.mirGen().ensureBallast()) return false; @@ -4781,7 +4798,7 @@ CheckStatementList(FunctionCompiler &f, ParseNode *stmtList) static bool CheckStatement(FunctionCompiler &f, ParseNode *stmt, LabelVector *maybeLabels) { - JS_CHECK_RECURSION(f.cx(), return false); + JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed()); if (!f.mirGen().ensureBallast()) return false; diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 92a84cf57df3..d0c13dfd9410 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -665,7 +665,7 @@ GetNativeStackLimit(JSContext *cx) * extra space so that we can ensure that crucial code is able to run. */ -#define JS_CHECK_RECURSION(cx, onerror) \ +#define JS_CHECK_RECURSION(cx, onerror) \ JS_BEGIN_MACRO \ int stackDummy_; \ if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_)) { \ @@ -674,6 +674,14 @@ GetNativeStackLimit(JSContext *cx) } \ JS_END_MACRO +#define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \ + JS_BEGIN_MACRO \ + int stackDummy_; \ + if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_)) { \ + onerror; \ + } \ + JS_END_MACRO + #define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \ JS_BEGIN_MACRO \ if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \