1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jscntxt.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1394 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * JS execution context. 1.12 + */ 1.13 + 1.14 +#include "jscntxtinlines.h" 1.15 + 1.16 +#include "mozilla/ArrayUtils.h" 1.17 +#include "mozilla/DebugOnly.h" 1.18 +#include "mozilla/MemoryReporting.h" 1.19 + 1.20 +#include <ctype.h> 1.21 +#include <stdarg.h> 1.22 +#include <string.h> 1.23 +#ifdef ANDROID 1.24 +# include <android/log.h> 1.25 +# include <fstream> 1.26 +# include <string> 1.27 +#endif // ANDROID 1.28 + 1.29 +#include "jsatom.h" 1.30 +#include "jscompartment.h" 1.31 +#include "jsexn.h" 1.32 +#include "jsfun.h" 1.33 +#include "jsgc.h" 1.34 +#include "jsiter.h" 1.35 +#include "jsobj.h" 1.36 +#include "jsopcode.h" 1.37 +#include "jsprf.h" 1.38 +#include "jspubtd.h" 1.39 +#include "jsscript.h" 1.40 +#include "jsstr.h" 1.41 +#include "jstypes.h" 1.42 +#include "jswatchpoint.h" 1.43 +#include "jsworkers.h" 1.44 + 1.45 +#include "gc/Marking.h" 1.46 +#ifdef JS_ION 1.47 +#include "jit/Ion.h" 1.48 +#endif 1.49 +#include "js/CharacterEncoding.h" 1.50 +#include "js/OldDebugAPI.h" 1.51 +#include "vm/Shape.h" 1.52 +#include "yarr/BumpPointerAllocator.h" 1.53 + 1.54 +#include "jsobjinlines.h" 1.55 +#include "jsscriptinlines.h" 1.56 + 1.57 +#include "vm/Stack-inl.h" 1.58 + 1.59 +using namespace js; 1.60 +using namespace js::gc; 1.61 + 1.62 +using mozilla::DebugOnly; 1.63 +using mozilla::PodArrayZero; 1.64 +using mozilla::PodZero; 1.65 +using mozilla::PointerRangeSize; 1.66 + 1.67 +bool 1.68 +js::AutoCycleDetector::init() 1.69 +{ 1.70 + ObjectSet &set = cx->cycleDetectorSet; 1.71 + hashsetAddPointer = set.lookupForAdd(obj); 1.72 + if (!hashsetAddPointer) { 1.73 + if (!set.add(hashsetAddPointer, obj)) 1.74 + return false; 1.75 + cyclic = false; 1.76 + hashsetGenerationAtInit = set.generation(); 1.77 + } 1.78 + return true; 1.79 +} 1.80 + 1.81 +js::AutoCycleDetector::~AutoCycleDetector() 1.82 +{ 1.83 + if (!cyclic) { 1.84 + if (hashsetGenerationAtInit == cx->cycleDetectorSet.generation()) 1.85 + cx->cycleDetectorSet.remove(hashsetAddPointer); 1.86 + else 1.87 + cx->cycleDetectorSet.remove(obj); 1.88 + } 1.89 +} 1.90 + 1.91 +void 1.92 +js::TraceCycleDetectionSet(JSTracer *trc, js::ObjectSet &set) 1.93 +{ 1.94 + for (js::ObjectSet::Enum e(set); !e.empty(); e.popFront()) { 1.95 + JSObject *prior = e.front(); 1.96 + MarkObjectRoot(trc, const_cast<JSObject **>(&e.front()), "cycle detector table entry"); 1.97 + if (prior != e.front()) 1.98 + e.rekeyFront(e.front()); 1.99 + } 1.100 +} 1.101 + 1.102 +void 1.103 +JSCompartment::sweepCallsiteClones() 1.104 +{ 1.105 + if (callsiteClones.initialized()) { 1.106 + for (CallsiteCloneTable::Enum e(callsiteClones); !e.empty(); e.popFront()) { 1.107 + CallsiteCloneKey key = e.front().key(); 1.108 + JSFunction *fun = e.front().value(); 1.109 + if (!IsScriptMarked(&key.script) || !IsObjectMarked(&fun)) 1.110 + e.removeFront(); 1.111 + } 1.112 + } 1.113 +} 1.114 + 1.115 +JSFunction * 1.116 +js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction *fun, 1.117 + JSScript *script, jsbytecode *pc) 1.118 +{ 1.119 + JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite()); 1.120 + JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope()); 1.121 + JS_ASSERT(types::UseNewTypeForClone(fun)); 1.122 + 1.123 + /* 1.124 + * If we start allocating function objects in the nursery, then the callsite 1.125 + * clone table will need a postbarrier. 1.126 + */ 1.127 + JS_ASSERT(fun->isTenured()); 1.128 + 1.129 + if (!table.initialized()) 1.130 + return nullptr; 1.131 + 1.132 + CallsiteCloneTable::Ptr p = table.readonlyThreadsafeLookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc))); 1.133 + if (p) 1.134 + return p->value(); 1.135 + 1.136 + return nullptr; 1.137 +} 1.138 + 1.139 +JSFunction * 1.140 +js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript script, jsbytecode *pc) 1.141 +{ 1.142 + if (JSFunction *clone = ExistingCloneFunctionAtCallsite(cx->compartment()->callsiteClones, fun, script, pc)) 1.143 + return clone; 1.144 + 1.145 + RootedObject parent(cx, fun->environment()); 1.146 + JSFunction *clone = CloneFunctionObject(cx, fun, parent); 1.147 + if (!clone) 1.148 + return nullptr; 1.149 + 1.150 + /* 1.151 + * Store a link back to the original for function.caller and avoid cloning 1.152 + * clones. 1.153 + */ 1.154 + clone->nonLazyScript()->setIsCallsiteClone(fun); 1.155 + 1.156 + typedef CallsiteCloneKey Key; 1.157 + typedef CallsiteCloneTable Table; 1.158 + 1.159 + Table &table = cx->compartment()->callsiteClones; 1.160 + if (!table.initialized() && !table.init()) 1.161 + return nullptr; 1.162 + 1.163 + if (!table.putNew(Key(fun, script, script->pcToOffset(pc)), clone)) 1.164 + return nullptr; 1.165 + 1.166 + return clone; 1.167 +} 1.168 + 1.169 +JSContext * 1.170 +js::NewContext(JSRuntime *rt, size_t stackChunkSize) 1.171 +{ 1.172 + JS_AbortIfWrongThread(rt); 1.173 + 1.174 + JSContext *cx = js_new<JSContext>(rt); 1.175 + if (!cx) 1.176 + return nullptr; 1.177 + 1.178 + if (!cx->cycleDetectorSet.init()) { 1.179 + js_delete(cx); 1.180 + return nullptr; 1.181 + } 1.182 + 1.183 + /* 1.184 + * Here the GC lock is still held after js_InitContextThreadAndLockGC took it and 1.185 + * the GC is not running on another thread. 1.186 + */ 1.187 + rt->contextList.insertBack(cx); 1.188 + 1.189 + /* 1.190 + * If cx is the first context on this runtime, initialize well-known atoms, 1.191 + * keywords, numbers, strings and self-hosted scripts. If one of these 1.192 + * steps should fail, the runtime will be left in a partially initialized 1.193 + * state, with zeroes and nulls stored in the default-initialized remainder 1.194 + * of the struct. 1.195 + */ 1.196 + if (!rt->haveCreatedContext) { 1.197 +#ifdef JS_THREADSAFE 1.198 + JS_BeginRequest(cx); 1.199 +#endif 1.200 + bool ok = rt->initializeAtoms(cx); 1.201 + if (ok) 1.202 + ok = rt->initSelfHosting(cx); 1.203 + 1.204 + if (ok && !rt->parentRuntime) 1.205 + ok = rt->transformToPermanentAtoms(); 1.206 + 1.207 +#ifdef JS_THREADSAFE 1.208 + JS_EndRequest(cx); 1.209 +#endif 1.210 + if (!ok) { 1.211 + DestroyContext(cx, DCM_NEW_FAILED); 1.212 + return nullptr; 1.213 + } 1.214 + 1.215 + rt->haveCreatedContext = true; 1.216 + } 1.217 + 1.218 + JSContextCallback cxCallback = rt->cxCallback; 1.219 + if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW, rt->cxCallbackData)) { 1.220 + DestroyContext(cx, DCM_NEW_FAILED); 1.221 + return nullptr; 1.222 + } 1.223 + 1.224 + return cx; 1.225 +} 1.226 + 1.227 +void 1.228 +js::DestroyContext(JSContext *cx, DestroyContextMode mode) 1.229 +{ 1.230 + JSRuntime *rt = cx->runtime(); 1.231 + JS_AbortIfWrongThread(rt); 1.232 + 1.233 +#ifdef JS_THREADSAFE 1.234 + if (cx->outstandingRequests != 0) 1.235 + MOZ_CRASH(); 1.236 +#endif 1.237 + 1.238 +#if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG) 1.239 + for (int i = 0; i < THING_ROOT_LIMIT; ++i) 1.240 + JS_ASSERT(cx->thingGCRooters[i] == nullptr); 1.241 +#endif 1.242 + 1.243 + if (mode != DCM_NEW_FAILED) { 1.244 + if (JSContextCallback cxCallback = rt->cxCallback) { 1.245 + /* 1.246 + * JSCONTEXT_DESTROY callback is not allowed to fail and must 1.247 + * return true. 1.248 + */ 1.249 + JS_ALWAYS_TRUE(cxCallback(cx, JSCONTEXT_DESTROY, 1.250 + rt->cxCallbackData)); 1.251 + } 1.252 + } 1.253 + 1.254 + cx->remove(); 1.255 + bool last = !rt->hasContexts(); 1.256 + if (last) { 1.257 + /* 1.258 + * Dump remaining type inference results while we still have a context. 1.259 + * This printing depends on atoms still existing. 1.260 + */ 1.261 + for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) 1.262 + c->types.print(cx, false); 1.263 + } 1.264 + if (mode == DCM_FORCE_GC) { 1.265 + JS_ASSERT(!rt->isHeapBusy()); 1.266 + JS::PrepareForFullGC(rt); 1.267 + GC(rt, GC_NORMAL, JS::gcreason::DESTROY_CONTEXT); 1.268 + } 1.269 + js_delete_poison(cx); 1.270 +} 1.271 + 1.272 +bool 1.273 +AutoResolving::alreadyStartedSlow() const 1.274 +{ 1.275 + JS_ASSERT(link); 1.276 + AutoResolving *cursor = link; 1.277 + do { 1.278 + JS_ASSERT(this != cursor); 1.279 + if (object.get() == cursor->object && id.get() == cursor->id && kind == cursor->kind) 1.280 + return true; 1.281 + } while (!!(cursor = cursor->link)); 1.282 + return false; 1.283 +} 1.284 + 1.285 +static void 1.286 +ReportError(JSContext *cx, const char *message, JSErrorReport *reportp, 1.287 + JSErrorCallback callback, void *userRef) 1.288 +{ 1.289 + /* 1.290 + * Check the error report, and set a JavaScript-catchable exception 1.291 + * if the error is defined to have an associated exception. If an 1.292 + * exception is thrown, then the JSREPORT_EXCEPTION flag will be set 1.293 + * on the error report, and exception-aware hosts should ignore it. 1.294 + */ 1.295 + JS_ASSERT(reportp); 1.296 + if ((!callback || callback == js_GetErrorMessage) && 1.297 + reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION) 1.298 + { 1.299 + reportp->flags |= JSREPORT_EXCEPTION; 1.300 + } 1.301 + 1.302 + /* 1.303 + * Call the error reporter only if an exception wasn't raised. 1.304 + * 1.305 + * If an exception was raised, then we call the debugErrorHook 1.306 + * (if present) to give it a chance to see the error before it 1.307 + * propagates out of scope. This is needed for compatibility 1.308 + * with the old scheme. 1.309 + */ 1.310 + if (!JS_IsRunning(cx) || !js_ErrorToException(cx, message, reportp, callback, userRef)) { 1.311 + if (message) 1.312 + CallErrorReporter(cx, message, reportp); 1.313 + } else if (JSDebugErrorHook hook = cx->runtime()->debugHooks.debugErrorHook) { 1.314 + /* 1.315 + * If we've already chewed up all the C stack, don't call into the 1.316 + * error reporter since this may trigger an infinite recursion where 1.317 + * the reporter triggers an over-recursion. 1.318 + */ 1.319 + int stackDummy; 1.320 + if (!JS_CHECK_STACK_SIZE(GetNativeStackLimit(cx), &stackDummy)) 1.321 + return; 1.322 + 1.323 + if (cx->errorReporter) 1.324 + hook(cx, message, reportp, cx->runtime()->debugHooks.debugErrorHookData); 1.325 + } 1.326 +} 1.327 + 1.328 +/* 1.329 + * The given JSErrorReport object have been zeroed and must not outlive 1.330 + * cx->fp() (otherwise report->originPrincipals may become invalid). 1.331 + */ 1.332 +static void 1.333 +PopulateReportBlame(JSContext *cx, JSErrorReport *report) 1.334 +{ 1.335 + /* 1.336 + * Walk stack until we find a frame that is associated with a non-builtin 1.337 + * rather than a builtin frame. 1.338 + */ 1.339 + NonBuiltinFrameIter iter(cx); 1.340 + if (iter.done()) 1.341 + return; 1.342 + 1.343 + report->filename = iter.scriptFilename(); 1.344 + report->lineno = iter.computeLine(&report->column); 1.345 + report->originPrincipals = iter.originPrincipals(); 1.346 +} 1.347 + 1.348 +/* 1.349 + * Since memory has been exhausted, avoid the normal error-handling path which 1.350 + * allocates an error object, report and callstack. If code is running, simply 1.351 + * throw the static atom "out of memory". If code is not running, call the 1.352 + * error reporter directly. 1.353 + * 1.354 + * Furthermore, callers of js_ReportOutOfMemory (viz., malloc) assume a GC does 1.355 + * not occur, so GC must be avoided or suppressed. 1.356 + */ 1.357 +void 1.358 +js_ReportOutOfMemory(ThreadSafeContext *cxArg) 1.359 +{ 1.360 +#ifdef JS_MORE_DETERMINISTIC 1.361 + /* 1.362 + * OOMs are non-deterministic, especially across different execution modes 1.363 + * (e.g. interpreter vs JIT). In more-deterministic builds, print to stderr 1.364 + * so that the fuzzers can detect this. 1.365 + */ 1.366 + fprintf(stderr, "js_ReportOutOfMemory called\n"); 1.367 +#endif 1.368 + 1.369 + if (cxArg->isForkJoinContext()) { 1.370 + cxArg->asForkJoinContext()->setPendingAbortFatal(ParallelBailoutOutOfMemory); 1.371 + return; 1.372 + } 1.373 + 1.374 + if (!cxArg->isJSContext()) 1.375 + return; 1.376 + 1.377 + JSContext *cx = cxArg->asJSContext(); 1.378 + cx->runtime()->hadOutOfMemory = true; 1.379 + 1.380 + /* Report the oom. */ 1.381 + if (JS::OutOfMemoryCallback oomCallback = cx->runtime()->oomCallback) { 1.382 + AutoSuppressGC suppressGC(cx); 1.383 + oomCallback(cx); 1.384 + } 1.385 + 1.386 + if (JS_IsRunning(cx)) { 1.387 + cx->setPendingException(StringValue(cx->names().outOfMemory)); 1.388 + return; 1.389 + } 1.390 + 1.391 + /* Get the message for this error, but we don't expand any arguments. */ 1.392 + const JSErrorFormatString *efs = 1.393 + js_GetLocalizedErrorMessage(cx, nullptr, nullptr, JSMSG_OUT_OF_MEMORY); 1.394 + const char *msg = efs ? efs->format : "Out of memory"; 1.395 + 1.396 + /* Fill out the report, but don't do anything that requires allocation. */ 1.397 + JSErrorReport report; 1.398 + PodZero(&report); 1.399 + report.flags = JSREPORT_ERROR; 1.400 + report.errorNumber = JSMSG_OUT_OF_MEMORY; 1.401 + PopulateReportBlame(cx, &report); 1.402 + 1.403 + /* Report the error. */ 1.404 + if (JSErrorReporter onError = cx->errorReporter) { 1.405 + AutoSuppressGC suppressGC(cx); 1.406 + onError(cx, msg, &report); 1.407 + } 1.408 + 1.409 + /* 1.410 + * We would like to enforce the invariant that any exception reported 1.411 + * during an OOM situation does not require wrapping. Besides avoiding 1.412 + * allocation when memory is low, this reduces the number of places where 1.413 + * we might need to GC. 1.414 + * 1.415 + * When JS code is running, we set the pending exception to an atom, which 1.416 + * does not need wrapping. If no JS code is running, no exception should be 1.417 + * set at all. 1.418 + */ 1.419 + JS_ASSERT(!cx->isExceptionPending()); 1.420 +} 1.421 + 1.422 +JS_FRIEND_API(void) 1.423 +js_ReportOverRecursed(JSContext *maybecx) 1.424 +{ 1.425 +#ifdef JS_MORE_DETERMINISTIC 1.426 + /* 1.427 + * We cannot make stack depth deterministic across different 1.428 + * implementations (e.g. JIT vs. interpreter will differ in 1.429 + * their maximum stack depth). 1.430 + * However, we can detect externally when we hit the maximum 1.431 + * stack depth which is useful for external testing programs 1.432 + * like fuzzers. 1.433 + */ 1.434 + fprintf(stderr, "js_ReportOverRecursed called\n"); 1.435 +#endif 1.436 + if (maybecx) 1.437 + JS_ReportErrorNumber(maybecx, js_GetErrorMessage, nullptr, JSMSG_OVER_RECURSED); 1.438 +} 1.439 + 1.440 +void 1.441 +js_ReportOverRecursed(ThreadSafeContext *cx) 1.442 +{ 1.443 + if (cx->isJSContext()) 1.444 + js_ReportOverRecursed(cx->asJSContext()); 1.445 + else if (cx->isExclusiveContext()) 1.446 + cx->asExclusiveContext()->addPendingOverRecursed(); 1.447 +} 1.448 + 1.449 +void 1.450 +js_ReportAllocationOverflow(ThreadSafeContext *cxArg) 1.451 +{ 1.452 + if (!cxArg) 1.453 + return; 1.454 + 1.455 + if (cxArg->isForkJoinContext()) { 1.456 + cxArg->asForkJoinContext()->setPendingAbortFatal(ParallelBailoutOutOfMemory); 1.457 + return; 1.458 + } 1.459 + 1.460 + if (!cxArg->isJSContext()) 1.461 + return; 1.462 + JSContext *cx = cxArg->asJSContext(); 1.463 + 1.464 + AutoSuppressGC suppressGC(cx); 1.465 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_ALLOC_OVERFLOW); 1.466 +} 1.467 + 1.468 +/* 1.469 + * Given flags and the state of cx, decide whether we should report an 1.470 + * error, a warning, or just continue execution normally. Return 1.471 + * true if we should continue normally, without reporting anything; 1.472 + * otherwise, adjust *flags as appropriate and return false. 1.473 + */ 1.474 +static bool 1.475 +checkReportFlags(JSContext *cx, unsigned *flags) 1.476 +{ 1.477 + if (JSREPORT_IS_STRICT_MODE_ERROR(*flags)) { 1.478 + /* 1.479 + * Error in strict code; warning with extra warnings option; okay 1.480 + * otherwise. We assume that if the top frame is a native, then it is 1.481 + * strict if the nearest scripted frame is strict, see bug 536306. 1.482 + */ 1.483 + JSScript *script = cx->currentScript(); 1.484 + if (script && script->strict()) 1.485 + *flags &= ~JSREPORT_WARNING; 1.486 + else if (cx->options().extraWarnings()) 1.487 + *flags |= JSREPORT_WARNING; 1.488 + else 1.489 + return true; 1.490 + } else if (JSREPORT_IS_STRICT(*flags)) { 1.491 + /* Warning/error only when JSOPTION_STRICT is set. */ 1.492 + if (!cx->options().extraWarnings()) 1.493 + return true; 1.494 + } 1.495 + 1.496 + /* Warnings become errors when JSOPTION_WERROR is set. */ 1.497 + if (JSREPORT_IS_WARNING(*flags) && cx->options().werror()) 1.498 + *flags &= ~JSREPORT_WARNING; 1.499 + 1.500 + return false; 1.501 +} 1.502 + 1.503 +bool 1.504 +js_ReportErrorVA(JSContext *cx, unsigned flags, const char *format, va_list ap) 1.505 +{ 1.506 + char *message; 1.507 + jschar *ucmessage; 1.508 + size_t messagelen; 1.509 + JSErrorReport report; 1.510 + bool warning; 1.511 + 1.512 + if (checkReportFlags(cx, &flags)) 1.513 + return true; 1.514 + 1.515 + message = JS_vsmprintf(format, ap); 1.516 + if (!message) 1.517 + return false; 1.518 + messagelen = strlen(message); 1.519 + 1.520 + PodZero(&report); 1.521 + report.flags = flags; 1.522 + report.errorNumber = JSMSG_USER_DEFINED_ERROR; 1.523 + report.ucmessage = ucmessage = InflateString(cx, message, &messagelen); 1.524 + PopulateReportBlame(cx, &report); 1.525 + 1.526 + warning = JSREPORT_IS_WARNING(report.flags); 1.527 + 1.528 + ReportError(cx, message, &report, nullptr, nullptr); 1.529 + js_free(message); 1.530 + js_free(ucmessage); 1.531 + return warning; 1.532 +} 1.533 + 1.534 +/* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */ 1.535 +void 1.536 +js::ReportUsageError(JSContext *cx, HandleObject callee, const char *msg) 1.537 +{ 1.538 + const char *usageStr = "usage"; 1.539 + PropertyName *usageAtom = Atomize(cx, usageStr, strlen(usageStr))->asPropertyName(); 1.540 + RootedId id(cx, NameToId(usageAtom)); 1.541 + DebugOnly<Shape *> shape = static_cast<Shape *>(callee->nativeLookup(cx, id)); 1.542 + JS_ASSERT(!shape->configurable()); 1.543 + JS_ASSERT(!shape->writable()); 1.544 + JS_ASSERT(shape->hasDefaultGetter()); 1.545 + 1.546 + RootedValue usage(cx); 1.547 + if (!JS_LookupProperty(cx, callee, "usage", &usage)) 1.548 + return; 1.549 + 1.550 + if (JSVAL_IS_VOID(usage)) { 1.551 + JS_ReportError(cx, "%s", msg); 1.552 + } else { 1.553 + JSString *str = JSVAL_TO_STRING(usage); 1.554 + JS::Anchor<JSString *> a_str(str); 1.555 + const jschar *chars = JS_GetStringCharsZ(cx, str); 1.556 + if (!chars) 1.557 + return; 1.558 + JS_ReportError(cx, "%s. Usage: %hs", msg, chars); 1.559 + } 1.560 +} 1.561 + 1.562 +bool 1.563 +js::PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *report, 1.564 + bool reportWarnings) 1.565 +{ 1.566 + if (!report) { 1.567 + fprintf(file, "%s\n", message); 1.568 + fflush(file); 1.569 + return false; 1.570 + } 1.571 + 1.572 + /* Conditionally ignore reported warnings. */ 1.573 + if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) 1.574 + return false; 1.575 + 1.576 + char *prefix = nullptr; 1.577 + if (report->filename) 1.578 + prefix = JS_smprintf("%s:", report->filename); 1.579 + if (report->lineno) { 1.580 + char *tmp = prefix; 1.581 + prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column); 1.582 + JS_free(cx, tmp); 1.583 + } 1.584 + if (JSREPORT_IS_WARNING(report->flags)) { 1.585 + char *tmp = prefix; 1.586 + prefix = JS_smprintf("%s%swarning: ", 1.587 + tmp ? tmp : "", 1.588 + JSREPORT_IS_STRICT(report->flags) ? "strict " : ""); 1.589 + JS_free(cx, tmp); 1.590 + } 1.591 + 1.592 + /* embedded newlines -- argh! */ 1.593 + const char *ctmp; 1.594 + while ((ctmp = strchr(message, '\n')) != 0) { 1.595 + ctmp++; 1.596 + if (prefix) 1.597 + fputs(prefix, file); 1.598 + fwrite(message, 1, ctmp - message, file); 1.599 + message = ctmp; 1.600 + } 1.601 + 1.602 + /* If there were no filename or lineno, the prefix might be empty */ 1.603 + if (prefix) 1.604 + fputs(prefix, file); 1.605 + fputs(message, file); 1.606 + 1.607 + if (report->linebuf) { 1.608 + /* report->linebuf usually ends with a newline. */ 1.609 + int n = strlen(report->linebuf); 1.610 + fprintf(file, ":\n%s%s%s%s", 1.611 + prefix, 1.612 + report->linebuf, 1.613 + (n > 0 && report->linebuf[n-1] == '\n') ? "" : "\n", 1.614 + prefix); 1.615 + n = report->tokenptr - report->linebuf; 1.616 + for (int i = 0, j = 0; i < n; i++) { 1.617 + if (report->linebuf[i] == '\t') { 1.618 + for (int k = (j + 8) & ~7; j < k; j++) { 1.619 + fputc('.', file); 1.620 + } 1.621 + continue; 1.622 + } 1.623 + fputc('.', file); 1.624 + j++; 1.625 + } 1.626 + fputc('^', file); 1.627 + } 1.628 + fputc('\n', file); 1.629 + fflush(file); 1.630 + JS_free(cx, prefix); 1.631 + return true; 1.632 +} 1.633 + 1.634 +char * 1.635 +js_strdup(ExclusiveContext *cx, const char *s) 1.636 +{ 1.637 + size_t n = strlen(s) + 1; 1.638 + void *p = cx->malloc_(n); 1.639 + if (!p) 1.640 + return nullptr; 1.641 + return (char *)js_memcpy(p, s, n); 1.642 +} 1.643 + 1.644 +/* 1.645 + * The arguments from ap need to be packaged up into an array and stored 1.646 + * into the report struct. 1.647 + * 1.648 + * The format string addressed by the error number may contain operands 1.649 + * identified by the format {N}, where N is a decimal digit. Each of these 1.650 + * is to be replaced by the Nth argument from the va_list. The complete 1.651 + * message is placed into reportp->ucmessage converted to a JSString. 1.652 + * 1.653 + * Returns true if the expansion succeeds (can fail if out of memory). 1.654 + */ 1.655 +bool 1.656 +js_ExpandErrorArguments(ExclusiveContext *cx, JSErrorCallback callback, 1.657 + void *userRef, const unsigned errorNumber, 1.658 + char **messagep, JSErrorReport *reportp, 1.659 + ErrorArgumentsType argumentsType, va_list ap) 1.660 +{ 1.661 + const JSErrorFormatString *efs; 1.662 + int i; 1.663 + int argCount; 1.664 + bool messageArgsPassed = !!reportp->messageArgs; 1.665 + 1.666 + *messagep = nullptr; 1.667 + 1.668 + /* Most calls supply js_GetErrorMessage; if this is so, assume nullptr. */ 1.669 + if (!callback || callback == js_GetErrorMessage) 1.670 + efs = js_GetLocalizedErrorMessage(cx, userRef, nullptr, errorNumber); 1.671 + else 1.672 + efs = callback(userRef, nullptr, errorNumber); 1.673 + if (efs) { 1.674 + reportp->exnType = efs->exnType; 1.675 + 1.676 + size_t totalArgsLength = 0; 1.677 + size_t argLengths[10]; /* only {0} thru {9} supported */ 1.678 + argCount = efs->argCount; 1.679 + JS_ASSERT(argCount <= 10); 1.680 + if (argCount > 0) { 1.681 + /* 1.682 + * Gather the arguments into an array, and accumulate 1.683 + * their sizes. We allocate 1 more than necessary and 1.684 + * null it out to act as the caboose when we free the 1.685 + * pointers later. 1.686 + */ 1.687 + if (messageArgsPassed) { 1.688 + JS_ASSERT(!reportp->messageArgs[argCount]); 1.689 + } else { 1.690 + reportp->messageArgs = cx->pod_malloc<const jschar*>(argCount + 1); 1.691 + if (!reportp->messageArgs) 1.692 + return false; 1.693 + /* nullptr-terminate for easy copying. */ 1.694 + reportp->messageArgs[argCount] = nullptr; 1.695 + } 1.696 + for (i = 0; i < argCount; i++) { 1.697 + if (messageArgsPassed) { 1.698 + /* Do nothing. */ 1.699 + } else if (argumentsType == ArgumentsAreASCII) { 1.700 + char *charArg = va_arg(ap, char *); 1.701 + size_t charArgLength = strlen(charArg); 1.702 + reportp->messageArgs[i] = InflateString(cx, charArg, &charArgLength); 1.703 + if (!reportp->messageArgs[i]) 1.704 + goto error; 1.705 + } else { 1.706 + reportp->messageArgs[i] = va_arg(ap, jschar *); 1.707 + } 1.708 + argLengths[i] = js_strlen(reportp->messageArgs[i]); 1.709 + totalArgsLength += argLengths[i]; 1.710 + } 1.711 + } 1.712 + /* 1.713 + * Parse the error format, substituting the argument X 1.714 + * for {X} in the format. 1.715 + */ 1.716 + if (argCount > 0) { 1.717 + if (efs->format) { 1.718 + jschar *buffer, *fmt, *out; 1.719 + int expandedArgs = 0; 1.720 + size_t expandedLength; 1.721 + size_t len = strlen(efs->format); 1.722 + 1.723 + buffer = fmt = InflateString(cx, efs->format, &len); 1.724 + if (!buffer) 1.725 + goto error; 1.726 + expandedLength = len 1.727 + - (3 * argCount) /* exclude the {n} */ 1.728 + + totalArgsLength; 1.729 + 1.730 + /* 1.731 + * Note - the above calculation assumes that each argument 1.732 + * is used once and only once in the expansion !!! 1.733 + */ 1.734 + reportp->ucmessage = out = cx->pod_malloc<jschar>(expandedLength + 1); 1.735 + if (!out) { 1.736 + js_free(buffer); 1.737 + goto error; 1.738 + } 1.739 + while (*fmt) { 1.740 + if (*fmt == '{') { 1.741 + if (isdigit(fmt[1])) { 1.742 + int d = JS7_UNDEC(fmt[1]); 1.743 + JS_ASSERT(d < argCount); 1.744 + js_strncpy(out, reportp->messageArgs[d], 1.745 + argLengths[d]); 1.746 + out += argLengths[d]; 1.747 + fmt += 3; 1.748 + expandedArgs++; 1.749 + continue; 1.750 + } 1.751 + } 1.752 + *out++ = *fmt++; 1.753 + } 1.754 + JS_ASSERT(expandedArgs == argCount); 1.755 + *out = 0; 1.756 + js_free(buffer); 1.757 + TwoByteChars ucmsg(reportp->ucmessage, 1.758 + PointerRangeSize(static_cast<const jschar *>(reportp->ucmessage), 1.759 + static_cast<const jschar *>(out))); 1.760 + *messagep = LossyTwoByteCharsToNewLatin1CharsZ(cx, ucmsg).c_str(); 1.761 + if (!*messagep) 1.762 + goto error; 1.763 + } 1.764 + } else { 1.765 + /* Non-null messageArgs should have at least one non-null arg. */ 1.766 + JS_ASSERT(!reportp->messageArgs); 1.767 + /* 1.768 + * Zero arguments: the format string (if it exists) is the 1.769 + * entire message. 1.770 + */ 1.771 + if (efs->format) { 1.772 + size_t len; 1.773 + *messagep = js_strdup(cx, efs->format); 1.774 + if (!*messagep) 1.775 + goto error; 1.776 + len = strlen(*messagep); 1.777 + reportp->ucmessage = InflateString(cx, *messagep, &len); 1.778 + if (!reportp->ucmessage) 1.779 + goto error; 1.780 + } 1.781 + } 1.782 + } 1.783 + if (*messagep == nullptr) { 1.784 + /* where's the right place for this ??? */ 1.785 + const char *defaultErrorMessage 1.786 + = "No error message available for error number %d"; 1.787 + size_t nbytes = strlen(defaultErrorMessage) + 16; 1.788 + *messagep = cx->pod_malloc<char>(nbytes); 1.789 + if (!*messagep) 1.790 + goto error; 1.791 + JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber); 1.792 + } 1.793 + return true; 1.794 + 1.795 +error: 1.796 + if (!messageArgsPassed && reportp->messageArgs) { 1.797 + /* free the arguments only if we allocated them */ 1.798 + if (argumentsType == ArgumentsAreASCII) { 1.799 + i = 0; 1.800 + while (reportp->messageArgs[i]) 1.801 + js_free((void *)reportp->messageArgs[i++]); 1.802 + } 1.803 + js_free((void *)reportp->messageArgs); 1.804 + reportp->messageArgs = nullptr; 1.805 + } 1.806 + if (reportp->ucmessage) { 1.807 + js_free((void *)reportp->ucmessage); 1.808 + reportp->ucmessage = nullptr; 1.809 + } 1.810 + if (*messagep) { 1.811 + js_free((void *)*messagep); 1.812 + *messagep = nullptr; 1.813 + } 1.814 + return false; 1.815 +} 1.816 + 1.817 +bool 1.818 +js_ReportErrorNumberVA(JSContext *cx, unsigned flags, JSErrorCallback callback, 1.819 + void *userRef, const unsigned errorNumber, 1.820 + ErrorArgumentsType argumentsType, va_list ap) 1.821 +{ 1.822 + JSErrorReport report; 1.823 + char *message; 1.824 + bool warning; 1.825 + 1.826 + if (checkReportFlags(cx, &flags)) 1.827 + return true; 1.828 + warning = JSREPORT_IS_WARNING(flags); 1.829 + 1.830 + PodZero(&report); 1.831 + report.flags = flags; 1.832 + report.errorNumber = errorNumber; 1.833 + PopulateReportBlame(cx, &report); 1.834 + 1.835 + if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber, 1.836 + &message, &report, argumentsType, ap)) { 1.837 + return false; 1.838 + } 1.839 + 1.840 + ReportError(cx, message, &report, callback, userRef); 1.841 + 1.842 + js_free(message); 1.843 + if (report.messageArgs) { 1.844 + /* 1.845 + * js_ExpandErrorArguments owns its messageArgs only if it had to 1.846 + * inflate the arguments (from regular |char *|s). 1.847 + */ 1.848 + if (argumentsType == ArgumentsAreASCII) { 1.849 + int i = 0; 1.850 + while (report.messageArgs[i]) 1.851 + js_free((void *)report.messageArgs[i++]); 1.852 + } 1.853 + js_free((void *)report.messageArgs); 1.854 + } 1.855 + js_free((void *)report.ucmessage); 1.856 + 1.857 + return warning; 1.858 +} 1.859 + 1.860 +bool 1.861 +js_ReportErrorNumberUCArray(JSContext *cx, unsigned flags, JSErrorCallback callback, 1.862 + void *userRef, const unsigned errorNumber, 1.863 + const jschar **args) 1.864 +{ 1.865 + if (checkReportFlags(cx, &flags)) 1.866 + return true; 1.867 + bool warning = JSREPORT_IS_WARNING(flags); 1.868 + 1.869 + JSErrorReport report; 1.870 + PodZero(&report); 1.871 + report.flags = flags; 1.872 + report.errorNumber = errorNumber; 1.873 + PopulateReportBlame(cx, &report); 1.874 + report.messageArgs = args; 1.875 + 1.876 + char *message; 1.877 + va_list dummy; 1.878 + if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber, 1.879 + &message, &report, ArgumentsAreUnicode, dummy)) { 1.880 + return false; 1.881 + } 1.882 + 1.883 + ReportError(cx, message, &report, callback, userRef); 1.884 + 1.885 + js_free(message); 1.886 + js_free((void *)report.ucmessage); 1.887 + 1.888 + return warning; 1.889 +} 1.890 + 1.891 +void 1.892 +js::CallErrorReporter(JSContext *cx, const char *message, JSErrorReport *reportp) 1.893 +{ 1.894 + JS_ASSERT(message); 1.895 + JS_ASSERT(reportp); 1.896 + 1.897 + // If debugErrorHook is present, give it a chance to veto sending the error 1.898 + // on to the regular ErrorReporter. 1.899 + if (cx->errorReporter) { 1.900 + JSDebugErrorHook hook = cx->runtime()->debugHooks.debugErrorHook; 1.901 + if (hook && !hook(cx, message, reportp, cx->runtime()->debugHooks.debugErrorHookData)) 1.902 + return; 1.903 + } 1.904 + 1.905 + if (JSErrorReporter onError = cx->errorReporter) 1.906 + onError(cx, message, reportp); 1.907 +} 1.908 + 1.909 +void 1.910 +js_ReportIsNotDefined(JSContext *cx, const char *name) 1.911 +{ 1.912 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_DEFINED, name); 1.913 +} 1.914 + 1.915 +bool 1.916 +js_ReportIsNullOrUndefined(JSContext *cx, int spindex, HandleValue v, 1.917 + HandleString fallback) 1.918 +{ 1.919 + char *bytes; 1.920 + bool ok; 1.921 + 1.922 + bytes = DecompileValueGenerator(cx, spindex, v, fallback); 1.923 + if (!bytes) 1.924 + return false; 1.925 + 1.926 + if (strcmp(bytes, js_undefined_str) == 0 || 1.927 + strcmp(bytes, js_null_str) == 0) { 1.928 + ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, 1.929 + js_GetErrorMessage, nullptr, 1.930 + JSMSG_NO_PROPERTIES, bytes, 1.931 + nullptr, nullptr); 1.932 + } else if (v.isUndefined()) { 1.933 + ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, 1.934 + js_GetErrorMessage, nullptr, 1.935 + JSMSG_UNEXPECTED_TYPE, bytes, 1.936 + js_undefined_str, nullptr); 1.937 + } else { 1.938 + JS_ASSERT(v.isNull()); 1.939 + ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, 1.940 + js_GetErrorMessage, nullptr, 1.941 + JSMSG_UNEXPECTED_TYPE, bytes, 1.942 + js_null_str, nullptr); 1.943 + } 1.944 + 1.945 + js_free(bytes); 1.946 + return ok; 1.947 +} 1.948 + 1.949 +void 1.950 +js_ReportMissingArg(JSContext *cx, HandleValue v, unsigned arg) 1.951 +{ 1.952 + char argbuf[11]; 1.953 + char *bytes; 1.954 + RootedAtom atom(cx); 1.955 + 1.956 + JS_snprintf(argbuf, sizeof argbuf, "%u", arg); 1.957 + bytes = nullptr; 1.958 + if (IsFunctionObject(v)) { 1.959 + atom = v.toObject().as<JSFunction>().atom(); 1.960 + bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, 1.961 + v, atom); 1.962 + if (!bytes) 1.963 + return; 1.964 + } 1.965 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.966 + JSMSG_MISSING_FUN_ARG, argbuf, 1.967 + bytes ? bytes : ""); 1.968 + js_free(bytes); 1.969 +} 1.970 + 1.971 +bool 1.972 +js_ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNumber, 1.973 + int spindex, HandleValue v, HandleString fallback, 1.974 + const char *arg1, const char *arg2) 1.975 +{ 1.976 + char *bytes; 1.977 + bool ok; 1.978 + 1.979 + JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1); 1.980 + JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3); 1.981 + bytes = DecompileValueGenerator(cx, spindex, v, fallback); 1.982 + if (!bytes) 1.983 + return false; 1.984 + 1.985 + ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, 1.986 + nullptr, errorNumber, bytes, arg1, arg2); 1.987 + js_free(bytes); 1.988 + return ok; 1.989 +} 1.990 + 1.991 +const JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = { 1.992 +#define MSG_DEF(name, number, count, exception, format) \ 1.993 + { format, count, exception } , 1.994 +#include "js.msg" 1.995 +#undef MSG_DEF 1.996 +}; 1.997 + 1.998 +JS_FRIEND_API(const JSErrorFormatString *) 1.999 +js_GetErrorMessage(void *userRef, const char *locale, const unsigned errorNumber) 1.1000 +{ 1.1001 + if ((errorNumber > 0) && (errorNumber < JSErr_Limit)) 1.1002 + return &js_ErrorFormatString[errorNumber]; 1.1003 + return nullptr; 1.1004 +} 1.1005 + 1.1006 +bool 1.1007 +js::InvokeInterruptCallback(JSContext *cx) 1.1008 +{ 1.1009 + JS_ASSERT_REQUEST_DEPTH(cx); 1.1010 + 1.1011 + JSRuntime *rt = cx->runtime(); 1.1012 + JS_ASSERT(rt->interrupt); 1.1013 + 1.1014 + // Reset the callback counter first, then run GC and yield. If another 1.1015 + // thread is racing us here we will accumulate another callback request 1.1016 + // which will be serviced at the next opportunity. 1.1017 + rt->interrupt = false; 1.1018 + 1.1019 + // IonMonkey sets its stack limit to UINTPTR_MAX to trigger interrupt 1.1020 + // callbacks. 1.1021 + rt->resetJitStackLimit(); 1.1022 + 1.1023 + js::gc::GCIfNeeded(cx); 1.1024 + 1.1025 +#ifdef JS_ION 1.1026 +#ifdef JS_THREADSAFE 1.1027 + rt->interruptPar = false; 1.1028 +#endif 1.1029 + 1.1030 + // A worker thread may have requested an interrupt after finishing an Ion 1.1031 + // compilation. 1.1032 + jit::AttachFinishedCompilations(cx); 1.1033 +#endif 1.1034 + 1.1035 + // Important: Additional callbacks can occur inside the callback handler 1.1036 + // if it re-enters the JS engine. The embedding must ensure that the 1.1037 + // callback is disconnected before attempting such re-entry. 1.1038 + JSInterruptCallback cb = cx->runtime()->interruptCallback; 1.1039 + if (!cb || cb(cx)) 1.1040 + return true; 1.1041 + 1.1042 + // No need to set aside any pending exception here: ComputeStackString 1.1043 + // already does that. 1.1044 + Rooted<JSString*> stack(cx, ComputeStackString(cx)); 1.1045 + const jschar *chars = stack ? stack->getCharsZ(cx) : nullptr; 1.1046 + if (!chars) 1.1047 + chars = MOZ_UTF16("(stack not available)"); 1.1048 + JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr, 1.1049 + JSMSG_TERMINATED, chars); 1.1050 + 1.1051 + return false; 1.1052 +} 1.1053 + 1.1054 +bool 1.1055 +js::HandleExecutionInterrupt(JSContext *cx) 1.1056 +{ 1.1057 + if (cx->runtime()->interrupt) 1.1058 + return InvokeInterruptCallback(cx); 1.1059 + return true; 1.1060 +} 1.1061 + 1.1062 +ThreadSafeContext::ThreadSafeContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind) 1.1063 + : ContextFriendFields(rt), 1.1064 + contextKind_(kind), 1.1065 + perThreadData(pt), 1.1066 + allocator_(nullptr) 1.1067 +{ 1.1068 +} 1.1069 + 1.1070 +bool 1.1071 +ThreadSafeContext::isForkJoinContext() const 1.1072 +{ 1.1073 + return contextKind_ == Context_ForkJoin; 1.1074 +} 1.1075 + 1.1076 +ForkJoinContext * 1.1077 +ThreadSafeContext::asForkJoinContext() 1.1078 +{ 1.1079 + JS_ASSERT(isForkJoinContext()); 1.1080 + return reinterpret_cast<ForkJoinContext *>(this); 1.1081 +} 1.1082 + 1.1083 +void 1.1084 +ThreadSafeContext::recoverFromOutOfMemory() 1.1085 +{ 1.1086 + // If this is not a JSContext, there's nothing to do. 1.1087 + if (JSContext *maybecx = maybeJSContext()) { 1.1088 + if (maybecx->isExceptionPending()) { 1.1089 + MOZ_ASSERT(maybecx->isThrowingOutOfMemory()); 1.1090 + maybecx->clearPendingException(); 1.1091 + } else { 1.1092 + MOZ_ASSERT(maybecx->runtime()->hadOutOfMemory); 1.1093 + } 1.1094 + } 1.1095 +} 1.1096 + 1.1097 +JSContext::JSContext(JSRuntime *rt) 1.1098 + : ExclusiveContext(rt, &rt->mainThread, Context_JS), 1.1099 + throwing(false), 1.1100 + unwrappedException_(UndefinedValue()), 1.1101 + options_(), 1.1102 + reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY), 1.1103 + resolvingList(nullptr), 1.1104 + generatingError(false), 1.1105 + savedFrameChains_(), 1.1106 + defaultCompartmentObject_(nullptr), 1.1107 + cycleDetectorSet(MOZ_THIS_IN_INITIALIZER_LIST()), 1.1108 + errorReporter(nullptr), 1.1109 + data(nullptr), 1.1110 + data2(nullptr), 1.1111 +#ifdef JS_THREADSAFE 1.1112 + outstandingRequests(0), 1.1113 +#endif 1.1114 + iterValue(MagicValue(JS_NO_ITER_VALUE)), 1.1115 + jitIsBroken(false), 1.1116 +#ifdef MOZ_TRACE_JSCALLS 1.1117 + functionCallback(nullptr), 1.1118 +#endif 1.1119 + innermostGenerator_(nullptr) 1.1120 +{ 1.1121 +#ifdef DEBUG 1.1122 + stackIterAssertionEnabled = true; 1.1123 +#endif 1.1124 + 1.1125 + JS_ASSERT(static_cast<ContextFriendFields*>(this) == 1.1126 + ContextFriendFields::get(this)); 1.1127 +} 1.1128 + 1.1129 +JSContext::~JSContext() 1.1130 +{ 1.1131 + /* Free the stuff hanging off of cx. */ 1.1132 + JS_ASSERT(!resolvingList); 1.1133 +} 1.1134 + 1.1135 +bool 1.1136 +JSContext::getPendingException(MutableHandleValue rval) 1.1137 +{ 1.1138 + JS_ASSERT(throwing); 1.1139 + rval.set(unwrappedException_); 1.1140 + if (IsAtomsCompartment(compartment())) 1.1141 + return true; 1.1142 + clearPendingException(); 1.1143 + if (!compartment()->wrap(this, rval)) 1.1144 + return false; 1.1145 + assertSameCompartment(this, rval); 1.1146 + setPendingException(rval); 1.1147 + return true; 1.1148 +} 1.1149 + 1.1150 +bool 1.1151 +JSContext::isThrowingOutOfMemory() 1.1152 +{ 1.1153 + return throwing && unwrappedException_ == StringValue(names().outOfMemory); 1.1154 +} 1.1155 + 1.1156 +void 1.1157 +JSContext::enterGenerator(JSGenerator *gen) 1.1158 +{ 1.1159 + JS_ASSERT(!gen->prevGenerator); 1.1160 + gen->prevGenerator = innermostGenerator_; 1.1161 + innermostGenerator_ = gen; 1.1162 +} 1.1163 + 1.1164 +void 1.1165 +JSContext::leaveGenerator(JSGenerator *gen) 1.1166 +{ 1.1167 + JS_ASSERT(innermostGenerator_ == gen); 1.1168 + innermostGenerator_ = innermostGenerator_->prevGenerator; 1.1169 + gen->prevGenerator = nullptr; 1.1170 +} 1.1171 + 1.1172 + 1.1173 +bool 1.1174 +JSContext::runningWithTrustedPrincipals() const 1.1175 +{ 1.1176 + return !compartment() || compartment()->principals == runtime()->trustedPrincipals(); 1.1177 +} 1.1178 + 1.1179 +bool 1.1180 +JSContext::saveFrameChain() 1.1181 +{ 1.1182 + if (!savedFrameChains_.append(SavedFrameChain(compartment(), enterCompartmentDepth_))) 1.1183 + return false; 1.1184 + 1.1185 + if (Activation *act = mainThread().activation()) 1.1186 + act->saveFrameChain(); 1.1187 + 1.1188 + setCompartment(nullptr); 1.1189 + enterCompartmentDepth_ = 0; 1.1190 + 1.1191 + return true; 1.1192 +} 1.1193 + 1.1194 +void 1.1195 +JSContext::restoreFrameChain() 1.1196 +{ 1.1197 + JS_ASSERT(enterCompartmentDepth_ == 0); // We're about to clobber it, and it 1.1198 + // will be wrong forevermore. 1.1199 + SavedFrameChain sfc = savedFrameChains_.popCopy(); 1.1200 + setCompartment(sfc.compartment); 1.1201 + enterCompartmentDepth_ = sfc.enterCompartmentCount; 1.1202 + 1.1203 + if (Activation *act = mainThread().activation()) 1.1204 + act->restoreFrameChain(); 1.1205 +} 1.1206 + 1.1207 +bool 1.1208 +JSContext::currentlyRunning() const 1.1209 +{ 1.1210 + for (ActivationIterator iter(runtime()); !iter.done(); ++iter) { 1.1211 + if (iter->cx() == this) { 1.1212 + if (iter->hasSavedFrameChain()) 1.1213 + return false; 1.1214 + return true; 1.1215 + } 1.1216 + } 1.1217 + 1.1218 + return false; 1.1219 +} 1.1220 + 1.1221 +static bool 1.1222 +ComputeIsJITBroken() 1.1223 +{ 1.1224 +#if !defined(ANDROID) || defined(GONK) 1.1225 + return false; 1.1226 +#else // ANDROID 1.1227 + if (getenv("JS_IGNORE_JIT_BROKENNESS")) { 1.1228 + return false; 1.1229 + } 1.1230 + 1.1231 + std::string line; 1.1232 + 1.1233 + // Check for the known-bad kernel version (2.6.29). 1.1234 + std::ifstream osrelease("/proc/sys/kernel/osrelease"); 1.1235 + std::getline(osrelease, line); 1.1236 + __android_log_print(ANDROID_LOG_INFO, "Gecko", "Detected osrelease `%s'", 1.1237 + line.c_str()); 1.1238 + 1.1239 + if (line.npos == line.find("2.6.29")) { 1.1240 + // We're using something other than 2.6.29, so the JITs should work. 1.1241 + __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are not broken"); 1.1242 + return false; 1.1243 + } 1.1244 + 1.1245 + // We're using 2.6.29, and this causes trouble with the JITs on i9000. 1.1246 + line = ""; 1.1247 + bool broken = false; 1.1248 + std::ifstream cpuinfo("/proc/cpuinfo"); 1.1249 + do { 1.1250 + if (0 == line.find("Hardware")) { 1.1251 + static const char* const blacklist[] = { 1.1252 + "SCH-I400", // Samsung Continuum 1.1253 + "SGH-T959", // Samsung i9000, Vibrant device 1.1254 + "SGH-I897", // Samsung i9000, Captivate device 1.1255 + "SCH-I500", // Samsung i9000, Fascinate device 1.1256 + "SPH-D700", // Samsung i9000, Epic device 1.1257 + "GT-I9000", // Samsung i9000, UK/Europe device 1.1258 + nullptr 1.1259 + }; 1.1260 + for (const char* const* hw = &blacklist[0]; *hw; ++hw) { 1.1261 + if (line.npos != line.find(*hw)) { 1.1262 + __android_log_print(ANDROID_LOG_INFO, "Gecko", 1.1263 + "Blacklisted device `%s'", *hw); 1.1264 + broken = true; 1.1265 + break; 1.1266 + } 1.1267 + } 1.1268 + break; 1.1269 + } 1.1270 + std::getline(cpuinfo, line); 1.1271 + } while(!cpuinfo.fail() && !cpuinfo.eof()); 1.1272 + 1.1273 + __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are %sbroken", 1.1274 + broken ? "" : "not "); 1.1275 + 1.1276 + return broken; 1.1277 +#endif // ifndef ANDROID 1.1278 +} 1.1279 + 1.1280 +static bool 1.1281 +IsJITBrokenHere() 1.1282 +{ 1.1283 + static bool computedIsBroken = false; 1.1284 + static bool isBroken = false; 1.1285 + if (!computedIsBroken) { 1.1286 + isBroken = ComputeIsJITBroken(); 1.1287 + computedIsBroken = true; 1.1288 + } 1.1289 + return isBroken; 1.1290 +} 1.1291 + 1.1292 +void 1.1293 +JSContext::updateJITEnabled() 1.1294 +{ 1.1295 + jitIsBroken = IsJITBrokenHere(); 1.1296 +} 1.1297 + 1.1298 +size_t 1.1299 +JSContext::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const 1.1300 +{ 1.1301 + /* 1.1302 + * There are other JSContext members that could be measured; the following 1.1303 + * ones have been found by DMD to be worth measuring. More stuff may be 1.1304 + * added later. 1.1305 + */ 1.1306 + return mallocSizeOf(this) + cycleDetectorSet.sizeOfExcludingThis(mallocSizeOf); 1.1307 +} 1.1308 + 1.1309 +void 1.1310 +JSContext::mark(JSTracer *trc) 1.1311 +{ 1.1312 + /* Stack frames and slots are traced by StackSpace::mark. */ 1.1313 + 1.1314 + /* Mark other roots-by-definition in the JSContext. */ 1.1315 + if (defaultCompartmentObject_) 1.1316 + MarkObjectRoot(trc, &defaultCompartmentObject_, "default compartment object"); 1.1317 + if (isExceptionPending()) 1.1318 + MarkValueRoot(trc, &unwrappedException_, "unwrapped exception"); 1.1319 + 1.1320 + TraceCycleDetectionSet(trc, cycleDetectorSet); 1.1321 + 1.1322 + MarkValueRoot(trc, &iterValue, "iterValue"); 1.1323 +} 1.1324 + 1.1325 +void * 1.1326 +ThreadSafeContext::stackLimitAddressForJitCode(StackKind kind) 1.1327 +{ 1.1328 +#ifdef JS_ARM_SIMULATOR 1.1329 + return runtime_->mainThread.addressOfSimulatorStackLimit(); 1.1330 +#endif 1.1331 + return stackLimitAddress(kind); 1.1332 +} 1.1333 + 1.1334 +JSVersion 1.1335 +JSContext::findVersion() const 1.1336 +{ 1.1337 + if (JSScript *script = currentScript(nullptr, ALLOW_CROSS_COMPARTMENT)) 1.1338 + return script->getVersion(); 1.1339 + 1.1340 + if (compartment() && compartment()->options().version() != JSVERSION_UNKNOWN) 1.1341 + return compartment()->options().version(); 1.1342 + 1.1343 + return runtime()->defaultVersion(); 1.1344 +} 1.1345 + 1.1346 +#if defined JS_THREADSAFE && defined DEBUG 1.1347 + 1.1348 +JS::AutoCheckRequestDepth::AutoCheckRequestDepth(JSContext *cx) 1.1349 + : cx(cx) 1.1350 +{ 1.1351 + JS_ASSERT(cx->runtime()->requestDepth || cx->runtime()->isHeapBusy()); 1.1352 + JS_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); 1.1353 + cx->runtime()->checkRequestDepth++; 1.1354 +} 1.1355 + 1.1356 +JS::AutoCheckRequestDepth::AutoCheckRequestDepth(ContextFriendFields *cxArg) 1.1357 + : cx(static_cast<ThreadSafeContext *>(cxArg)->maybeJSContext()) 1.1358 +{ 1.1359 + if (cx) { 1.1360 + JS_ASSERT(cx->runtime()->requestDepth || cx->runtime()->isHeapBusy()); 1.1361 + JS_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); 1.1362 + cx->runtime()->checkRequestDepth++; 1.1363 + } 1.1364 +} 1.1365 + 1.1366 +JS::AutoCheckRequestDepth::~AutoCheckRequestDepth() 1.1367 +{ 1.1368 + if (cx) { 1.1369 + JS_ASSERT(cx->runtime()->checkRequestDepth != 0); 1.1370 + cx->runtime()->checkRequestDepth--; 1.1371 + } 1.1372 +} 1.1373 + 1.1374 +#endif 1.1375 + 1.1376 +#ifdef JS_CRASH_DIAGNOSTICS 1.1377 +void CompartmentChecker::check(InterpreterFrame *fp) 1.1378 +{ 1.1379 + if (fp) 1.1380 + check(fp->scopeChain()); 1.1381 +} 1.1382 + 1.1383 +void CompartmentChecker::check(AbstractFramePtr frame) 1.1384 +{ 1.1385 + if (frame) 1.1386 + check(frame.scopeChain()); 1.1387 +} 1.1388 +#endif 1.1389 + 1.1390 +void 1.1391 +js::CrashAtUnhandlableOOM(const char *reason) 1.1392 +{ 1.1393 + char msgbuf[1024]; 1.1394 + JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason); 1.1395 + MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__); 1.1396 + MOZ_CRASH(); 1.1397 +}