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