LCOV - code coverage report
Current view: top level - js/src - jscntxt.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 235 716 32.8 %
Date: 2017-07-14 16:53:18 Functions: 33 83 39.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * JS execution context.
       9             :  */
      10             : 
      11             : #include "jscntxtinlines.h"
      12             : 
      13             : #include "mozilla/ArrayUtils.h"
      14             : #include "mozilla/DebugOnly.h"
      15             : #include "mozilla/MemoryReporting.h"
      16             : #include "mozilla/Sprintf.h"
      17             : 
      18             : #include <ctype.h>
      19             : #include <stdarg.h>
      20             : #include <string.h>
      21             : #ifdef ANDROID
      22             : # include <android/log.h>
      23             : # include <fstream>
      24             : # include <string>
      25             : #endif // ANDROID
      26             : #ifdef XP_WIN
      27             : #include <processthreadsapi.h>
      28             : #endif // XP_WIN
      29             : 
      30             : #include "jsatom.h"
      31             : #include "jscompartment.h"
      32             : #include "jsdtoa.h"
      33             : #include "jsexn.h"
      34             : #include "jsfun.h"
      35             : #include "jsgc.h"
      36             : #include "jsiter.h"
      37             : #include "jsnativestack.h"
      38             : #include "jsobj.h"
      39             : #include "jsopcode.h"
      40             : #include "jsprf.h"
      41             : #include "jspubtd.h"
      42             : #include "jsscript.h"
      43             : #include "jsstr.h"
      44             : #include "jstypes.h"
      45             : #include "jswatchpoint.h"
      46             : #include "jswin.h"
      47             : 
      48             : #include "gc/Marking.h"
      49             : #include "jit/Ion.h"
      50             : #include "jit/PcScriptCache.h"
      51             : #include "js/CharacterEncoding.h"
      52             : #include "vm/ErrorReporting.h"
      53             : #include "vm/HelperThreads.h"
      54             : #include "vm/Shape.h"
      55             : #include "wasm/WasmSignalHandlers.h"
      56             : 
      57             : #include "jsobjinlines.h"
      58             : #include "jsscriptinlines.h"
      59             : 
      60             : #include "vm/Stack-inl.h"
      61             : 
      62             : using namespace js;
      63             : using namespace js::gc;
      64             : 
      65             : using mozilla::DebugOnly;
      66             : using mozilla::PodArrayZero;
      67             : using mozilla::PointerRangeSize;
      68             : 
      69             : bool
      70        2407 : js::AutoCycleDetector::init()
      71             : {
      72        2407 :     MOZ_ASSERT(cyclic);
      73             : 
      74        2407 :     AutoCycleDetector::Vector& vector = cx->cycleDetectorVector();
      75             : 
      76        2410 :     for (JSObject* obj2 : vector) {
      77           3 :         if (MOZ_UNLIKELY(obj == obj2))
      78           0 :             return true;
      79             :     }
      80             : 
      81        2407 :     if (!vector.append(obj))
      82           0 :         return false;
      83             : 
      84        2407 :     cyclic = false;
      85        2407 :     return true;
      86             : }
      87             : 
      88        4814 : js::AutoCycleDetector::~AutoCycleDetector()
      89             : {
      90        2407 :     if (MOZ_LIKELY(!cyclic)) {
      91        2407 :         AutoCycleDetector::Vector& vec = cx->cycleDetectorVector();
      92        2407 :         MOZ_ASSERT(vec.back() == obj);
      93        2407 :         if (vec.length() > 1) {
      94           3 :             vec.popBack();
      95             :         } else {
      96             :             // Avoid holding on to unused heap allocations.
      97        2404 :             vec.clearAndFree();
      98             :         }
      99             :     }
     100        2407 : }
     101             : 
     102             : bool
     103          40 : JSContext::init(ContextKind kind)
     104             : {
     105             :     // Skip most of the initialization if this thread will not be running JS.
     106          40 :     if (kind == ContextKind::Cooperative) {
     107             :         // Get a platform-native handle for this thread, used by js::InterruptRunningJitCode.
     108             : #ifdef XP_WIN
     109             :         size_t openFlags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME |
     110             :                            THREAD_QUERY_INFORMATION;
     111             :         HANDLE self = OpenThread(openFlags, false, GetCurrentThreadId());
     112             :         if (!self)
     113             :         return false;
     114             :         static_assert(sizeof(HANDLE) <= sizeof(threadNative_), "need bigger field");
     115             :         threadNative_ = (size_t)self;
     116             : #else
     117             :         static_assert(sizeof(pthread_t) <= sizeof(threadNative_), "need bigger field");
     118           4 :         threadNative_ = (size_t)pthread_self();
     119             : #endif
     120             : 
     121           4 :         if (!regexpStack.ref().init())
     122           0 :             return false;
     123             : 
     124           4 :         if (!fx.initInstance())
     125           0 :             return false;
     126             : 
     127             : #ifdef JS_SIMULATOR
     128             :         simulator_ = js::jit::Simulator::Create(this);
     129             :         if (!simulator_)
     130             :             return false;
     131             : #endif
     132             : 
     133           4 :         if (!wasm::EnsureSignalHandlers(this))
     134           0 :             return false;
     135             :     }
     136             : 
     137             :     // Set the ContextKind last, so that ProtectedData checks will allow us to
     138             :     // initialize this context before it becomes the runtime's active context.
     139          40 :     kind_ = kind;
     140             : 
     141          40 :     return true;
     142             : }
     143             : 
     144             : JSContext*
     145           4 : js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime)
     146             : {
     147           8 :     AutoNoteSingleThreadedRegion anstr;
     148             : 
     149           4 :     MOZ_RELEASE_ASSERT(!TlsContext.get());
     150             : 
     151           4 :     JSRuntime* runtime = js_new<JSRuntime>(parentRuntime);
     152           4 :     if (!runtime)
     153           0 :         return nullptr;
     154             : 
     155           4 :     JSContext* cx = js_new<JSContext>(runtime, JS::ContextOptions());
     156           4 :     if (!cx) {
     157           0 :         js_delete(runtime);
     158           0 :         return nullptr;
     159             :     }
     160             : 
     161           4 :     if (!runtime->init(cx, maxBytes, maxNurseryBytes)) {
     162           0 :         runtime->destroyRuntime();
     163           0 :         js_delete(cx);
     164           0 :         js_delete(runtime);
     165           0 :         return nullptr;
     166             :     }
     167             : 
     168           4 :     if (!cx->init(ContextKind::Cooperative)) {
     169           0 :         runtime->destroyRuntime();
     170           0 :         js_delete(cx);
     171           0 :         js_delete(runtime);
     172           0 :         return nullptr;
     173             :     }
     174             : 
     175           4 :     return cx;
     176             : }
     177             : 
     178             : JSContext*
     179           0 : js::NewCooperativeContext(JSContext* siblingContext)
     180             : {
     181           0 :     MOZ_RELEASE_ASSERT(!TlsContext.get());
     182             : 
     183           0 :     JSRuntime* runtime = siblingContext->runtime();
     184             : 
     185           0 :     JSContext* cx = js_new<JSContext>(runtime, JS::ContextOptions());
     186           0 :     if (!cx || !cx->init(ContextKind::Cooperative)) {
     187           0 :         js_delete(cx);
     188           0 :         return nullptr;
     189             :     }
     190             : 
     191           0 :     runtime->setNewbornActiveContext(cx);
     192           0 :     return cx;
     193             : }
     194             : 
     195             : void
     196           0 : js::YieldCooperativeContext(JSContext* cx)
     197             : {
     198           0 :     MOZ_ASSERT(cx == TlsContext.get());
     199           0 :     MOZ_ASSERT(cx->runtime()->activeContext() == cx);
     200           0 :     cx->runtime()->setActiveContext(nullptr);
     201           0 : }
     202             : 
     203             : void
     204           0 : js::ResumeCooperativeContext(JSContext* cx)
     205             : {
     206           0 :     MOZ_ASSERT(cx == TlsContext.get());
     207           0 :     MOZ_ASSERT(cx->runtime()->activeContext() == nullptr);
     208           0 :     cx->runtime()->setActiveContext(cx);
     209           0 : }
     210             : 
     211             : static void
     212           0 : FreeJobQueueHandling(JSContext* cx)
     213             : {
     214           0 :     if (!cx->jobQueue)
     215           0 :         return;
     216             : 
     217           0 :     cx->jobQueue->reset();
     218           0 :     FreeOp* fop = cx->defaultFreeOp();
     219           0 :     fop->delete_(cx->jobQueue.ref());
     220           0 :     cx->getIncumbentGlobalCallback = nullptr;
     221           0 :     cx->enqueuePromiseJobCallback = nullptr;
     222           0 :     cx->enqueuePromiseJobCallbackData = nullptr;
     223             : }
     224             : 
     225             : void
     226           0 : js::DestroyContext(JSContext* cx)
     227             : {
     228           0 :     JS_AbortIfWrongThread(cx);
     229             : 
     230           0 :     if (cx->outstandingRequests != 0)
     231           0 :         MOZ_CRASH("Attempted to destroy a context while it is in a request.");
     232             : 
     233           0 :     cx->checkNoGCRooters();
     234             : 
     235             :     // Cancel all off thread Ion compiles before destroying a cooperative
     236             :     // context. Completed Ion compiles may try to interrupt arbitrary
     237             :     // cooperative contexts which they have read off the owner context of a
     238             :     // zone group. See HelperThread::handleIonWorkload.
     239           0 :     CancelOffThreadIonCompile(cx->runtime());
     240             : 
     241           0 :     FreeJobQueueHandling(cx);
     242             : 
     243           0 :     if (cx->runtime()->cooperatingContexts().length() == 1) {
     244             :         // Destroy the runtime along with its last context.
     245           0 :         cx->runtime()->destroyRuntime();
     246           0 :         js_delete(cx->runtime());
     247             : 
     248           0 :         js_delete_poison(cx);
     249             :     } else {
     250           0 :         DebugOnly<bool> found = false;
     251           0 :         for (size_t i = 0; i < cx->runtime()->cooperatingContexts().length(); i++) {
     252           0 :             CooperatingContext& target = cx->runtime()->cooperatingContexts()[i];
     253           0 :             if (cx == target.context()) {
     254           0 :                 cx->runtime()->cooperatingContexts().erase(&target);
     255           0 :                 found = true;
     256           0 :                 break;
     257             :             }
     258             :         }
     259           0 :         MOZ_ASSERT(found);
     260             : 
     261           0 :         cx->runtime()->deleteActiveContext(cx);
     262             :     }
     263           0 : }
     264             : 
     265             : void
     266           0 : JS::RootingContext::checkNoGCRooters() {
     267             : #ifdef DEBUG
     268           0 :     for (auto const& stackRootPtr : stackRoots_)
     269           0 :         MOZ_ASSERT(stackRootPtr == nullptr);
     270             : #endif
     271           0 : }
     272             : 
     273             : bool
     274        1013 : AutoResolving::alreadyStartedSlow() const
     275             : {
     276        1013 :     MOZ_ASSERT(link);
     277        1013 :     AutoResolving* cursor = link;
     278        1013 :     do {
     279        1013 :         MOZ_ASSERT(this != cursor);
     280        1013 :         if (object.get() == cursor->object && id.get() == cursor->id && kind == cursor->kind)
     281           0 :             return true;
     282        1013 :     } while (!!(cursor = cursor->link));
     283        1013 :     return false;
     284             : }
     285             : 
     286             : static void
     287           2 : ReportError(JSContext* cx, JSErrorReport* reportp, JSErrorCallback callback,
     288             :             void* userRef)
     289             : {
     290             :     /*
     291             :      * Check the error report, and set a JavaScript-catchable exception
     292             :      * if the error is defined to have an associated exception.  If an
     293             :      * exception is thrown, then the JSREPORT_EXCEPTION flag will be set
     294             :      * on the error report, and exception-aware hosts should ignore it.
     295             :      */
     296           2 :     MOZ_ASSERT(reportp);
     297           4 :     if ((!callback || callback == GetErrorMessage) &&
     298           2 :         reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
     299             :     {
     300           0 :         reportp->flags |= JSREPORT_EXCEPTION;
     301             :     }
     302             : 
     303           2 :     if (JSREPORT_IS_WARNING(reportp->flags)) {
     304           0 :         CallWarningReporter(cx, reportp);
     305           0 :         return;
     306             :     }
     307             : 
     308           2 :     ErrorToException(cx, reportp, callback, userRef);
     309             : }
     310             : 
     311             : /*
     312             :  * The given JSErrorReport object have been zeroed and must not outlive
     313             :  * cx->fp() (otherwise owned fields may become invalid).
     314             :  */
     315             : static void
     316           2 : PopulateReportBlame(JSContext* cx, JSErrorReport* report)
     317             : {
     318           2 :     JSCompartment* compartment = cx->compartment();
     319           2 :     if (!compartment)
     320           0 :         return;
     321             : 
     322             :     /*
     323             :      * Walk stack until we find a frame that is associated with a non-builtin
     324             :      * rather than a builtin frame and which we're allowed to know about.
     325             :      */
     326           4 :     NonBuiltinFrameIter iter(cx, compartment->principals());
     327           2 :     if (iter.done())
     328           0 :         return;
     329             : 
     330           2 :     report->filename = iter.filename();
     331           2 :     report->lineno = iter.computeLine(&report->column);
     332             :     // XXX: Make the column 1-based as in other browsers, instead of 0-based
     333             :     // which is how SpiderMonkey stores it internally. This will be
     334             :     // unnecessary once bug 1144340 is fixed.
     335           2 :     report->column++;
     336           2 :     report->isMuted = iter.mutedErrors();
     337             : }
     338             : 
     339             : /*
     340             :  * Since memory has been exhausted, avoid the normal error-handling path which
     341             :  * allocates an error object, report and callstack. If code is running, simply
     342             :  * throw the static atom "out of memory". If code is not running, call the
     343             :  * error reporter directly.
     344             :  *
     345             :  * Furthermore, callers of ReportOutOfMemory (viz., malloc) assume a GC does
     346             :  * not occur, so GC must be avoided or suppressed.
     347             :  */
     348             : void
     349           0 : js::ReportOutOfMemory(JSContext* cx)
     350             : {
     351             : #ifdef JS_MORE_DETERMINISTIC
     352             :     /*
     353             :      * OOMs are non-deterministic, especially across different execution modes
     354             :      * (e.g. interpreter vs JIT). In more-deterministic builds, print to stderr
     355             :      * so that the fuzzers can detect this.
     356             :      */
     357             :     fprintf(stderr, "ReportOutOfMemory called\n");
     358             : #endif
     359             : 
     360           0 :     if (cx->helperThread())
     361           0 :         return cx->addPendingOutOfMemory();
     362             : 
     363           0 :     cx->runtime()->hadOutOfMemory = true;
     364           0 :     AutoSuppressGC suppressGC(cx);
     365             : 
     366             :     /* Report the oom. */
     367           0 :     if (JS::OutOfMemoryCallback oomCallback = cx->runtime()->oomCallback)
     368           0 :         oomCallback(cx, cx->runtime()->oomCallbackData);
     369             : 
     370           0 :     cx->setPendingException(StringValue(cx->names().outOfMemory));
     371             : }
     372             : 
     373             : mozilla::GenericErrorResult<OOM&>
     374           0 : js::ReportOutOfMemoryResult(JSContext* cx)
     375             : {
     376           0 :     ReportOutOfMemory(cx);
     377           0 :     return cx->alreadyReportedOOM();
     378             : }
     379             : 
     380             : void
     381           0 : js::ReportOverRecursed(JSContext* maybecx, unsigned errorNumber)
     382             : {
     383             : #ifdef JS_MORE_DETERMINISTIC
     384             :     /*
     385             :      * We cannot make stack depth deterministic across different
     386             :      * implementations (e.g. JIT vs. interpreter will differ in
     387             :      * their maximum stack depth).
     388             :      * However, we can detect externally when we hit the maximum
     389             :      * stack depth which is useful for external testing programs
     390             :      * like fuzzers.
     391             :      */
     392             :     fprintf(stderr, "ReportOverRecursed called\n");
     393             : #endif
     394           0 :     if (maybecx) {
     395           0 :         if (!maybecx->helperThread()) {
     396           0 :             JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr, errorNumber);
     397           0 :             maybecx->overRecursed_ = true;
     398             :         } else {
     399           0 :             maybecx->addPendingOverRecursed();
     400             :         }
     401             :     }
     402           0 : }
     403             : 
     404             : JS_FRIEND_API(void)
     405           0 : js::ReportOverRecursed(JSContext* maybecx)
     406             : {
     407           0 :     ReportOverRecursed(maybecx, JSMSG_OVER_RECURSED);
     408           0 : }
     409             : 
     410             : void
     411           0 : js::ReportAllocationOverflow(JSContext* cx)
     412             : {
     413           0 :     if (!cx)
     414           0 :         return;
     415             : 
     416           0 :     if (cx->helperThread())
     417           0 :         return;
     418             : 
     419           0 :     AutoSuppressGC suppressGC(cx);
     420           0 :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ALLOC_OVERFLOW);
     421             : }
     422             : 
     423             : /*
     424             :  * Given flags and the state of cx, decide whether we should report an
     425             :  * error, a warning, or just continue execution normally.  Return
     426             :  * true if we should continue normally, without reporting anything;
     427             :  * otherwise, adjust *flags as appropriate and return false.
     428             :  */
     429             : static bool
     430           2 : checkReportFlags(JSContext* cx, unsigned* flags)
     431             : {
     432           2 :     if (JSREPORT_IS_STRICT(*flags)) {
     433             :         /* Warning/error only when JSOPTION_STRICT is set. */
     434           0 :         if (!cx->compartment()->behaviors().extraWarnings(cx))
     435           0 :             return true;
     436             :     }
     437             : 
     438             :     /* Warnings become errors when JSOPTION_WERROR is set. */
     439           2 :     if (JSREPORT_IS_WARNING(*flags) && cx->options().werror())
     440           0 :         *flags &= ~JSREPORT_WARNING;
     441             : 
     442           2 :     return false;
     443             : }
     444             : 
     445             : bool
     446           0 : js::ReportErrorVA(JSContext* cx, unsigned flags, const char* format,
     447             :                   ErrorArgumentsType argumentsType, va_list ap)
     448             : {
     449           0 :     JSErrorReport report;
     450             : 
     451           0 :     if (checkReportFlags(cx, &flags))
     452           0 :         return true;
     453             : 
     454           0 :     UniqueChars message(JS_vsmprintf(format, ap));
     455           0 :     if (!message) {
     456           0 :         ReportOutOfMemory(cx);
     457           0 :         return false;
     458             :     }
     459             : 
     460           0 :     MOZ_ASSERT_IF(argumentsType == ArgumentsAreASCII, JS::StringIsASCII(message.get()));
     461             : 
     462           0 :     report.flags = flags;
     463           0 :     report.errorNumber = JSMSG_USER_DEFINED_ERROR;
     464           0 :     if (argumentsType == ArgumentsAreASCII || argumentsType == ArgumentsAreUTF8) {
     465           0 :         report.initOwnedMessage(message.release());
     466             :     } else {
     467           0 :         MOZ_ASSERT(argumentsType == ArgumentsAreLatin1);
     468           0 :         Latin1Chars latin1(message.get(), strlen(message.get()));
     469           0 :         UTF8CharsZ utf8(JS::CharsToNewUTF8CharsZ(cx, latin1));
     470           0 :         if (!utf8)
     471           0 :             return false;
     472           0 :         report.initOwnedMessage(reinterpret_cast<const char*>(utf8.get()));
     473             :     }
     474           0 :     PopulateReportBlame(cx, &report);
     475             : 
     476           0 :     bool warning = JSREPORT_IS_WARNING(report.flags);
     477             : 
     478           0 :     ReportError(cx, &report, nullptr, nullptr);
     479           0 :     return warning;
     480             : }
     481             : 
     482             : /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
     483             : void
     484           0 : js::ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg)
     485             : {
     486           0 :     const char* usageStr = "usage";
     487           0 :     PropertyName* usageAtom = Atomize(cx, usageStr, strlen(usageStr))->asPropertyName();
     488           0 :     RootedId id(cx, NameToId(usageAtom));
     489           0 :     DebugOnly<Shape*> shape = static_cast<Shape*>(callee->as<JSFunction>().lookup(cx, id));
     490           0 :     MOZ_ASSERT(!shape->configurable());
     491           0 :     MOZ_ASSERT(!shape->writable());
     492           0 :     MOZ_ASSERT(shape->hasDefaultGetter());
     493             : 
     494           0 :     RootedValue usage(cx);
     495           0 :     if (!JS_GetProperty(cx, callee, "usage", &usage))
     496           0 :         return;
     497             : 
     498           0 :     if (!usage.isString()) {
     499           0 :         JS_ReportErrorASCII(cx, "%s", msg);
     500             :     } else {
     501           0 :         RootedString usageStr(cx, usage.toString());
     502           0 :         JSAutoByteString str;
     503           0 :         if (!str.encodeUtf8(cx, usageStr))
     504           0 :             return;
     505           0 :         JS_ReportErrorUTF8(cx, "%s. Usage: %s", msg, str.ptr());
     506             :     }
     507             : }
     508             : 
     509             : enum class PrintErrorKind {
     510             :     Error,
     511             :     Warning,
     512             :     StrictWarning,
     513             :     Note
     514             : };
     515             : 
     516             : static void
     517           0 : PrintErrorLine(JSContext* cx, FILE* file, const char* prefix, JSErrorReport* report)
     518             : {
     519           0 :     if (const char16_t* linebuf = report->linebuf()) {
     520           0 :         size_t n = report->linebufLength();
     521             : 
     522           0 :         fputs(":\n", file);
     523           0 :         if (prefix)
     524           0 :             fputs(prefix, file);
     525             : 
     526           0 :         for (size_t i = 0; i < n; i++)
     527           0 :             fputc(static_cast<char>(linebuf[i]), file);
     528             : 
     529             :         // linebuf usually ends with a newline. If not, add one here.
     530           0 :         if (n == 0 || linebuf[n-1] != '\n')
     531           0 :             fputc('\n', file);
     532             : 
     533           0 :         if (prefix)
     534           0 :             fputs(prefix, file);
     535             : 
     536           0 :         n = report->tokenOffset();
     537           0 :         for (size_t i = 0, j = 0; i < n; i++) {
     538           0 :             if (linebuf[i] == '\t') {
     539           0 :                 for (size_t k = (j + 8) & ~7; j < k; j++)
     540           0 :                     fputc('.', file);
     541           0 :                 continue;
     542             :             }
     543           0 :             fputc('.', file);
     544           0 :             j++;
     545             :         }
     546           0 :         fputc('^', file);
     547             :     }
     548           0 : }
     549             : 
     550             : static void
     551           0 : PrintErrorLine(JSContext* cx, FILE* file, const char* prefix, JSErrorNotes::Note* note)
     552             : {
     553           0 : }
     554             : 
     555             : template <typename T>
     556             : static bool
     557           0 : PrintSingleError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
     558             :                  T* report, PrintErrorKind kind)
     559             : {
     560           0 :     UniqueChars prefix;
     561           0 :     if (report->filename)
     562           0 :         prefix = JS_smprintf("%s:", report->filename);
     563             : 
     564           0 :     if (report->lineno) {
     565           0 :         prefix = JS_smprintf("%s%u:%u ", prefix ? prefix.get() : "", report->lineno,
     566             :                                         report->column);
     567             :     }
     568             : 
     569           0 :     if (kind != PrintErrorKind::Error) {
     570           0 :         const char* kindPrefix = nullptr;
     571           0 :         switch (kind) {
     572             :           case PrintErrorKind::Error:
     573           0 :             MOZ_CRASH("unreachable");
     574             :           case PrintErrorKind::Warning:
     575           0 :             kindPrefix = "warning";
     576           0 :             break;
     577             :           case PrintErrorKind::StrictWarning:
     578           0 :             kindPrefix = "strict warning";
     579           0 :             break;
     580             :           case PrintErrorKind::Note:
     581           0 :             kindPrefix = "note";
     582           0 :             break;
     583             :         }
     584             : 
     585           0 :         prefix = JS_smprintf("%s%s: ", prefix ? prefix.get() : "", kindPrefix);
     586             :     }
     587             : 
     588           0 :     const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str();
     589             : 
     590             :     /* embedded newlines -- argh! */
     591             :     const char* ctmp;
     592           0 :     while ((ctmp = strchr(message, '\n')) != 0) {
     593           0 :         ctmp++;
     594           0 :         if (prefix)
     595           0 :             fputs(prefix.get(), file);
     596           0 :         fwrite(message, 1, ctmp - message, file);
     597           0 :         message = ctmp;
     598             :     }
     599             : 
     600             :     /* If there were no filename or lineno, the prefix might be empty */
     601           0 :     if (prefix)
     602           0 :         fputs(prefix.get(), file);
     603           0 :     fputs(message, file);
     604             : 
     605           0 :     PrintErrorLine(cx, file, prefix.get(), report);
     606           0 :     fputc('\n', file);
     607             : 
     608           0 :     fflush(file);
     609           0 :     return true;
     610             : }
     611             : 
     612             : bool
     613           0 : js::PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
     614             :                JSErrorReport* report, bool reportWarnings)
     615             : {
     616           0 :     MOZ_ASSERT(report);
     617             : 
     618             :     /* Conditionally ignore reported warnings. */
     619           0 :     if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings)
     620           0 :         return false;
     621             : 
     622           0 :     PrintErrorKind kind = PrintErrorKind::Error;
     623           0 :     if (JSREPORT_IS_WARNING(report->flags)) {
     624           0 :         if (JSREPORT_IS_STRICT(report->flags))
     625           0 :             kind = PrintErrorKind::StrictWarning;
     626             :         else
     627           0 :             kind = PrintErrorKind::Warning;
     628             :     }
     629           0 :     PrintSingleError(cx, file, toStringResult, report, kind);
     630             : 
     631           0 :     if (report->notes) {
     632           0 :         for (auto&& note : *report->notes)
     633           0 :             PrintSingleError(cx, file, JS::ConstUTF8CharsZ(), note.get(), PrintErrorKind::Note);
     634             :     }
     635             : 
     636           0 :     return true;
     637             : }
     638             : 
     639             : class MOZ_RAII AutoMessageArgs
     640             : {
     641             :     size_t totalLength_;
     642             :     /* only {0} thru {9} supported */
     643             :     mozilla::Array<const char*, JS::MaxNumErrorArguments> args_;
     644             :     mozilla::Array<size_t, JS::MaxNumErrorArguments> lengths_;
     645             :     uint16_t count_;
     646             :     bool allocatedElements_ : 1;
     647             : 
     648             :   public:
     649           2 :     AutoMessageArgs()
     650           2 :       : totalLength_(0), count_(0), allocatedElements_(false)
     651             :     {
     652           2 :         PodArrayZero(args_);
     653           2 :     }
     654             : 
     655           2 :     ~AutoMessageArgs()
     656           2 :     {
     657             :         /* free the arguments only if we allocated them */
     658           2 :         if (allocatedElements_) {
     659           2 :             uint16_t i = 0;
     660          10 :             while (i < count_) {
     661           4 :                 if (args_[i])
     662           4 :                     js_free((void*)args_[i]);
     663           4 :                 i++;
     664             :             }
     665             :         }
     666           2 :     }
     667             : 
     668           4 :     const char* args(size_t i) const {
     669           4 :         MOZ_ASSERT(i < count_);
     670           4 :         return args_[i];
     671             :     }
     672             : 
     673           2 :     size_t totalLength() const {
     674           2 :         return totalLength_;
     675             :     }
     676             : 
     677           8 :     size_t lengths(size_t i) const {
     678           8 :         MOZ_ASSERT(i < count_);
     679           8 :         return lengths_[i];
     680             :     }
     681             : 
     682           8 :     uint16_t count() const {
     683           8 :         return count_;
     684             :     }
     685             : 
     686             :     /* Gather the arguments into an array, and accumulate their sizes. */
     687           2 :     bool init(JSContext* cx, const char16_t** argsArg, uint16_t countArg,
     688             :               ErrorArgumentsType typeArg, va_list ap) {
     689           2 :         MOZ_ASSERT(countArg > 0);
     690             : 
     691           2 :         count_ = countArg;
     692             : 
     693           6 :         for (uint16_t i = 0; i < count_; i++) {
     694           4 :             switch (typeArg) {
     695             :               case ArgumentsAreASCII:
     696             :               case ArgumentsAreUTF8: {
     697           0 :                 MOZ_ASSERT(!argsArg);
     698           0 :                 args_[i] = va_arg(ap, char*);
     699           0 :                 MOZ_ASSERT_IF(typeArg == ArgumentsAreASCII, JS::StringIsASCII(args_[i]));
     700           0 :                 lengths_[i] = strlen(args_[i]);
     701           0 :                 break;
     702             :               }
     703             :               case ArgumentsAreLatin1: {
     704           4 :                 MOZ_ASSERT(!argsArg);
     705           4 :                 const Latin1Char* latin1 = va_arg(ap, Latin1Char*);
     706           4 :                 size_t len = strlen(reinterpret_cast<const char*>(latin1));
     707           4 :                 mozilla::Range<const Latin1Char> range(latin1, len);
     708           4 :                 char* utf8 = JS::CharsToNewUTF8CharsZ(cx, range).c_str();
     709           4 :                 if (!utf8)
     710           0 :                     return false;
     711             : 
     712           4 :                 args_[i] = utf8;
     713           4 :                 lengths_[i] = strlen(utf8);
     714           4 :                 allocatedElements_ = true;
     715           4 :                 break;
     716             :               }
     717             :               case ArgumentsAreUnicode: {
     718           0 :                 const char16_t* uc = argsArg ? argsArg[i] : va_arg(ap, char16_t*);
     719           0 :                 size_t len = js_strlen(uc);
     720           0 :                 mozilla::Range<const char16_t> range(uc, len);
     721           0 :                 char* utf8 = JS::CharsToNewUTF8CharsZ(cx, range).c_str();
     722           0 :                 if (!utf8)
     723           0 :                     return false;
     724             : 
     725           0 :                 args_[i] = utf8;
     726           0 :                 lengths_[i] = strlen(utf8);
     727           0 :                 allocatedElements_ = true;
     728           0 :                 break;
     729             :               }
     730             :             }
     731           4 :             totalLength_ += lengths_[i];
     732             :         }
     733           2 :         return true;
     734             :     }
     735             : };
     736             : 
     737             : static void
     738           2 : SetExnType(JSErrorReport* reportp, int16_t exnType)
     739             : {
     740           2 :     reportp->exnType = exnType;
     741           2 : }
     742             : 
     743             : static void
     744           0 : SetExnType(JSErrorNotes::Note* notep, int16_t exnType)
     745             : {
     746             :     // Do nothing for JSErrorNotes::Note.
     747           0 : }
     748             : 
     749             : /*
     750             :  * The arguments from ap need to be packaged up into an array and stored
     751             :  * into the report struct.
     752             :  *
     753             :  * The format string addressed by the error number may contain operands
     754             :  * identified by the format {N}, where N is a decimal digit. Each of these
     755             :  * is to be replaced by the Nth argument from the va_list. The complete
     756             :  * message is placed into reportp->message_.
     757             :  *
     758             :  * Returns true if the expansion succeeds (can fail if out of memory).
     759             :  */
     760             : template <typename T>
     761             : bool
     762           2 : ExpandErrorArgumentsHelper(JSContext* cx, JSErrorCallback callback,
     763             :                            void* userRef, const unsigned errorNumber,
     764             :                            const char16_t** messageArgs,
     765             :                            ErrorArgumentsType argumentsType,
     766             :                            T* reportp, va_list ap)
     767             : {
     768             :     const JSErrorFormatString* efs;
     769             : 
     770           2 :     if (!callback)
     771           0 :         callback = GetErrorMessage;
     772             : 
     773             :     {
     774           4 :         AutoSuppressGC suppressGC(cx);
     775           2 :         efs = callback(userRef, errorNumber);
     776             :     }
     777             : 
     778           2 :     if (efs) {
     779           2 :         SetExnType(reportp, efs->exnType);
     780             : 
     781           2 :         MOZ_ASSERT_IF(argumentsType == ArgumentsAreASCII, JS::StringIsASCII(efs->format));
     782             : 
     783           2 :         uint16_t argCount = efs->argCount;
     784           2 :         MOZ_RELEASE_ASSERT(argCount <= JS::MaxNumErrorArguments);
     785           2 :         if (argCount > 0) {
     786             :             /*
     787             :              * Parse the error format, substituting the argument X
     788             :              * for {X} in the format.
     789             :              */
     790           2 :             if (efs->format) {
     791             :                 const char* fmt;
     792             :                 char* out;
     793             : #ifdef DEBUG
     794           2 :                 int expandedArgs = 0;
     795             : #endif
     796             :                 size_t expandedLength;
     797           2 :                 size_t len = strlen(efs->format);
     798             : 
     799           4 :                 AutoMessageArgs args;
     800           2 :                 if (!args.init(cx, messageArgs, argCount, argumentsType, ap))
     801           0 :                     return false;
     802             : 
     803           2 :                 expandedLength = len
     804           2 :                                  - (3 * args.count()) /* exclude the {n} */
     805           2 :                                  + args.totalLength();
     806             : 
     807             :                 /*
     808             :                 * Note - the above calculation assumes that each argument
     809             :                 * is used once and only once in the expansion !!!
     810             :                 */
     811           2 :                 char* utf8 = out = cx->pod_malloc<char>(expandedLength + 1);
     812           2 :                 if (!out)
     813           0 :                     return false;
     814             : 
     815           2 :                 fmt = efs->format;
     816          26 :                 while (*fmt) {
     817          12 :                     if (*fmt == '{') {
     818           4 :                         if (isdigit(fmt[1])) {
     819           4 :                             int d = JS7_UNDEC(fmt[1]);
     820           4 :                             MOZ_RELEASE_ASSERT(d < args.count());
     821           4 :                             strncpy(out, args.args(d), args.lengths(d));
     822           4 :                             out += args.lengths(d);
     823           4 :                             fmt += 3;
     824             : #ifdef DEBUG
     825           4 :                             expandedArgs++;
     826             : #endif
     827           4 :                             continue;
     828             :                         }
     829             :                     }
     830           8 :                     *out++ = *fmt++;
     831             :                 }
     832           2 :                 MOZ_ASSERT(expandedArgs == args.count());
     833           2 :                 *out = 0;
     834             : 
     835           2 :                 reportp->initOwnedMessage(utf8);
     836             :             }
     837             :         } else {
     838             :             /* Non-null messageArgs should have at least one non-null arg. */
     839           0 :             MOZ_ASSERT(!messageArgs);
     840             :             /*
     841             :              * Zero arguments: the format string (if it exists) is the
     842             :              * entire message.
     843             :              */
     844           0 :             if (efs->format)
     845           0 :                 reportp->initBorrowedMessage(efs->format);
     846             :         }
     847             :     }
     848           2 :     if (!reportp->message()) {
     849             :         /* where's the right place for this ??? */
     850             :         const char* defaultErrorMessage
     851           0 :             = "No error message available for error number %d";
     852           0 :         size_t nbytes = strlen(defaultErrorMessage) + 16;
     853           0 :         char* message = cx->pod_malloc<char>(nbytes);
     854           0 :         if (!message)
     855           0 :             return false;
     856           0 :         snprintf(message, nbytes, defaultErrorMessage, errorNumber);
     857           0 :         reportp->initOwnedMessage(message);
     858             :     }
     859           2 :     return true;
     860             : }
     861             : 
     862             : bool
     863           2 : js::ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
     864             :                            void* userRef, const unsigned errorNumber,
     865             :                            const char16_t** messageArgs,
     866             :                            ErrorArgumentsType argumentsType,
     867             :                            JSErrorReport* reportp, va_list ap)
     868             : {
     869             :     return ExpandErrorArgumentsHelper(cx, callback, userRef, errorNumber,
     870           2 :                                       messageArgs, argumentsType, reportp, ap);
     871             : }
     872             : 
     873             : bool
     874           0 : js::ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
     875             :                            void* userRef, const unsigned errorNumber,
     876             :                            const char16_t** messageArgs,
     877             :                            ErrorArgumentsType argumentsType,
     878             :                            JSErrorNotes::Note* notep, va_list ap)
     879             : {
     880             :     return ExpandErrorArgumentsHelper(cx, callback, userRef, errorNumber,
     881           0 :                                       messageArgs, argumentsType, notep, ap);
     882             : }
     883             : 
     884             : bool
     885           2 : js::ReportErrorNumberVA(JSContext* cx, unsigned flags, JSErrorCallback callback,
     886             :                         void* userRef, const unsigned errorNumber,
     887             :                         ErrorArgumentsType argumentsType, va_list ap)
     888             : {
     889           4 :     JSErrorReport report;
     890             :     bool warning;
     891             : 
     892           2 :     if (checkReportFlags(cx, &flags))
     893           0 :         return true;
     894           2 :     warning = JSREPORT_IS_WARNING(flags);
     895             : 
     896           2 :     report.flags = flags;
     897           2 :     report.errorNumber = errorNumber;
     898           2 :     PopulateReportBlame(cx, &report);
     899             : 
     900           2 :     if (!ExpandErrorArgumentsVA(cx, callback, userRef, errorNumber,
     901             :                                 nullptr, argumentsType, &report, ap)) {
     902           0 :         return false;
     903             :     }
     904             : 
     905           2 :     ReportError(cx, &report, callback, userRef);
     906             : 
     907           2 :     return warning;
     908             : }
     909             : 
     910             : static bool
     911           0 : ExpandErrorArguments(JSContext* cx, JSErrorCallback callback,
     912             :                      void* userRef, const unsigned errorNumber,
     913             :                      const char16_t** messageArgs,
     914             :                      ErrorArgumentsType argumentsType,
     915             :                      JSErrorReport* reportp, ...)
     916             : {
     917             :     va_list ap;
     918           0 :     va_start(ap, reportp);
     919             :     bool expanded = js::ExpandErrorArgumentsVA(cx, callback, userRef, errorNumber,
     920           0 :                                                messageArgs, argumentsType, reportp, ap);
     921           0 :     va_end(ap);
     922           0 :     return expanded;
     923             : }
     924             : 
     925             : bool
     926           0 : js::ReportErrorNumberUCArray(JSContext* cx, unsigned flags, JSErrorCallback callback,
     927             :                              void* userRef, const unsigned errorNumber,
     928             :                              const char16_t** args)
     929             : {
     930           0 :     if (checkReportFlags(cx, &flags))
     931           0 :         return true;
     932           0 :     bool warning = JSREPORT_IS_WARNING(flags);
     933             : 
     934           0 :     JSErrorReport report;
     935           0 :     report.flags = flags;
     936           0 :     report.errorNumber = errorNumber;
     937           0 :     PopulateReportBlame(cx, &report);
     938             : 
     939           0 :     if (!ExpandErrorArguments(cx, callback, userRef, errorNumber,
     940             :                               args, ArgumentsAreUnicode, &report))
     941             :     {
     942           0 :         return false;
     943             :     }
     944             : 
     945           0 :     ReportError(cx, &report, callback, userRef);
     946             : 
     947           0 :     return warning;
     948             : }
     949             : 
     950             : bool
     951           0 : js::ReportIsNotDefined(JSContext* cx, HandleId id)
     952             : {
     953           0 :     JSAutoByteString printable;
     954           0 :     if (ValueToPrintable(cx, IdToValue(id), &printable)) {
     955           0 :         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_DEFINED,
     956           0 :                                    printable.ptr());
     957             :     }
     958           0 :     return false;
     959             : }
     960             : 
     961             : bool
     962           0 : js::ReportIsNotDefined(JSContext* cx, HandlePropertyName name)
     963             : {
     964           0 :     RootedId id(cx, NameToId(name));
     965           0 :     return ReportIsNotDefined(cx, id);
     966             : }
     967             : 
     968             : bool
     969           2 : js::ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v,
     970             :                             HandleString fallback)
     971             : {
     972             :     bool ok;
     973             : 
     974           4 :     UniqueChars bytes = DecompileValueGenerator(cx, spindex, v, fallback);
     975           2 :     if (!bytes)
     976           0 :         return false;
     977             : 
     978           4 :     if (strcmp(bytes.get(), js_undefined_str) == 0 ||
     979           2 :         strcmp(bytes.get(), js_null_str) == 0) {
     980           0 :         ok = JS_ReportErrorFlagsAndNumberLatin1(cx, JSREPORT_ERROR,
     981             :                                                 GetErrorMessage, nullptr,
     982             :                                                 JSMSG_NO_PROPERTIES,
     983           0 :                                                 bytes.get());
     984           2 :     } else if (v.isUndefined()) {
     985           1 :         ok = JS_ReportErrorFlagsAndNumberLatin1(cx, JSREPORT_ERROR,
     986             :                                                 GetErrorMessage, nullptr,
     987             :                                                 JSMSG_UNEXPECTED_TYPE,
     988           1 :                                                 bytes.get(), js_undefined_str);
     989             :     } else {
     990           1 :         MOZ_ASSERT(v.isNull());
     991           1 :         ok = JS_ReportErrorFlagsAndNumberLatin1(cx, JSREPORT_ERROR,
     992             :                                                 GetErrorMessage, nullptr,
     993             :                                                 JSMSG_UNEXPECTED_TYPE,
     994           1 :                                                 bytes.get(), js_null_str);
     995             :     }
     996             : 
     997           2 :     return ok;
     998             : }
     999             : 
    1000             : void
    1001           0 : js::ReportMissingArg(JSContext* cx, HandleValue v, unsigned arg)
    1002             : {
    1003             :     char argbuf[11];
    1004           0 :     UniqueChars bytes;
    1005             : 
    1006           0 :     SprintfLiteral(argbuf, "%u", arg);
    1007           0 :     if (IsFunctionObject(v)) {
    1008           0 :         RootedAtom name(cx, v.toObject().as<JSFunction>().explicitName());
    1009           0 :         bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, name);
    1010           0 :         if (!bytes)
    1011           0 :             return;
    1012             :     }
    1013           0 :     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1014             :                                JSMSG_MISSING_FUN_ARG,
    1015           0 :                                argbuf, bytes ? bytes.get() : "");
    1016             : }
    1017             : 
    1018             : bool
    1019           0 : js::ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNumber,
    1020             :                           int spindex, HandleValue v, HandleString fallback,
    1021             :                           const char* arg1, const char* arg2)
    1022             : {
    1023           0 :     UniqueChars bytes;
    1024             :     bool ok;
    1025             : 
    1026           0 :     MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
    1027           0 :     MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
    1028           0 :     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
    1029           0 :     if (!bytes)
    1030           0 :         return false;
    1031             : 
    1032           0 :     ok = JS_ReportErrorFlagsAndNumberLatin1(cx, flags, GetErrorMessage, nullptr, errorNumber,
    1033           0 :                                             bytes.get(), arg1, arg2);
    1034           0 :     return ok;
    1035             : }
    1036             : 
    1037             : JSObject*
    1038           0 : js::CreateErrorNotesArray(JSContext* cx, JSErrorReport* report)
    1039             : {
    1040           0 :     RootedArrayObject notesArray(cx, NewDenseEmptyArray(cx));
    1041           0 :     if (!notesArray)
    1042           0 :         return nullptr;
    1043             : 
    1044           0 :     if (!report->notes)
    1045           0 :         return notesArray;
    1046             : 
    1047           0 :     for (auto&& note : *report->notes) {
    1048           0 :         RootedPlainObject noteObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
    1049           0 :         if (!noteObj)
    1050           0 :             return nullptr;
    1051             : 
    1052           0 :         RootedString messageStr(cx, note->newMessageString(cx));
    1053           0 :         if (!messageStr)
    1054           0 :             return nullptr;
    1055           0 :         RootedValue messageVal(cx, StringValue(messageStr));
    1056           0 :         if (!DefineProperty(cx, noteObj, cx->names().message, messageVal))
    1057           0 :             return nullptr;
    1058             : 
    1059           0 :         RootedValue filenameVal(cx);
    1060           0 :         if (note->filename) {
    1061           0 :             RootedString filenameStr(cx, NewStringCopyZ<CanGC>(cx, note->filename));
    1062           0 :             if (!filenameStr)
    1063           0 :                 return nullptr;
    1064           0 :             filenameVal = StringValue(filenameStr);
    1065             :         }
    1066           0 :         if (!DefineProperty(cx, noteObj, cx->names().fileName, filenameVal))
    1067           0 :             return nullptr;
    1068             : 
    1069           0 :         RootedValue linenoVal(cx, Int32Value(note->lineno));
    1070           0 :         if (!DefineProperty(cx, noteObj, cx->names().lineNumber, linenoVal))
    1071           0 :             return nullptr;
    1072           0 :         RootedValue columnVal(cx, Int32Value(note->column));
    1073           0 :         if (!DefineProperty(cx, noteObj, cx->names().columnNumber, columnVal))
    1074           0 :             return nullptr;
    1075             : 
    1076           0 :         if (!NewbornArrayPush(cx, notesArray, ObjectValue(*noteObj)))
    1077           0 :             return nullptr;
    1078             :     }
    1079             : 
    1080           0 :     return notesArray;
    1081             : }
    1082             : 
    1083             : const JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
    1084             : #define MSG_DEF(name, count, exception, format) \
    1085             :     { #name, format, count, exception } ,
    1086             : #include "js.msg"
    1087             : #undef MSG_DEF
    1088             : };
    1089             : 
    1090             : JS_FRIEND_API(const JSErrorFormatString*)
    1091           4 : js::GetErrorMessage(void* userRef, const unsigned errorNumber)
    1092             : {
    1093           4 :     if (errorNumber > 0 && errorNumber < JSErr_Limit)
    1094           4 :         return &js_ErrorFormatString[errorNumber];
    1095           0 :     return nullptr;
    1096             : }
    1097             : 
    1098             : void
    1099           0 : JSContext::recoverFromOutOfMemory()
    1100             : {
    1101           0 :     if (helperThread()) {
    1102             :         // Keep in sync with addPendingOutOfMemory.
    1103           0 :         if (ParseTask* task = helperThread()->parseTask())
    1104           0 :             task->outOfMemory = false;
    1105             :     } else {
    1106           0 :         if (isExceptionPending()) {
    1107           0 :             MOZ_ASSERT(isThrowingOutOfMemory());
    1108           0 :             clearPendingException();
    1109             :         }
    1110             :     }
    1111           0 : }
    1112             : 
    1113             : static bool
    1114           0 : InternalEnqueuePromiseJobCallback(JSContext* cx, JS::HandleObject job,
    1115             :                                   JS::HandleObject allocationSite,
    1116             :                                   JS::HandleObject incumbentGlobal, void* data)
    1117             : {
    1118           0 :     MOZ_ASSERT(job);
    1119           0 :     return cx->jobQueue->append(job);
    1120             : }
    1121             : 
    1122             : static bool
    1123           0 : InternalStartAsyncTaskCallback(JSContext* cx, JS::AsyncTask* task)
    1124             : {
    1125           0 :     task->user = cx;
    1126             : 
    1127           0 :     ExclusiveData<InternalAsyncTasks>::Guard asyncTasks = cx->asyncTasks.lock();
    1128           0 :     asyncTasks->outstanding++;
    1129           0 :     return true;
    1130             : }
    1131             : 
    1132             : static bool
    1133           0 : InternalFinishAsyncTaskCallback(JS::AsyncTask* task)
    1134             : {
    1135           0 :     JSContext* cx = (JSContext*)task->user;
    1136             : 
    1137           0 :     ExclusiveData<InternalAsyncTasks>::Guard asyncTasks = cx->asyncTasks.lock();
    1138           0 :     MOZ_ASSERT(asyncTasks->outstanding > 0);
    1139           0 :     asyncTasks->outstanding--;
    1140           0 :     return asyncTasks->finished.append(task);
    1141             : }
    1142             : 
    1143             : namespace {
    1144             : class MOZ_STACK_CLASS ReportExceptionClosure : public ScriptEnvironmentPreparer::Closure
    1145             : {
    1146             :   public:
    1147           0 :     explicit ReportExceptionClosure(HandleValue exn)
    1148           0 :         : exn_(exn)
    1149             :     {
    1150           0 :     }
    1151             : 
    1152           0 :     bool operator()(JSContext* cx) override
    1153             :     {
    1154           0 :         cx->setPendingException(exn_);
    1155           0 :         return false;
    1156             :     }
    1157             : 
    1158             :   private:
    1159             :     HandleValue exn_;
    1160             : };
    1161             : } // anonymous namespace
    1162             : 
    1163             : JS_FRIEND_API(bool)
    1164           0 : js::UseInternalJobQueues(JSContext* cx)
    1165             : {
    1166             :     // Internal job queue handling must be set up very early. Self-hosting
    1167             :     // initialization is as good a marker for that as any.
    1168           0 :     MOZ_RELEASE_ASSERT(!cx->runtime()->hasInitializedSelfHosting(),
    1169             :                        "js::UseInternalJobQueues must be called early during runtime startup.");
    1170           0 :     MOZ_ASSERT(!cx->jobQueue);
    1171           0 :     auto* queue = cx->new_<PersistentRooted<JobQueue>>(cx, JobQueue(SystemAllocPolicy()));
    1172           0 :     if (!queue)
    1173           0 :         return false;
    1174             : 
    1175           0 :     cx->jobQueue = queue;
    1176             : 
    1177           0 :     JS::SetEnqueuePromiseJobCallback(cx, InternalEnqueuePromiseJobCallback);
    1178           0 :     JS::SetAsyncTaskCallbacks(cx, InternalStartAsyncTaskCallback, InternalFinishAsyncTaskCallback);
    1179             : 
    1180           0 :     return true;
    1181             : }
    1182             : 
    1183             : JS_FRIEND_API(void)
    1184           0 : js::StopDrainingJobQueue(JSContext* cx)
    1185             : {
    1186           0 :     MOZ_ASSERT(cx->jobQueue);
    1187           0 :     cx->stopDrainingJobQueue = true;
    1188           0 : }
    1189             : 
    1190             : JS_FRIEND_API(void)
    1191           0 : js::RunJobs(JSContext* cx)
    1192             : {
    1193           0 :     MOZ_ASSERT(cx->jobQueue);
    1194             : 
    1195           0 :     if (cx->drainingJobQueue || cx->stopDrainingJobQueue)
    1196           0 :         return;
    1197             : 
    1198             :     while (true) {
    1199             :         // Wait for any outstanding async tasks to finish so that the
    1200             :         // finishedAsyncTasks list is fixed.
    1201             :         while (true) {
    1202           0 :             AutoLockHelperThreadState lock;
    1203           0 :             if (!cx->asyncTasks.lock()->outstanding)
    1204           0 :                 break;
    1205           0 :             HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
    1206           0 :         }
    1207             : 
    1208             :         // Lock the whole time while copying back the asyncTasks finished queue
    1209             :         // so that any new tasks created during finish() cannot racily join the
    1210             :         // job queue.  Call finish() only thereafter, to avoid a circular mutex
    1211             :         // dependency (see also bug 1297901).
    1212           0 :         Vector<JS::AsyncTask*, 0, SystemAllocPolicy> finished;
    1213             :         {
    1214           0 :             ExclusiveData<InternalAsyncTasks>::Guard asyncTasks = cx->asyncTasks.lock();
    1215           0 :             finished = Move(asyncTasks->finished);
    1216           0 :             asyncTasks->finished.clear();
    1217             :         }
    1218             : 
    1219           0 :         for (JS::AsyncTask* task : finished)
    1220           0 :             task->finish(cx);
    1221             : 
    1222             :         // It doesn't make sense for job queue draining to be reentrant. At the
    1223             :         // same time we don't want to assert against it, because that'd make
    1224             :         // drainJobQueue unsafe for fuzzers. We do want fuzzers to test this,
    1225             :         // so we simply ignore nested calls of drainJobQueue.
    1226           0 :         cx->drainingJobQueue = true;
    1227             : 
    1228           0 :         RootedObject job(cx);
    1229           0 :         JS::HandleValueArray args(JS::HandleValueArray::empty());
    1230           0 :         RootedValue rval(cx);
    1231             : 
    1232             :         // Execute jobs in a loop until we've reached the end of the queue.
    1233             :         // Since executing a job can trigger enqueuing of additional jobs,
    1234             :         // it's crucial to re-check the queue length during each iteration.
    1235           0 :         for (size_t i = 0; i < cx->jobQueue->length(); i++) {
    1236             :             // A previous job might have set this flag. E.g., the js shell
    1237             :             // sets it if the `quit` builtin function is called.
    1238           0 :             if (cx->stopDrainingJobQueue)
    1239           0 :                 break;
    1240             : 
    1241           0 :             job = cx->jobQueue->get()[i];
    1242             : 
    1243             :             // It's possible that queue draining was interrupted prematurely,
    1244             :             // leaving the queue partly processed. In that case, slots for
    1245             :             // already-executed entries will contain nullptrs, which we should
    1246             :             // just skip.
    1247           0 :             if (!job)
    1248           0 :                 continue;
    1249             : 
    1250           0 :             cx->jobQueue->get()[i] = nullptr;
    1251           0 :             AutoCompartment ac(cx, job);
    1252             :             {
    1253           0 :                 if (!JS::Call(cx, UndefinedHandleValue, job, args, &rval)) {
    1254             :                     // Nothing we can do about uncatchable exceptions.
    1255           0 :                     if (!cx->isExceptionPending())
    1256           0 :                         continue;
    1257           0 :                     RootedValue exn(cx);
    1258           0 :                     if (cx->getPendingException(&exn)) {
    1259             :                         /*
    1260             :                          * Clear the exception, because
    1261             :                          * PrepareScriptEnvironmentAndInvoke will assert that we don't
    1262             :                          * have one.
    1263             :                          */
    1264           0 :                         cx->clearPendingException();
    1265           0 :                         ReportExceptionClosure reportExn(exn);
    1266           0 :                         PrepareScriptEnvironmentAndInvoke(cx, cx->global(), reportExn);
    1267             :                     }
    1268             :                 }
    1269             :             }
    1270             :         }
    1271             : 
    1272           0 :         cx->drainingJobQueue = false;
    1273             : 
    1274           0 :         if (cx->stopDrainingJobQueue) {
    1275           0 :             cx->stopDrainingJobQueue = false;
    1276           0 :             break;
    1277             :         }
    1278             : 
    1279           0 :         cx->jobQueue->clear();
    1280             : 
    1281             :         // It's possible a job added an async task, and it's also possible
    1282             :         // that task has already finished.
    1283             :         {
    1284           0 :             ExclusiveData<InternalAsyncTasks>::Guard asyncTasks = cx->asyncTasks.lock();
    1285           0 :             if (asyncTasks->outstanding == 0 && asyncTasks->finished.length() == 0)
    1286           0 :                 break;
    1287             :         }
    1288           0 :     }
    1289             : }
    1290             : 
    1291             : JS::Error JSContext::reportedError;
    1292             : JS::OOM JSContext::reportedOOM;
    1293             : 
    1294             : mozilla::GenericErrorResult<OOM&>
    1295           0 : JSContext::alreadyReportedOOM()
    1296             : {
    1297             : #ifdef DEBUG
    1298           0 :     if (helperThread()) {
    1299             :         // Keep in sync with addPendingOutOfMemory.
    1300           0 :         if (ParseTask* task = helperThread()->parseTask())
    1301           0 :             MOZ_ASSERT(task->outOfMemory);
    1302             :     } else {
    1303           0 :         MOZ_ASSERT(isThrowingOutOfMemory());
    1304             :     }
    1305             : #endif
    1306           0 :     return mozilla::Err(reportedOOM);
    1307             : }
    1308             : 
    1309             : mozilla::GenericErrorResult<JS::Error&>
    1310           0 : JSContext::alreadyReportedError()
    1311             : {
    1312             : #ifdef DEBUG
    1313           0 :     if (!helperThread())
    1314           0 :         MOZ_ASSERT(isExceptionPending());
    1315             : #endif
    1316           0 :     return mozilla::Err(reportedError);
    1317             : }
    1318             : 
    1319          40 : JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
    1320             :   : runtime_(runtime),
    1321             :     kind_(ContextKind::Background),
    1322             :     threadNative_(0),
    1323             :     helperThread_(nullptr),
    1324             :     options_(options),
    1325             :     arenas_(nullptr),
    1326             :     enterCompartmentDepth_(0),
    1327             :     jitActivation(nullptr),
    1328             :     activation_(nullptr),
    1329             :     profilingActivation_(nullptr),
    1330          40 :     nativeStackBase(GetNativeStackBase()),
    1331             :     entryMonitor(nullptr),
    1332             :     noExecuteDebuggerTop(nullptr),
    1333             :     handlingSegFault(false),
    1334             :     activityCallback(nullptr),
    1335             :     activityCallbackArg(nullptr),
    1336             :     requestDepth(0),
    1337             : #ifdef DEBUG
    1338             :     checkRequestDepth(0),
    1339             : #endif
    1340             : #ifdef JS_SIMULATOR
    1341             :     simulator_(nullptr),
    1342             : #endif
    1343             : #ifdef JS_TRACE_LOGGING
    1344             :     traceLogger(nullptr),
    1345             : #endif
    1346             :     autoFlushICache_(nullptr),
    1347             :     dtoaState(nullptr),
    1348             :     heapState(JS::HeapState::Idle),
    1349             :     suppressGC(0),
    1350             : #ifdef DEBUG
    1351             :     ionCompiling(false),
    1352             :     ionCompilingSafeForMinorGC(false),
    1353             :     performingGC(false),
    1354             :     gcSweeping(false),
    1355             :     gcHelperStateThread(false),
    1356             :     noGCOrAllocationCheck(0),
    1357             :     noNurseryAllocationCheck(0),
    1358             :     disableStrictProxyCheckingCount(0),
    1359             : #endif
    1360             : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
    1361             :     runningOOMTest(false),
    1362             : #endif
    1363             :     enableAccessValidation(false),
    1364             :     inUnsafeRegion(0),
    1365             :     generationalDisabled(0),
    1366             :     compactingDisabledCount(0),
    1367             :     keepAtoms(0),
    1368             :     suppressProfilerSampling(false),
    1369             :     tempLifoAlloc_((size_t)TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
    1370             :     debuggerMutations(0),
    1371             :     propertyRemovals(0),
    1372             :     ionPcScriptCache(nullptr),
    1373             :     throwing(false),
    1374             :     overRecursed_(false),
    1375             :     propagatingForcedReturn_(false),
    1376             :     liveVolatileJitFrameIterators_(nullptr),
    1377             :     reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
    1378             :     resolvingList(nullptr),
    1379             : #ifdef DEBUG
    1380             :     enteredPolicy(nullptr),
    1381             : #endif
    1382             :     generatingError(false),
    1383             :     cycleDetectorVector_(this),
    1384             :     data(nullptr),
    1385             :     outstandingRequests(0),
    1386             :     jitIsBroken(false),
    1387             :     asyncCauseForNewActivations(nullptr),
    1388             :     asyncCallIsExplicit(false),
    1389             :     interruptCallbackDisabled(false),
    1390             :     interrupt_(false),
    1391             :     handlingJitInterrupt_(false),
    1392             :     osrTempData_(nullptr),
    1393          80 :     ionReturnOverride_(MagicValue(JS_ARG_POISON)),
    1394             :     jitStackLimit(UINTPTR_MAX),
    1395             :     jitStackLimitNoInterrupt(UINTPTR_MAX),
    1396             :     getIncumbentGlobalCallback(nullptr),
    1397             :     enqueuePromiseJobCallback(nullptr),
    1398             :     enqueuePromiseJobCallbackData(nullptr),
    1399             :     jobQueue(nullptr),
    1400             :     drainingJobQueue(false),
    1401             :     stopDrainingJobQueue(false),
    1402             :     asyncTasks(mutexid::InternalAsyncTasks),
    1403             :     promiseRejectionTrackerCallback(nullptr),
    1404         160 :     promiseRejectionTrackerCallbackData(nullptr)
    1405             : {
    1406          40 :     MOZ_ASSERT(static_cast<JS::RootingContext*>(this) ==
    1407             :                JS::RootingContext::get(this));
    1408             : 
    1409          40 :     MOZ_ASSERT(!TlsContext.get());
    1410          40 :     TlsContext.set(this);
    1411             : 
    1412         160 :     for (size_t i = 0; i < mozilla::ArrayLength(nativeStackQuota); i++)
    1413         120 :         nativeStackQuota[i] = 0;
    1414          40 : }
    1415             : 
    1416           0 : JSContext::~JSContext()
    1417             : {
    1418             :     // Clear the ContextKind first, so that ProtectedData checks will allow us to
    1419             :     // destroy this context even if the runtime is already gone.
    1420           0 :     kind_ = ContextKind::Background;
    1421             : 
    1422             : #ifdef XP_WIN
    1423             :     if (threadNative_)
    1424             :         CloseHandle((HANDLE)threadNative_.ref());
    1425             : #endif
    1426             : 
    1427             :     /* Free the stuff hanging off of cx. */
    1428           0 :     MOZ_ASSERT(!resolvingList);
    1429             : 
    1430           0 :     js_delete(ionPcScriptCache.ref());
    1431             : 
    1432           0 :     if (dtoaState)
    1433           0 :         DestroyDtoaState(dtoaState);
    1434             : 
    1435           0 :     fx.destroyInstance();
    1436           0 :     freeOsrTempData();
    1437             : 
    1438             : #ifdef JS_SIMULATOR
    1439             :     js::jit::Simulator::Destroy(simulator_);
    1440             : #endif
    1441             : 
    1442             : #ifdef JS_TRACE_LOGGING
    1443           0 :     if (traceLogger)
    1444           0 :         DestroyTraceLogger(traceLogger);
    1445             : #endif
    1446             : 
    1447           0 :     MOZ_ASSERT(TlsContext.get() == this);
    1448           0 :     TlsContext.set(nullptr);
    1449           0 : }
    1450             : 
    1451             : void
    1452          93 : JSContext::setRuntime(JSRuntime* rt)
    1453             : {
    1454          93 :     MOZ_ASSERT(!resolvingList);
    1455          93 :     MOZ_ASSERT(!compartment());
    1456          93 :     MOZ_ASSERT(!activation());
    1457          93 :     MOZ_ASSERT(!unwrappedException_.ref().initialized());
    1458          93 :     MOZ_ASSERT(!asyncStackForNewActivations_.ref().initialized());
    1459             : 
    1460          93 :     runtime_ = rt;
    1461          93 : }
    1462             : 
    1463             : bool
    1464        2071 : JSContext::getPendingException(MutableHandleValue rval)
    1465             : {
    1466        2071 :     MOZ_ASSERT(throwing);
    1467        2071 :     rval.set(unwrappedException());
    1468        2071 :     if (IsAtomsCompartment(compartment()))
    1469           0 :         return true;
    1470        2071 :     bool wasOverRecursed = overRecursed_;
    1471        2071 :     clearPendingException();
    1472        2071 :     if (!compartment()->wrap(this, rval))
    1473           0 :         return false;
    1474        2071 :     assertSameCompartment(this, rval);
    1475        2071 :     setPendingException(rval);
    1476        2071 :     overRecursed_ = wasOverRecursed;
    1477        2071 :     return true;
    1478             : }
    1479             : 
    1480             : bool
    1481           3 : JSContext::isThrowingOutOfMemory()
    1482             : {
    1483           3 :     return throwing && unwrappedException() == StringValue(names().outOfMemory);
    1484             : }
    1485             : 
    1486             : bool
    1487        4142 : JSContext::isClosingGenerator()
    1488             : {
    1489        4142 :     return throwing && unwrappedException().isMagic(JS_GENERATOR_CLOSING);
    1490             : }
    1491             : 
    1492             : bool
    1493           0 : JSContext::isThrowingDebuggeeWouldRun()
    1494             : {
    1495           0 :     return throwing &&
    1496           0 :            unwrappedException().isObject() &&
    1497           0 :            unwrappedException().toObject().is<ErrorObject>() &&
    1498           0 :            unwrappedException().toObject().as<ErrorObject>().type() == JSEXN_DEBUGGEEWOULDRUN;
    1499             : }
    1500             : 
    1501             : static bool
    1502           0 : ComputeIsJITBroken()
    1503             : {
    1504             : #if !defined(ANDROID)
    1505           0 :     return false;
    1506             : #else  // ANDROID
    1507             :     if (getenv("JS_IGNORE_JIT_BROKENNESS")) {
    1508             :         return false;
    1509             :     }
    1510             : 
    1511             :     std::string line;
    1512             : 
    1513             :     // Check for the known-bad kernel version (2.6.29).
    1514             :     std::ifstream osrelease("/proc/sys/kernel/osrelease");
    1515             :     std::getline(osrelease, line);
    1516             :     __android_log_print(ANDROID_LOG_INFO, "Gecko", "Detected osrelease `%s'",
    1517             :                         line.c_str());
    1518             : 
    1519             :     if (line.npos == line.find("2.6.29")) {
    1520             :         // We're using something other than 2.6.29, so the JITs should work.
    1521             :         __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are not broken");
    1522             :         return false;
    1523             :     }
    1524             : 
    1525             :     // We're using 2.6.29, and this causes trouble with the JITs on i9000.
    1526             :     line = "";
    1527             :     bool broken = false;
    1528             :     std::ifstream cpuinfo("/proc/cpuinfo");
    1529             :     do {
    1530             :         if (0 == line.find("Hardware")) {
    1531             :             static const char* const blacklist[] = {
    1532             :                 "SCH-I400",     // Samsung Continuum
    1533             :                 "SGH-T959",     // Samsung i9000, Vibrant device
    1534             :                 "SGH-I897",     // Samsung i9000, Captivate device
    1535             :                 "SCH-I500",     // Samsung i9000, Fascinate device
    1536             :                 "SPH-D700",     // Samsung i9000, Epic device
    1537             :                 "GT-I9000",     // Samsung i9000, UK/Europe device
    1538             :                 nullptr
    1539             :             };
    1540             :             for (const char* const* hw = &blacklist[0]; *hw; ++hw) {
    1541             :                 if (line.npos != line.find(*hw)) {
    1542             :                     __android_log_print(ANDROID_LOG_INFO, "Gecko",
    1543             :                                         "Blacklisted device `%s'", *hw);
    1544             :                     broken = true;
    1545             :                     break;
    1546             :                 }
    1547             :             }
    1548             :             break;
    1549             :         }
    1550             :         std::getline(cpuinfo, line);
    1551             :     } while(!cpuinfo.fail() && !cpuinfo.eof());
    1552             : 
    1553             :     __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are %sbroken",
    1554             :                         broken ? "" : "not ");
    1555             : 
    1556             :     return broken;
    1557             : #endif  // ifndef ANDROID
    1558             : }
    1559             : 
    1560             : static bool
    1561           0 : IsJITBrokenHere()
    1562             : {
    1563             :     static bool computedIsBroken = false;
    1564             :     static bool isBroken = false;
    1565           0 :     if (!computedIsBroken) {
    1566           0 :         isBroken = ComputeIsJITBroken();
    1567           0 :         computedIsBroken = true;
    1568             :     }
    1569           0 :     return isBroken;
    1570             : }
    1571             : 
    1572             : void
    1573           0 : JSContext::updateJITEnabled()
    1574             : {
    1575           0 :     jitIsBroken = IsJITBrokenHere();
    1576           0 : }
    1577             : 
    1578             : size_t
    1579           0 : JSContext::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
    1580             : {
    1581             :     /*
    1582             :      * There are other JSContext members that could be measured; the following
    1583             :      * ones have been found by DMD to be worth measuring.  More stuff may be
    1584             :      * added later.
    1585             :      */
    1586           0 :     return cycleDetectorVector().sizeOfExcludingThis(mallocSizeOf);
    1587             : }
    1588             : 
    1589             : void
    1590          22 : JSContext::trace(JSTracer* trc)
    1591             : {
    1592          22 :     cycleDetectorVector().trace(trc);
    1593             : 
    1594          22 :     if (trc->isMarkingTracer() && compartment_)
    1595           0 :         compartment_->mark();
    1596          22 : }
    1597             : 
    1598             : void*
    1599           0 : JSContext::stackLimitAddressForJitCode(JS::StackKind kind)
    1600             : {
    1601             : #ifdef JS_SIMULATOR
    1602             :     return addressOfSimulatorStackLimit();
    1603             : #else
    1604           0 :     return stackLimitAddress(kind);
    1605             : #endif
    1606             : }
    1607             : 
    1608             : uintptr_t
    1609           0 : JSContext::stackLimitForJitCode(JS::StackKind kind)
    1610             : {
    1611             : #ifdef JS_SIMULATOR
    1612             :     return simulator()->stackLimit();
    1613             : #else
    1614           0 :     return stackLimit(kind);
    1615             : #endif
    1616             : }
    1617             : 
    1618             : void
    1619          31 : JSContext::resetJitStackLimit()
    1620             : {
    1621             :     // Note that, for now, we use the untrusted limit for ion. This is fine,
    1622             :     // because it's the most conservative limit, and if we hit it, we'll bail
    1623             :     // out of ion into the interpreter, which will do a proper recursion check.
    1624             : #ifdef JS_SIMULATOR
    1625             :     jitStackLimit = jit::Simulator::StackLimit();
    1626             : #else
    1627          31 :     jitStackLimit = nativeStackLimit[JS::StackForUntrustedScript];
    1628             : #endif
    1629          31 :     jitStackLimitNoInterrupt = jitStackLimit;
    1630          31 : }
    1631             : 
    1632             : void
    1633           4 : JSContext::initJitStackLimit()
    1634             : {
    1635           4 :     resetJitStackLimit();
    1636           4 : }
    1637             : 
    1638             : JSVersion
    1639       10807 : JSContext::findVersion()
    1640             : {
    1641       10807 :     if (JSScript* script = currentScript(nullptr, ALLOW_CROSS_COMPARTMENT))
    1642        6316 :         return script->getVersion();
    1643             : 
    1644        4491 :     if (compartment() && compartment()->behaviors().version() != JSVERSION_UNKNOWN)
    1645        1079 :         return compartment()->behaviors().version();
    1646             : 
    1647        3412 :     if (!CurrentThreadCanAccessRuntime(runtime()))
    1648           0 :         return JSVERSION_DEFAULT;
    1649             : 
    1650        3412 :     return runtime()->defaultVersion();
    1651             : }
    1652             : 
    1653             : #ifdef DEBUG
    1654             : 
    1655      708322 : JS::AutoCheckRequestDepth::AutoCheckRequestDepth(JSContext* cxArg)
    1656      708322 :   : cx(cxArg->helperThread() ? nullptr : cxArg)
    1657             : {
    1658      708372 :     if (cx) {
    1659      633365 :         MOZ_ASSERT(cx->requestDepth || JS::CurrentThreadIsHeapBusy());
    1660      633374 :         MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
    1661      633374 :         cx->checkRequestDepth++;
    1662             :     }
    1663      708381 : }
    1664             : 
    1665     1416689 : JS::AutoCheckRequestDepth::~AutoCheckRequestDepth()
    1666             : {
    1667      708342 :     if (cx) {
    1668      633366 :         MOZ_ASSERT(cx->checkRequestDepth != 0);
    1669      633367 :         cx->checkRequestDepth--;
    1670             :     }
    1671      708347 : }
    1672             : 
    1673             : #endif
    1674             : 
    1675             : #ifdef JS_CRASH_DIAGNOSTICS
    1676             : void
    1677           0 : CompartmentChecker::check(InterpreterFrame* fp)
    1678             : {
    1679           0 :     if (fp)
    1680           0 :         check(fp->environmentChain());
    1681           0 : }
    1682             : 
    1683             : void
    1684       18549 : CompartmentChecker::check(AbstractFramePtr frame)
    1685             : {
    1686       18549 :     if (frame)
    1687       18549 :         check(frame.environmentChain());
    1688       18549 : }
    1689             : #endif
    1690             : 
    1691             : void
    1692           0 : AutoEnterOOMUnsafeRegion::crash(const char* reason)
    1693             : {
    1694             :     char msgbuf[1024];
    1695           0 :     SprintfLiteral(msgbuf, "[unhandlable oom] %s", reason);
    1696           0 :     MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
    1697           0 :     MOZ_CRASH();
    1698             : }
    1699             : 
    1700             : AutoEnterOOMUnsafeRegion::AnnotateOOMAllocationSizeCallback
    1701             : AutoEnterOOMUnsafeRegion::annotateOOMSizeCallback = nullptr;
    1702             : 
    1703             : void
    1704           0 : AutoEnterOOMUnsafeRegion::crash(size_t size, const char* reason)
    1705             : {
    1706             :     {
    1707           0 :         JS::AutoSuppressGCAnalysis suppress;
    1708           0 :         if (annotateOOMSizeCallback)
    1709           0 :             annotateOOMSizeCallback(size);
    1710             :     }
    1711           0 :     crash(reason);
    1712             : }

Generated by: LCOV version 1.13