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/. */
8 * JS execution context.
11 #include "jscntxtinlines.h"
13 #include "mozilla/ArrayUtils.h"
14 #include "mozilla/DebugOnly.h"
15 #include "mozilla/MemoryReporting.h"
21 # include <android/log.h>
27 #include "jscompartment.h"
39 #include "jswatchpoint.h"
41 #include "gc/Marking.h"
43 #include "js/CharacterEncoding.h"
44 #include "vm/HelperThreads.h"
47 #include "jsobjinlines.h"
48 #include "jsscriptinlines.h"
50 #include "vm/Stack-inl.h"
53 using namespace js::gc
;
55 using mozilla::DebugOnly
;
56 using mozilla::PodArrayZero
;
57 using mozilla::PointerRangeSize
;
60 js::AutoCycleDetector::init()
62 ObjectSet
& set
= cx
->cycleDetectorSet
;
63 hashsetAddPointer
= set
.lookupForAdd(obj
);
64 if (!hashsetAddPointer
) {
65 if (!set
.add(hashsetAddPointer
, obj
))
68 hashsetGenerationAtInit
= set
.generation();
73 js::AutoCycleDetector::~AutoCycleDetector()
76 if (hashsetGenerationAtInit
== cx
->cycleDetectorSet
.generation())
77 cx
->cycleDetectorSet
.remove(hashsetAddPointer
);
79 cx
->cycleDetectorSet
.remove(obj
);
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");
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()))
106 } else if (key
!= e
.front().key()) {
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())
130 CallsiteCloneTable::Ptr p
= table
.readonlyThreadsafeLookup(CallsiteCloneKey(fun
, script
, script
->pcToOffset(pc
)));
138 js::CloneFunctionAtCallsite(JSContext
* cx
, HandleFunction fun
, HandleScript script
, jsbytecode
* pc
)
140 if (JSFunction
* clone
= ExistingCloneFunctionAtCallsite(cx
->compartment()->callsiteClones
, fun
, script
, pc
))
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
);
153 * Store a link back to the original for function.caller and avoid cloning
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())
165 if (!table
.putNew(Key(fun
, script
, script
->pcToOffset(pc
)), clone
))
172 js::NewContext(JSRuntime
* rt
, size_t stackChunkSize
)
174 JS_AbortIfWrongThread(rt
);
176 JSContext
* cx
= js_new
<JSContext
>(rt
);
180 if (!cx
->cycleDetectorSet
.init()) {
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
198 if (!rt
->haveCreatedContext
) {
200 bool ok
= rt
->initializeAtoms(cx
);
202 ok
= rt
->initSelfHosting(cx
);
204 if (ok
&& !rt
->parentRuntime
)
205 ok
= rt
->transformToPermanentAtoms();
210 DestroyContext(cx
, DCM_NEW_FAILED
);
214 rt
->haveCreatedContext
= true;
217 JSContextCallback cxCallback
= rt
->cxCallback
;
218 if (cxCallback
&& !cxCallback(cx
, JSCONTEXT_NEW
, rt
->cxCallbackData
)) {
219 DestroyContext(cx
, DCM_NEW_FAILED
);
227 js::DestroyContext(JSContext
* cx
, DestroyContextMode mode
)
229 JSRuntime
* rt
= cx
->runtime();
230 JS_AbortIfWrongThread(rt
);
232 if (cx
->outstandingRequests
!= 0)
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
243 JS_ALWAYS_TRUE(cxCallback(cx
, JSCONTEXT_DESTROY
,
244 rt
->cxCallbackData
));
249 bool last
= !rt
->hasContexts();
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
);
267 ContextFriendFields::checkNoGCRooters() {
269 for (int i
= 0; i
< THING_ROOT_LIMIT
; ++i
)
270 MOZ_ASSERT(thingGCRooters
[i
] == nullptr);
275 AutoResolving::alreadyStartedSlow() const
278 AutoResolving
* cursor
= link
;
280 MOZ_ASSERT(this != cursor
);
281 if (object
.get() == cursor
->object
&& id
.get() == cursor
->id
&& kind
== cursor
->kind
)
283 } while (!!(cursor
= cursor
->link
));
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.
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
)) {
311 * Call the error reporter only if an exception wasn't raised.
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).
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
);
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.
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");
359 if (!cxArg
->isJSContext())
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
));
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
402 MOZ_ASSERT(!cx
->isExceptionPending());
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
417 fprintf(stderr
, "js_ReportOverRecursed called\n");
420 JS_ReportErrorNumber(maybecx
, js_GetErrorMessage
, nullptr, JSMSG_OVER_RECURSED
);
421 maybecx
->overRecursed_
= true;
426 js_ReportOverRecursed(ExclusiveContext
* cx
)
428 if (cx
->isJSContext())
429 js_ReportOverRecursed(cx
->asJSContext());
431 cx
->addPendingOverRecursed();
435 js_ReportAllocationOverflow(ExclusiveContext
* cxArg
)
440 if (!cxArg
->isJSContext())
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.
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.
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
;
471 } else if (JSREPORT_IS_STRICT(*flags
)) {
472 /* Warning/error only when JSOPTION_STRICT is set. */
473 if (!cx
->compartment()->options().extraWarnings(cx
))
477 /* Warnings become errors when JSOPTION_WERROR is set. */
478 if (JSREPORT_IS_WARNING(*flags
) && cx
->runtime()->options().werror())
479 *flags
&= ~JSREPORT_WARNING
;
485 js_ReportErrorVA(JSContext
* cx
, unsigned flags
, const char* format
, va_list ap
)
490 JSErrorReport report
;
493 if (checkReportFlags(cx
, &flags
))
496 message
= JS_vsmprintf(format
, ap
);
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);
514 /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
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
))
530 if (!usage
.isString()) {
531 JS_ReportError(cx
, "%s", msg
);
533 JSString
* str
= usage
.toString();
534 if (!str
->ensureFlat(cx
))
536 AutoStableStringChars
chars(cx
);
537 if (!chars
.initTwoByte(cx
, str
))
540 JS_ReportError(cx
, "%s. Usage: %hs", msg
, chars
.twoByteRange().start().get());
545 js::PrintError(JSContext
* cx
, FILE* file
, const char* message
, JSErrorReport
* report
,
549 fprintf(file
, "%s\n", message
);
554 /* Conditionally ignore reported warnings. */
555 if (JSREPORT_IS_WARNING(report
->flags
) && !reportWarnings
)
558 char* prefix
= nullptr;
559 if (report
->filename
)
560 prefix
= JS_smprintf("%s:", report
->filename
);
561 if (report
->lineno
) {
563 prefix
= JS_smprintf("%s%u:%u ", tmp
? tmp
: "", report
->lineno
, report
->column
);
566 if (JSREPORT_IS_WARNING(report
->flags
)) {
568 prefix
= JS_smprintf("%s%swarning: ",
570 JSREPORT_IS_STRICT(report
->flags
) ? "strict " : "");
574 /* embedded newlines -- argh! */
576 while ((ctmp
= strchr(message
, '\n')) != 0) {
580 fwrite(message
, 1, ctmp
- message
, file
);
584 /* If there were no filename or lineno, the prefix might be empty */
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",
595 (n
> 0 && report
->linebuf
[n
-1] == '\n') ? "" : "\n",
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
++) {
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).
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
;
636 bool messageArgsPassed
= !!reportp
->messageArgs
;
641 callback
= js_GetErrorMessage
;
644 AutoSuppressGC
suppressGC(cx
);
645 efs
= callback(userRef
, errorNumber
);
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);
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
662 if (messageArgsPassed
) {
663 MOZ_ASSERT(!reportp
->messageArgs
[argCount
]);
665 reportp
->messageArgs
= cx
->pod_malloc
<const char16_t
*>(argCount
+ 1);
666 if (!reportp
->messageArgs
)
668 /* nullptr-terminate for easy copying. */
669 reportp
->messageArgs
[argCount
] = nullptr;
671 for (i
= 0; i
< argCount
; i
++) {
672 if (messageArgsPassed
) {
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
])
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.
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
);
702 - (3 * argCount
) /* exclude the {n} */
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);
716 if (isdigit(fmt
[1])) {
717 int d
= JS7_UNDEC(fmt
[1]);
718 MOZ_ASSERT(d
< argCount
);
719 js_strncpy(out
, reportp
->messageArgs
[d
],
721 out
+= argLengths
[d
];
729 MOZ_ASSERT(expandedArgs
== argCount
);
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();
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
748 *messagep
= DuplicateString(cx
, efs
->format
).release();
751 len
= strlen(*messagep
);
752 reportp
->ucmessage
= InflateString(cx
, *messagep
, &len
);
753 if (!reportp
->ucmessage
)
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
);
766 JS_snprintf(*messagep
, nbytes
, defaultErrorMessage
, errorNumber
);
771 if (!messageArgsPassed
&& reportp
->messageArgs
) {
772 /* free the arguments only if we allocated them */
773 if (argumentsType
== ArgumentsAreASCII
) {
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;
786 js_free((void*)*messagep
);
793 js_ReportErrorNumberVA(JSContext
* cx
, unsigned flags
, JSErrorCallback callback
,
794 void* userRef
, const unsigned errorNumber
,
795 ErrorArgumentsType argumentsType
, va_list ap
)
797 JSErrorReport report
;
801 if (checkReportFlags(cx
, &flags
))
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
)) {
814 ReportError(cx
, message
, &report
, callback
, userRef
);
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
) {
824 while (report
.messageArgs
[i
])
825 js_free((void*)report
.messageArgs
[i
++]);
827 js_free((void*)report
.messageArgs
);
829 js_free((void*)report
.ucmessage
);
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
))
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
;
851 if (!js_ExpandErrorArguments(cx
, callback
, userRef
, errorNumber
,
852 &message
, &report
, ArgumentsAreUnicode
, dummy
)) {
856 ReportError(cx
, message
, &report
, callback
, userRef
);
859 js_free((void*)report
.ucmessage
);
865 js::CallErrorReporter(JSContext
* cx
, const char* message
, JSErrorReport
* reportp
)
870 if (JSErrorReporter onError
= cx
->runtime()->errorReporter
)
871 onError(cx
, message
, reportp
);
875 js_ReportIsNotDefined(JSContext
* cx
, const char* name
)
877 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_NOT_DEFINED
, name
);
881 js_ReportIsNullOrUndefined(JSContext
* cx
, int spindex
, HandleValue v
,
882 HandleString fallback
)
887 bytes
= DecompileValueGenerator(cx
, spindex
, v
, fallback
);
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
,
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);
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);
915 js_ReportMissingArg(JSContext
* cx
, HandleValue v
, unsigned arg
)
921 JS_snprintf(argbuf
, sizeof argbuf
, "%u", arg
);
923 if (IsFunctionObject(v
)) {
924 atom
= v
.toObject().as
<JSFunction
>().atom();
925 bytes
= DecompileValueGenerator(cx
, JSDVG_SEARCH_STACK
,
930 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr,
931 JSMSG_MISSING_FUN_ARG
, argbuf
,
937 js_ReportValueErrorFlags(JSContext
* cx
, unsigned flags
, const unsigned errorNumber
,
938 int spindex
, HandleValue v
, HandleString fallback
,
939 const char* arg1
, const char* arg2
)
944 MOZ_ASSERT(js_ErrorFormatString
[errorNumber
].argCount
>= 1);
945 MOZ_ASSERT(js_ErrorFormatString
[errorNumber
].argCount
<= 3);
946 bytes
= DecompileValueGenerator(cx
, spindex
, v
, fallback
);
950 ok
= JS_ReportErrorFlagsAndNumber(cx
, flags
, js_GetErrorMessage
,
951 nullptr, errorNumber
, bytes
, arg1
, arg2
);
956 const JSErrorFormatString js_ErrorFormatString
[JSErr_Limit
] = {
957 #define MSG_DEF(name, count, exception, format) \
958 { format, count, exception } ,
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
];
971 ThreadSafeContext::ThreadSafeContext(JSRuntime
* rt
, PerThreadData
* pt
, ContextKind kind
)
972 : ContextFriendFields(rt
),
980 ThreadSafeContext::isForkJoinContext() const
982 return contextKind_
== Context_ForkJoin
;
986 ThreadSafeContext::asForkJoinContext()
988 MOZ_ASSERT(isForkJoinContext());
989 return reinterpret_cast<ForkJoinContext
*>(this);
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
),
1007 unwrappedException_(UndefinedValue()),
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),
1019 outstandingRequests(0),
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
);
1033 JSContext::getPendingException(MutableHandleValue rval
)
1035 MOZ_ASSERT(throwing
);
1036 rval
.set(unwrappedException_
);
1037 if (IsAtomsCompartment(compartment()))
1039 bool wasOverRecursed
= overRecursed_
;
1040 clearPendingException();
1041 if (!compartment()->wrap(this, rval
))
1043 assertSameCompartment(this, rval
);
1044 setPendingException(rval
);
1045 overRecursed_
= wasOverRecursed
;
1050 JSContext::isThrowingOutOfMemory()
1052 return throwing
&& unwrappedException_
== StringValue(names().outOfMemory
);
1056 JSContext::saveFrameChain()
1058 if (!savedFrameChains_
.append(SavedFrameChain(compartment(), enterCompartmentDepth_
)))
1061 if (Activation
* act
= mainThread().activation())
1062 act
->saveFrameChain();
1064 setCompartment(nullptr);
1065 enterCompartmentDepth_
= 0;
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();
1084 JSContext::currentlyRunning() const
1086 for (ActivationIterator
iter(runtime()); !iter
.done(); ++iter
) {
1087 if (iter
->cx() == this) {
1088 if (iter
->hasSavedFrameChain())
1098 ComputeIsJITBroken()
1100 #if !defined(ANDROID) || defined(GONK)
1103 if (getenv("JS_IGNORE_JIT_BROKENNESS")) {
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'",
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");
1121 // We're using 2.6.29, and this causes trouble with the JITs on i9000.
1123 bool broken
= false;
1124 std::ifstream
cpuinfo("/proc/cpuinfo");
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
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
);
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 ");
1153 #endif // ifndef ANDROID
1159 static bool computedIsBroken
= false;
1160 static bool isBroken
= false;
1161 if (!computedIsBroken
) {
1162 isBroken
= ComputeIsJITBroken();
1163 computedIsBroken
= true;
1169 JSContext::updateJITEnabled()
1171 jitIsBroken
= IsJITBrokenHere();
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
1182 return mallocSizeOf(this) + cycleDetectorSet
.sizeOfExcludingThis(mallocSizeOf
);
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
);
1197 compartment_
->mark();
1201 ThreadSafeContext::stackLimitAddressForJitCode(StackKind kind
)
1203 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
1204 return runtime_
->mainThread
.addressOfSimulatorStackLimit();
1206 return stackLimitAddress(kind
);
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();
1223 JS::AutoCheckRequestDepth::AutoCheckRequestDepth(JSContext
* 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())
1235 MOZ_ASSERT(cx
->runtime()->requestDepth
|| cx
->runtime()->isHeapBusy());
1236 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx
->runtime()));
1237 cx
->runtime()->checkRequestDepth
++;
1241 JS::AutoCheckRequestDepth::~AutoCheckRequestDepth()
1244 MOZ_ASSERT(cx
->runtime()->checkRequestDepth
!= 0);
1245 cx
->runtime()->checkRequestDepth
--;
1251 #ifdef JS_CRASH_DIAGNOSTICS
1252 void CompartmentChecker::check(InterpreterFrame
* fp
)
1255 check(fp
->scopeChain());
1258 void CompartmentChecker::check(AbstractFramePtr frame
)
1261 check(frame
.scopeChain());
1266 js::CrashAtUnhandlableOOM(const char* reason
)
1269 JS_snprintf(msgbuf
, sizeof(msgbuf
), "[unhandlable oom] %s", reason
);
1270 MOZ_ReportAssertionFailure(msgbuf
, __FILE__
, __LINE__
);