js/src/jscntxt.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     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/. */
     7 /*
     8  * JS execution context.
     9  */
    11 #include "jscntxtinlines.h"
    13 #include "mozilla/ArrayUtils.h"
    14 #include "mozilla/DebugOnly.h"
    15 #include "mozilla/MemoryReporting.h"
    17 #include <ctype.h>
    18 #include <stdarg.h>
    19 #include <string.h>
    20 #ifdef ANDROID
    21 # include <android/log.h>
    22 # include <fstream>
    23 # include <string>
    24 #endif  // ANDROID
    26 #include "jsatom.h"
    27 #include "jscompartment.h"
    28 #include "jsexn.h"
    29 #include "jsfun.h"
    30 #include "jsgc.h"
    31 #include "jsiter.h"
    32 #include "jsobj.h"
    33 #include "jsopcode.h"
    34 #include "jsprf.h"
    35 #include "jspubtd.h"
    36 #include "jsscript.h"
    37 #include "jsstr.h"
    38 #include "jstypes.h"
    39 #include "jswatchpoint.h"
    40 #include "jsworkers.h"
    42 #include "gc/Marking.h"
    43 #ifdef JS_ION
    44 #include "jit/Ion.h"
    45 #endif
    46 #include "js/CharacterEncoding.h"
    47 #include "js/OldDebugAPI.h"
    48 #include "vm/Shape.h"
    49 #include "yarr/BumpPointerAllocator.h"
    51 #include "jsobjinlines.h"
    52 #include "jsscriptinlines.h"
    54 #include "vm/Stack-inl.h"
    56 using namespace js;
    57 using namespace js::gc;
    59 using mozilla::DebugOnly;
    60 using mozilla::PodArrayZero;
    61 using mozilla::PodZero;
    62 using mozilla::PointerRangeSize;
    64 bool
    65 js::AutoCycleDetector::init()
    66 {
    67     ObjectSet &set = cx->cycleDetectorSet;
    68     hashsetAddPointer = set.lookupForAdd(obj);
    69     if (!hashsetAddPointer) {
    70         if (!set.add(hashsetAddPointer, obj))
    71             return false;
    72         cyclic = false;
    73         hashsetGenerationAtInit = set.generation();
    74     }
    75     return true;
    76 }
    78 js::AutoCycleDetector::~AutoCycleDetector()
    79 {
    80     if (!cyclic) {
    81         if (hashsetGenerationAtInit == cx->cycleDetectorSet.generation())
    82             cx->cycleDetectorSet.remove(hashsetAddPointer);
    83         else
    84             cx->cycleDetectorSet.remove(obj);
    85     }
    86 }
    88 void
    89 js::TraceCycleDetectionSet(JSTracer *trc, js::ObjectSet &set)
    90 {
    91     for (js::ObjectSet::Enum e(set); !e.empty(); e.popFront()) {
    92         JSObject *prior = e.front();
    93         MarkObjectRoot(trc, const_cast<JSObject **>(&e.front()), "cycle detector table entry");
    94         if (prior != e.front())
    95             e.rekeyFront(e.front());
    96     }
    97 }
    99 void
   100 JSCompartment::sweepCallsiteClones()
   101 {
   102     if (callsiteClones.initialized()) {
   103         for (CallsiteCloneTable::Enum e(callsiteClones); !e.empty(); e.popFront()) {
   104             CallsiteCloneKey key = e.front().key();
   105             JSFunction *fun = e.front().value();
   106             if (!IsScriptMarked(&key.script) || !IsObjectMarked(&fun))
   107                 e.removeFront();
   108         }
   109     }
   110 }
   112 JSFunction *
   113 js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction *fun,
   114                                     JSScript *script, jsbytecode *pc)
   115 {
   116     JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite());
   117     JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope());
   118     JS_ASSERT(types::UseNewTypeForClone(fun));
   120     /*
   121      * If we start allocating function objects in the nursery, then the callsite
   122      * clone table will need a postbarrier.
   123      */
   124     JS_ASSERT(fun->isTenured());
   126     if (!table.initialized())
   127         return nullptr;
   129     CallsiteCloneTable::Ptr p = table.readonlyThreadsafeLookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc)));
   130     if (p)
   131         return p->value();
   133     return nullptr;
   134 }
   136 JSFunction *
   137 js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript script, jsbytecode *pc)
   138 {
   139     if (JSFunction *clone = ExistingCloneFunctionAtCallsite(cx->compartment()->callsiteClones, fun, script, pc))
   140         return clone;
   142     RootedObject parent(cx, fun->environment());
   143     JSFunction *clone = CloneFunctionObject(cx, fun, parent);
   144     if (!clone)
   145         return nullptr;
   147     /*
   148      * Store a link back to the original for function.caller and avoid cloning
   149      * clones.
   150      */
   151     clone->nonLazyScript()->setIsCallsiteClone(fun);
   153     typedef CallsiteCloneKey Key;
   154     typedef CallsiteCloneTable Table;
   156     Table &table = cx->compartment()->callsiteClones;
   157     if (!table.initialized() && !table.init())
   158         return nullptr;
   160     if (!table.putNew(Key(fun, script, script->pcToOffset(pc)), clone))
   161         return nullptr;
   163     return clone;
   164 }
   166 JSContext *
   167 js::NewContext(JSRuntime *rt, size_t stackChunkSize)
   168 {
   169     JS_AbortIfWrongThread(rt);
   171     JSContext *cx = js_new<JSContext>(rt);
   172     if (!cx)
   173         return nullptr;
   175     if (!cx->cycleDetectorSet.init()) {
   176         js_delete(cx);
   177         return nullptr;
   178     }
   180     /*
   181      * Here the GC lock is still held after js_InitContextThreadAndLockGC took it and
   182      * the GC is not running on another thread.
   183      */
   184     rt->contextList.insertBack(cx);
   186     /*
   187      * If cx is the first context on this runtime, initialize well-known atoms,
   188      * keywords, numbers, strings and self-hosted scripts. If one of these
   189      * steps should fail, the runtime will be left in a partially initialized
   190      * state, with zeroes and nulls stored in the default-initialized remainder
   191      * of the struct.
   192      */
   193     if (!rt->haveCreatedContext) {
   194 #ifdef JS_THREADSAFE
   195         JS_BeginRequest(cx);
   196 #endif
   197         bool ok = rt->initializeAtoms(cx);
   198         if (ok)
   199             ok = rt->initSelfHosting(cx);
   201         if (ok && !rt->parentRuntime)
   202             ok = rt->transformToPermanentAtoms();
   204 #ifdef JS_THREADSAFE
   205         JS_EndRequest(cx);
   206 #endif
   207         if (!ok) {
   208             DestroyContext(cx, DCM_NEW_FAILED);
   209             return nullptr;
   210         }
   212         rt->haveCreatedContext = true;
   213     }
   215     JSContextCallback cxCallback = rt->cxCallback;
   216     if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW, rt->cxCallbackData)) {
   217         DestroyContext(cx, DCM_NEW_FAILED);
   218         return nullptr;
   219     }
   221     return cx;
   222 }
   224 void
   225 js::DestroyContext(JSContext *cx, DestroyContextMode mode)
   226 {
   227     JSRuntime *rt = cx->runtime();
   228     JS_AbortIfWrongThread(rt);
   230 #ifdef JS_THREADSAFE
   231     if (cx->outstandingRequests != 0)
   232         MOZ_CRASH();
   233 #endif
   235 #if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG)
   236     for (int i = 0; i < THING_ROOT_LIMIT; ++i)
   237         JS_ASSERT(cx->thingGCRooters[i] == nullptr);
   238 #endif
   240     if (mode != DCM_NEW_FAILED) {
   241         if (JSContextCallback cxCallback = rt->cxCallback) {
   242             /*
   243              * JSCONTEXT_DESTROY callback is not allowed to fail and must
   244              * return true.
   245              */
   246             JS_ALWAYS_TRUE(cxCallback(cx, JSCONTEXT_DESTROY,
   247                                       rt->cxCallbackData));
   248         }
   249     }
   251     cx->remove();
   252     bool last = !rt->hasContexts();
   253     if (last) {
   254         /*
   255          * Dump remaining type inference results while we still have a context.
   256          * This printing depends on atoms still existing.
   257          */
   258         for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
   259             c->types.print(cx, false);
   260     }
   261     if (mode == DCM_FORCE_GC) {
   262         JS_ASSERT(!rt->isHeapBusy());
   263         JS::PrepareForFullGC(rt);
   264         GC(rt, GC_NORMAL, JS::gcreason::DESTROY_CONTEXT);
   265     }
   266     js_delete_poison(cx);
   267 }
   269 bool
   270 AutoResolving::alreadyStartedSlow() const
   271 {
   272     JS_ASSERT(link);
   273     AutoResolving *cursor = link;
   274     do {
   275         JS_ASSERT(this != cursor);
   276         if (object.get() == cursor->object && id.get() == cursor->id && kind == cursor->kind)
   277             return true;
   278     } while (!!(cursor = cursor->link));
   279     return false;
   280 }
   282 static void
   283 ReportError(JSContext *cx, const char *message, JSErrorReport *reportp,
   284             JSErrorCallback callback, void *userRef)
   285 {
   286     /*
   287      * Check the error report, and set a JavaScript-catchable exception
   288      * if the error is defined to have an associated exception.  If an
   289      * exception is thrown, then the JSREPORT_EXCEPTION flag will be set
   290      * on the error report, and exception-aware hosts should ignore it.
   291      */
   292     JS_ASSERT(reportp);
   293     if ((!callback || callback == js_GetErrorMessage) &&
   294         reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
   295     {
   296         reportp->flags |= JSREPORT_EXCEPTION;
   297     }
   299     /*
   300      * Call the error reporter only if an exception wasn't raised.
   301      *
   302      * If an exception was raised, then we call the debugErrorHook
   303      * (if present) to give it a chance to see the error before it
   304      * propagates out of scope.  This is needed for compatibility
   305      * with the old scheme.
   306      */
   307     if (!JS_IsRunning(cx) || !js_ErrorToException(cx, message, reportp, callback, userRef)) {
   308         if (message)
   309             CallErrorReporter(cx, message, reportp);
   310     } else if (JSDebugErrorHook hook = cx->runtime()->debugHooks.debugErrorHook) {
   311         /*
   312          * If we've already chewed up all the C stack, don't call into the
   313          * error reporter since this may trigger an infinite recursion where
   314          * the reporter triggers an over-recursion.
   315          */
   316         int stackDummy;
   317         if (!JS_CHECK_STACK_SIZE(GetNativeStackLimit(cx), &stackDummy))
   318             return;
   320         if (cx->errorReporter)
   321             hook(cx, message, reportp, cx->runtime()->debugHooks.debugErrorHookData);
   322     }
   323 }
   325 /*
   326  * The given JSErrorReport object have been zeroed and must not outlive
   327  * cx->fp() (otherwise report->originPrincipals may become invalid).
   328  */
   329 static void
   330 PopulateReportBlame(JSContext *cx, JSErrorReport *report)
   331 {
   332     /*
   333      * Walk stack until we find a frame that is associated with a non-builtin
   334      * rather than a builtin frame.
   335      */
   336     NonBuiltinFrameIter iter(cx);
   337     if (iter.done())
   338         return;
   340     report->filename = iter.scriptFilename();
   341     report->lineno = iter.computeLine(&report->column);
   342     report->originPrincipals = iter.originPrincipals();
   343 }
   345 /*
   346  * Since memory has been exhausted, avoid the normal error-handling path which
   347  * allocates an error object, report and callstack. If code is running, simply
   348  * throw the static atom "out of memory". If code is not running, call the
   349  * error reporter directly.
   350  *
   351  * Furthermore, callers of js_ReportOutOfMemory (viz., malloc) assume a GC does
   352  * not occur, so GC must be avoided or suppressed.
   353  */
   354 void
   355 js_ReportOutOfMemory(ThreadSafeContext *cxArg)
   356 {
   357 #ifdef JS_MORE_DETERMINISTIC
   358     /*
   359      * OOMs are non-deterministic, especially across different execution modes
   360      * (e.g. interpreter vs JIT). In more-deterministic builds, print to stderr
   361      * so that the fuzzers can detect this.
   362      */
   363     fprintf(stderr, "js_ReportOutOfMemory called\n");
   364 #endif
   366     if (cxArg->isForkJoinContext()) {
   367         cxArg->asForkJoinContext()->setPendingAbortFatal(ParallelBailoutOutOfMemory);
   368         return;
   369     }
   371     if (!cxArg->isJSContext())
   372         return;
   374     JSContext *cx = cxArg->asJSContext();
   375     cx->runtime()->hadOutOfMemory = true;
   377     /* Report the oom. */
   378     if (JS::OutOfMemoryCallback oomCallback = cx->runtime()->oomCallback) {
   379         AutoSuppressGC suppressGC(cx);
   380         oomCallback(cx);
   381     }
   383     if (JS_IsRunning(cx)) {
   384         cx->setPendingException(StringValue(cx->names().outOfMemory));
   385         return;
   386     }
   388     /* Get the message for this error, but we don't expand any arguments. */
   389     const JSErrorFormatString *efs =
   390         js_GetLocalizedErrorMessage(cx, nullptr, nullptr, JSMSG_OUT_OF_MEMORY);
   391     const char *msg = efs ? efs->format : "Out of memory";
   393     /* Fill out the report, but don't do anything that requires allocation. */
   394     JSErrorReport report;
   395     PodZero(&report);
   396     report.flags = JSREPORT_ERROR;
   397     report.errorNumber = JSMSG_OUT_OF_MEMORY;
   398     PopulateReportBlame(cx, &report);
   400     /* Report the error. */
   401     if (JSErrorReporter onError = cx->errorReporter) {
   402         AutoSuppressGC suppressGC(cx);
   403         onError(cx, msg, &report);
   404     }
   406     /*
   407      * We would like to enforce the invariant that any exception reported
   408      * during an OOM situation does not require wrapping. Besides avoiding
   409      * allocation when memory is low, this reduces the number of places where
   410      * we might need to GC.
   411      *
   412      * When JS code is running, we set the pending exception to an atom, which
   413      * does not need wrapping. If no JS code is running, no exception should be
   414      * set at all.
   415      */
   416     JS_ASSERT(!cx->isExceptionPending());
   417 }
   419 JS_FRIEND_API(void)
   420 js_ReportOverRecursed(JSContext *maybecx)
   421 {
   422 #ifdef JS_MORE_DETERMINISTIC
   423     /*
   424      * We cannot make stack depth deterministic across different
   425      * implementations (e.g. JIT vs. interpreter will differ in
   426      * their maximum stack depth).
   427      * However, we can detect externally when we hit the maximum
   428      * stack depth which is useful for external testing programs
   429      * like fuzzers.
   430      */
   431     fprintf(stderr, "js_ReportOverRecursed called\n");
   432 #endif
   433     if (maybecx)
   434         JS_ReportErrorNumber(maybecx, js_GetErrorMessage, nullptr, JSMSG_OVER_RECURSED);
   435 }
   437 void
   438 js_ReportOverRecursed(ThreadSafeContext *cx)
   439 {
   440     if (cx->isJSContext())
   441         js_ReportOverRecursed(cx->asJSContext());
   442     else if (cx->isExclusiveContext())
   443         cx->asExclusiveContext()->addPendingOverRecursed();
   444 }
   446 void
   447 js_ReportAllocationOverflow(ThreadSafeContext *cxArg)
   448 {
   449     if (!cxArg)
   450         return;
   452     if (cxArg->isForkJoinContext()) {
   453         cxArg->asForkJoinContext()->setPendingAbortFatal(ParallelBailoutOutOfMemory);
   454         return;
   455     }
   457     if (!cxArg->isJSContext())
   458         return;
   459     JSContext *cx = cxArg->asJSContext();
   461     AutoSuppressGC suppressGC(cx);
   462     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_ALLOC_OVERFLOW);
   463 }
   465 /*
   466  * Given flags and the state of cx, decide whether we should report an
   467  * error, a warning, or just continue execution normally.  Return
   468  * true if we should continue normally, without reporting anything;
   469  * otherwise, adjust *flags as appropriate and return false.
   470  */
   471 static bool
   472 checkReportFlags(JSContext *cx, unsigned *flags)
   473 {
   474     if (JSREPORT_IS_STRICT_MODE_ERROR(*flags)) {
   475         /*
   476          * Error in strict code; warning with extra warnings option; okay
   477          * otherwise.  We assume that if the top frame is a native, then it is
   478          * strict if the nearest scripted frame is strict, see bug 536306.
   479          */
   480         JSScript *script = cx->currentScript();
   481         if (script && script->strict())
   482             *flags &= ~JSREPORT_WARNING;
   483         else if (cx->options().extraWarnings())
   484             *flags |= JSREPORT_WARNING;
   485         else
   486             return true;
   487     } else if (JSREPORT_IS_STRICT(*flags)) {
   488         /* Warning/error only when JSOPTION_STRICT is set. */
   489         if (!cx->options().extraWarnings())
   490             return true;
   491     }
   493     /* Warnings become errors when JSOPTION_WERROR is set. */
   494     if (JSREPORT_IS_WARNING(*flags) && cx->options().werror())
   495         *flags &= ~JSREPORT_WARNING;
   497     return false;
   498 }
   500 bool
   501 js_ReportErrorVA(JSContext *cx, unsigned flags, const char *format, va_list ap)
   502 {
   503     char *message;
   504     jschar *ucmessage;
   505     size_t messagelen;
   506     JSErrorReport report;
   507     bool warning;
   509     if (checkReportFlags(cx, &flags))
   510         return true;
   512     message = JS_vsmprintf(format, ap);
   513     if (!message)
   514         return false;
   515     messagelen = strlen(message);
   517     PodZero(&report);
   518     report.flags = flags;
   519     report.errorNumber = JSMSG_USER_DEFINED_ERROR;
   520     report.ucmessage = ucmessage = InflateString(cx, message, &messagelen);
   521     PopulateReportBlame(cx, &report);
   523     warning = JSREPORT_IS_WARNING(report.flags);
   525     ReportError(cx, message, &report, nullptr, nullptr);
   526     js_free(message);
   527     js_free(ucmessage);
   528     return warning;
   529 }
   531 /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
   532 void
   533 js::ReportUsageError(JSContext *cx, HandleObject callee, const char *msg)
   534 {
   535     const char *usageStr = "usage";
   536     PropertyName *usageAtom = Atomize(cx, usageStr, strlen(usageStr))->asPropertyName();
   537     RootedId id(cx, NameToId(usageAtom));
   538     DebugOnly<Shape *> shape = static_cast<Shape *>(callee->nativeLookup(cx, id));
   539     JS_ASSERT(!shape->configurable());
   540     JS_ASSERT(!shape->writable());
   541     JS_ASSERT(shape->hasDefaultGetter());
   543     RootedValue usage(cx);
   544     if (!JS_LookupProperty(cx, callee, "usage", &usage))
   545         return;
   547     if (JSVAL_IS_VOID(usage)) {
   548         JS_ReportError(cx, "%s", msg);
   549     } else {
   550         JSString *str = JSVAL_TO_STRING(usage);
   551         JS::Anchor<JSString *> a_str(str);
   552         const jschar *chars = JS_GetStringCharsZ(cx, str);
   553         if (!chars)
   554             return;
   555         JS_ReportError(cx, "%s. Usage: %hs", msg, chars);
   556     }
   557 }
   559 bool
   560 js::PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *report,
   561                bool reportWarnings)
   562 {
   563     if (!report) {
   564         fprintf(file, "%s\n", message);
   565         fflush(file);
   566         return false;
   567     }
   569     /* Conditionally ignore reported warnings. */
   570     if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings)
   571         return false;
   573     char *prefix = nullptr;
   574     if (report->filename)
   575         prefix = JS_smprintf("%s:", report->filename);
   576     if (report->lineno) {
   577         char *tmp = prefix;
   578         prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column);
   579         JS_free(cx, tmp);
   580     }
   581     if (JSREPORT_IS_WARNING(report->flags)) {
   582         char *tmp = prefix;
   583         prefix = JS_smprintf("%s%swarning: ",
   584                              tmp ? tmp : "",
   585                              JSREPORT_IS_STRICT(report->flags) ? "strict " : "");
   586         JS_free(cx, tmp);
   587     }
   589     /* embedded newlines -- argh! */
   590     const char *ctmp;
   591     while ((ctmp = strchr(message, '\n')) != 0) {
   592         ctmp++;
   593         if (prefix)
   594             fputs(prefix, file);
   595         fwrite(message, 1, ctmp - message, file);
   596         message = ctmp;
   597     }
   599     /* If there were no filename or lineno, the prefix might be empty */
   600     if (prefix)
   601         fputs(prefix, file);
   602     fputs(message, file);
   604     if (report->linebuf) {
   605         /* report->linebuf usually ends with a newline. */
   606         int n = strlen(report->linebuf);
   607         fprintf(file, ":\n%s%s%s%s",
   608                 prefix,
   609                 report->linebuf,
   610                 (n > 0 && report->linebuf[n-1] == '\n') ? "" : "\n",
   611                 prefix);
   612         n = report->tokenptr - report->linebuf;
   613         for (int i = 0, j = 0; i < n; i++) {
   614             if (report->linebuf[i] == '\t') {
   615                 for (int k = (j + 8) & ~7; j < k; j++) {
   616                     fputc('.', file);
   617                 }
   618                 continue;
   619             }
   620             fputc('.', file);
   621             j++;
   622         }
   623         fputc('^', file);
   624     }
   625     fputc('\n', file);
   626     fflush(file);
   627     JS_free(cx, prefix);
   628     return true;
   629 }
   631 char *
   632 js_strdup(ExclusiveContext *cx, const char *s)
   633 {
   634     size_t n = strlen(s) + 1;
   635     void *p = cx->malloc_(n);
   636     if (!p)
   637         return nullptr;
   638     return (char *)js_memcpy(p, s, n);
   639 }
   641 /*
   642  * The arguments from ap need to be packaged up into an array and stored
   643  * into the report struct.
   644  *
   645  * The format string addressed by the error number may contain operands
   646  * identified by the format {N}, where N is a decimal digit. Each of these
   647  * is to be replaced by the Nth argument from the va_list. The complete
   648  * message is placed into reportp->ucmessage converted to a JSString.
   649  *
   650  * Returns true if the expansion succeeds (can fail if out of memory).
   651  */
   652 bool
   653 js_ExpandErrorArguments(ExclusiveContext *cx, JSErrorCallback callback,
   654                         void *userRef, const unsigned errorNumber,
   655                         char **messagep, JSErrorReport *reportp,
   656                         ErrorArgumentsType argumentsType, va_list ap)
   657 {
   658     const JSErrorFormatString *efs;
   659     int i;
   660     int argCount;
   661     bool messageArgsPassed = !!reportp->messageArgs;
   663     *messagep = nullptr;
   665     /* Most calls supply js_GetErrorMessage; if this is so, assume nullptr. */
   666     if (!callback || callback == js_GetErrorMessage)
   667         efs = js_GetLocalizedErrorMessage(cx, userRef, nullptr, errorNumber);
   668     else
   669         efs = callback(userRef, nullptr, errorNumber);
   670     if (efs) {
   671         reportp->exnType = efs->exnType;
   673         size_t totalArgsLength = 0;
   674         size_t argLengths[10]; /* only {0} thru {9} supported */
   675         argCount = efs->argCount;
   676         JS_ASSERT(argCount <= 10);
   677         if (argCount > 0) {
   678             /*
   679              * Gather the arguments into an array, and accumulate
   680              * their sizes. We allocate 1 more than necessary and
   681              * null it out to act as the caboose when we free the
   682              * pointers later.
   683              */
   684             if (messageArgsPassed) {
   685                 JS_ASSERT(!reportp->messageArgs[argCount]);
   686             } else {
   687                 reportp->messageArgs = cx->pod_malloc<const jschar*>(argCount + 1);
   688                 if (!reportp->messageArgs)
   689                     return false;
   690                 /* nullptr-terminate for easy copying. */
   691                 reportp->messageArgs[argCount] = nullptr;
   692             }
   693             for (i = 0; i < argCount; i++) {
   694                 if (messageArgsPassed) {
   695                     /* Do nothing. */
   696                 } else if (argumentsType == ArgumentsAreASCII) {
   697                     char *charArg = va_arg(ap, char *);
   698                     size_t charArgLength = strlen(charArg);
   699                     reportp->messageArgs[i] = InflateString(cx, charArg, &charArgLength);
   700                     if (!reportp->messageArgs[i])
   701                         goto error;
   702                 } else {
   703                     reportp->messageArgs[i] = va_arg(ap, jschar *);
   704                 }
   705                 argLengths[i] = js_strlen(reportp->messageArgs[i]);
   706                 totalArgsLength += argLengths[i];
   707             }
   708         }
   709         /*
   710          * Parse the error format, substituting the argument X
   711          * for {X} in the format.
   712          */
   713         if (argCount > 0) {
   714             if (efs->format) {
   715                 jschar *buffer, *fmt, *out;
   716                 int expandedArgs = 0;
   717                 size_t expandedLength;
   718                 size_t len = strlen(efs->format);
   720                 buffer = fmt = InflateString(cx, efs->format, &len);
   721                 if (!buffer)
   722                     goto error;
   723                 expandedLength = len
   724                                  - (3 * argCount)       /* exclude the {n} */
   725                                  + totalArgsLength;
   727                 /*
   728                 * Note - the above calculation assumes that each argument
   729                 * is used once and only once in the expansion !!!
   730                 */
   731                 reportp->ucmessage = out = cx->pod_malloc<jschar>(expandedLength + 1);
   732                 if (!out) {
   733                     js_free(buffer);
   734                     goto error;
   735                 }
   736                 while (*fmt) {
   737                     if (*fmt == '{') {
   738                         if (isdigit(fmt[1])) {
   739                             int d = JS7_UNDEC(fmt[1]);
   740                             JS_ASSERT(d < argCount);
   741                             js_strncpy(out, reportp->messageArgs[d],
   742                                        argLengths[d]);
   743                             out += argLengths[d];
   744                             fmt += 3;
   745                             expandedArgs++;
   746                             continue;
   747                         }
   748                     }
   749                     *out++ = *fmt++;
   750                 }
   751                 JS_ASSERT(expandedArgs == argCount);
   752                 *out = 0;
   753                 js_free(buffer);
   754                 TwoByteChars ucmsg(reportp->ucmessage,
   755                                    PointerRangeSize(static_cast<const jschar *>(reportp->ucmessage),
   756                                                     static_cast<const jschar *>(out)));
   757                 *messagep = LossyTwoByteCharsToNewLatin1CharsZ(cx, ucmsg).c_str();
   758                 if (!*messagep)
   759                     goto error;
   760             }
   761         } else {
   762             /* Non-null messageArgs should have at least one non-null arg. */
   763             JS_ASSERT(!reportp->messageArgs);
   764             /*
   765              * Zero arguments: the format string (if it exists) is the
   766              * entire message.
   767              */
   768             if (efs->format) {
   769                 size_t len;
   770                 *messagep = js_strdup(cx, efs->format);
   771                 if (!*messagep)
   772                     goto error;
   773                 len = strlen(*messagep);
   774                 reportp->ucmessage = InflateString(cx, *messagep, &len);
   775                 if (!reportp->ucmessage)
   776                     goto error;
   777             }
   778         }
   779     }
   780     if (*messagep == nullptr) {
   781         /* where's the right place for this ??? */
   782         const char *defaultErrorMessage
   783             = "No error message available for error number %d";
   784         size_t nbytes = strlen(defaultErrorMessage) + 16;
   785         *messagep = cx->pod_malloc<char>(nbytes);
   786         if (!*messagep)
   787             goto error;
   788         JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
   789     }
   790     return true;
   792 error:
   793     if (!messageArgsPassed && reportp->messageArgs) {
   794         /* free the arguments only if we allocated them */
   795         if (argumentsType == ArgumentsAreASCII) {
   796             i = 0;
   797             while (reportp->messageArgs[i])
   798                 js_free((void *)reportp->messageArgs[i++]);
   799         }
   800         js_free((void *)reportp->messageArgs);
   801         reportp->messageArgs = nullptr;
   802     }
   803     if (reportp->ucmessage) {
   804         js_free((void *)reportp->ucmessage);
   805         reportp->ucmessage = nullptr;
   806     }
   807     if (*messagep) {
   808         js_free((void *)*messagep);
   809         *messagep = nullptr;
   810     }
   811     return false;
   812 }
   814 bool
   815 js_ReportErrorNumberVA(JSContext *cx, unsigned flags, JSErrorCallback callback,
   816                        void *userRef, const unsigned errorNumber,
   817                        ErrorArgumentsType argumentsType, va_list ap)
   818 {
   819     JSErrorReport report;
   820     char *message;
   821     bool warning;
   823     if (checkReportFlags(cx, &flags))
   824         return true;
   825     warning = JSREPORT_IS_WARNING(flags);
   827     PodZero(&report);
   828     report.flags = flags;
   829     report.errorNumber = errorNumber;
   830     PopulateReportBlame(cx, &report);
   832     if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
   833                                  &message, &report, argumentsType, ap)) {
   834         return false;
   835     }
   837     ReportError(cx, message, &report, callback, userRef);
   839     js_free(message);
   840     if (report.messageArgs) {
   841         /*
   842          * js_ExpandErrorArguments owns its messageArgs only if it had to
   843          * inflate the arguments (from regular |char *|s).
   844          */
   845         if (argumentsType == ArgumentsAreASCII) {
   846             int i = 0;
   847             while (report.messageArgs[i])
   848                 js_free((void *)report.messageArgs[i++]);
   849         }
   850         js_free((void *)report.messageArgs);
   851     }
   852     js_free((void *)report.ucmessage);
   854     return warning;
   855 }
   857 bool
   858 js_ReportErrorNumberUCArray(JSContext *cx, unsigned flags, JSErrorCallback callback,
   859                             void *userRef, const unsigned errorNumber,
   860                             const jschar **args)
   861 {
   862     if (checkReportFlags(cx, &flags))
   863         return true;
   864     bool warning = JSREPORT_IS_WARNING(flags);
   866     JSErrorReport report;
   867     PodZero(&report);
   868     report.flags = flags;
   869     report.errorNumber = errorNumber;
   870     PopulateReportBlame(cx, &report);
   871     report.messageArgs = args;
   873     char *message;
   874     va_list dummy;
   875     if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
   876                                  &message, &report, ArgumentsAreUnicode, dummy)) {
   877         return false;
   878     }
   880     ReportError(cx, message, &report, callback, userRef);
   882     js_free(message);
   883     js_free((void *)report.ucmessage);
   885     return warning;
   886 }
   888 void
   889 js::CallErrorReporter(JSContext *cx, const char *message, JSErrorReport *reportp)
   890 {
   891     JS_ASSERT(message);
   892     JS_ASSERT(reportp);
   894     // If debugErrorHook is present, give it a chance to veto sending the error
   895     // on to the regular ErrorReporter.
   896     if (cx->errorReporter) {
   897         JSDebugErrorHook hook = cx->runtime()->debugHooks.debugErrorHook;
   898         if (hook && !hook(cx, message, reportp, cx->runtime()->debugHooks.debugErrorHookData))
   899             return;
   900     }
   902     if (JSErrorReporter onError = cx->errorReporter)
   903         onError(cx, message, reportp);
   904 }
   906 void
   907 js_ReportIsNotDefined(JSContext *cx, const char *name)
   908 {
   909     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_DEFINED, name);
   910 }
   912 bool
   913 js_ReportIsNullOrUndefined(JSContext *cx, int spindex, HandleValue v,
   914                            HandleString fallback)
   915 {
   916     char *bytes;
   917     bool ok;
   919     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
   920     if (!bytes)
   921         return false;
   923     if (strcmp(bytes, js_undefined_str) == 0 ||
   924         strcmp(bytes, js_null_str) == 0) {
   925         ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
   926                                           js_GetErrorMessage, nullptr,
   927                                           JSMSG_NO_PROPERTIES, bytes,
   928                                           nullptr, nullptr);
   929     } else if (v.isUndefined()) {
   930         ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
   931                                           js_GetErrorMessage, nullptr,
   932                                           JSMSG_UNEXPECTED_TYPE, bytes,
   933                                           js_undefined_str, nullptr);
   934     } else {
   935         JS_ASSERT(v.isNull());
   936         ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
   937                                           js_GetErrorMessage, nullptr,
   938                                           JSMSG_UNEXPECTED_TYPE, bytes,
   939                                           js_null_str, nullptr);
   940     }
   942     js_free(bytes);
   943     return ok;
   944 }
   946 void
   947 js_ReportMissingArg(JSContext *cx, HandleValue v, unsigned arg)
   948 {
   949     char argbuf[11];
   950     char *bytes;
   951     RootedAtom atom(cx);
   953     JS_snprintf(argbuf, sizeof argbuf, "%u", arg);
   954     bytes = nullptr;
   955     if (IsFunctionObject(v)) {
   956         atom = v.toObject().as<JSFunction>().atom();
   957         bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
   958                                         v, atom);
   959         if (!bytes)
   960             return;
   961     }
   962     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
   963                          JSMSG_MISSING_FUN_ARG, argbuf,
   964                          bytes ? bytes : "");
   965     js_free(bytes);
   966 }
   968 bool
   969 js_ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNumber,
   970                          int spindex, HandleValue v, HandleString fallback,
   971                          const char *arg1, const char *arg2)
   972 {
   973     char *bytes;
   974     bool ok;
   976     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
   977     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
   978     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
   979     if (!bytes)
   980         return false;
   982     ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage,
   983                                       nullptr, errorNumber, bytes, arg1, arg2);
   984     js_free(bytes);
   985     return ok;
   986 }
   988 const JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
   989 #define MSG_DEF(name, number, count, exception, format) \
   990     { format, count, exception } ,
   991 #include "js.msg"
   992 #undef MSG_DEF
   993 };
   995 JS_FRIEND_API(const JSErrorFormatString *)
   996 js_GetErrorMessage(void *userRef, const char *locale, const unsigned errorNumber)
   997 {
   998     if ((errorNumber > 0) && (errorNumber < JSErr_Limit))
   999         return &js_ErrorFormatString[errorNumber];
  1000     return nullptr;
  1003 bool
  1004 js::InvokeInterruptCallback(JSContext *cx)
  1006     JS_ASSERT_REQUEST_DEPTH(cx);
  1008     JSRuntime *rt = cx->runtime();
  1009     JS_ASSERT(rt->interrupt);
  1011     // Reset the callback counter first, then run GC and yield. If another
  1012     // thread is racing us here we will accumulate another callback request
  1013     // which will be serviced at the next opportunity.
  1014     rt->interrupt = false;
  1016     // IonMonkey sets its stack limit to UINTPTR_MAX to trigger interrupt
  1017     // callbacks.
  1018     rt->resetJitStackLimit();
  1020     js::gc::GCIfNeeded(cx);
  1022 #ifdef JS_ION
  1023 #ifdef JS_THREADSAFE
  1024     rt->interruptPar = false;
  1025 #endif
  1027     // A worker thread may have requested an interrupt after finishing an Ion
  1028     // compilation.
  1029     jit::AttachFinishedCompilations(cx);
  1030 #endif
  1032     // Important: Additional callbacks can occur inside the callback handler
  1033     // if it re-enters the JS engine. The embedding must ensure that the
  1034     // callback is disconnected before attempting such re-entry.
  1035     JSInterruptCallback cb = cx->runtime()->interruptCallback;
  1036     if (!cb || cb(cx))
  1037         return true;
  1039     // No need to set aside any pending exception here: ComputeStackString
  1040     // already does that.
  1041     Rooted<JSString*> stack(cx, ComputeStackString(cx));
  1042     const jschar *chars = stack ? stack->getCharsZ(cx) : nullptr;
  1043     if (!chars)
  1044         chars = MOZ_UTF16("(stack not available)");
  1045     JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
  1046                                    JSMSG_TERMINATED, chars);
  1048     return false;
  1051 bool
  1052 js::HandleExecutionInterrupt(JSContext *cx)
  1054     if (cx->runtime()->interrupt)
  1055         return InvokeInterruptCallback(cx);
  1056     return true;
  1059 ThreadSafeContext::ThreadSafeContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind)
  1060   : ContextFriendFields(rt),
  1061     contextKind_(kind),
  1062     perThreadData(pt),
  1063     allocator_(nullptr)
  1067 bool
  1068 ThreadSafeContext::isForkJoinContext() const
  1070     return contextKind_ == Context_ForkJoin;
  1073 ForkJoinContext *
  1074 ThreadSafeContext::asForkJoinContext()
  1076     JS_ASSERT(isForkJoinContext());
  1077     return reinterpret_cast<ForkJoinContext *>(this);
  1080 void
  1081 ThreadSafeContext::recoverFromOutOfMemory()
  1083     // If this is not a JSContext, there's nothing to do.
  1084     if (JSContext *maybecx = maybeJSContext()) {
  1085         if (maybecx->isExceptionPending()) {
  1086             MOZ_ASSERT(maybecx->isThrowingOutOfMemory());
  1087             maybecx->clearPendingException();
  1088         } else {
  1089             MOZ_ASSERT(maybecx->runtime()->hadOutOfMemory);
  1094 JSContext::JSContext(JSRuntime *rt)
  1095   : ExclusiveContext(rt, &rt->mainThread, Context_JS),
  1096     throwing(false),
  1097     unwrappedException_(UndefinedValue()),
  1098     options_(),
  1099     reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
  1100     resolvingList(nullptr),
  1101     generatingError(false),
  1102     savedFrameChains_(),
  1103     defaultCompartmentObject_(nullptr),
  1104     cycleDetectorSet(MOZ_THIS_IN_INITIALIZER_LIST()),
  1105     errorReporter(nullptr),
  1106     data(nullptr),
  1107     data2(nullptr),
  1108 #ifdef JS_THREADSAFE
  1109     outstandingRequests(0),
  1110 #endif
  1111     iterValue(MagicValue(JS_NO_ITER_VALUE)),
  1112     jitIsBroken(false),
  1113 #ifdef MOZ_TRACE_JSCALLS
  1114     functionCallback(nullptr),
  1115 #endif
  1116     innermostGenerator_(nullptr)
  1118 #ifdef DEBUG
  1119     stackIterAssertionEnabled = true;
  1120 #endif
  1122     JS_ASSERT(static_cast<ContextFriendFields*>(this) ==
  1123               ContextFriendFields::get(this));
  1126 JSContext::~JSContext()
  1128     /* Free the stuff hanging off of cx. */
  1129     JS_ASSERT(!resolvingList);
  1132 bool
  1133 JSContext::getPendingException(MutableHandleValue rval)
  1135     JS_ASSERT(throwing);
  1136     rval.set(unwrappedException_);
  1137     if (IsAtomsCompartment(compartment()))
  1138         return true;
  1139     clearPendingException();
  1140     if (!compartment()->wrap(this, rval))
  1141         return false;
  1142     assertSameCompartment(this, rval);
  1143     setPendingException(rval);
  1144     return true;
  1147 bool
  1148 JSContext::isThrowingOutOfMemory()
  1150     return throwing && unwrappedException_ == StringValue(names().outOfMemory);
  1153 void
  1154 JSContext::enterGenerator(JSGenerator *gen)
  1156     JS_ASSERT(!gen->prevGenerator);
  1157     gen->prevGenerator = innermostGenerator_;
  1158     innermostGenerator_ = gen;
  1161 void
  1162 JSContext::leaveGenerator(JSGenerator *gen)
  1164     JS_ASSERT(innermostGenerator_ == gen);
  1165     innermostGenerator_ = innermostGenerator_->prevGenerator;
  1166     gen->prevGenerator = nullptr;
  1170 bool
  1171 JSContext::runningWithTrustedPrincipals() const
  1173     return !compartment() || compartment()->principals == runtime()->trustedPrincipals();
  1176 bool
  1177 JSContext::saveFrameChain()
  1179     if (!savedFrameChains_.append(SavedFrameChain(compartment(), enterCompartmentDepth_)))
  1180         return false;
  1182     if (Activation *act = mainThread().activation())
  1183         act->saveFrameChain();
  1185     setCompartment(nullptr);
  1186     enterCompartmentDepth_ = 0;
  1188     return true;
  1191 void
  1192 JSContext::restoreFrameChain()
  1194     JS_ASSERT(enterCompartmentDepth_ == 0); // We're about to clobber it, and it
  1195                                             // will be wrong forevermore.
  1196     SavedFrameChain sfc = savedFrameChains_.popCopy();
  1197     setCompartment(sfc.compartment);
  1198     enterCompartmentDepth_ = sfc.enterCompartmentCount;
  1200     if (Activation *act = mainThread().activation())
  1201         act->restoreFrameChain();
  1204 bool
  1205 JSContext::currentlyRunning() const
  1207     for (ActivationIterator iter(runtime()); !iter.done(); ++iter) {
  1208         if (iter->cx() == this) {
  1209             if (iter->hasSavedFrameChain())
  1210                 return false;
  1211             return true;
  1215     return false;
  1218 static bool
  1219 ComputeIsJITBroken()
  1221 #if !defined(ANDROID) || defined(GONK)
  1222     return false;
  1223 #else  // ANDROID
  1224     if (getenv("JS_IGNORE_JIT_BROKENNESS")) {
  1225         return false;
  1228     std::string line;
  1230     // Check for the known-bad kernel version (2.6.29).
  1231     std::ifstream osrelease("/proc/sys/kernel/osrelease");
  1232     std::getline(osrelease, line);
  1233     __android_log_print(ANDROID_LOG_INFO, "Gecko", "Detected osrelease `%s'",
  1234                         line.c_str());
  1236     if (line.npos == line.find("2.6.29")) {
  1237         // We're using something other than 2.6.29, so the JITs should work.
  1238         __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are not broken");
  1239         return false;
  1242     // We're using 2.6.29, and this causes trouble with the JITs on i9000.
  1243     line = "";
  1244     bool broken = false;
  1245     std::ifstream cpuinfo("/proc/cpuinfo");
  1246     do {
  1247         if (0 == line.find("Hardware")) {
  1248             static const char* const blacklist[] = {
  1249                 "SCH-I400",     // Samsung Continuum
  1250                 "SGH-T959",     // Samsung i9000, Vibrant device
  1251                 "SGH-I897",     // Samsung i9000, Captivate device
  1252                 "SCH-I500",     // Samsung i9000, Fascinate device
  1253                 "SPH-D700",     // Samsung i9000, Epic device
  1254                 "GT-I9000",     // Samsung i9000, UK/Europe device
  1255                 nullptr
  1256             };
  1257             for (const char* const* hw = &blacklist[0]; *hw; ++hw) {
  1258                 if (line.npos != line.find(*hw)) {
  1259                     __android_log_print(ANDROID_LOG_INFO, "Gecko",
  1260                                         "Blacklisted device `%s'", *hw);
  1261                     broken = true;
  1262                     break;
  1265             break;
  1267         std::getline(cpuinfo, line);
  1268     } while(!cpuinfo.fail() && !cpuinfo.eof());
  1270     __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are %sbroken",
  1271                         broken ? "" : "not ");
  1273     return broken;
  1274 #endif  // ifndef ANDROID
  1277 static bool
  1278 IsJITBrokenHere()
  1280     static bool computedIsBroken = false;
  1281     static bool isBroken = false;
  1282     if (!computedIsBroken) {
  1283         isBroken = ComputeIsJITBroken();
  1284         computedIsBroken = true;
  1286     return isBroken;
  1289 void
  1290 JSContext::updateJITEnabled()
  1292     jitIsBroken = IsJITBrokenHere();
  1295 size_t
  1296 JSContext::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
  1298     /*
  1299      * There are other JSContext members that could be measured; the following
  1300      * ones have been found by DMD to be worth measuring.  More stuff may be
  1301      * added later.
  1302      */
  1303     return mallocSizeOf(this) + cycleDetectorSet.sizeOfExcludingThis(mallocSizeOf);
  1306 void
  1307 JSContext::mark(JSTracer *trc)
  1309     /* Stack frames and slots are traced by StackSpace::mark. */
  1311     /* Mark other roots-by-definition in the JSContext. */
  1312     if (defaultCompartmentObject_)
  1313         MarkObjectRoot(trc, &defaultCompartmentObject_, "default compartment object");
  1314     if (isExceptionPending())
  1315         MarkValueRoot(trc, &unwrappedException_, "unwrapped exception");
  1317     TraceCycleDetectionSet(trc, cycleDetectorSet);
  1319     MarkValueRoot(trc, &iterValue, "iterValue");
  1322 void *
  1323 ThreadSafeContext::stackLimitAddressForJitCode(StackKind kind)
  1325 #ifdef JS_ARM_SIMULATOR
  1326     return runtime_->mainThread.addressOfSimulatorStackLimit();
  1327 #endif
  1328     return stackLimitAddress(kind);
  1331 JSVersion
  1332 JSContext::findVersion() const
  1334     if (JSScript *script = currentScript(nullptr, ALLOW_CROSS_COMPARTMENT))
  1335         return script->getVersion();
  1337     if (compartment() && compartment()->options().version() != JSVERSION_UNKNOWN)
  1338         return compartment()->options().version();
  1340     return runtime()->defaultVersion();
  1343 #if defined JS_THREADSAFE && defined DEBUG
  1345 JS::AutoCheckRequestDepth::AutoCheckRequestDepth(JSContext *cx)
  1346     : cx(cx)
  1348     JS_ASSERT(cx->runtime()->requestDepth || cx->runtime()->isHeapBusy());
  1349     JS_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
  1350     cx->runtime()->checkRequestDepth++;
  1353 JS::AutoCheckRequestDepth::AutoCheckRequestDepth(ContextFriendFields *cxArg)
  1354     : cx(static_cast<ThreadSafeContext *>(cxArg)->maybeJSContext())
  1356     if (cx) {
  1357         JS_ASSERT(cx->runtime()->requestDepth || cx->runtime()->isHeapBusy());
  1358         JS_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
  1359         cx->runtime()->checkRequestDepth++;
  1363 JS::AutoCheckRequestDepth::~AutoCheckRequestDepth()
  1365     if (cx) {
  1366         JS_ASSERT(cx->runtime()->checkRequestDepth != 0);
  1367         cx->runtime()->checkRequestDepth--;
  1371 #endif
  1373 #ifdef JS_CRASH_DIAGNOSTICS
  1374 void CompartmentChecker::check(InterpreterFrame *fp)
  1376     if (fp)
  1377         check(fp->scopeChain());
  1380 void CompartmentChecker::check(AbstractFramePtr frame)
  1382     if (frame)
  1383         check(frame.scopeChain());
  1385 #endif
  1387 void
  1388 js::CrashAtUnhandlableOOM(const char *reason)
  1390     char msgbuf[1024];
  1391     JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
  1392     MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
  1393     MOZ_CRASH();

mercurial