LCOV - app.info - js/src/jscntxt.cpp

LCOV - code coverage report
| Current view: | directory - js/src - jscntxt.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 505 | 386 | 76.4 %
| Date: | 2012-04-07 | Functions: | 47 | 41 | 87.2 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=8 sw=4 et tw=80:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla Communicator client code, released
          18                 :  * March 31, 1998.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  * Netscape Communications Corporation.
          22                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          23                 :  * the Initial Developer. All Rights Reserved.
          24                 :  *
          25                 :  * Contributor(s):
          26                 :  *
          27                 :  * Alternatively, the contents of this file may be used under the terms of
          28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          31                 :  * of those above. If you wish to allow use of your version of this file only
          32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          33                 :  * use your version of this file under the terms of the MPL, indicate your
          34                 :  * decision by deleting the provisions above and replace them with the notice
          35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          36                 :  * the provisions above, a recipient may use your version of this file under
          37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          38                 :  *
          39                 :  * ***** END LICENSE BLOCK ***** */
          40                 :
          41                 : /*
          42                 :  * JS execution context.
          43                 :  */
          44                 :
          45                 : #include <limits.h> /* make sure that <features.h> is included and we can use
          46                 :                        __GLIBC__ to detect glibc presence */
          47                 : #include <new>
          48                 : #include <stdarg.h>
          49                 : #include <stdlib.h>
          50                 : #include <string.h>
          51                 : #ifdef ANDROID
          52                 : # include <android/log.h>
          53                 : # include <fstream>
          54                 : # include <string>
          55                 : #endif  // ANDROID
          56                 :
          57                 : #include "jstypes.h"
          58                 : #include "jsutil.h"
          59                 : #include "jsclist.h"
          60                 : #include "jsprf.h"
          61                 : #include "jsatom.h"
          62                 : #include "jscntxt.h"
          63                 : #include "jsversion.h"
          64                 : #include "jsdbgapi.h"
          65                 : #include "jsexn.h"
          66                 : #include "jsfun.h"
          67                 : #include "jsgc.h"
          68                 : #include "jsgcmark.h"
          69                 : #include "jsiter.h"
          70                 : #include "jslock.h"
          71                 : #include "jsmath.h"
          72                 : #include "jsnum.h"
          73                 : #include "jsobj.h"
          74                 : #include "jsopcode.h"
          75                 : #include "jspubtd.h"
          76                 : #include "jsscope.h"
          77                 : #include "jsscript.h"
          78                 : #include "jsstr.h"
          79                 :
          80                 : #ifdef JS_METHODJIT
          81                 : # include "assembler/assembler/MacroAssembler.h"
          82                 : # include "methodjit/MethodJIT.h"
          83                 : #endif
          84                 : #include "frontend/TokenStream.h"
          85                 : #include "frontend/ParseMaps.h"
          86                 : #include "yarr/BumpPointerAllocator.h"
          87                 :
          88                 : #include "jsatominlines.h"
          89                 : #include "jscntxtinlines.h"
          90                 : #include "jscompartment.h"
          91                 : #include "jsobjinlines.h"
          92                 :
          93                 : using namespace js;
          94                 : using namespace js::gc;
          95                 :
          96                 : void
          97               0 : JSRuntime::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, size_t *temporary,
          98                 :                                size_t *regexpCode, size_t *stackCommitted, size_t *gcMarkerSize)
          99                 : {
         100               0 :     if (normal)
         101               0 :         *normal = mallocSizeOf(dtoaState);
         102                 :
         103               0 :     if (temporary)
         104               0 :         *temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
         105                 :
         106               0 :     if (regexpCode) {
         107               0 :         size_t method = 0, regexp = 0, unused = 0;
         108               0 :         if (execAlloc_)
         109               0 :             execAlloc_->sizeOfCode(&method, &regexp, &unused);
         110               0 :         JS_ASSERT(method == 0);     /* this execAlloc is only used for regexp code */
         111               0 :         *regexpCode = regexp + unused;
         112                 :     }
         113                 :
         114               0 :     if (stackCommitted)
         115               0 :         *stackCommitted = stackSpace.sizeOfCommitted();
         116                 :
         117               0 :     if (gcMarkerSize)
         118               0 :         *gcMarkerSize = gcMarker.sizeOfExcludingThis(mallocSizeOf);
         119               0 : }
         120                 :
         121                 : void
         122             172 : JSRuntime::triggerOperationCallback()
         123                 : {
         124                 :     /*
         125                 :      * Use JS_ATOMIC_SET in the hope that it ensures the write will become
         126                 :      * immediately visible to other processors polling the flag.
         127                 :      */
         128             172 :     JS_ATOMIC_SET(&interrupt, 1);
         129             172 : }
         130                 :
         131                 : void
         132               0 : JSRuntime::setJitHardening(bool enabled)
         133                 : {
         134               0 :     jitHardening = enabled;
         135               0 :     if (execAlloc_)
         136               0 :         execAlloc_->setRandomize(enabled);
         137               0 : }
         138                 :
         139                 : JSC::ExecutableAllocator *
         140            1015 : JSRuntime::createExecutableAllocator(JSContext *cx)
         141                 : {
         142            1015 :     JS_ASSERT(!execAlloc_);
         143            1015 :     JS_ASSERT(cx->runtime == this);
         144                 :
         145                 :     JSC::AllocationBehavior randomize =
         146            1015 :         jitHardening ? JSC::AllocationCanRandomize : JSC::AllocationDeterministic;
         147            1015 :     execAlloc_ = new_<JSC::ExecutableAllocator>(randomize);
         148            1015 :     if (!execAlloc_)
         149               0 :         js_ReportOutOfMemory(cx);
         150            1015 :     return execAlloc_;
         151                 : }
         152                 :
         153                 : WTF::BumpPointerAllocator *
         154              90 : JSRuntime::createBumpPointerAllocator(JSContext *cx)
         155                 : {
         156              90 :     JS_ASSERT(!bumpAlloc_);
         157              90 :     JS_ASSERT(cx->runtime == this);
         158                 :
         159              90 :     bumpAlloc_ = new_<WTF::BumpPointerAllocator>();
         160              90 :     if (!bumpAlloc_)
         161               0 :         js_ReportOutOfMemory(cx);
         162              90 :     return bumpAlloc_;
         163                 : }
         164                 :
         165                 : JSScript *
         166               0 : js_GetCurrentScript(JSContext *cx)
         167                 : {
         168               0 :     return cx->hasfp() ? cx->fp()->maybeScript() : NULL;
         169                 : }
         170                 :
         171                 : JSContext *
         172           18771 : js_NewContext(JSRuntime *rt, size_t stackChunkSize)
         173                 : {
         174           18771 :     JS_AbortIfWrongThread(rt);
         175                 :
         176           18771 :     JSContext *cx = OffTheBooks::new_<JSContext>(rt);
         177           18771 :     if (!cx)
         178               0 :         return NULL;
         179                 :
         180           18771 :     JS_ASSERT(cx->findVersion() == JSVERSION_DEFAULT);
         181                 :
         182           18771 :     if (!cx->busyArrays.init()) {
         183               0 :         Foreground::delete_(cx);
         184               0 :         return NULL;
         185                 :     }
         186                 :
         187                 :     /*
         188                 :      * Here the GC lock is still held after js_InitContextThreadAndLockGC took it and
         189                 :      * the GC is not running on another thread.
         190                 :      */
         191           18771 :     bool first = JS_CLIST_IS_EMPTY(&rt->contextList);
         192           18771 :     JS_APPEND_LINK(&cx->link, &rt->contextList);
         193                 :
         194           18771 :     js_InitRandom(cx);
         195                 :
         196                 :     /*
         197                 :      * If cx is the first context on this runtime, initialize well-known atoms,
         198                 :      * keywords, numbers, and strings.  If one of these steps should fail, the
         199                 :      * runtime will be left in a partially initialized state, with zeroes and
         200                 :      * nulls stored in the default-initialized remainder of the struct.  We'll
         201                 :      * clean the runtime up under js_DestroyContext, because cx will be "last"
         202                 :      * as well as "first".
         203                 :      */
         204           18771 :     if (first) {
         205                 : #ifdef JS_THREADSAFE
         206           18761 :         JS_BeginRequest(cx);
         207                 : #endif
         208           18761 :         bool ok = rt->staticStrings.init(cx);
         209           18761 :         if (ok)
         210           18761 :             ok = InitCommonAtoms(cx);
         211                 :
         212                 : #ifdef JS_THREADSAFE
         213           18761 :         JS_EndRequest(cx);
         214                 : #endif
         215           18761 :         if (!ok) {
         216               0 :             js_DestroyContext(cx, JSDCM_NEW_FAILED);
         217               0 :             return NULL;
         218                 :         }
         219                 :     }
         220                 :
         221           18771 :     JSContextCallback cxCallback = rt->cxCallback;
         222           18771 :     if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) {
         223               0 :         js_DestroyContext(cx, JSDCM_NEW_FAILED);
         224               0 :         return NULL;
         225                 :     }
         226                 :
         227           18771 :     return cx;
         228                 : }
         229                 :
         230                 : void
         231           18771 : js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
         232                 : {
         233           18771 :     JSRuntime *rt = cx->runtime;
         234           18771 :     JS_AbortIfWrongThread(rt);
         235                 :
         236           18771 :     JS_ASSERT(!cx->enumerators);
         237                 :
         238                 : #ifdef JS_THREADSAFE
         239           18771 :     JS_ASSERT(cx->outstandingRequests == 0);
         240                 : #endif
         241                 :
         242           18771 :     if (mode != JSDCM_NEW_FAILED) {
         243           18771 :         if (JSContextCallback cxCallback = rt->cxCallback) {
         244                 :             /*
         245                 :              * JSCONTEXT_DESTROY callback is not allowed to fail and must
         246                 :              * return true.
         247                 :              */
         248               0 :             DebugOnly<JSBool> callbackStatus = cxCallback(cx, JSCONTEXT_DESTROY);
         249               0 :             JS_ASSERT(callbackStatus);
         250                 :         }
         251                 :     }
         252                 :
         253           18771 :     JS_REMOVE_LINK(&cx->link);
         254           18771 :     bool last = !rt->hasContexts();
         255           18771 :     if (last) {
         256           18761 :         JS_ASSERT(!rt->gcRunning);
         257                 :
         258                 : #ifdef JS_THREADSAFE
         259                 :         {
         260           37522 :             AutoLockGC lock(rt);
         261           18761 :             rt->gcHelperThread.waitBackgroundSweepEnd();
         262                 :         }
         263                 : #endif
         264                 :
         265                 :         /*
         266                 :          * Dump remaining type inference results first. This printing
         267                 :          * depends on atoms still existing.
         268                 :          */
         269           60022 :         for (CompartmentsIter c(rt); !c.done(); c.next())
         270           41261 :             c->types.print(cx, false);
         271                 :
         272                 :         /* Unpin all common atoms before final GC. */
         273           18761 :         FinishCommonAtoms(cx->runtime);
         274                 :
         275                 :         /* Clear debugging state to remove GC roots. */
         276           60022 :         for (CompartmentsIter c(rt); !c.done(); c.next())
         277           41261 :             c->clearTraps(cx);
         278           18761 :         JS_ClearAllWatchPoints(cx);
         279                 :
         280           18761 :         PrepareForFullGC(rt);
         281           18761 :         GC(cx, GC_NORMAL, gcreason::LAST_CONTEXT);
         282              10 :     } else if (mode == JSDCM_FORCE_GC) {
         283              10 :         JS_ASSERT(!rt->gcRunning);
         284              10 :         PrepareForFullGC(rt);
         285              10 :         GC(cx, GC_NORMAL, gcreason::DESTROY_CONTEXT);
         286               0 :     } else if (mode == JSDCM_MAYBE_GC) {
         287               0 :         JS_ASSERT(!rt->gcRunning);
         288               0 :         JS_MaybeGC(cx);
         289                 :     }
         290                 :
         291                 : #ifdef JS_THREADSAFE
         292                 :     {
         293           37542 :         AutoLockGC lock(rt);
         294           18771 :         rt->gcHelperThread.waitBackgroundSweepEnd();
         295                 :     }
         296                 : #endif
         297           18771 :     Foreground::delete_(cx);
         298           18771 : }
         299                 :
         300                 : namespace js {
         301                 :
         302                 : bool
         303          150616 : AutoResolving::alreadyStartedSlow() const
         304                 : {
         305          150616 :     JS_ASSERT(link);
         306          150616 :     AutoResolving *cursor = link;
         307          619432 :     do {
         308          626381 :         JS_ASSERT(this != cursor);
         309          626381 :         if (object == cursor->object && id == cursor->id && kind == cursor->kind)
         310            6949 :             return true;
         311                 :     } while (!!(cursor = cursor->link));
         312          143667 :     return false;
         313                 : }
         314                 :
         315                 : } /* namespace js */
         316                 :
         317                 : static void
         318          475006 : ReportError(JSContext *cx, const char *message, JSErrorReport *reportp,
         319                 :             JSErrorCallback callback, void *userRef)
         320                 : {
         321                 :     /*
         322                 :      * Check the error report, and set a JavaScript-catchable exception
         323                 :      * if the error is defined to have an associated exception.  If an
         324                 :      * exception is thrown, then the JSREPORT_EXCEPTION flag will be set
         325                 :      * on the error report, and exception-aware hosts should ignore it.
         326                 :      */
         327          475006 :     JS_ASSERT(reportp);
         328          475006 :     if ((!callback || callback == js_GetErrorMessage) &&
         329                 :         reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
         330             153 :         reportp->flags |= JSREPORT_EXCEPTION;
         331                 :
         332                 :     /*
         333                 :      * Call the error reporter only if an exception wasn't raised.
         334                 :      *
         335                 :      * If an exception was raised, then we call the debugErrorHook
         336                 :      * (if present) to give it a chance to see the error before it
         337                 :      * propagates out of scope.  This is needed for compatibility
         338                 :      * with the old scheme.
         339                 :      */
         340          949858 :     if (!JS_IsRunning(cx) ||
         341          474852 :         !js_ErrorToException(cx, message, reportp, callback, userRef)) {
         342          464689 :         js_ReportErrorAgain(cx, message, reportp);
         343           10317 :     } else if (JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook) {
         344               0 :         if (cx->errorReporter)
         345               0 :             hook(cx, message, reportp, cx->runtime->debugHooks.debugErrorHookData);
         346                 :     }
         347          475006 : }
         348                 :
         349                 : /*
         350                 :  * The given JSErrorReport object have been zeroed and must not outlive
         351                 :  * cx->fp() (otherwise report->originPrincipals may become invalid).
         352                 :  */
         353                 : static void
         354          475025 : PopulateReportBlame(JSContext *cx, JSErrorReport *report)
         355                 : {
         356                 :     /*
         357                 :      * Walk stack until we find a frame that is associated with some script
         358                 :      * rather than a native frame.
         359                 :      */
         360          475025 :     for (FrameRegsIter iter(cx); !iter.done(); ++iter) {
         361          474871 :         if (iter.fp()->isScriptFrame()) {
         362          474871 :             report->filename = iter.fp()->script()->filename;
         363          474871 :             report->lineno = PCToLineNumber(iter.fp()->script(), iter.pc());
         364          474871 :             report->originPrincipals = iter.fp()->script()->originPrincipals;
         365          474871 :             break;
         366                 :         }
         367                 :     }
         368          475025 : }
         369                 :
         370                 : /*
         371                 :  * We don't post an exception in this case, since doing so runs into
         372                 :  * complications of pre-allocating an exception object which required
         373                 :  * running the Exception class initializer early etc.
         374                 :  * Instead we just invoke the errorReporter with an "Out Of Memory"
         375                 :  * type message, and then hope the process ends swiftly.
         376                 :  */
         377                 : void
         378              19 : js_ReportOutOfMemory(JSContext *cx)
         379                 : {
         380              19 :     cx->runtime->hadOutOfMemory = true;
         381                 :
         382                 :     JSErrorReport report;
         383              19 :     JSErrorReporter onError = cx->errorReporter;
         384                 :
         385                 :     /* Get the message for this error, but we won't expand any arguments. */
         386                 :     const JSErrorFormatString *efs =
         387              19 :         js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY);
         388              19 :     const char *msg = efs ? efs->format : "Out of memory";
         389                 :
         390                 :     /* Fill out the report, but don't do anything that requires allocation. */
         391              19 :     PodZero(&report);
         392              19 :     report.flags = JSREPORT_ERROR;
         393              19 :     report.errorNumber = JSMSG_OUT_OF_MEMORY;
         394              19 :     PopulateReportBlame(cx, &report);
         395                 :
         396                 :     /*
         397                 :      * If debugErrorHook is present then we give it a chance to veto sending
         398                 :      * the error on to the regular ErrorReporter. We also clear a pending
         399                 :      * exception if any now so the hooks can replace the out-of-memory error
         400                 :      * by a script-catchable exception.
         401                 :      */
         402              19 :     cx->clearPendingException();
         403              19 :     if (onError) {
         404              19 :         JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook;
         405              19 :         if (hook &&
         406               0 :             !hook(cx, msg, &report, cx->runtime->debugHooks.debugErrorHookData)) {
         407               0 :             onError = NULL;
         408                 :         }
         409                 :     }
         410                 :
         411              19 :     if (onError) {
         412              38 :         AutoAtomicIncrement incr(&cx->runtime->inOOMReport);
         413              19 :         onError(cx, msg, &report);
         414                 :     }
         415              19 : }
         416                 :
         417                 : JS_FRIEND_API(void)
         418          464779 : js_ReportOverRecursed(JSContext *maybecx)
         419                 : {
         420                 : #ifdef JS_MORE_DETERMINISTIC
         421                 :     /*
         422                 :      * We cannot make stack depth deterministic across different
         423                 :      * implementations (e.g. JIT vs. interpreter will differ in
         424                 :      * their maximum stack depth).
         425                 :      * However, we can detect externally when we hit the maximum
         426                 :      * stack depth which is useful for external testing programs
         427                 :      * like fuzzers.
         428                 :      */
         429                 :     fprintf(stderr, "js_ReportOverRecursed called\n");
         430                 : #endif
         431          464779 :     if (maybecx)
         432          464779 :         JS_ReportErrorNumber(maybecx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
         433          464779 : }
         434                 :
         435                 : void
         436              18 : js_ReportAllocationOverflow(JSContext *maybecx)
         437                 : {
         438              18 :     if (maybecx)
         439              18 :         JS_ReportErrorNumber(maybecx, js_GetErrorMessage, NULL, JSMSG_ALLOC_OVERFLOW);
         440              18 : }
         441                 :
         442                 : /*
         443                 :  * Given flags and the state of cx, decide whether we should report an
         444                 :  * error, a warning, or just continue execution normally.  Return
         445                 :  * true if we should continue normally, without reporting anything;
         446                 :  * otherwise, adjust *flags as appropriate and return false.
         447                 :  */
         448                 : static bool
         449          475592 : checkReportFlags(JSContext *cx, unsigned *flags)
         450                 : {
         451          475592 :     if (JSREPORT_IS_STRICT_MODE_ERROR(*flags)) {
         452                 :         /*
         453                 :          * Error in strict code; warning with strict option; okay otherwise.
         454                 :          * We assume that if the top frame is a native, then it is strict if
         455                 :          * the nearest scripted frame is strict, see bug 536306.
         456                 :          */
         457              83 :         JSScript *script = cx->stack.currentScript();
         458              83 :         if (script && script->strictModeCode)
         459              28 :             *flags &= ~JSREPORT_WARNING;
         460              55 :         else if (cx->hasStrictOption())
         461               0 :             *flags |= JSREPORT_WARNING;
         462                 :         else
         463              55 :             return true;
         464          475509 :     } else if (JSREPORT_IS_STRICT(*flags)) {
         465                 :         /* Warning/error only when JSOPTION_STRICT is set. */
         466             531 :         if (!cx->hasStrictOption())
         467             531 :             return true;
         468                 :     }
         469                 :
         470                 :     /* Warnings become errors when JSOPTION_WERROR is set. */
         471          475006 :     if (JSREPORT_IS_WARNING(*flags) && cx->hasWErrorOption())
         472               0 :         *flags &= ~JSREPORT_WARNING;
         473                 :
         474          475006 :     return false;
         475                 : }
         476                 :
         477                 : JSBool
         478              63 : js_ReportErrorVA(JSContext *cx, unsigned flags, const char *format, va_list ap)
         479                 : {
         480                 :     char *message;
         481                 :     jschar *ucmessage;
         482                 :     size_t messagelen;
         483                 :     JSErrorReport report;
         484                 :     JSBool warning;
         485                 :
         486              63 :     if (checkReportFlags(cx, &flags))
         487               0 :         return JS_TRUE;
         488                 :
         489              63 :     message = JS_vsmprintf(format, ap);
         490              63 :     if (!message)
         491               0 :         return JS_FALSE;
         492              63 :     messagelen = strlen(message);
         493                 :
         494              63 :     PodZero(&report);
         495              63 :     report.flags = flags;
         496              63 :     report.errorNumber = JSMSG_USER_DEFINED_ERROR;
         497              63 :     report.ucmessage = ucmessage = InflateString(cx, message, &messagelen);
         498              63 :     PopulateReportBlame(cx, &report);
         499                 :
         500              63 :     warning = JSREPORT_IS_WARNING(report.flags);
         501                 :
         502              63 :     ReportError(cx, message, &report, NULL, NULL);
         503              63 :     Foreground::free_(message);
         504              63 :     Foreground::free_(ucmessage);
         505              63 :     return warning;
         506                 : }
         507                 :
         508                 : namespace js {
         509                 :
         510                 : /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
         511                 : void
         512               0 : ReportUsageError(JSContext *cx, JSObject *callee, const char *msg)
         513                 : {
         514               0 :     const char *usageStr = "usage";
         515               0 :     JSAtom *usageAtom = js_Atomize(cx, usageStr, strlen(usageStr));
         516               0 :     DebugOnly<const Shape *> shape = callee->nativeLookup(cx, ATOM_TO_JSID(usageAtom));
         517               0 :     JS_ASSERT(!shape->configurable());
         518               0 :     JS_ASSERT(!shape->writable());
         519               0 :     JS_ASSERT(shape->hasDefaultGetter());
         520                 :
         521                 :     jsval usage;
         522               0 :     if (!JS_LookupProperty(cx, callee, "usage", &usage))
         523                 :         return;
         524                 :
         525               0 :     if (JSVAL_IS_VOID(usage)) {
         526               0 :         JS_ReportError(cx, "%s", msg);
         527                 :     } else {
         528               0 :         JSString *str = JSVAL_TO_STRING(usage);
         529               0 :         JS::Anchor<JSString *> a_str(str);
         530               0 :         const jschar *chars = JS_GetStringCharsZ(cx, str);
         531               0 :         if (!chars)
         532                 :             return;
         533               0 :         JS_ReportError(cx, "%s. Usage: %hs", msg, chars);
         534                 :     }
         535                 : }
         536                 :
         537                 : } /* namespace js */
         538                 :
         539                 : /*
         540                 :  * The arguments from ap need to be packaged up into an array and stored
         541                 :  * into the report struct.
         542                 :  *
         543                 :  * The format string addressed by the error number may contain operands
         544                 :  * identified by the format {N}, where N is a decimal digit. Each of these
         545                 :  * is to be replaced by the Nth argument from the va_list. The complete
         546                 :  * message is placed into reportp->ucmessage converted to a JSString.
         547                 :  *
         548                 :  * Returns true if the expansion succeeds (can fail if out of memory).
         549                 :  */
         550                 : JSBool
         551          475550 : js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
         552                 :                         void *userRef, const unsigned errorNumber,
         553                 :                         char **messagep, JSErrorReport *reportp,
         554                 :                         bool charArgs, va_list ap)
         555                 : {
         556                 :     const JSErrorFormatString *efs;
         557                 :     int i;
         558                 :     int argCount;
         559                 :
         560          475550 :     *messagep = NULL;
         561                 :
         562                 :     /* Most calls supply js_GetErrorMessage; if this is so, assume NULL. */
         563          475550 :     if (!callback || callback == js_GetErrorMessage)
         564          475280 :         efs = js_GetLocalizedErrorMessage(cx, userRef, NULL, errorNumber);
         565                 :     else
         566             270 :         efs = callback(userRef, NULL, errorNumber);
         567          475550 :     if (efs) {
         568          475550 :         size_t totalArgsLength = 0;
         569                 :         size_t argLengths[10]; /* only {0} thru {9} supported */
         570          475550 :         argCount = efs->argCount;
         571          475550 :         JS_ASSERT(argCount <= 10);
         572          475550 :         if (argCount > 0) {
         573                 :             /*
         574                 :              * Gather the arguments into an array, and accumulate
         575                 :              * their sizes. We allocate 1 more than necessary and
         576                 :              * null it out to act as the caboose when we free the
         577                 :              * pointers later.
         578                 :              */
         579                 :             reportp->messageArgs = (const jschar **)
         580            9515 :                 cx->malloc_(sizeof(jschar *) * (argCount + 1));
         581            9515 :             if (!reportp->messageArgs)
         582               0 :                 return JS_FALSE;
         583            9515 :             reportp->messageArgs[argCount] = NULL;
         584           25049 :             for (i = 0; i < argCount; i++) {
         585           15534 :                 if (charArgs) {
         586           15534 :                     char *charArg = va_arg(ap, char *);
         587           15534 :                     size_t charArgLength = strlen(charArg);
         588           15534 :                     reportp->messageArgs[i] = InflateString(cx, charArg, &charArgLength);
         589           15534 :                     if (!reportp->messageArgs[i])
         590               0 :                         goto error;
         591                 :                 } else {
         592               0 :                     reportp->messageArgs[i] = va_arg(ap, jschar *);
         593                 :                 }
         594           15534 :                 argLengths[i] = js_strlen(reportp->messageArgs[i]);
         595           15534 :                 totalArgsLength += argLengths[i];
         596                 :             }
         597                 :             /* NULL-terminate for easy copying. */
         598            9515 :             reportp->messageArgs[i] = NULL;
         599                 :         }
         600                 :         /*
         601                 :          * Parse the error format, substituting the argument X
         602                 :          * for {X} in the format.
         603                 :          */
         604          475550 :         if (argCount > 0) {
         605            9515 :             if (efs->format) {
         606                 :                 jschar *buffer, *fmt, *out;
         607            9515 :                 int expandedArgs = 0;
         608                 :                 size_t expandedLength;
         609            9515 :                 size_t len = strlen(efs->format);
         610                 :
         611            9515 :                 buffer = fmt = InflateString(cx, efs->format, &len);
         612            9515 :                 if (!buffer)
         613               0 :                     goto error;
         614                 :                 expandedLength = len
         615                 :                                  - (3 * argCount)       /* exclude the {n} */
         616            9515 :                                  + totalArgsLength;
         617                 :
         618                 :                 /*
         619                 :                 * Note - the above calculation assumes that each argument
         620                 :                 * is used once and only once in the expansion !!!
         621                 :                 */
         622                 :                 reportp->ucmessage = out = (jschar *)
         623            9515 :                     cx->malloc_((expandedLength + 1) * sizeof(jschar));
         624            9515 :                 if (!out) {
         625               0 :                     cx->free_(buffer);
         626               0 :                     goto error;
         627                 :                 }
         628          264057 :                 while (*fmt) {
         629          245027 :                     if (*fmt == '{') {
         630           15534 :                         if (isdigit(fmt[1])) {
         631           15534 :                             int d = JS7_UNDEC(fmt[1]);
         632           15534 :                             JS_ASSERT(d < argCount);
         633           15534 :                             js_strncpy(out, reportp->messageArgs[d],
         634           31068 :                                        argLengths[d]);
         635           15534 :                             out += argLengths[d];
         636           15534 :                             fmt += 3;
         637           15534 :                             expandedArgs++;
         638           15534 :                             continue;
         639                 :                         }
         640                 :                     }
         641          229493 :                     *out++ = *fmt++;
         642                 :                 }
         643            9515 :                 JS_ASSERT(expandedArgs == argCount);
         644            9515 :                 *out = 0;
         645            9515 :                 cx->free_(buffer);
         646                 :                 *messagep = DeflateString(cx, reportp->ucmessage,
         647            9515 :                                           size_t(out - reportp->ucmessage));
         648            9515 :                 if (!*messagep)
         649               0 :                     goto error;
         650                 :             }
         651                 :         } else {
         652                 :             /*
         653                 :              * Zero arguments: the format string (if it exists) is the
         654                 :              * entire message.
         655                 :              */
         656          466035 :             if (efs->format) {
         657                 :                 size_t len;
         658          466035 :                 *messagep = JS_strdup(cx, efs->format);
         659          466035 :                 if (!*messagep)
         660               0 :                     goto error;
         661          466035 :                 len = strlen(*messagep);
         662          466035 :                 reportp->ucmessage = InflateString(cx, *messagep, &len);
         663          466035 :                 if (!reportp->ucmessage)
         664               0 :                     goto error;
         665                 :             }
         666                 :         }
         667                 :     }
         668          475550 :     if (*messagep == NULL) {
         669                 :         /* where's the right place for this ??? */
         670                 :         const char *defaultErrorMessage
         671               0 :             = "No error message available for error number %d";
         672               0 :         size_t nbytes = strlen(defaultErrorMessage) + 16;
         673               0 :         *messagep = (char *)cx->malloc_(nbytes);
         674               0 :         if (!*messagep)
         675               0 :             goto error;
         676               0 :         JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
         677                 :     }
         678          475550 :     return JS_TRUE;
         679                 :
         680                 : error:
         681               0 :     if (reportp->messageArgs) {
         682                 :         /* free the arguments only if we allocated them */
         683               0 :         if (charArgs) {
         684               0 :             i = 0;
         685               0 :             while (reportp->messageArgs[i])
         686               0 :                 cx->free_((void *)reportp->messageArgs[i++]);
         687                 :         }
         688               0 :         cx->free_((void *)reportp->messageArgs);
         689               0 :         reportp->messageArgs = NULL;
         690                 :     }
         691               0 :     if (reportp->ucmessage) {
         692               0 :         cx->free_((void *)reportp->ucmessage);
         693               0 :         reportp->ucmessage = NULL;
         694                 :     }
         695               0 :     if (*messagep) {
         696               0 :         cx->free_((void *)*messagep);
         697               0 :         *messagep = NULL;
         698                 :     }
         699               0 :     return JS_FALSE;
         700                 : }
         701                 :
         702                 : JSBool
         703          475529 : js_ReportErrorNumberVA(JSContext *cx, unsigned flags, JSErrorCallback callback,
         704                 :                        void *userRef, const unsigned errorNumber,
         705                 :                        JSBool charArgs, va_list ap)
         706                 : {
         707                 :     JSErrorReport report;
         708                 :     char *message;
         709                 :     JSBool warning;
         710                 :
         711          475529 :     if (checkReportFlags(cx, &flags))
         712             586 :         return JS_TRUE;
         713          474943 :     warning = JSREPORT_IS_WARNING(flags);
         714                 :
         715          474943 :     PodZero(&report);
         716          474943 :     report.flags = flags;
         717          474943 :     report.errorNumber = errorNumber;
         718          474943 :     PopulateReportBlame(cx, &report);
         719                 :
         720          474943 :     if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
         721          474943 :                                  &message, &report, !!charArgs, ap)) {
         722               0 :         return JS_FALSE;
         723                 :     }
         724                 :
         725          474943 :     ReportError(cx, message, &report, callback, userRef);
         726                 :
         727          474943 :     if (message)
         728          474943 :         cx->free_(message);
         729          474943 :     if (report.messageArgs) {
         730                 :         /*
         731                 :          * js_ExpandErrorArguments owns its messageArgs only if it had to
         732                 :          * inflate the arguments (from regular |char *|s).
         733                 :          */
         734            9308 :         if (charArgs) {
         735            9308 :             int i = 0;
         736           33754 :             while (report.messageArgs[i])
         737           15138 :                 cx->free_((void *)report.messageArgs[i++]);
         738                 :         }
         739            9308 :         cx->free_((void *)report.messageArgs);
         740                 :     }
         741          474943 :     if (report.ucmessage)
         742          474943 :         cx->free_((void *)report.ucmessage);
         743                 :
         744          474943 :     return warning;
         745                 : }
         746                 :
         747                 : JS_FRIEND_API(void)
         748          465386 : js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp)
         749                 : {
         750                 :     JSErrorReporter onError;
         751                 :
         752          465386 :     if (!message)
         753               0 :         return;
         754                 :
         755          465386 :     if (cx->lastMessage)
         756          464439 :         Foreground::free_(cx->lastMessage);
         757          465386 :     cx->lastMessage = JS_strdup(cx, message);
         758          465386 :     if (!cx->lastMessage)
         759               0 :         return;
         760          465386 :     onError = cx->errorReporter;
         761                 :
         762                 :     /*
         763                 :      * If debugErrorHook is present then we give it a chance to veto
         764                 :      * sending the error on to the regular ErrorReporter.
         765                 :      */
         766          465386 :     if (onError) {
         767             914 :         JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook;
         768             914 :         if (hook && !hook(cx, cx->lastMessage, reportp, cx->runtime->debugHooks.debugErrorHookData))
         769               0 :             onError = NULL;
         770                 :     }
         771          465386 :     if (onError)
         772             914 :         onError(cx, cx->lastMessage, reportp);
         773                 : }
         774                 :
         775                 : void
         776            1441 : js_ReportIsNotDefined(JSContext *cx, const char *name)
         777                 : {
         778            1441 :     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name);
         779            1441 : }
         780                 :
         781                 : JSBool
         782             313 : js_ReportIsNullOrUndefined(JSContext *cx, int spindex, const Value &v,
         783                 :                            JSString *fallback)
         784                 : {
         785                 :     char *bytes;
         786                 :     JSBool ok;
         787                 :
         788             313 :     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
         789             313 :     if (!bytes)
         790               0 :         return JS_FALSE;
         791                 :
         792             617 :     if (strcmp(bytes, js_undefined_str) == 0 ||
         793             304 :         strcmp(bytes, js_null_str) == 0) {
         794                 :         ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
         795                 :                                           js_GetErrorMessage, NULL,
         796                 :                                           JSMSG_NO_PROPERTIES, bytes,
         797              36 :                                           NULL, NULL);
         798             277 :     } else if (v.isUndefined()) {
         799                 :         ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
         800                 :                                           js_GetErrorMessage, NULL,
         801                 :                                           JSMSG_UNEXPECTED_TYPE, bytes,
         802             232 :                                           js_undefined_str, NULL);
         803                 :     } else {
         804              45 :         JS_ASSERT(v.isNull());
         805                 :         ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
         806                 :                                           js_GetErrorMessage, NULL,
         807                 :                                           JSMSG_UNEXPECTED_TYPE, bytes,
         808              45 :                                           js_null_str, NULL);
         809                 :     }
         810                 :
         811             313 :     cx->free_(bytes);
         812             313 :     return ok;
         813                 : }
         814                 :
         815                 : void
         816               0 : js_ReportMissingArg(JSContext *cx, const Value &v, unsigned arg)
         817                 : {
         818                 :     char argbuf[11];
         819                 :     char *bytes;
         820                 :     JSAtom *atom;
         821                 :
         822               0 :     JS_snprintf(argbuf, sizeof argbuf, "%u", arg);
         823               0 :     bytes = NULL;
         824               0 :     if (IsFunctionObject(v)) {
         825               0 :         atom = v.toObject().toFunction()->atom;
         826                 :         bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
         827               0 :                                         v, atom);
         828               0 :         if (!bytes)
         829               0 :             return;
         830                 :     }
         831                 :     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
         832                 :                          JSMSG_MISSING_FUN_ARG, argbuf,
         833               0 :                          bytes ? bytes : "");
         834               0 :     cx->free_(bytes);
         835                 : }
         836                 :
         837                 : JSBool
         838            3133 : js_ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNumber,
         839                 :                          int spindex, const Value &v, JSString *fallback,
         840                 :                          const char *arg1, const char *arg2)
         841                 : {
         842                 :     char *bytes;
         843                 :     JSBool ok;
         844                 :
         845            3133 :     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
         846            3133 :     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
         847            3133 :     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
         848            3133 :     if (!bytes)
         849               0 :         return JS_FALSE;
         850                 :
         851                 :     ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage,
         852            3133 :                                       NULL, errorNumber, bytes, arg1, arg2);
         853            3133 :     cx->free_(bytes);
         854            3133 :     return ok;
         855                 : }
         856                 :
         857                 : JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
         858                 : #define MSG_DEF(name, number, count, exception, format) \
         859                 :     { format, count, exception } ,
         860                 : #include "js.msg"
         861                 : #undef MSG_DEF
         862                 : };
         863                 :
         864                 : JS_FRIEND_API(const JSErrorFormatString *)
         865          950416 : js_GetErrorMessage(void *userRef, const char *locale, const unsigned errorNumber)
         866                 : {
         867          950416 :     if ((errorNumber > 0) && (errorNumber < JSErr_Limit))
         868          950416 :         return &js_ErrorFormatString[errorNumber];
         869               0 :     return NULL;
         870                 : }
         871                 :
         872                 : JSBool
         873             160 : js_InvokeOperationCallback(JSContext *cx)
         874                 : {
         875             160 :     JS_ASSERT_REQUEST_DEPTH(cx);
         876                 :
         877             160 :     JSRuntime *rt = cx->runtime;
         878             160 :     JS_ASSERT(rt->interrupt != 0);
         879                 :
         880                 :     /*
         881                 :      * Reset the callback counter first, then run GC and yield. If another
         882                 :      * thread is racing us here we will accumulate another callback request
         883                 :      * which will be serviced at the next opportunity.
         884                 :      */
         885             160 :     JS_ATOMIC_SET(&rt->interrupt, 0);
         886                 :
         887             160 :     if (rt->gcIsNeeded)
         888             160 :         GCSlice(cx, GC_NORMAL, rt->gcTriggerReason);
         889                 :
         890                 : #ifdef JS_THREADSAFE
         891                 :     /*
         892                 :      * We automatically yield the current context every time the operation
         893                 :      * callback is hit since we might be called as a result of an impending
         894                 :      * GC on another thread, which would deadlock if we do not yield.
         895                 :      * Operation callbacks are supposed to happen rarely (seconds, not
         896                 :      * milliseconds) so it is acceptable to yield at every callback.
         897                 :      *
         898                 :      * As the GC can be canceled before it does any request checks we yield
         899                 :      * even if rt->gcIsNeeded was true above. See bug 590533.
         900                 :      */
         901             160 :     JS_YieldRequest(cx);
         902                 : #endif
         903                 :
         904             160 :     JSOperationCallback cb = cx->operationCallback;
         905                 :
         906                 :     /*
         907                 :      * Important: Additional callbacks can occur inside the callback handler
         908                 :      * if it re-enters the JS engine. The embedding must ensure that the
         909                 :      * callback is disconnected before attempting such re-entry.
         910                 :      */
         911                 :
         912             160 :     return !cb || cb(cx);
         913                 : }
         914                 :
         915                 : JSBool
         916             458 : js_HandleExecutionInterrupt(JSContext *cx)
         917                 : {
         918             458 :     JSBool result = JS_TRUE;
         919             458 :     if (cx->runtime->interrupt)
         920             160 :         result = js_InvokeOperationCallback(cx) && result;
         921             458 :     return result;
         922                 : }
         923                 :
         924                 : jsbytecode*
         925          919961 : js_GetCurrentBytecodePC(JSContext* cx)
         926                 : {
         927          919961 :     return cx->hasfp() ? cx->regs().pc : NULL;
         928                 : }
         929                 :
         930                 : void
         931           18771 : DSTOffsetCache::purge()
         932                 : {
         933                 :     /*
         934                 :      * NB: The initial range values are carefully chosen to result in a cache
         935                 :      *     miss on first use given the range of possible values.  Be careful
         936                 :      *     to keep these values and the caching algorithm in sync!
         937                 :      */
         938           18771 :     offsetMilliseconds = 0;
         939           18771 :     rangeStartSeconds = rangeEndSeconds = INT64_MIN;
         940           18771 :     oldOffsetMilliseconds = 0;
         941           18771 :     oldRangeStartSeconds = oldRangeEndSeconds = INT64_MIN;
         942                 :
         943           18771 :     sanityCheck();
         944           18771 : }
         945                 :
         946                 : /*
         947                 :  * Since getDSTOffsetMilliseconds guarantees that all times seen will be
         948                 :  * positive, we can initialize the range at construction time with large
         949                 :  * negative numbers to ensure the first computation is always a cache miss and
         950                 :  * doesn't return a bogus offset.
         951                 :  */
         952           18771 : DSTOffsetCache::DSTOffsetCache()
         953                 : {
         954           18771 :     purge();
         955           18771 : }
         956                 :
         957           18771 : JSContext::JSContext(JSRuntime *rt)
         958                 :   : ContextFriendFields(rt),
         959                 :     defaultVersion(JSVERSION_DEFAULT),
         960                 :     hasVersionOverride(false),
         961                 :     throwing(false),
         962                 :     exception(UndefinedValue()),
         963                 :     runOptions(0),
         964                 :     reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
         965                 :     localeCallbacks(NULL),
         966                 :     resolvingList(NULL),
         967                 :     generatingError(false),
         968                 :     compartment(NULL),
         969                 :     stack(thisDuringConstruction()),  /* depends on cx->thread_ */
         970                 :     parseMapPool_(NULL),
         971                 :     globalObject(NULL),
         972                 :     sharpObjectMap(thisDuringConstruction()),
         973                 :     argumentFormatMap(NULL),
         974                 :     lastMessage(NULL),
         975                 :     errorReporter(NULL),
         976                 :     operationCallback(NULL),
         977                 :     data(NULL),
         978                 :     data2(NULL),
         979                 : #ifdef JS_THREADSAFE
         980                 :     outstandingRequests(0),
         981                 : #endif
         982                 :     resolveFlags(0),
         983                 :     rngSeed(0),
         984                 :     iterValue(MagicValue(JS_NO_ITER_VALUE)),
         985                 : #ifdef JS_METHODJIT
         986                 :     methodJitEnabled(false),
         987                 : #endif
         988                 :     inferenceEnabled(false),
         989                 : #ifdef MOZ_TRACE_JSCALLS
         990                 :     functionCallback(NULL),
         991                 : #endif
         992                 :     enumerators(NULL),
         993                 : #ifdef JS_THREADSAFE
         994                 :     gcBackgroundFree(NULL),
         995                 : #endif
         996                 :     activeCompilations(0)
         997                 : #ifdef DEBUG
         998           18771 :     , stackIterAssertionEnabled(true)
         999                 : #endif
        1000                 : {
        1001           18771 :     PodZero(&link);
        1002                 : #ifdef JSGC_ROOT_ANALYSIS
        1003                 :     PodArrayZero(thingGCRooters);
        1004                 : #ifdef DEBUG
        1005                 :     checkGCRooters = NULL;
        1006                 : #endif
        1007                 : #endif
        1008           18771 : }
        1009                 :
        1010           37542 : JSContext::~JSContext()
        1011                 : {
        1012                 :     /* Free the stuff hanging off of cx. */
        1013           18771 :     if (parseMapPool_)
        1014           17423 :         Foreground::delete_<ParseMapPool>(parseMapPool_);
        1015                 :
        1016           18771 :     if (lastMessage)
        1017             947 :         Foreground::free_(lastMessage);
        1018                 :
        1019                 :     /* Remove any argument formatters. */
        1020           18771 :     JSArgumentFormatMap *map = argumentFormatMap;
        1021           37542 :     while (map) {
        1022               0 :         JSArgumentFormatMap *temp = map;
        1023               0 :         map = map->next;
        1024               0 :         Foreground::free_(temp);
        1025                 :     }
        1026                 :
        1027           18771 :     JS_ASSERT(!resolvingList);
        1028           18771 : }
        1029                 :
        1030                 : void
        1031          304269 : JSContext::resetCompartment()
        1032                 : {
        1033                 :     JSObject *scopeobj;
        1034          304269 :     if (stack.hasfp()) {
        1035          191146 :         scopeobj = &fp()->scopeChain();
        1036                 :     } else {
        1037          113123 :         scopeobj = globalObject;
        1038          113123 :         if (!scopeobj)
        1039               2 :             goto error;
        1040                 :
        1041                 :         /*
        1042                 :          * Innerize. Assert, but check anyway, that this succeeds. (It
        1043                 :          * can only fail due to bugs in the engine or embedding.)
        1044                 :          */
        1045          113121 :         OBJ_TO_INNER_OBJECT(this, scopeobj);
        1046          113121 :         if (!scopeobj)
        1047               0 :             goto error;
        1048                 :     }
        1049                 :
        1050          304267 :     compartment = scopeobj->compartment();
        1051          304267 :     inferenceEnabled = compartment->types.inferenceEnabled;
        1052                 :
        1053          304267 :     if (isExceptionPending())
        1054            3055 :         wrapPendingException();
        1055          304267 :     updateJITEnabled();
        1056          304267 :     return;
        1057                 :
        1058                 : error:
        1059                 :
        1060                 :     /*
        1061                 :      * If we try to use the context without a selected compartment,
        1062                 :      * we will crash.
        1063                 :      */
        1064               2 :     compartment = NULL;
        1065                 : }
        1066                 :
        1067                 : /*
        1068                 :  * Since this function is only called in the context of a pending exception,
        1069                 :  * the caller must subsequently take an error path. If wrapping fails, it will
        1070                 :  * set a new (uncatchable) exception to be used in place of the original.
        1071                 :  */
        1072                 : void
        1073            3055 : JSContext::wrapPendingException()
        1074                 : {
        1075            3055 :     Value v = getPendingException();
        1076            3055 :     clearPendingException();
        1077            3055 :     if (compartment->wrap(this, &v))
        1078            3045 :         setPendingException(v);
        1079            3055 : }
        1080                 :
        1081                 : JSGenerator *
        1082           15714 : JSContext::generatorFor(StackFrame *fp) const
        1083                 : {
        1084           15714 :     JS_ASSERT(stack.containsSlow(fp));
        1085           15714 :     JS_ASSERT(fp->isGeneratorFrame());
        1086           15714 :     JS_ASSERT(!fp->isFloatingGenerator());
        1087           15714 :     JS_ASSERT(!genStack.empty());
        1088                 :
        1089           15714 :     if (JS_LIKELY(fp == genStack.back()->liveFrame()))
        1090           15714 :         return genStack.back();
        1091                 :
        1092                 :     /* General case; should only be needed for debug APIs. */
        1093               0 :     for (size_t i = 0; i < genStack.length(); ++i) {
        1094               0 :         if (genStack[i]->liveFrame() == fp)
        1095               0 :             return genStack[i];
        1096                 :     }
        1097               0 :     JS_NOT_REACHED("no matching generator");
        1098                 :     return NULL;
        1099                 : }
        1100                 :
        1101                 : bool
        1102         9471560 : JSContext::runningWithTrustedPrincipals() const
        1103                 : {
        1104         9471560 :     return !compartment || compartment->principals == runtime->trustedPrincipals();
        1105                 : }
        1106                 :
        1107                 : void
        1108        16533840 : JSRuntime::updateMallocCounter(JSContext *cx, size_t nbytes)
        1109                 : {
        1110                 :     /* We tolerate any thread races when updating gcMallocBytes. */
        1111        16533840 :     ptrdiff_t oldCount = gcMallocBytes;
        1112        16533840 :     ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes);
        1113        16533840 :     gcMallocBytes = newCount;
        1114        16533840 :     if (JS_UNLIKELY(newCount <= 0 && oldCount > 0))
        1115             144 :         onTooMuchMalloc();
        1116        16533696 :     else if (cx && cx->compartment)
        1117        16143748 :         cx->compartment->updateMallocCounter(nbytes);
        1118        16533840 : }
        1119                 :
        1120                 : JS_FRIEND_API(void)
        1121             144 : JSRuntime::onTooMuchMalloc()
        1122                 : {
        1123             144 :     TriggerGC(this, gcreason::TOO_MUCH_MALLOC);
        1124             144 : }
        1125                 :
        1126                 : JS_FRIEND_API(void *)
        1127               9 : JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
        1128                 : {
        1129                 :     /*
        1130                 :      * Retry when we are done with the background sweeping and have stopped
        1131                 :      * all the allocations and released the empty GC chunks.
        1132                 :      */
        1133               9 :     ShrinkGCBuffers(this);
        1134                 : #ifdef JS_THREADSAFE
        1135                 :     {
        1136              18 :         AutoLockGC lock(this);
        1137               9 :         gcHelperThread.waitBackgroundSweepOrAllocEnd();
        1138                 :     }
        1139                 : #endif
        1140               9 :     if (!p)
        1141               0 :         p = OffTheBooks::malloc_(nbytes);
        1142               9 :     else if (p == reinterpret_cast<void *>(1))
        1143               9 :         p = OffTheBooks::calloc_(nbytes);
        1144                 :     else
        1145               0 :       p = OffTheBooks::realloc_(p, nbytes);
        1146               9 :     if (p)
        1147               0 :         return p;
        1148               9 :     if (cx)
        1149               9 :         js_ReportOutOfMemory(cx);
        1150               9 :     return NULL;
        1151                 : }
        1152                 :
        1153                 : void
        1154           21103 : JSContext::purge()
        1155                 : {
        1156           21103 :     if (!activeCompilations) {
        1157           21091 :         Foreground::delete_<ParseMapPool>(parseMapPool_);
        1158           21091 :         parseMapPool_ = NULL;
        1159                 :     }
        1160           21103 : }
        1161                 :
        1162                 : #if defined(JS_METHODJIT)
        1163                 : static bool
        1164           14521 : ComputeIsJITBroken()
        1165                 : {
        1166                 : #if !defined(ANDROID) || defined(GONK)
        1167           14521 :     return false;
        1168                 : #else  // ANDROID
        1169                 :     if (getenv("JS_IGNORE_JIT_BROKENNESS")) {
        1170                 :         return false;
        1171                 :     }
        1172                 :
        1173                 :     std::string line;
        1174                 :
        1175                 :     // Check for the known-bad kernel version (2.6.29).
        1176                 :     std::ifstream osrelease("/proc/sys/kernel/osrelease");
        1177                 :     std::getline(osrelease, line);
        1178                 :     __android_log_print(ANDROID_LOG_INFO, "Gecko", "Detected osrelease `%s'",
        1179                 :                         line.c_str());
        1180                 :
        1181                 :     if (line.npos == line.find("2.6.29")) {
        1182                 :         // We're using something other than 2.6.29, so the JITs should work.
        1183                 :         __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are not broken");
        1184                 :         return false;
        1185                 :     }
        1186                 :
        1187                 :     // We're using 2.6.29, and this causes trouble with the JITs on i9000.
        1188                 :     line = "";
        1189                 :     bool broken = false;
        1190                 :     std::ifstream cpuinfo("/proc/cpuinfo");
        1191                 :     do {
        1192                 :         if (0 == line.find("Hardware")) {
        1193                 :             const char* blacklist[] = {
        1194                 :                 "SCH-I400",     // Samsung Continuum
        1195                 :                 "SGH-T959",     // Samsung i9000, Vibrant device
        1196                 :                 "SGH-I897",     // Samsung i9000, Captivate device
        1197                 :                 "SCH-I500",     // Samsung i9000, Fascinate device
        1198                 :                 "SPH-D700",     // Samsung i9000, Epic device
        1199                 :                 "GT-I9000",     // Samsung i9000, UK/Europe device
        1200                 :                 NULL
        1201                 :             };
        1202                 :             for (const char** hw = &blacklist[0]; *hw; ++hw) {
        1203                 :                 if (line.npos != line.find(*hw)) {
        1204                 :                     __android_log_print(ANDROID_LOG_INFO, "Gecko",
        1205                 :                                         "Blacklisted device `%s'", *hw);
        1206                 :                     broken = true;
        1207                 :                     break;
        1208                 :                 }
        1209                 :             }
        1210                 :             break;
        1211                 :         }
        1212                 :         std::getline(cpuinfo, line);
        1213                 :     } while(!cpuinfo.fail() && !cpuinfo.eof());
        1214                 :
        1215                 :     __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are %sbroken",
        1216                 :                         broken ? "" : "not ");
        1217                 :
        1218                 :     return broken;
        1219                 : #endif  // ifndef ANDROID
        1220                 : }
        1221                 :
        1222                 : static bool
        1223          274650 : IsJITBrokenHere()
        1224                 : {
        1225                 :     static bool computedIsBroken = false;
        1226                 :     static bool isBroken = false;
        1227          274650 :     if (!computedIsBroken) {
        1228           14521 :         isBroken = ComputeIsJITBroken();
        1229           14521 :         computedIsBroken = true;
        1230                 :     }
        1231          274650 :     return isBroken;
        1232                 : }
        1233                 : #endif
        1234                 :
        1235                 : void
        1236          422963 : JSContext::updateJITEnabled()
        1237                 : {
        1238                 : #ifdef JS_METHODJIT
        1239                 :     // This allocator randomization is actually a compartment-wide option.
        1240          422963 :     if (compartment && compartment->hasJaegerCompartment())
        1241          181343 :         compartment->jaegerCompartment()->execAlloc()->setRandomize(runtime->getJitHardening());
        1242          422963 :     methodJitEnabled = (runOptions & JSOPTION_METHODJIT) && !IsJITBrokenHere();
        1243                 : #endif
        1244          422963 : }
        1245                 :
        1246                 : size_t
        1247               0 : JSContext::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const
        1248                 : {
        1249                 :     /*
        1250                 :      * There are other JSContext members that could be measured; the following
        1251                 :      * ones have been found by DMD to be worth measuring.  More stuff may be
        1252                 :      * added later.
        1253                 :      */
        1254               0 :     return mallocSizeOf(this) + busyArrays.sizeOfExcludingThis(mallocSizeOf);
        1255                 : }
        1256                 :
        1257                 : void
        1258           22875 : JSContext::mark(JSTracer *trc)
        1259                 : {
        1260                 :     /* Stack frames and slots are traced by StackSpace::mark. */
        1261                 :
        1262                 :     /* Mark other roots-by-definition in the JSContext. */
        1263           22875 :     if (globalObject && !hasRunOption(JSOPTION_UNROOTED_GLOBAL))
        1264           22875 :         MarkObjectRoot(trc, &globalObject, "global object");
        1265           22875 :     if (isExceptionPending())
        1266              73 :         MarkValueRoot(trc, &exception, "exception");
        1267                 :
        1268           22875 :     if (sharpObjectMap.depth > 0)
        1269               2 :         js_TraceSharpMap(trc, &sharpObjectMap);
        1270                 :
        1271           22875 :     MarkValueRoot(trc, &iterValue, "iterValue");
        1272           22875 : }
        1273                 :
        1274                 : namespace JS {
        1275                 :
        1276                 : #if defined JS_THREADSAFE && defined DEBUG
        1277                 :
        1278      1162197621 : AutoCheckRequestDepth::AutoCheckRequestDepth(JSContext *cx)
        1279      1162197621 :     : cx(cx)
        1280                 : {
        1281      1162197621 :     JS_ASSERT(cx->runtime->requestDepth || cx->runtime->gcRunning);
        1282      1162197621 :     JS_ASSERT(cx->runtime->onOwnerThread());
        1283      1162197621 :     cx->runtime->checkRequestDepth++;
        1284      1162197621 : }
        1285                 :
        1286      1162197621 : AutoCheckRequestDepth::~AutoCheckRequestDepth()
        1287                 : {
        1288      1162197621 :     JS_ASSERT(cx->runtime->checkRequestDepth != 0);
        1289      1162197621 :     cx->runtime->checkRequestDepth--;
        1290      1162197621 : }
        1291                 :
        1292                 : #endif
        1293                 :
        1294                 : } // namespace JS

Generated by: LCOV version 1.7