Bumping manifests a=b2g-bump
[gecko.git] / js / src / jscntxt.cpp
blob75a6c8cea2397bbe54e20d831d56afe26cce6040
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * JS execution context.
9 */
11 #include "jscntxtinlines.h"
13 #include "mozilla/ArrayUtils.h"
14 #include "mozilla/DebugOnly.h"
15 #include "mozilla/MemoryReporting.h"
17 #include <ctype.h>
18 #include <stdarg.h>
19 #include <string.h>
20 #ifdef ANDROID
21 # include <android/log.h>
22 # include <fstream>
23 # include <string>
24 #endif // ANDROID
26 #include "jsatom.h"
27 #include "jscompartment.h"
28 #include "jsexn.h"
29 #include "jsfun.h"
30 #include "jsgc.h"
31 #include "jsiter.h"
32 #include "jsobj.h"
33 #include "jsopcode.h"
34 #include "jsprf.h"
35 #include "jspubtd.h"
36 #include "jsscript.h"
37 #include "jsstr.h"
38 #include "jstypes.h"
39 #include "jswatchpoint.h"
41 #include "gc/Marking.h"
42 #include "jit/Ion.h"
43 #include "js/CharacterEncoding.h"
44 #include "vm/HelperThreads.h"
45 #include "vm/Shape.h"
47 #include "jsobjinlines.h"
48 #include "jsscriptinlines.h"
50 #include "vm/Stack-inl.h"
52 using namespace js;
53 using namespace js::gc;
55 using mozilla::DebugOnly;
56 using mozilla::PodArrayZero;
57 using mozilla::PointerRangeSize;
59 bool
60 js::AutoCycleDetector::init()
62 ObjectSet& set = cx->cycleDetectorSet;
63 hashsetAddPointer = set.lookupForAdd(obj);
64 if (!hashsetAddPointer) {
65 if (!set.add(hashsetAddPointer, obj))
66 return false;
67 cyclic = false;
68 hashsetGenerationAtInit = set.generation();
70 return true;
73 js::AutoCycleDetector::~AutoCycleDetector()
75 if (!cyclic) {
76 if (hashsetGenerationAtInit == cx->cycleDetectorSet.generation())
77 cx->cycleDetectorSet.remove(hashsetAddPointer);
78 else
79 cx->cycleDetectorSet.remove(obj);
83 void
84 js::TraceCycleDetectionSet(JSTracer* trc, js::ObjectSet& set)
86 for (js::ObjectSet::Enum e(set); !e.empty(); e.popFront()) {
87 JSObject* key = e.front();
88 trc->setTracingLocation((void*)&e.front());
89 MarkObjectRoot(trc, &key, "cycle detector table entry");
90 if (key != e.front())
91 e.rekeyFront(key);
95 void
96 JSCompartment::sweepCallsiteClones()
98 if (callsiteClones.initialized()) {
99 for (CallsiteCloneTable::Enum e(callsiteClones); !e.empty(); e.popFront()) {
100 CallsiteCloneKey key = e.front().key();
101 if (IsObjectAboutToBeFinalizedFromAnyThread(&key.original) ||
102 IsScriptAboutToBeFinalizedFromAnyThread(&key.script) ||
103 IsObjectAboutToBeFinalizedFromAnyThread(e.front().value().unsafeGet()))
105 e.removeFront();
106 } else if (key != e.front().key()) {
107 e.rekeyFront(key);
113 JSFunction*
114 js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable& table, JSFunction* fun,
115 JSScript* script, jsbytecode* pc)
117 MOZ_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite());
118 MOZ_ASSERT(!fun->nonLazyScript()->enclosingStaticScope());
119 MOZ_ASSERT(types::UseNewTypeForClone(fun));
122 * If we start allocating function objects in the nursery, then the callsite
123 * clone table will need a postbarrier.
125 MOZ_ASSERT(fun->isTenured());
127 if (!table.initialized())
128 return nullptr;
130 CallsiteCloneTable::Ptr p = table.readonlyThreadsafeLookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc)));
131 if (p)
132 return p->value();
134 return nullptr;
137 JSFunction*
138 js::CloneFunctionAtCallsite(JSContext* cx, HandleFunction fun, HandleScript script, jsbytecode* pc)
140 if (JSFunction* clone = ExistingCloneFunctionAtCallsite(cx->compartment()->callsiteClones, fun, script, pc))
141 return clone;
143 MOZ_ASSERT(fun->isSelfHostedBuiltin(),
144 "only self-hosted builtin functions may be cloned at call sites, and "
145 "Function.prototype.caller relies on this");
147 RootedObject parent(cx, fun->environment());
148 JSFunction* clone = CloneFunctionObject(cx, fun, parent);
149 if (!clone)
150 return nullptr;
153 * Store a link back to the original for function.caller and avoid cloning
154 * clones.
156 clone->nonLazyScript()->setIsCallsiteClone(fun);
158 typedef CallsiteCloneKey Key;
159 typedef CallsiteCloneTable Table;
161 Table& table = cx->compartment()->callsiteClones;
162 if (!table.initialized() && !table.init())
163 return nullptr;
165 if (!table.putNew(Key(fun, script, script->pcToOffset(pc)), clone))
166 return nullptr;
168 return clone;
171 JSContext*
172 js::NewContext(JSRuntime* rt, size_t stackChunkSize)
174 JS_AbortIfWrongThread(rt);
176 JSContext* cx = js_new<JSContext>(rt);
177 if (!cx)
178 return nullptr;
180 if (!cx->cycleDetectorSet.init()) {
181 js_delete(cx);
182 return nullptr;
186 * Here the GC lock is still held after js_InitContextThreadAndLockGC took it and
187 * the GC is not running on another thread.
189 rt->contextList.insertBack(cx);
192 * If cx is the first context on this runtime, initialize well-known atoms,
193 * keywords, numbers, strings and self-hosted scripts. If one of these
194 * steps should fail, the runtime will be left in a partially initialized
195 * state, with zeroes and nulls stored in the default-initialized remainder
196 * of the struct.
198 if (!rt->haveCreatedContext) {
199 JS_BeginRequest(cx);
200 bool ok = rt->initializeAtoms(cx);
201 if (ok)
202 ok = rt->initSelfHosting(cx);
204 if (ok && !rt->parentRuntime)
205 ok = rt->transformToPermanentAtoms();
207 JS_EndRequest(cx);
209 if (!ok) {
210 DestroyContext(cx, DCM_NEW_FAILED);
211 return nullptr;
214 rt->haveCreatedContext = true;
217 JSContextCallback cxCallback = rt->cxCallback;
218 if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW, rt->cxCallbackData)) {
219 DestroyContext(cx, DCM_NEW_FAILED);
220 return nullptr;
223 return cx;
226 void
227 js::DestroyContext(JSContext* cx, DestroyContextMode mode)
229 JSRuntime* rt = cx->runtime();
230 JS_AbortIfWrongThread(rt);
232 if (cx->outstandingRequests != 0)
233 MOZ_CRASH();
235 cx->checkNoGCRooters();
237 if (mode != DCM_NEW_FAILED) {
238 if (JSContextCallback cxCallback = rt->cxCallback) {
240 * JSCONTEXT_DESTROY callback is not allowed to fail and must
241 * return true.
243 JS_ALWAYS_TRUE(cxCallback(cx, JSCONTEXT_DESTROY,
244 rt->cxCallbackData));
248 cx->remove();
249 bool last = !rt->hasContexts();
250 if (last) {
252 * Dump remaining type inference results while we still have a context.
253 * This printing depends on atoms still existing.
255 for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
256 c->types.print(cx, false);
258 if (mode == DCM_FORCE_GC) {
259 MOZ_ASSERT(!rt->isHeapBusy());
260 JS::PrepareForFullGC(rt);
261 rt->gc.gc(GC_NORMAL, JS::gcreason::DESTROY_CONTEXT);
263 js_delete_poison(cx);
266 void
267 ContextFriendFields::checkNoGCRooters() {
268 #ifdef DEBUG
269 for (int i = 0; i < THING_ROOT_LIMIT; ++i)
270 MOZ_ASSERT(thingGCRooters[i] == nullptr);
271 #endif
274 bool
275 AutoResolving::alreadyStartedSlow() const
277 MOZ_ASSERT(link);
278 AutoResolving* cursor = link;
279 do {
280 MOZ_ASSERT(this != cursor);
281 if (object.get() == cursor->object && id.get() == cursor->id && kind == cursor->kind)
282 return true;
283 } while (!!(cursor = cursor->link));
284 return false;
287 static void
288 ReportError(JSContext* cx, const char* message, JSErrorReport* reportp,
289 JSErrorCallback callback, void* userRef)
292 * Check the error report, and set a JavaScript-catchable exception
293 * if the error is defined to have an associated exception. If an
294 * exception is thrown, then the JSREPORT_EXCEPTION flag will be set
295 * on the error report, and exception-aware hosts should ignore it.
297 MOZ_ASSERT(reportp);
298 if ((!callback || callback == js_GetErrorMessage) &&
299 reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
301 reportp->flags |= JSREPORT_EXCEPTION;
304 if (cx->options().autoJSAPIOwnsErrorReporting() || JS_IsRunning(cx)) {
305 if (js_ErrorToException(cx, message, reportp, callback, userRef)) {
306 return;
311 * Call the error reporter only if an exception wasn't raised.
313 if (message) {
314 CallErrorReporter(cx, message, reportp);
319 * The given JSErrorReport object have been zeroed and must not outlive
320 * cx->fp() (otherwise owned fields may become invalid).
322 static void
323 PopulateReportBlame(JSContext* cx, JSErrorReport* report)
326 * Walk stack until we find a frame that is associated with a non-builtin
327 * rather than a builtin frame.
329 NonBuiltinFrameIter iter(cx);
330 if (iter.done())
331 return;
333 report->filename = iter.scriptFilename();
334 report->lineno = iter.computeLine(&report->column);
335 report->isMuted = iter.mutedErrors();
339 * Since memory has been exhausted, avoid the normal error-handling path which
340 * allocates an error object, report and callstack. If code is running, simply
341 * throw the static atom "out of memory". If code is not running, call the
342 * error reporter directly.
344 * Furthermore, callers of js_ReportOutOfMemory (viz., malloc) assume a GC does
345 * not occur, so GC must be avoided or suppressed.
347 void
348 js_ReportOutOfMemory(ExclusiveContext* cxArg)
350 #ifdef JS_MORE_DETERMINISTIC
352 * OOMs are non-deterministic, especially across different execution modes
353 * (e.g. interpreter vs JIT). In more-deterministic builds, print to stderr
354 * so that the fuzzers can detect this.
356 fprintf(stderr, "js_ReportOutOfMemory called\n");
357 #endif
359 if (!cxArg->isJSContext())
360 return;
362 JSContext* cx = cxArg->asJSContext();
363 cx->runtime()->hadOutOfMemory = true;
365 /* Report the oom. */
366 if (JS::OutOfMemoryCallback oomCallback = cx->runtime()->oomCallback) {
367 AutoSuppressGC suppressGC(cx);
368 oomCallback(cx, cx->runtime()->oomCallbackData);
371 if (JS_IsRunning(cx)) {
372 cx->setPendingException(StringValue(cx->names().outOfMemory));
373 return;
376 /* Get the message for this error, but we don't expand any arguments. */
377 const JSErrorFormatString* efs = js_GetErrorMessage(nullptr, JSMSG_OUT_OF_MEMORY);
378 const char* msg = efs ? efs->format : "Out of memory";
380 /* Fill out the report, but don't do anything that requires allocation. */
381 JSErrorReport report;
382 report.flags = JSREPORT_ERROR;
383 report.errorNumber = JSMSG_OUT_OF_MEMORY;
384 PopulateReportBlame(cx, &report);
386 /* Report the error. */
387 if (JSErrorReporter onError = cx->runtime()->errorReporter) {
388 AutoSuppressGC suppressGC(cx);
389 onError(cx, msg, &report);
393 * We would like to enforce the invariant that any exception reported
394 * during an OOM situation does not require wrapping. Besides avoiding
395 * allocation when memory is low, this reduces the number of places where
396 * we might need to GC.
398 * When JS code is running, we set the pending exception to an atom, which
399 * does not need wrapping. If no JS code is running, no exception should be
400 * set at all.
402 MOZ_ASSERT(!cx->isExceptionPending());
405 JS_FRIEND_API(void)
406 js_ReportOverRecursed(JSContext* maybecx)
408 #ifdef JS_MORE_DETERMINISTIC
410 * We cannot make stack depth deterministic across different
411 * implementations (e.g. JIT vs. interpreter will differ in
412 * their maximum stack depth).
413 * However, we can detect externally when we hit the maximum
414 * stack depth which is useful for external testing programs
415 * like fuzzers.
417 fprintf(stderr, "js_ReportOverRecursed called\n");
418 #endif
419 if (maybecx) {
420 JS_ReportErrorNumber(maybecx, js_GetErrorMessage, nullptr, JSMSG_OVER_RECURSED);
421 maybecx->overRecursed_ = true;
425 void
426 js_ReportOverRecursed(ExclusiveContext* cx)
428 if (cx->isJSContext())
429 js_ReportOverRecursed(cx->asJSContext());
430 else
431 cx->addPendingOverRecursed();
434 void
435 js_ReportAllocationOverflow(ExclusiveContext* cxArg)
437 if (!cxArg)
438 return;
440 if (!cxArg->isJSContext())
441 return;
442 JSContext* cx = cxArg->asJSContext();
444 AutoSuppressGC suppressGC(cx);
445 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_ALLOC_OVERFLOW);
449 * Given flags and the state of cx, decide whether we should report an
450 * error, a warning, or just continue execution normally. Return
451 * true if we should continue normally, without reporting anything;
452 * otherwise, adjust *flags as appropriate and return false.
454 static bool
455 checkReportFlags(JSContext* cx, unsigned* flags)
457 if (JSREPORT_IS_STRICT_MODE_ERROR(*flags)) {
459 * Error in strict code; warning with extra warnings option; okay
460 * otherwise. We assume that if the top frame is a native, then it is
461 * strict if the nearest scripted frame is strict, see bug 536306.
463 jsbytecode* pc;
464 JSScript* script = cx->currentScript(&pc);
465 if (script && IsCheckStrictOp(JSOp(*pc)))
466 *flags &= ~JSREPORT_WARNING;
467 else if (cx->compartment()->options().extraWarnings(cx))
468 *flags |= JSREPORT_WARNING;
469 else
470 return true;
471 } else if (JSREPORT_IS_STRICT(*flags)) {
472 /* Warning/error only when JSOPTION_STRICT is set. */
473 if (!cx->compartment()->options().extraWarnings(cx))
474 return true;
477 /* Warnings become errors when JSOPTION_WERROR is set. */
478 if (JSREPORT_IS_WARNING(*flags) && cx->runtime()->options().werror())
479 *flags &= ~JSREPORT_WARNING;
481 return false;
484 bool
485 js_ReportErrorVA(JSContext* cx, unsigned flags, const char* format, va_list ap)
487 char* message;
488 char16_t* ucmessage;
489 size_t messagelen;
490 JSErrorReport report;
491 bool warning;
493 if (checkReportFlags(cx, &flags))
494 return true;
496 message = JS_vsmprintf(format, ap);
497 if (!message)
498 return false;
499 messagelen = strlen(message);
501 report.flags = flags;
502 report.errorNumber = JSMSG_USER_DEFINED_ERROR;
503 report.ucmessage = ucmessage = InflateString(cx, message, &messagelen);
504 PopulateReportBlame(cx, &report);
506 warning = JSREPORT_IS_WARNING(report.flags);
508 ReportError(cx, message, &report, nullptr, nullptr);
509 js_free(message);
510 js_free(ucmessage);
511 return warning;
514 /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
515 void
516 js::ReportUsageError(JSContext* cx, HandleObject callee, const char* msg)
518 const char* usageStr = "usage";
519 PropertyName* usageAtom = Atomize(cx, usageStr, strlen(usageStr))->asPropertyName();
520 RootedId id(cx, NameToId(usageAtom));
521 DebugOnly<Shape*> shape = static_cast<Shape*>(callee->as<JSFunction>().lookup(cx, id));
522 MOZ_ASSERT(!shape->configurable());
523 MOZ_ASSERT(!shape->writable());
524 MOZ_ASSERT(shape->hasDefaultGetter());
526 RootedValue usage(cx);
527 if (!JS_GetProperty(cx, callee, "usage", &usage))
528 return;
530 if (!usage.isString()) {
531 JS_ReportError(cx, "%s", msg);
532 } else {
533 JSString* str = usage.toString();
534 if (!str->ensureFlat(cx))
535 return;
536 AutoStableStringChars chars(cx);
537 if (!chars.initTwoByte(cx, str))
538 return;
540 JS_ReportError(cx, "%s. Usage: %hs", msg, chars.twoByteRange().start().get());
544 bool
545 js::PrintError(JSContext* cx, FILE* file, const char* message, JSErrorReport* report,
546 bool reportWarnings)
548 if (!report) {
549 fprintf(file, "%s\n", message);
550 fflush(file);
551 return false;
554 /* Conditionally ignore reported warnings. */
555 if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings)
556 return false;
558 char* prefix = nullptr;
559 if (report->filename)
560 prefix = JS_smprintf("%s:", report->filename);
561 if (report->lineno) {
562 char* tmp = prefix;
563 prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column);
564 JS_free(cx, tmp);
566 if (JSREPORT_IS_WARNING(report->flags)) {
567 char* tmp = prefix;
568 prefix = JS_smprintf("%s%swarning: ",
569 tmp ? tmp : "",
570 JSREPORT_IS_STRICT(report->flags) ? "strict " : "");
571 JS_free(cx, tmp);
574 /* embedded newlines -- argh! */
575 const char* ctmp;
576 while ((ctmp = strchr(message, '\n')) != 0) {
577 ctmp++;
578 if (prefix)
579 fputs(prefix, file);
580 fwrite(message, 1, ctmp - message, file);
581 message = ctmp;
584 /* If there were no filename or lineno, the prefix might be empty */
585 if (prefix)
586 fputs(prefix, file);
587 fputs(message, file);
589 if (report->linebuf) {
590 /* report->linebuf usually ends with a newline. */
591 int n = strlen(report->linebuf);
592 fprintf(file, ":\n%s%s%s%s",
593 prefix,
594 report->linebuf,
595 (n > 0 && report->linebuf[n-1] == '\n') ? "" : "\n",
596 prefix);
597 n = report->tokenptr - report->linebuf;
598 for (int i = 0, j = 0; i < n; i++) {
599 if (report->linebuf[i] == '\t') {
600 for (int k = (j + 8) & ~7; j < k; j++) {
601 fputc('.', file);
603 continue;
605 fputc('.', file);
606 j++;
608 fputc('^', file);
610 fputc('\n', file);
611 fflush(file);
612 JS_free(cx, prefix);
613 return true;
617 * The arguments from ap need to be packaged up into an array and stored
618 * into the report struct.
620 * The format string addressed by the error number may contain operands
621 * identified by the format {N}, where N is a decimal digit. Each of these
622 * is to be replaced by the Nth argument from the va_list. The complete
623 * message is placed into reportp->ucmessage converted to a JSString.
625 * Returns true if the expansion succeeds (can fail if out of memory).
627 bool
628 js_ExpandErrorArguments(ExclusiveContext* cx, JSErrorCallback callback,
629 void* userRef, const unsigned errorNumber,
630 char** messagep, JSErrorReport* reportp,
631 ErrorArgumentsType argumentsType, va_list ap)
633 const JSErrorFormatString* efs;
634 int i;
635 int argCount;
636 bool messageArgsPassed = !!reportp->messageArgs;
638 *messagep = nullptr;
640 if (!callback)
641 callback = js_GetErrorMessage;
644 AutoSuppressGC suppressGC(cx);
645 efs = callback(userRef, errorNumber);
648 if (efs) {
649 reportp->exnType = efs->exnType;
651 size_t totalArgsLength = 0;
652 size_t argLengths[10]; /* only {0} thru {9} supported */
653 argCount = efs->argCount;
654 MOZ_ASSERT(argCount <= 10);
655 if (argCount > 0) {
657 * Gather the arguments into an array, and accumulate
658 * their sizes. We allocate 1 more than necessary and
659 * null it out to act as the caboose when we free the
660 * pointers later.
662 if (messageArgsPassed) {
663 MOZ_ASSERT(!reportp->messageArgs[argCount]);
664 } else {
665 reportp->messageArgs = cx->pod_malloc<const char16_t*>(argCount + 1);
666 if (!reportp->messageArgs)
667 return false;
668 /* nullptr-terminate for easy copying. */
669 reportp->messageArgs[argCount] = nullptr;
671 for (i = 0; i < argCount; i++) {
672 if (messageArgsPassed) {
673 /* Do nothing. */
674 } else if (argumentsType == ArgumentsAreASCII) {
675 char* charArg = va_arg(ap, char*);
676 size_t charArgLength = strlen(charArg);
677 reportp->messageArgs[i] = InflateString(cx, charArg, &charArgLength);
678 if (!reportp->messageArgs[i])
679 goto error;
680 } else {
681 reportp->messageArgs[i] = va_arg(ap, char16_t*);
683 argLengths[i] = js_strlen(reportp->messageArgs[i]);
684 totalArgsLength += argLengths[i];
688 * Parse the error format, substituting the argument X
689 * for {X} in the format.
691 if (argCount > 0) {
692 if (efs->format) {
693 char16_t* buffer, *fmt, *out;
694 int expandedArgs = 0;
695 size_t expandedLength;
696 size_t len = strlen(efs->format);
698 buffer = fmt = InflateString(cx, efs->format, &len);
699 if (!buffer)
700 goto error;
701 expandedLength = len
702 - (3 * argCount) /* exclude the {n} */
703 + totalArgsLength;
706 * Note - the above calculation assumes that each argument
707 * is used once and only once in the expansion !!!
709 reportp->ucmessage = out = cx->pod_malloc<char16_t>(expandedLength + 1);
710 if (!out) {
711 js_free(buffer);
712 goto error;
714 while (*fmt) {
715 if (*fmt == '{') {
716 if (isdigit(fmt[1])) {
717 int d = JS7_UNDEC(fmt[1]);
718 MOZ_ASSERT(d < argCount);
719 js_strncpy(out, reportp->messageArgs[d],
720 argLengths[d]);
721 out += argLengths[d];
722 fmt += 3;
723 expandedArgs++;
724 continue;
727 *out++ = *fmt++;
729 MOZ_ASSERT(expandedArgs == argCount);
730 *out = 0;
731 js_free(buffer);
732 size_t msgLen = PointerRangeSize(static_cast<const char16_t*>(reportp->ucmessage),
733 static_cast<const char16_t*>(out));
734 mozilla::Range<const char16_t> ucmsg(reportp->ucmessage, msgLen);
735 *messagep = JS::LossyTwoByteCharsToNewLatin1CharsZ(cx, ucmsg).c_str();
736 if (!*messagep)
737 goto error;
739 } else {
740 /* Non-null messageArgs should have at least one non-null arg. */
741 MOZ_ASSERT(!reportp->messageArgs);
743 * Zero arguments: the format string (if it exists) is the
744 * entire message.
746 if (efs->format) {
747 size_t len;
748 *messagep = DuplicateString(cx, efs->format).release();
749 if (!*messagep)
750 goto error;
751 len = strlen(*messagep);
752 reportp->ucmessage = InflateString(cx, *messagep, &len);
753 if (!reportp->ucmessage)
754 goto error;
758 if (*messagep == nullptr) {
759 /* where's the right place for this ??? */
760 const char* defaultErrorMessage
761 = "No error message available for error number %d";
762 size_t nbytes = strlen(defaultErrorMessage) + 16;
763 *messagep = cx->pod_malloc<char>(nbytes);
764 if (!*messagep)
765 goto error;
766 JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
768 return true;
770 error:
771 if (!messageArgsPassed && reportp->messageArgs) {
772 /* free the arguments only if we allocated them */
773 if (argumentsType == ArgumentsAreASCII) {
774 i = 0;
775 while (reportp->messageArgs[i])
776 js_free((void*)reportp->messageArgs[i++]);
778 js_free((void*)reportp->messageArgs);
779 reportp->messageArgs = nullptr;
781 if (reportp->ucmessage) {
782 js_free((void*)reportp->ucmessage);
783 reportp->ucmessage = nullptr;
785 if (*messagep) {
786 js_free((void*)*messagep);
787 *messagep = nullptr;
789 return false;
792 bool
793 js_ReportErrorNumberVA(JSContext* cx, unsigned flags, JSErrorCallback callback,
794 void* userRef, const unsigned errorNumber,
795 ErrorArgumentsType argumentsType, va_list ap)
797 JSErrorReport report;
798 char* message;
799 bool warning;
801 if (checkReportFlags(cx, &flags))
802 return true;
803 warning = JSREPORT_IS_WARNING(flags);
805 report.flags = flags;
806 report.errorNumber = errorNumber;
807 PopulateReportBlame(cx, &report);
809 if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
810 &message, &report, argumentsType, ap)) {
811 return false;
814 ReportError(cx, message, &report, callback, userRef);
816 js_free(message);
817 if (report.messageArgs) {
819 * js_ExpandErrorArguments owns its messageArgs only if it had to
820 * inflate the arguments (from regular |char*|s).
822 if (argumentsType == ArgumentsAreASCII) {
823 int i = 0;
824 while (report.messageArgs[i])
825 js_free((void*)report.messageArgs[i++]);
827 js_free((void*)report.messageArgs);
829 js_free((void*)report.ucmessage);
831 return warning;
834 bool
835 js_ReportErrorNumberUCArray(JSContext* cx, unsigned flags, JSErrorCallback callback,
836 void* userRef, const unsigned errorNumber,
837 const char16_t** args)
839 if (checkReportFlags(cx, &flags))
840 return true;
841 bool warning = JSREPORT_IS_WARNING(flags);
843 JSErrorReport report;
844 report.flags = flags;
845 report.errorNumber = errorNumber;
846 PopulateReportBlame(cx, &report);
847 report.messageArgs = args;
849 char* message;
850 va_list dummy;
851 if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
852 &message, &report, ArgumentsAreUnicode, dummy)) {
853 return false;
856 ReportError(cx, message, &report, callback, userRef);
858 js_free(message);
859 js_free((void*)report.ucmessage);
861 return warning;
864 void
865 js::CallErrorReporter(JSContext* cx, const char* message, JSErrorReport* reportp)
867 MOZ_ASSERT(message);
868 MOZ_ASSERT(reportp);
870 if (JSErrorReporter onError = cx->runtime()->errorReporter)
871 onError(cx, message, reportp);
874 void
875 js_ReportIsNotDefined(JSContext* cx, const char* name)
877 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_DEFINED, name);
880 bool
881 js_ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v,
882 HandleString fallback)
884 char* bytes;
885 bool ok;
887 bytes = DecompileValueGenerator(cx, spindex, v, fallback);
888 if (!bytes)
889 return false;
891 if (strcmp(bytes, js_undefined_str) == 0 ||
892 strcmp(bytes, js_null_str) == 0) {
893 ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
894 js_GetErrorMessage, nullptr,
895 JSMSG_NO_PROPERTIES, bytes,
896 nullptr, nullptr);
897 } else if (v.isUndefined()) {
898 ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
899 js_GetErrorMessage, nullptr,
900 JSMSG_UNEXPECTED_TYPE, bytes,
901 js_undefined_str, nullptr);
902 } else {
903 MOZ_ASSERT(v.isNull());
904 ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
905 js_GetErrorMessage, nullptr,
906 JSMSG_UNEXPECTED_TYPE, bytes,
907 js_null_str, nullptr);
910 js_free(bytes);
911 return ok;
914 void
915 js_ReportMissingArg(JSContext* cx, HandleValue v, unsigned arg)
917 char argbuf[11];
918 char* bytes;
919 RootedAtom atom(cx);
921 JS_snprintf(argbuf, sizeof argbuf, "%u", arg);
922 bytes = nullptr;
923 if (IsFunctionObject(v)) {
924 atom = v.toObject().as<JSFunction>().atom();
925 bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
926 v, atom);
927 if (!bytes)
928 return;
930 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
931 JSMSG_MISSING_FUN_ARG, argbuf,
932 bytes ? bytes : "");
933 js_free(bytes);
936 bool
937 js_ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNumber,
938 int spindex, HandleValue v, HandleString fallback,
939 const char* arg1, const char* arg2)
941 char* bytes;
942 bool ok;
944 MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
945 MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
946 bytes = DecompileValueGenerator(cx, spindex, v, fallback);
947 if (!bytes)
948 return false;
950 ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage,
951 nullptr, errorNumber, bytes, arg1, arg2);
952 js_free(bytes);
953 return ok;
956 const JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
957 #define MSG_DEF(name, count, exception, format) \
958 { format, count, exception } ,
959 #include "js.msg"
960 #undef MSG_DEF
963 JS_FRIEND_API(const JSErrorFormatString*)
964 js_GetErrorMessage(void* userRef, const unsigned errorNumber)
966 if (errorNumber > 0 && errorNumber < JSErr_Limit)
967 return &js_ErrorFormatString[errorNumber];
968 return nullptr;
971 ThreadSafeContext::ThreadSafeContext(JSRuntime* rt, PerThreadData* pt, ContextKind kind)
972 : ContextFriendFields(rt),
973 contextKind_(kind),
974 perThreadData(pt),
975 allocator_(nullptr)
979 bool
980 ThreadSafeContext::isForkJoinContext() const
982 return contextKind_ == Context_ForkJoin;
985 ForkJoinContext*
986 ThreadSafeContext::asForkJoinContext()
988 MOZ_ASSERT(isForkJoinContext());
989 return reinterpret_cast<ForkJoinContext*>(this);
992 void
993 ThreadSafeContext::recoverFromOutOfMemory()
995 // If this is not a JSContext, there's nothing to do.
996 if (JSContext* maybecx = maybeJSContext()) {
997 if (maybecx->isExceptionPending()) {
998 MOZ_ASSERT(maybecx->isThrowingOutOfMemory());
999 maybecx->clearPendingException();
1004 JSContext::JSContext(JSRuntime* rt)
1005 : ExclusiveContext(rt, &rt->mainThread, Context_JS),
1006 throwing(false),
1007 unwrappedException_(UndefinedValue()),
1008 options_(),
1009 overRecursed_(false),
1010 propagatingForcedReturn_(false),
1011 liveVolatileJitFrameIterators_(nullptr),
1012 reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
1013 resolvingList(nullptr),
1014 generatingError(false),
1015 savedFrameChains_(),
1016 cycleDetectorSet(this),
1017 data(nullptr),
1018 data2(nullptr),
1019 outstandingRequests(0),
1020 jitIsBroken(false)
1022 MOZ_ASSERT(static_cast<ContextFriendFields*>(this) ==
1023 ContextFriendFields::get(this));
1026 JSContext::~JSContext()
1028 /* Free the stuff hanging off of cx. */
1029 MOZ_ASSERT(!resolvingList);
1032 bool
1033 JSContext::getPendingException(MutableHandleValue rval)
1035 MOZ_ASSERT(throwing);
1036 rval.set(unwrappedException_);
1037 if (IsAtomsCompartment(compartment()))
1038 return true;
1039 bool wasOverRecursed = overRecursed_;
1040 clearPendingException();
1041 if (!compartment()->wrap(this, rval))
1042 return false;
1043 assertSameCompartment(this, rval);
1044 setPendingException(rval);
1045 overRecursed_ = wasOverRecursed;
1046 return true;
1049 bool
1050 JSContext::isThrowingOutOfMemory()
1052 return throwing && unwrappedException_ == StringValue(names().outOfMemory);
1055 bool
1056 JSContext::saveFrameChain()
1058 if (!savedFrameChains_.append(SavedFrameChain(compartment(), enterCompartmentDepth_)))
1059 return false;
1061 if (Activation* act = mainThread().activation())
1062 act->saveFrameChain();
1064 setCompartment(nullptr);
1065 enterCompartmentDepth_ = 0;
1067 return true;
1070 void
1071 JSContext::restoreFrameChain()
1073 MOZ_ASSERT(enterCompartmentDepth_ == 0); // We're about to clobber it, and it
1074 // will be wrong forevermore.
1075 SavedFrameChain sfc = savedFrameChains_.popCopy();
1076 setCompartment(sfc.compartment);
1077 enterCompartmentDepth_ = sfc.enterCompartmentCount;
1079 if (Activation* act = mainThread().activation())
1080 act->restoreFrameChain();
1083 bool
1084 JSContext::currentlyRunning() const
1086 for (ActivationIterator iter(runtime()); !iter.done(); ++iter) {
1087 if (iter->cx() == this) {
1088 if (iter->hasSavedFrameChain())
1089 return false;
1090 return true;
1094 return false;
1097 static bool
1098 ComputeIsJITBroken()
1100 #if !defined(ANDROID) || defined(GONK)
1101 return false;
1102 #else // ANDROID
1103 if (getenv("JS_IGNORE_JIT_BROKENNESS")) {
1104 return false;
1107 std::string line;
1109 // Check for the known-bad kernel version (2.6.29).
1110 std::ifstream osrelease("/proc/sys/kernel/osrelease");
1111 std::getline(osrelease, line);
1112 __android_log_print(ANDROID_LOG_INFO, "Gecko", "Detected osrelease `%s'",
1113 line.c_str());
1115 if (line.npos == line.find("2.6.29")) {
1116 // We're using something other than 2.6.29, so the JITs should work.
1117 __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are not broken");
1118 return false;
1121 // We're using 2.6.29, and this causes trouble with the JITs on i9000.
1122 line = "";
1123 bool broken = false;
1124 std::ifstream cpuinfo("/proc/cpuinfo");
1125 do {
1126 if (0 == line.find("Hardware")) {
1127 static const char* const blacklist[] = {
1128 "SCH-I400", // Samsung Continuum
1129 "SGH-T959", // Samsung i9000, Vibrant device
1130 "SGH-I897", // Samsung i9000, Captivate device
1131 "SCH-I500", // Samsung i9000, Fascinate device
1132 "SPH-D700", // Samsung i9000, Epic device
1133 "GT-I9000", // Samsung i9000, UK/Europe device
1134 nullptr
1136 for (const char* const* hw = &blacklist[0]; *hw; ++hw) {
1137 if (line.npos != line.find(*hw)) {
1138 __android_log_print(ANDROID_LOG_INFO, "Gecko",
1139 "Blacklisted device `%s'", *hw);
1140 broken = true;
1141 break;
1144 break;
1146 std::getline(cpuinfo, line);
1147 } while(!cpuinfo.fail() && !cpuinfo.eof());
1149 __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are %sbroken",
1150 broken ? "" : "not ");
1152 return broken;
1153 #endif // ifndef ANDROID
1156 static bool
1157 IsJITBrokenHere()
1159 static bool computedIsBroken = false;
1160 static bool isBroken = false;
1161 if (!computedIsBroken) {
1162 isBroken = ComputeIsJITBroken();
1163 computedIsBroken = true;
1165 return isBroken;
1168 void
1169 JSContext::updateJITEnabled()
1171 jitIsBroken = IsJITBrokenHere();
1174 size_t
1175 JSContext::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
1178 * There are other JSContext members that could be measured; the following
1179 * ones have been found by DMD to be worth measuring. More stuff may be
1180 * added later.
1182 return mallocSizeOf(this) + cycleDetectorSet.sizeOfExcludingThis(mallocSizeOf);
1185 void
1186 JSContext::mark(JSTracer* trc)
1188 /* Stack frames and slots are traced by StackSpace::mark. */
1190 /* Mark other roots-by-definition in the JSContext. */
1191 if (isExceptionPending())
1192 MarkValueRoot(trc, &unwrappedException_, "unwrapped exception");
1194 TraceCycleDetectionSet(trc, cycleDetectorSet);
1196 if (compartment_)
1197 compartment_->mark();
1200 void*
1201 ThreadSafeContext::stackLimitAddressForJitCode(StackKind kind)
1203 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
1204 return runtime_->mainThread.addressOfSimulatorStackLimit();
1205 #endif
1206 return stackLimitAddress(kind);
1209 JSVersion
1210 JSContext::findVersion() const
1212 if (JSScript* script = currentScript(nullptr, ALLOW_CROSS_COMPARTMENT))
1213 return script->getVersion();
1215 if (compartment() && compartment()->options().version() != JSVERSION_UNKNOWN)
1216 return compartment()->options().version();
1218 return runtime()->defaultVersion();
1221 #ifdef DEBUG
1223 JS::AutoCheckRequestDepth::AutoCheckRequestDepth(JSContext* cx)
1224 : cx(cx)
1226 MOZ_ASSERT(cx->runtime()->requestDepth || cx->runtime()->isHeapBusy());
1227 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
1228 cx->runtime()->checkRequestDepth++;
1231 JS::AutoCheckRequestDepth::AutoCheckRequestDepth(ContextFriendFields* cxArg)
1232 : cx(static_cast<ThreadSafeContext*>(cxArg)->maybeJSContext())
1234 if (cx) {
1235 MOZ_ASSERT(cx->runtime()->requestDepth || cx->runtime()->isHeapBusy());
1236 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
1237 cx->runtime()->checkRequestDepth++;
1241 JS::AutoCheckRequestDepth::~AutoCheckRequestDepth()
1243 if (cx) {
1244 MOZ_ASSERT(cx->runtime()->checkRequestDepth != 0);
1245 cx->runtime()->checkRequestDepth--;
1249 #endif
1251 #ifdef JS_CRASH_DIAGNOSTICS
1252 void CompartmentChecker::check(InterpreterFrame* fp)
1254 if (fp)
1255 check(fp->scopeChain());
1258 void CompartmentChecker::check(AbstractFramePtr frame)
1260 if (frame)
1261 check(frame.scopeChain());
1263 #endif
1265 void
1266 js::CrashAtUnhandlableOOM(const char* reason)
1268 char msgbuf[1024];
1269 JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
1270 MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
1271 MOZ_CRASH();