1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=80:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
17 * The Original Code is Mozilla Communicator client code, released
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.
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.
39 * ***** END LICENSE BLOCK ***** */
42 * JS execution context.
49 # include <android/log.h>
63 #include "jsversion.h"
71 #include "jsnativestack.h"
79 #include "jsstaticcheck.h"
84 # include "assembler/assembler/MacroAssembler.h"
87 #include "jscntxtinlines.h"
88 #include "jscompartment.h"
89 #include "jsinterpinlines.h"
90 #include "jsobjinlines.h"
95 # define INCL_DOSMEMMGR
99 # include <sys/mman.h>
100 # if !defined(MAP_ANONYMOUS)
101 # if defined(MAP_ANON)
102 # define MAP_ANONYMOUS MAP_ANON
104 # define MAP_ANONYMOUS 0
110 using namespace js::gc;
112 static const size_t ARENA_HEADER_SIZE_HACK = 40;
113 static const size_t TEMP_POOL_CHUNK_SIZE = 4096 - ARENA_HEADER_SIZE_HACK;
116 FreeContext(JSContext *cx);
119 JS_REQUIRES_STACK bool
120 StackSegment::contains(const JSStackFrame *fp) const
122 JS_ASSERT(inContext());
126 JS_ASSERT(cx->hasfp());
128 stop = cx->activeSegment()->initialFrame->prev();
130 JS_ASSERT(suspendedRegs && suspendedRegs->fp);
131 start = suspendedRegs->fp;
132 stop = initialFrame->prev();
134 for (JSStackFrame *f = start; f != stop; f = f->prev()) {
147 p = VirtualAlloc(NULL, CAPACITY_BYTES, MEM_RESERVE, PAGE_READWRITE);
150 void *check = VirtualAlloc(p, COMMIT_BYTES, MEM_COMMIT, PAGE_READWRITE);
153 base = reinterpret_cast<Value *>(p);
154 commitEnd = base + COMMIT_VALS;
155 end = base + CAPACITY_VALS;
156 #elif defined(XP_OS2)
157 if (DosAllocMem(&p, CAPACITY_BYTES, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY) &&
158 DosAllocMem(&p, CAPACITY_BYTES, PAG_COMMIT | PAG_READ | PAG_WRITE))
160 base = reinterpret_cast<Value *>(p);
161 end = base + CAPACITY_VALS;
163 JS_ASSERT(CAPACITY_BYTES % getpagesize() == 0);
164 p = mmap(NULL, CAPACITY_BYTES, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
167 base = reinterpret_cast<Value *>(p);
168 end = base + CAPACITY_VALS;
177 VirtualFree(base, (commitEnd - base) * sizeof(Value), MEM_DECOMMIT);
178 VirtualFree(base, 0, MEM_RELEASE);
179 #elif defined(XP_OS2)
183 munmap((caddr_t)base, CAPACITY_BYTES);
185 munmap(base, CAPACITY_BYTES);
192 StackSpace::bumpCommit(Value *from, ptrdiff_t nvals) const
194 JS_ASSERT(end - from >= nvals);
195 Value *newCommit = commitEnd;
196 Value *request = from + nvals;
198 /* Use a dumb loop; will probably execute once. */
199 JS_ASSERT((end - newCommit) % COMMIT_VALS == 0);
201 newCommit += COMMIT_VALS;
202 JS_ASSERT((end - newCommit) >= 0);
203 } while (newCommit < request);
205 /* The cast is safe because CAPACITY_BYTES is small. */
206 int32 size = static_cast<int32>(newCommit - commitEnd) * sizeof(Value);
208 if (!VirtualAlloc(commitEnd, size, MEM_COMMIT, PAGE_READWRITE))
210 commitEnd = newCommit;
216 StackSpace::mark(JSTracer *trc)
219 * The correctness/completeness of marking depends on the continuity
220 * invariants described by the StackSegment and StackSpace definitions.
223 * Stack slots might be torn or uninitialized in the presence of method
224 * JIT'd code. Arguments are an exception and are always fully synced
225 * (so they can be read by functions).
227 Value *end = firstUnused();
228 for (StackSegment *seg = currentSegment; seg; seg = seg->getPreviousInMemory()) {
229 STATIC_ASSERT(ubound(end) >= 0);
230 if (seg->inContext()) {
231 /* This may be the only pointer to the initialVarObj. */
232 if (seg->hasInitialVarObj())
233 MarkObject(trc, seg->getInitialVarObj(), "varobj");
235 /* Mark slots/args trailing off of the last stack frame. */
236 JSStackFrame *fp = seg->getCurrentFrame();
237 MarkStackRangeConservatively(trc, fp->slots(), end);
239 /* Mark stack frames and slots/args between stack frames. */
240 JSStackFrame *initial = seg->getInitialFrame();
241 for (JSStackFrame *f = fp; f != initial; f = f->prev()) {
242 js_TraceStackFrame(trc, f);
243 MarkStackRangeConservatively(trc, f->prev()->slots(), (Value *)f);
246 /* Mark initial stack frame and leading args. */
247 js_TraceStackFrame(trc, initial);
248 MarkStackRangeConservatively(trc, seg->valueRangeBegin(), (Value *)initial);
250 /* Mark slots/args trailing off segment. */
251 MarkValueRange(trc, seg->valueRangeBegin(), end, "stack");
258 StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
260 Value *start = firstUnused();
261 ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + 2 + argc;
262 if (!ensureSpace(cx, start, nvals))
265 StackSegment *seg = new(start) StackSegment;
266 seg->setPreviousInMemory(currentSegment);
267 currentSegment = seg;
271 ag->argv_ = seg->valueRangeBegin() + 2;
274 /* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
276 ag->prevInvokeSegment = invokeSegment;
278 ag->prevInvokeFrame = invokeFrame;
281 ag->prevInvokeArgEnd = invokeArgEnd;
282 invokeArgEnd = ag->argv() + ag->argc();
287 StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag)
289 JS_ASSERT(!currentSegment->inContext());
290 JS_ASSERT(ag.seg == currentSegment);
291 JS_ASSERT(invokeSegment == currentSegment);
292 JS_ASSERT(invokeArgEnd == ag.argv() + ag.argc());
294 currentSegment = currentSegment->getPreviousInMemory();
297 invokeSegment = ag.prevInvokeSegment;
298 invokeFrame = ag.prevInvokeFrame;
300 invokeArgEnd = ag.prevInvokeArgEnd;
304 StackSpace::getSegmentAndFrame(JSContext *cx, uintN vplen, uintN nslots,
305 FrameGuard *fg) const
307 Value *start = firstUnused();
308 uintN nvals = VALUES_PER_STACK_SEGMENT + vplen + VALUES_PER_STACK_FRAME + nslots;
309 if (!ensureSpace(cx, start, nvals))
312 fg->seg_ = new(start) StackSegment;
313 fg->vp_ = start + VALUES_PER_STACK_SEGMENT;
314 fg->fp_ = reinterpret_cast<JSStackFrame *>(fg->vp() + vplen);
319 StackSpace::pushSegmentAndFrame(JSContext *cx, JSFrameRegs *regs, FrameGuard *fg)
321 /* Caller should have already initialized regs. */
322 JS_ASSERT(regs->fp == fg->fp());
323 StackSegment *seg = fg->segment();
325 /* Register new segment/frame with the context. */
326 cx->pushSegmentAndFrame(seg, *regs);
328 /* Officially push the segment/frame on the stack. */
329 seg->setPreviousInMemory(currentSegment);
330 currentSegment = seg;
332 /* Mark as 'pushed' in the guard. */
337 StackSpace::popSegmentAndFrame(JSContext *cx)
339 JS_ASSERT(isCurrentAndActive(cx));
340 JS_ASSERT(cx->hasActiveSegment());
342 /* Officially pop the segment/frame from the stack. */
343 currentSegment = currentSegment->getPreviousInMemory();
345 /* Unregister pushed segment/frame from the context. */
346 cx->popSegmentAndFrame();
349 * N.B. This StackSpace should be GC-able without any operations after
350 * cx->popSegmentAndFrame executes since it can trigger GC.
354 FrameGuard::~FrameGuard()
358 JS_ASSERT(cx_->activeSegment() == segment());
359 JS_ASSERT(cx_->maybefp() == fp());
360 cx_->stack().popSegmentAndFrame(cx_);
364 StackSpace::getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const
366 return getSegmentAndFrame(cx, 2, script->nslots, fg);
370 StackSpace::pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg)
372 JSStackFrame *fp = fg->fp();
373 JSScript *script = fp->script();
374 fg->regs_.pc = script->code;
376 fg->regs_.sp = fp->base();
377 pushSegmentAndFrame(cx, &fg->regs_, fg);
378 fg->seg_->setInitialVarObj(initialVarObj);
382 StackSpace::pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *fg)
384 if (!getSegmentAndFrame(cx, 0 /*vplen*/, 0 /*nslots*/, fg))
386 fg->fp()->initDummyFrame(cx, scopeChain);
387 fg->regs_.fp = fg->fp();
389 fg->regs_.sp = fg->fp()->slots();
390 pushSegmentAndFrame(cx, &fg->regs_, fg);
395 StackSpace::getGeneratorFrame(JSContext *cx, uintN vplen, uintN nslots, GeneratorFrameGuard *fg)
397 return getSegmentAndFrame(cx, vplen, nslots, fg);
401 StackSpace::pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameGuard *fg)
403 JS_ASSERT(regs->fp == fg->fp());
404 JS_ASSERT(regs->fp->prev() == cx->maybefp());
405 pushSegmentAndFrame(cx, regs, fg);
409 StackSpace::bumpCommitAndLimit(JSStackFrame *base, Value *sp, uintN nvals, Value **limit) const
411 JS_ASSERT(sp >= firstUnused());
412 JS_ASSERT(sp + nvals >= *limit);
414 if (commitEnd <= *limit) {
415 Value *quotaEnd = (Value *)base + STACK_QUOTA;
416 if (sp + nvals < quotaEnd) {
417 if (!ensureSpace(NULL, sp, nvals))
419 *limit = Min(quotaEnd, commitEnd);
428 FrameRegsIter::initSlow()
437 JS_ASSERT(curseg->isSuspended());
438 curfp = curseg->getSuspendedFrame();
439 cursp = curseg->getSuspendedRegs()->sp;
440 curpc = curseg->getSuspendedRegs()->pc;
444 * Using the invariant described in the js::StackSegment comment, we know that,
445 * when a pair of prev-linked stack frames are in the same segment, the
446 * first frame's address is the top of the prev-frame's stack, modulo missing
450 FrameRegsIter::incSlow(JSStackFrame *fp, JSStackFrame *prev)
453 JS_ASSERT(curpc == curfp->pc(cx, fp));
454 JS_ASSERT(fp == curseg->getInitialFrame());
457 * If fp is in cs and the prev-frame is in csprev, it is not necessarily
458 * the case that |cs->getPreviousInContext == csprev| or that
459 * |csprev->getSuspendedFrame == prev| (because of indirect eval and
460 * JS_EvaluateInStackFrame). To compute prev's sp, we need to do a linear
461 * scan, keeping track of what is immediately after prev in memory.
463 curseg = curseg->getPreviousInContext();
464 cursp = curseg->getSuspendedRegs()->sp;
465 JSStackFrame *f = curseg->getSuspendedFrame();
467 if (f == curseg->getInitialFrame()) {
468 curseg = curseg->getPreviousInContext();
469 cursp = curseg->getSuspendedRegs()->sp;
470 f = curseg->getSuspendedFrame();
472 cursp = f->formalArgsEnd();
478 AllFramesIter::AllFramesIter(JSContext *cx)
479 : curcs(cx->stack().getCurrentSegment()),
480 curfp(curcs ? curcs->getCurrentFrame() : NULL)
485 AllFramesIter::operator++()
488 if (curfp == curcs->getInitialFrame()) {
489 curcs = curcs->getPreviousInMemory();
490 curfp = curcs ? curcs->getCurrentFrame() : NULL;
492 curfp = curfp->prev();
501 /* The data must be already zeroed. */
502 for (size_t i = 0; i != sizeof(*this); ++i)
503 JS_ASSERT(reinterpret_cast<uint8*>(this)[i] == 0);
505 if (!stackSpace.init())
507 dtoaState = js_NewDtoaState();
512 nativeStackBase = GetNativeStackBase();
515 /* Set the default size for the code cache to 16MB. */
516 maxCodeCacheBytes = 16 * 1024 * 1024;
523 JSThreadData::finish()
526 js_DestroyDtoaState(dtoaState);
528 js_FinishGSNCache(&gsnCache);
529 propertyCache.~PropertyCache();
534 JSThreadData::mark(JSTracer *trc)
536 stackSpace.mark(trc);
540 JSThreadData::purge(JSContext *cx)
542 js_PurgeGSNCache(&gsnCache);
544 /* FIXME: bug 506341. */
545 propertyCache.purge(cx);
553 JS_ASSERT(js_CurrentThreadId() == id);
554 JSThread *thread = (JSThread *) js_calloc(sizeof(JSThread));
557 JS_INIT_CLIST(&thread->contextList);
559 if (!thread->data.init()) {
567 DestroyThread(JSThread *thread)
569 /* The thread must have zero contexts. */
570 JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
573 * The conservative GC scanner should be disabled when the thread leaves
576 JS_ASSERT(!thread->data.conservativeGC.hasStackToScan());
578 thread->data.finish();
583 js_CurrentThread(JSRuntime *rt)
585 void *id = js_CurrentThreadId();
589 * We must not race with a GC that accesses cx->thread for JSContext
590 * instances on all threads, see bug 476934.
595 JSThread::Map::AddPtr p = rt->threads.lookupForAdd(id);
600 * If thread has no contexts, it might be left over from a previous
601 * thread with the same id but a different stack address.
603 if (JS_CLIST_IS_EMPTY(&thread->contextList))
604 thread->data.nativeStackBase = GetNativeStackBase();
607 thread = NewThread(id);
612 if (!rt->threads.relookupOrAdd(p, id, thread)) {
614 DestroyThread(thread);
618 /* Another thread cannot add an entry for the current thread id. */
619 JS_ASSERT(p->value == thread);
621 JS_ASSERT(thread->id == id);
624 char* gnsb = (char*) GetNativeStackBase();
625 JS_ASSERT(gnsb + 0 == (char*) thread->data.nativeStackBase ||
626 /* Work around apparent glibc bug; see bug 608526. */
627 gnsb + 0x1000 == (char*) thread->data.nativeStackBase ||
628 gnsb + 0x2000 == (char*) thread->data.nativeStackBase ||
629 gnsb + 0x3000 == (char*) thread->data.nativeStackBase);
636 js_InitContextThread(JSContext *cx)
638 JSThread *thread = js_CurrentThread(cx->runtime);
642 JS_APPEND_LINK(&cx->threadLinks, &thread->contextList);
648 js_ClearContextThread(JSContext *cx)
650 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
651 JS_REMOVE_AND_INIT_LINK(&cx->threadLinks);
655 #endif /* JS_THREADSAFE */
658 js_CurrentThreadData(JSRuntime *rt)
661 JSThread *thread = js_CurrentThread(rt);
665 return &thread->data;
667 return &rt->threadData;
672 js_InitThreads(JSRuntime *rt)
675 if (!rt->threads.init(4))
678 if (!rt->threadData.init())
685 js_FinishThreads(JSRuntime *rt)
688 if (!rt->threads.initialized())
690 for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
691 JSThread *thread = r.front().value;
692 JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
693 DestroyThread(thread);
697 rt->threadData.finish();
702 js_PurgeThreads(JSContext *cx)
705 for (JSThread::Map::Enum e(cx->runtime->threads);
708 JSThread *thread = e.front().value;
710 if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
711 JS_ASSERT(cx->thread != thread);
713 DestroyThread(thread);
716 thread->data.purge(cx);
720 cx->runtime->threadData.purge(cx);
725 js_NewContext(JSRuntime *rt, size_t stackChunkSize)
729 JSContextCallback cxCallback;
732 * We need to initialize the new context fully before adding it to the
733 * runtime list. After that it can be accessed from another thread via
734 * js_ContextIterator.
736 void *mem = js_calloc(sizeof *cx);
740 cx = new (mem) JSContext(rt);
741 cx->debugHooks = &rt->globalDebugHooks;
742 #if JS_STACK_GROWTH_DIRECTION > 0
743 cx->stackLimit = (jsuword) -1;
745 cx->scriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA;
746 JS_STATIC_ASSERT(JSVERSION_DEFAULT == 0);
747 JS_ASSERT(cx->findVersion() == JSVERSION_DEFAULT);
748 VOUCH_DOES_NOT_REQUIRE_STACK();
750 JS_InitArenaPool(&cx->tempPool, "temp", TEMP_POOL_CHUNK_SIZE, sizeof(jsdouble),
751 &cx->scriptStackQuota);
752 JS_InitArenaPool(&cx->regExpPool, "regExp", TEMP_POOL_CHUNK_SIZE, sizeof(int),
753 &cx->scriptStackQuota);
755 JS_ASSERT(cx->resolveFlags == 0);
757 if (!cx->busyArrays.init()) {
763 if (!js_InitContextThread(cx)) {
770 * Here the GC lock is still held after js_InitContextThread took it and
771 * the GC is not running on another thread.
774 if (rt->state == JSRTS_UP) {
775 JS_ASSERT(!JS_CLIST_IS_EMPTY(&rt->contextList));
779 if (rt->state == JSRTS_DOWN) {
780 JS_ASSERT(JS_CLIST_IS_EMPTY(&rt->contextList));
782 rt->state = JSRTS_LAUNCHING;
785 JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT);
788 * During the above wait after we are notified about the state change
789 * but before we wake up, another thread could enter the GC from
790 * js_DestroyContext, bug 478336. So we must wait here to ensure that
791 * when we exit the loop with the first flag set to true, that GC is
796 JS_APPEND_LINK(&cx->link, &rt->contextList);
802 * If cx is the first context on this runtime, initialize well-known atoms,
803 * keywords, numbers, and strings. If one of these steps should fail, the
804 * runtime will be left in a partially initialized state, with zeroes and
805 * nulls stored in the default-initialized remainder of the struct. We'll
806 * clean the runtime up under js_DestroyContext, because cx will be "last"
807 * as well as "first".
813 ok = js_InitCommonAtoms(cx);
816 * scriptFilenameTable may be left over from a previous episode of
817 * non-zero contexts alive in rt, so don't re-init the table if it's
820 if (ok && !rt->scriptFilenameTable)
821 ok = js_InitRuntimeScriptState(rt);
823 ok = js_InitRuntimeNumberState(cx);
829 js_DestroyContext(cx, JSDCM_NEW_FAILED);
834 rt->state = JSRTS_UP;
835 JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
838 cxCallback = rt->cxCallback;
839 if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) {
840 js_DestroyContext(cx, JSDCM_NEW_FAILED);
847 #if defined DEBUG && defined XP_UNIX
852 JSAutoFile() : mFile(NULL) {}
859 FILE *open(const char *fname, const char *mode) {
860 return mFile = fopen(fname, mode);
871 DumpEvalCacheMeter(JSContext *cx)
873 if (const char *filename = getenv("JS_EVALCACHE_STATFILE")) {
878 #define frob(x) { #x, offsetof(JSEvalCacheMeter, x) }
879 EVAL_CACHE_METER_LIST(frob)
882 JSEvalCacheMeter *ecm = &cx->compartment->evalCacheMeter;
884 static JSAutoFile fp;
885 if (!fp && !fp.open(filename, "w"))
888 fprintf(fp, "eval cache meter (%p):\n",
895 for (uintN i = 0; i < JS_ARRAY_LENGTH(table); ++i) {
896 fprintf(fp, "%-8.8s %llu\n",
898 (unsigned long long int) *(uint64 *)((uint8 *)ecm + table[i].offset));
900 fprintf(fp, "hit ratio %g%%\n", ecm->hit * 100. / ecm->probe);
901 fprintf(fp, "avg steps %g\n", double(ecm->step) / ecm->probe);
905 # define DUMP_EVAL_CACHE_METER(cx) DumpEvalCacheMeter(cx)
908 DumpFunctionCountMap(const char *title, JSRuntime::FunctionCountMap &map, FILE *fp)
910 fprintf(fp, "\n%s count map:\n", title);
912 for (JSRuntime::FunctionCountMap::Range r = map.all(); !r.empty(); r.popFront()) {
913 JSFunction *fun = r.front().key;
914 int32 count = r.front().value;
916 fprintf(fp, "%10d %s:%u\n", count, fun->u.i.script->filename, fun->u.i.script->lineno);
921 DumpFunctionMeter(JSContext *cx)
923 if (const char *filename = cx->runtime->functionMeterFilename) {
928 #define frob(x) { #x, offsetof(JSFunctionMeter, x) }
929 FUNCTION_KIND_METER_LIST(frob)
932 JSFunctionMeter *fm = &cx->runtime->functionMeter;
934 static JSAutoFile fp;
935 if (!fp && !fp.open(filename, "w"))
938 fprintf(fp, "function meter (%s):\n", cx->runtime->lastScriptFilename);
939 for (uintN i = 0; i < JS_ARRAY_LENGTH(table); ++i)
940 fprintf(fp, "%-19.19s %d\n", table[i].name, *(int32 *)((uint8 *)fm + table[i].offset));
942 DumpFunctionCountMap("method read barrier", cx->runtime->methodReadBarrierCountMap, fp);
943 DumpFunctionCountMap("unjoined function", cx->runtime->unjoinedFunctionCountMap, fp);
950 # define DUMP_FUNCTION_METER(cx) DumpFunctionMeter(cx)
952 #endif /* DEBUG && XP_UNIX */
954 #ifndef DUMP_EVAL_CACHE_METER
955 # define DUMP_EVAL_CACHE_METER(cx) ((void) 0)
958 #ifndef DUMP_FUNCTION_METER
959 # define DUMP_FUNCTION_METER(cx) ((void) 0)
963 js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
966 JSContextCallback cxCallback;
969 JS_ASSERT(!cx->enumerators);
974 * For API compatibility we allow to destroy contexts without a thread in
975 * optimized builds. We assume that the embedding knows that an OOM error
976 * cannot happen in JS_SetContextThread.
978 JS_ASSERT(cx->thread && CURRENT_THREAD_IS_ME(cx->thread));
980 JS_SetContextThread(cx);
983 * For API compatibility we support destroying contexts with non-zero
984 * cx->outstandingRequests but we assume that all JS_BeginRequest calls
985 * on this cx contributes to cx->thread->data.requestDepth and there is no
986 * JS_SuspendRequest calls that set aside the counter.
988 JS_ASSERT(cx->outstandingRequests <= cx->thread->data.requestDepth);
991 if (mode != JSDCM_NEW_FAILED) {
992 cxCallback = rt->cxCallback;
995 * JSCONTEXT_DESTROY callback is not allowed to fail and must
999 JSBool callbackStatus =
1001 cxCallback(cx, JSCONTEXT_DESTROY);
1002 JS_ASSERT(callbackStatus);
1007 JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING);
1008 #ifdef JS_THREADSAFE
1010 * Typically we are called outside a request, so ensure that the GC is not
1011 * running before removing the context from rt->contextList, see bug 477021.
1013 if (cx->thread->data.requestDepth == 0)
1016 JS_REMOVE_LINK(&cx->link);
1017 last = (rt->contextList.next == &rt->contextList);
1019 rt->state = JSRTS_LANDING;
1020 if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC
1021 #ifdef JS_THREADSAFE
1022 || cx->outstandingRequests != 0
1025 JS_ASSERT(!rt->gcRunning);
1030 #ifdef JS_THREADSAFE
1032 * If this thread is not in a request already, begin one now so
1033 * that we wait for any racing GC started on a not-last context to
1034 * finish, before we plow ahead and unpin atoms. Note that even
1035 * though we begin a request here if necessary, we end all
1036 * thread's requests before forcing a final GC. This lets any
1037 * not-last context destruction racing in another thread try to
1038 * force or maybe run the GC, but by that point, rt->state will
1039 * not be JSRTS_UP, and that GC attempt will return early.
1041 if (cx->thread->data.requestDepth == 0)
1042 JS_BeginRequest(cx);
1045 js_FinishRuntimeNumberState(cx);
1047 /* Unpin all common atoms before final GC. */
1048 js_FinishCommonAtoms(cx);
1050 /* Clear debugging state to remove GC roots. */
1051 JS_ClearAllTraps(cx);
1052 JS_ClearAllWatchPoints(cx);
1055 #ifdef JS_THREADSAFE
1057 * Destroying a context implicitly calls JS_EndRequest(). Also, we must
1058 * end our request here in case we are "last" -- in that event, another
1059 * js_DestroyContext that was not last might be waiting in the GC for our
1060 * request to end. We'll let it run below, just before we do the truly
1061 * final GC and then free atom state.
1063 while (cx->outstandingRequests != 0)
1068 js_GC(cx, NULL, GC_LAST_CONTEXT);
1069 DUMP_EVAL_CACHE_METER(cx);
1070 DUMP_FUNCTION_METER(cx);
1072 /* Take the runtime down, now that it has no contexts or atoms. */
1074 rt->state = JSRTS_DOWN;
1075 JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
1077 if (mode == JSDCM_FORCE_GC)
1078 js_GC(cx, NULL, GC_NORMAL);
1079 else if (mode == JSDCM_MAYBE_GC)
1085 #ifdef JS_THREADSAFE
1087 JSThread *t = cx->thread;
1089 js_ClearContextThread(cx);
1090 JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
1092 #ifdef JS_METER_DST_OFFSET_CACHING
1093 cx->dstOffsetCache.dumpStats();
1100 FreeContext(JSContext *cx)
1102 #ifdef JS_THREADSAFE
1103 JS_ASSERT(!cx->thread);
1106 /* Free the stuff hanging off of cx. */
1107 VOUCH_DOES_NOT_REQUIRE_STACK();
1108 JS_FinishArenaPool(&cx->tempPool);
1109 JS_FinishArenaPool(&cx->regExpPool);
1111 if (cx->lastMessage)
1112 js_free(cx->lastMessage);
1114 /* Remove any argument formatters. */
1115 JSArgumentFormatMap *map = cx->argumentFormatMap;
1117 JSArgumentFormatMap *temp = map;
1122 /* Destroy the resolve recursion damper. */
1123 if (cx->resolvingTable) {
1124 JS_DHashTableDestroy(cx->resolvingTable);
1125 cx->resolvingTable = NULL;
1128 /* Finally, free cx itself. */
1134 js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
1136 JSContext *cx = *iterp;
1138 Conditionally<AutoLockGC> lockIf(!!unlocked, rt);
1139 cx = js_ContextFromLinkField(cx ? cx->link.next : rt->contextList.next);
1140 if (&cx->link == &rt->contextList)
1146 JS_FRIEND_API(JSContext *)
1147 js_NextActiveContext(JSRuntime *rt, JSContext *cx)
1149 JSContext *iter = cx;
1150 #ifdef JS_THREADSAFE
1151 while ((cx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
1152 if (cx->outstandingRequests && cx->thread->data.requestDepth)
1157 return js_ContextIterator(rt, JS_FALSE, &iter);
1161 static JSDHashNumber
1162 resolving_HashKey(JSDHashTable *table, const void *ptr)
1164 const JSResolvingKey *key = (const JSResolvingKey *)ptr;
1166 return (JSDHashNumber(uintptr_t(key->obj)) >> JS_GCTHING_ALIGN) ^ JSID_BITS(key->id);
1170 resolving_MatchEntry(JSDHashTable *table,
1171 const JSDHashEntryHdr *hdr,
1174 const JSResolvingEntry *entry = (const JSResolvingEntry *)hdr;
1175 const JSResolvingKey *key = (const JSResolvingKey *)ptr;
1177 return entry->key.obj == key->obj && entry->key.id == key->id;
1180 static const JSDHashTableOps resolving_dhash_ops = {
1184 resolving_MatchEntry,
1185 JS_DHashMoveEntryStub,
1186 JS_DHashClearEntryStub,
1187 JS_DHashFinalizeStub,
1192 js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
1193 JSResolvingEntry **entryp)
1195 JSDHashTable *table;
1196 JSResolvingEntry *entry;
1198 table = cx->resolvingTable;
1200 table = JS_NewDHashTable(&resolving_dhash_ops, NULL,
1201 sizeof(JSResolvingEntry),
1205 cx->resolvingTable = table;
1208 entry = (JSResolvingEntry *)
1209 JS_DHashTableOperate(table, key, JS_DHASH_ADD);
1213 if (entry->flags & flag) {
1214 /* An entry for (key, flag) exists already -- dampen recursion. */
1217 /* Fill in key if we were the first to add entry, then set flag. */
1218 if (!entry->key.obj)
1220 entry->flags |= flag;
1226 JS_ReportOutOfMemory(cx);
1231 js_StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
1232 JSResolvingEntry *entry, uint32 generation)
1234 JSDHashTable *table;
1237 * Clear flag from entry->flags and return early if other flags remain.
1238 * We must take care to re-lookup entry if the table has changed since
1239 * it was found by js_StartResolving.
1241 table = cx->resolvingTable;
1242 if (!entry || table->generation != generation) {
1243 entry = (JSResolvingEntry *)
1244 JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP);
1246 JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&entry->hdr));
1247 entry->flags &= ~flag;
1252 * Do a raw remove only if fewer entries were removed than would cause
1253 * alpha to be less than .5 (alpha is at most .75). Otherwise, we just
1254 * call JS_DHashTableOperate to re-lookup the key and remove its entry,
1255 * compressing or shrinking the table as needed.
1257 if (table->removedCount < JS_DHASH_TABLE_SIZE(table) >> 2)
1258 JS_DHashTableRawRemove(table, &entry->hdr);
1260 JS_DHashTableOperate(table, key, JS_DHASH_REMOVE);
1264 ReportError(JSContext *cx, const char *message, JSErrorReport *reportp,
1265 JSErrorCallback callback, void *userRef)
1268 * Check the error report, and set a JavaScript-catchable exception
1269 * if the error is defined to have an associated exception. If an
1270 * exception is thrown, then the JSREPORT_EXCEPTION flag will be set
1271 * on the error report, and exception-aware hosts should ignore it.
1274 if ((!callback || callback == js_GetErrorMessage) &&
1275 reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
1276 reportp->flags |= JSREPORT_EXCEPTION;
1279 * Call the error reporter only if an exception wasn't raised.
1281 * If an exception was raised, then we call the debugErrorHook
1282 * (if present) to give it a chance to see the error before it
1283 * propagates out of scope. This is needed for compatability
1284 * with the old scheme.
1286 if (!JS_IsRunning(cx) ||
1287 !js_ErrorToException(cx, message, reportp, callback, userRef)) {
1288 js_ReportErrorAgain(cx, message, reportp);
1289 } else if (cx->debugHooks->debugErrorHook && cx->errorReporter) {
1290 JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
1291 /* test local in case debugErrorHook changed on another thread */
1293 hook(cx, message, reportp, cx->debugHooks->debugErrorHookData);
1297 /* The report must be initially zeroed. */
1299 PopulateReportBlame(JSContext *cx, JSErrorReport *report)
1302 * Walk stack until we find a frame that is associated with some script
1303 * rather than a native frame.
1305 for (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) {
1307 report->filename = fp->script()->filename;
1308 report->lineno = js_FramePCToLineNumber(cx, fp);
1315 * We don't post an exception in this case, since doing so runs into
1316 * complications of pre-allocating an exception object which required
1317 * running the Exception class initializer early etc.
1318 * Instead we just invoke the errorReporter with an "Out Of Memory"
1319 * type message, and then hope the process ends swiftly.
1322 js_ReportOutOfMemory(JSContext *cx)
1326 * If we are in a builtin called directly from trace, don't report an
1327 * error. We will retry in the interpreter instead.
1329 if (JS_ON_TRACE(cx) && !JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit)
1333 JSErrorReport report;
1334 JSErrorReporter onError = cx->errorReporter;
1336 /* Get the message for this error, but we won't expand any arguments. */
1337 const JSErrorFormatString *efs =
1338 js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY);
1339 const char *msg = efs ? efs->format : "Out of memory";
1341 /* Fill out the report, but don't do anything that requires allocation. */
1343 report.flags = JSREPORT_ERROR;
1344 report.errorNumber = JSMSG_OUT_OF_MEMORY;
1345 PopulateReportBlame(cx, &report);
1348 * If debugErrorHook is present then we give it a chance to veto sending
1349 * the error on to the regular ErrorReporter. We also clear a pending
1350 * exception if any now so the hooks can replace the out-of-memory error
1351 * by a script-catchable exception.
1353 cx->clearPendingException();
1355 JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
1357 !hook(cx, msg, &report, cx->debugHooks->debugErrorHookData)) {
1363 onError(cx, msg, &report);
1367 js_ReportOutOfScriptQuota(JSContext *cx)
1369 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1370 JSMSG_SCRIPT_STACK_QUOTA);
1374 js_ReportOverRecursed(JSContext *cx)
1376 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
1380 js_ReportAllocationOverflow(JSContext *cx)
1382 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ALLOC_OVERFLOW);
1386 * Given flags and the state of cx, decide whether we should report an
1387 * error, a warning, or just continue execution normally. Return
1388 * true if we should continue normally, without reporting anything;
1389 * otherwise, adjust *flags as appropriate and return false.
1392 checkReportFlags(JSContext *cx, uintN *flags)
1394 if (JSREPORT_IS_STRICT_MODE_ERROR(*flags)) {
1396 * Error in strict code; warning with strict option; okay otherwise.
1397 * We assume that if the top frame is a native, then it is strict if
1398 * the nearest scripted frame is strict, see bug 536306.
1400 JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
1401 if (fp && fp->script()->strictModeCode)
1402 *flags &= ~JSREPORT_WARNING;
1403 else if (cx->hasStrictOption())
1404 *flags |= JSREPORT_WARNING;
1407 } else if (JSREPORT_IS_STRICT(*flags)) {
1408 /* Warning/error only when JSOPTION_STRICT is set. */
1409 if (!cx->hasStrictOption())
1413 /* Warnings become errors when JSOPTION_WERROR is set. */
1414 if (JSREPORT_IS_WARNING(*flags) && cx->hasWErrorOption())
1415 *flags &= ~JSREPORT_WARNING;
1421 js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap)
1426 JSErrorReport report;
1429 if (checkReportFlags(cx, &flags))
1432 message = JS_vsmprintf(format, ap);
1435 messagelen = strlen(message);
1438 report.flags = flags;
1439 report.errorNumber = JSMSG_USER_DEFINED_ERROR;
1440 report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen);
1441 PopulateReportBlame(cx, &report);
1443 warning = JSREPORT_IS_WARNING(report.flags);
1445 ReportError(cx, message, &report, NULL, NULL);
1447 cx->free(ucmessage);
1452 * The arguments from ap need to be packaged up into an array and stored
1453 * into the report struct.
1455 * The format string addressed by the error number may contain operands
1456 * identified by the format {N}, where N is a decimal digit. Each of these
1457 * is to be replaced by the Nth argument from the va_list. The complete
1458 * message is placed into reportp->ucmessage converted to a JSString.
1460 * Returns true if the expansion succeeds (can fail if out of memory).
1463 js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
1464 void *userRef, const uintN errorNumber,
1465 char **messagep, JSErrorReport *reportp,
1466 bool charArgs, va_list ap)
1468 const JSErrorFormatString *efs;
1474 /* Most calls supply js_GetErrorMessage; if this is so, assume NULL. */
1475 if (!callback || callback == js_GetErrorMessage)
1476 efs = js_GetLocalizedErrorMessage(cx, userRef, NULL, errorNumber);
1478 efs = callback(userRef, NULL, errorNumber);
1480 size_t totalArgsLength = 0;
1481 size_t argLengths[10]; /* only {0} thru {9} supported */
1482 argCount = efs->argCount;
1483 JS_ASSERT(argCount <= 10);
1486 * Gather the arguments into an array, and accumulate
1487 * their sizes. We allocate 1 more than necessary and
1488 * null it out to act as the caboose when we free the
1491 reportp->messageArgs = (const jschar **)
1492 cx->malloc(sizeof(jschar *) * (argCount + 1));
1493 if (!reportp->messageArgs)
1495 reportp->messageArgs[argCount] = NULL;
1496 for (i = 0; i < argCount; i++) {
1498 char *charArg = va_arg(ap, char *);
1499 size_t charArgLength = strlen(charArg);
1500 reportp->messageArgs[i]
1501 = js_InflateString(cx, charArg, &charArgLength);
1502 if (!reportp->messageArgs[i])
1505 reportp->messageArgs[i] = va_arg(ap, jschar *);
1507 argLengths[i] = js_strlen(reportp->messageArgs[i]);
1508 totalArgsLength += argLengths[i];
1510 /* NULL-terminate for easy copying. */
1511 reportp->messageArgs[i] = NULL;
1514 * Parse the error format, substituting the argument X
1515 * for {X} in the format.
1519 jschar *buffer, *fmt, *out;
1520 int expandedArgs = 0;
1521 size_t expandedLength;
1522 size_t len = strlen(efs->format);
1524 buffer = fmt = js_InflateString (cx, efs->format, &len);
1527 expandedLength = len
1528 - (3 * argCount) /* exclude the {n} */
1532 * Note - the above calculation assumes that each argument
1533 * is used once and only once in the expansion !!!
1535 reportp->ucmessage = out = (jschar *)
1536 cx->malloc((expandedLength + 1) * sizeof(jschar));
1543 if (isdigit(fmt[1])) {
1544 int d = JS7_UNDEC(fmt[1]);
1545 JS_ASSERT(d < argCount);
1546 js_strncpy(out, reportp->messageArgs[d],
1548 out += argLengths[d];
1556 JS_ASSERT(expandedArgs == argCount);
1560 js_DeflateString(cx, reportp->ucmessage,
1561 (size_t)(out - reportp->ucmessage));
1567 * Zero arguments: the format string (if it exists) is the
1572 *messagep = JS_strdup(cx, efs->format);
1575 len = strlen(*messagep);
1576 reportp->ucmessage = js_InflateString(cx, *messagep, &len);
1577 if (!reportp->ucmessage)
1582 if (*messagep == NULL) {
1583 /* where's the right place for this ??? */
1584 const char *defaultErrorMessage
1585 = "No error message available for error number %d";
1586 size_t nbytes = strlen(defaultErrorMessage) + 16;
1587 *messagep = (char *)cx->malloc(nbytes);
1590 JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
1595 if (reportp->messageArgs) {
1596 /* free the arguments only if we allocated them */
1599 while (reportp->messageArgs[i])
1600 cx->free((void *)reportp->messageArgs[i++]);
1602 cx->free((void *)reportp->messageArgs);
1603 reportp->messageArgs = NULL;
1605 if (reportp->ucmessage) {
1606 cx->free((void *)reportp->ucmessage);
1607 reportp->ucmessage = NULL;
1610 cx->free((void *)*messagep);
1617 js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
1618 void *userRef, const uintN errorNumber,
1619 JSBool charArgs, va_list ap)
1621 JSErrorReport report;
1625 if (checkReportFlags(cx, &flags))
1627 warning = JSREPORT_IS_WARNING(flags);
1630 report.flags = flags;
1631 report.errorNumber = errorNumber;
1632 PopulateReportBlame(cx, &report);
1634 if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
1635 &message, &report, !!charArgs, ap)) {
1639 ReportError(cx, message, &report, callback, userRef);
1643 if (report.messageArgs) {
1645 * js_ExpandErrorArguments owns its messageArgs only if it had to
1646 * inflate the arguments (from regular |char *|s).
1650 while (report.messageArgs[i])
1651 cx->free((void *)report.messageArgs[i++]);
1653 cx->free((void *)report.messageArgs);
1655 if (report.ucmessage)
1656 cx->free((void *)report.ucmessage);
1662 js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp)
1664 JSErrorReporter onError;
1669 if (cx->lastMessage)
1670 js_free(cx->lastMessage);
1671 cx->lastMessage = JS_strdup(cx, message);
1672 if (!cx->lastMessage)
1674 onError = cx->errorReporter;
1677 * If debugErrorHook is present then we give it a chance to veto
1678 * sending the error on to the regular ErrorReporter.
1681 JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
1683 !hook(cx, cx->lastMessage, reportp,
1684 cx->debugHooks->debugErrorHookData)) {
1689 onError(cx, cx->lastMessage, reportp);
1693 js_ReportIsNotDefined(JSContext *cx, const char *name)
1695 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name);
1699 js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, const Value &v,
1705 bytes = DecompileValueGenerator(cx, spindex, v, fallback);
1709 if (strcmp(bytes, js_undefined_str) == 0 ||
1710 strcmp(bytes, js_null_str) == 0) {
1711 ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
1712 js_GetErrorMessage, NULL,
1713 JSMSG_NO_PROPERTIES, bytes,
1715 } else if (v.isUndefined()) {
1716 ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
1717 js_GetErrorMessage, NULL,
1718 JSMSG_UNEXPECTED_TYPE, bytes,
1719 js_undefined_str, NULL);
1721 JS_ASSERT(v.isNull());
1722 ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
1723 js_GetErrorMessage, NULL,
1724 JSMSG_UNEXPECTED_TYPE, bytes,
1733 js_ReportMissingArg(JSContext *cx, const Value &v, uintN arg)
1739 JS_snprintf(argbuf, sizeof argbuf, "%u", arg);
1741 if (IsFunctionObject(v)) {
1742 atom = GET_FUNCTION_PRIVATE(cx, &v.toObject())->atom;
1743 bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
1744 v, ATOM_TO_STRING(atom));
1748 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1749 JSMSG_MISSING_FUN_ARG, argbuf,
1750 bytes ? bytes : "");
1755 js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber,
1756 intN spindex, const Value &v, JSString *fallback,
1757 const char *arg1, const char *arg2)
1762 JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
1763 JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
1764 bytes = DecompileValueGenerator(cx, spindex, v, fallback);
1768 ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage,
1769 NULL, errorNumber, bytes, arg1, arg2);
1774 #if defined DEBUG && defined XP_UNIX
1775 /* For gdb usage. */
1776 void js_logon(JSContext *cx) { cx->logfp = stderr; cx->logPrevPc = NULL; }
1777 void js_logoff(JSContext *cx) { cx->logfp = NULL; }
1780 JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
1781 #define MSG_DEF(name, number, count, exception, format) \
1782 { format, count, exception } ,
1787 JS_FRIEND_API(const JSErrorFormatString *)
1788 js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber)
1790 if ((errorNumber > 0) && (errorNumber < JSErr_Limit))
1791 return &js_ErrorFormatString[errorNumber];
1796 js_InvokeOperationCallback(JSContext *cx)
1798 JSRuntime *rt = cx->runtime;
1799 JSThreadData *td = JS_THREAD_DATA(cx);
1801 JS_ASSERT_REQUEST_DEPTH(cx);
1802 JS_ASSERT(td->interruptFlags != 0);
1805 * Reset the callback counter first, then run GC and yield. If another
1806 * thread is racing us here we will accumulate another callback request
1807 * which will be serviced at the next opportunity.
1810 td->interruptFlags = 0;
1811 #ifdef JS_THREADSAFE
1812 JS_ATOMIC_DECREMENT(&rt->interruptCounter);
1816 if (rt->gcIsNeeded) {
1817 js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL);
1820 * On trace we can exceed the GC quota, see comments in NewGCArena. So
1821 * we check the quota and report OOM here when we are off trace.
1823 bool delayedOutOfMemory;
1825 delayedOutOfMemory = (rt->gcBytes > rt->gcMaxBytes);
1827 if (delayedOutOfMemory) {
1828 js_ReportOutOfMemory(cx);
1833 #ifdef JS_THREADSAFE
1835 * We automatically yield the current context every time the operation
1836 * callback is hit since we might be called as a result of an impending
1837 * GC on another thread, which would deadlock if we do not yield.
1838 * Operation callbacks are supposed to happen rarely (seconds, not
1839 * milliseconds) so it is acceptable to yield at every callback.
1841 * As the GC can be canceled before it does any request checks we yield
1842 * even if rt->gcIsNeeded was true above. See bug 590533.
1844 JS_YieldRequest(cx);
1847 JSOperationCallback cb = cx->operationCallback;
1850 * Important: Additional callbacks can occur inside the callback handler
1851 * if it re-enters the JS engine. The embedding must ensure that the
1852 * callback is disconnected before attempting such re-entry.
1855 return !cb || cb(cx);
1859 js_HandleExecutionInterrupt(JSContext *cx)
1861 JSBool result = JS_TRUE;
1862 if (JS_THREAD_DATA(cx)->interruptFlags)
1863 result = js_InvokeOperationCallback(cx) && result;
1870 TriggerOperationCallback(JSContext *cx)
1873 * We allow for cx to come from another thread. Thus we must deal with
1874 * possible JS_ClearContextThread calls when accessing cx->thread. But we
1875 * assume that the calling thread is in a request so JSThread cannot be
1879 #ifdef JS_THREADSAFE
1880 JSThread *thread = cx->thread;
1885 td = JS_THREAD_DATA(cx);
1887 td->triggerOperationCallback(cx->runtime);
1891 TriggerAllOperationCallbacks(JSRuntime *rt)
1893 for (ThreadDataIter i(rt); !i.empty(); i.popFront())
1894 i.threadData()->triggerOperationCallback(rt);
1897 } /* namespace js */
1900 js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
1903 fp = js_GetTopStackFrame(cx);
1904 while (fp && fp->isDummyFrame())
1906 JS_ASSERT_IF(fp, fp->isScriptFrame());
1911 js_GetCurrentBytecodePC(JSContext* cx)
1913 jsbytecode *pc, *imacpc;
1916 if (JS_ON_TRACE(cx)) {
1917 pc = JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit->pc;
1918 imacpc = JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit->imacpc;
1922 JS_ASSERT_NOT_ON_TRACE(cx); /* for static analysis */
1923 pc = cx->regs ? cx->regs->pc : NULL;
1926 imacpc = cx->fp()->maybeImacropc();
1930 * If we are inside GetProperty_tn or similar, return a pointer to the
1931 * current instruction in the script, not the CALL instruction in the
1932 * imacro, for the benefit of callers doing bytecode inspection.
1934 return (*pc == JSOP_CALL && imacpc) ? imacpc : pc;
1938 js_CurrentPCIsInImacro(JSContext *cx)
1941 VOUCH_DOES_NOT_REQUIRE_STACK();
1942 if (JS_ON_TRACE(cx))
1943 return JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit->imacpc != NULL;
1944 return cx->fp()->hasImacropc();
1951 DSTOffsetCache::purge()
1954 * NB: The initial range values are carefully chosen to result in a cache
1955 * miss on first use given the range of possible values. Be careful
1956 * to keep these values and the caching algorithm in sync!
1958 offsetMilliseconds = 0;
1959 rangeStartSeconds = rangeEndSeconds = INT64_MIN;
1960 oldOffsetMilliseconds = 0;
1961 oldRangeStartSeconds = oldRangeEndSeconds = INT64_MIN;
1963 #ifdef JS_METER_DST_OFFSET_CACHING
1964 totalCalculations = 0;
1966 missIncreasing = missDecreasing = 0;
1967 missIncreasingOffsetChangeExpand = missIncreasingOffsetChangeUpper = 0;
1968 missDecreasingOffsetChangeExpand = missDecreasingOffsetChangeLower = 0;
1969 missLargeIncrease = missLargeDecrease = 0;
1976 * Since getDSTOffsetMilliseconds guarantees that all times seen will be
1977 * positive, we can initialize the range at construction time with large
1978 * negative numbers to ensure the first computation is always a cache miss and
1979 * doesn't return a bogus offset.
1981 DSTOffsetCache::DSTOffsetCache()
1986 JSContext::JSContext(JSRuntime *rt)
1987 : hasVersionOverride(false),
1995 JSContext::resetCompartment()
1999 scopeobj = &fp()->scopeChain();
2001 scopeobj = globalObject;
2006 * Innerize. Assert, but check anyway, that this succeeds. (It
2007 * can only fail due to bugs in the engine or embedding.)
2009 OBJ_TO_INNER_OBJECT(this, scopeobj);
2014 compartment = scopeobj->compartment();
2016 if (isExceptionPending())
2017 wrapPendingException();
2023 * If we try to use the context without a selected compartment,
2030 * Since this function is only called in the context of a pending exception,
2031 * the caller must subsequently take an error path. If wrapping fails, it will
2032 * set a new (uncatchable) exception to be used in place of the original.
2035 JSContext::wrapPendingException()
2037 Value v = getPendingException();
2038 clearPendingException();
2039 if (compartment->wrap(this, &v))
2040 setPendingException(v);
2044 JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs)
2046 JS_ASSERT(regs != &newregs);
2047 if (hasActiveSegment())
2048 currentSegment->suspend(regs);
2049 newseg->setPreviousInContext(currentSegment);
2050 currentSegment = newseg;
2051 setCurrentRegs(&newregs);
2052 newseg->joinContext(this, newregs.fp);
2056 JSContext::popSegmentAndFrame()
2059 * NB: This function calls resetCompartment, which may GC, so the stack needs
2060 * to be in a GC-able state by that point.
2063 JS_ASSERT(currentSegment->maybeContext() == this);
2064 JS_ASSERT(currentSegment->getInitialFrame() == regs->fp);
2065 currentSegment->leaveContext();
2066 currentSegment = currentSegment->getPreviousInContext();
2067 if (currentSegment) {
2068 if (currentSegment->isSaved()) {
2069 setCurrentRegs(NULL);
2072 setCurrentRegs(currentSegment->getSuspendedRegs());
2073 currentSegment->resume();
2076 JS_ASSERT(regs->fp->prev() == NULL);
2077 setCurrentRegs(NULL);
2080 maybeMigrateVersionOverride();
2084 JSContext::saveActiveSegment()
2086 JS_ASSERT(hasActiveSegment());
2087 currentSegment->save(regs);
2088 setCurrentRegs(NULL);
2093 JSContext::restoreSegment()
2095 js::StackSegment *ccs = currentSegment;
2096 setCurrentRegs(ccs->getSuspendedRegs());
2102 JSContext::generatorFor(JSStackFrame *fp) const
2104 JS_ASSERT(stack().contains(fp) && fp->isGeneratorFrame());
2105 JS_ASSERT(!fp->isFloatingGenerator());
2106 JS_ASSERT(!genStack.empty());
2108 if (JS_LIKELY(fp == genStack.back()->liveFrame()))
2109 return genStack.back();
2111 /* General case; should only be needed for debug APIs. */
2112 for (size_t i = 0; i < genStack.length(); ++i) {
2113 if (genStack[i]->liveFrame() == fp)
2116 JS_NOT_REACHED("no matching generator");
2121 JSContext::containingSegment(const JSStackFrame *target)
2123 /* The context may have nothing running. */
2124 StackSegment *seg = currentSegment;
2128 /* The active segments's top frame is cx->regs->fp. */
2130 JS_ASSERT(regs->fp);
2131 JS_ASSERT(activeSegment() == seg);
2132 JSStackFrame *f = regs->fp;
2133 JSStackFrame *stop = seg->getInitialFrame()->prev();
2134 for (; f != stop; f = f->prev()) {
2138 seg = seg->getPreviousInContext();
2141 /* A suspended segment's top frame is its suspended frame. */
2142 for (; seg; seg = seg->getPreviousInContext()) {
2143 JSStackFrame *f = seg->getSuspendedFrame();
2144 JSStackFrame *stop = seg->getInitialFrame()->prev();
2145 for (; f != stop; f = f->prev()) {
2155 JSRuntime::onTooMuchMalloc()
2157 #ifdef JS_THREADSAFE
2158 AutoLockGC lock(this);
2161 * We can be called outside a request and can race against a GC that
2162 * mutates the JSThread set during the sweeping phase.
2169 JS_FRIEND_API(void *)
2170 JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
2172 #ifdef JS_THREADSAFE
2173 gcHelperThread.waitBackgroundSweepEnd(this);
2175 p = ::js_malloc(nbytes);
2176 else if (p == reinterpret_cast<void *>(1))
2177 p = ::js_calloc(nbytes);
2179 p = ::js_realloc(p, nbytes);
2184 js_ReportOutOfMemory(cx);
2189 * Release pool's arenas if the stackPool has existed for longer than the
2190 * limit specified by gcEmptyArenaPoolLifespan.
2193 FreeOldArenas(JSRuntime *rt, JSArenaPool *pool)
2195 JSArena *a = pool->current;
2196 if (a == pool->first.next && a->avail == a->base + sizeof(int64)) {
2197 int64 age = JS_Now() - *(int64 *) a->base;
2198 if (age > int64(rt->gcEmptyArenaPoolLifespan) * 1000)
2199 JS_FreeArenaPool(pool);
2206 FreeOldArenas(runtime, ®ExpPool);
2210 ComputeIsJITBroken()
2215 if (getenv("JS_IGNORE_JIT_BROKENNESS")) {
2221 // Check for the known-bad kernel version (2.6.29).
2222 std::ifstream osrelease("/proc/sys/kernel/osrelease");
2223 std::getline(osrelease, line);
2224 __android_log_print(ANDROID_LOG_INFO, "Gecko", "Detected osrelease `%s'",
2227 if (line.npos == line.find("2.6.29")) {
2228 // We're using something other than 2.6.29, so the JITs should work.
2229 __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are not broken");
2233 // We're using 2.6.29, and this causes trouble with the JITs on i9000.
2235 bool broken = false;
2236 std::ifstream cpuinfo("/proc/cpuinfo");
2238 if (0 == line.find("Hardware")) {
2239 const char* blacklist[] = {
2240 "SGH-T959", // Samsung i9000, Vibrant device
2241 "SGH-I897", // Samsung i9000, Captivate device
2242 "SCH-I500", // Samsung i9000, Fascinate device
2243 "SPH-D700", // Samsung i9000, Epic device
2244 "GT-I9000", // Samsung i9000, UK/Europe device
2247 for (const char** hw = &blacklist[0]; *hw; ++hw) {
2248 if (line.npos != line.find(*hw)) {
2249 __android_log_print(ANDROID_LOG_INFO, "Gecko",
2250 "Blacklisted device `%s'", *hw);
2257 std::getline(cpuinfo, line);
2258 } while(!cpuinfo.fail() && !cpuinfo.eof());
2260 __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are %sbroken",
2261 broken ? "" : "not ");
2264 #endif // ifndef ANDROID
2270 static bool computedIsBroken = false;
2271 static bool isBroken = false;
2272 if (!computedIsBroken) {
2273 isBroken = ComputeIsJITBroken();
2274 computedIsBroken = true;
2280 JSContext::updateJITEnabled()
2283 traceJitEnabled = ((runOptions & JSOPTION_JIT) &&
2284 !IsJITBrokenHere() &&
2285 (debugHooks == &js_NullDebugHooks ||
2286 (debugHooks == &runtime->globalDebugHooks &&
2287 !runtime->debuggerInhibitsJIT())));
2290 methodJitEnabled = (runOptions & JSOPTION_METHODJIT) &&
2292 # if defined JS_CPU_X86 || defined JS_CPU_X64
2293 && JSC::MacroAssemblerX86Common::getSSEState() >=
2294 JSC::MacroAssemblerX86Common::HasSSE2
2298 profilingEnabled = (runOptions & JSOPTION_PROFILING) && traceJitEnabled && methodJitEnabled;
2305 JS_FORCES_STACK JS_FRIEND_API(void)
2306 LeaveTrace(JSContext *cx)
2309 if (JS_ON_TRACE(cx))
2314 } /* namespace js */