Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jscntxt.cpp
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 #include <new>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #ifdef ANDROID
49 # include <android/log.h>
50 # include <fstream>
51 # include <string>
52 #endif  // ANDROID
53
54 #include "jsstdint.h"
55
56 #include "jstypes.h"
57 #include "jsarena.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 "jsiter.h"
69 #include "jslock.h"
70 #include "jsmath.h"
71 #include "jsnativestack.h"
72 #include "jsnum.h"
73 #include "jsobj.h"
74 #include "jsopcode.h"
75 #include "jspubtd.h"
76 #include "jsscan.h"
77 #include "jsscope.h"
78 #include "jsscript.h"
79 #include "jsstaticcheck.h"
80 #include "jsstr.h"
81 #include "jstracer.h"
82
83 #ifdef JS_METHODJIT
84 # include "assembler/assembler/MacroAssembler.h"
85 #endif
86
87 #include "jscntxtinlines.h"
88 #include "jscompartment.h"
89 #include "jsinterpinlines.h"
90 #include "jsobjinlines.h"
91
92 #ifdef XP_WIN
93 # include "jswin.h"
94 #elif defined(XP_OS2)
95 # define INCL_DOSMEMMGR
96 # include <os2.h>
97 #else
98 # include <unistd.h>
99 # include <sys/mman.h>
100 # if !defined(MAP_ANONYMOUS)
101 #  if defined(MAP_ANON)
102 #   define MAP_ANONYMOUS MAP_ANON
103 #  else
104 #   define MAP_ANONYMOUS 0
105 #  endif
106 # endif
107 #endif
108
109 using namespace js;
110 using namespace js::gc;
111
112 static const size_t ARENA_HEADER_SIZE_HACK = 40;
113 static const size_t TEMP_POOL_CHUNK_SIZE = 4096 - ARENA_HEADER_SIZE_HACK;
114
115 static void
116 FreeContext(JSContext *cx);
117
118 #ifdef DEBUG
119 JS_REQUIRES_STACK bool
120 StackSegment::contains(const JSStackFrame *fp) const
121 {
122     JS_ASSERT(inContext());
123     JSStackFrame *start;
124     JSStackFrame *stop;
125     if (isActive()) {
126         JS_ASSERT(cx->hasfp());
127         start = cx->fp();
128         stop = cx->activeSegment()->initialFrame->prev();
129     } else {
130         JS_ASSERT(suspendedRegs && suspendedRegs->fp);
131         start = suspendedRegs->fp;
132         stop = initialFrame->prev();
133     }
134     for (JSStackFrame *f = start; f != stop; f = f->prev()) {
135         if (f == fp)
136             return true;
137     }
138     return false;
139 }
140 #endif
141
142 bool
143 StackSpace::init()
144 {
145     void *p;
146 #ifdef XP_WIN
147     p = VirtualAlloc(NULL, CAPACITY_BYTES, MEM_RESERVE, PAGE_READWRITE);
148     if (!p)
149         return false;
150     void *check = VirtualAlloc(p, COMMIT_BYTES, MEM_COMMIT, PAGE_READWRITE);
151     if (p != check)
152         return false;
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))
159         return false;
160     base = reinterpret_cast<Value *>(p);
161     end = base + CAPACITY_VALS;
162 #else
163     JS_ASSERT(CAPACITY_BYTES % getpagesize() == 0);
164     p = mmap(NULL, CAPACITY_BYTES, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
165     if (p == MAP_FAILED)
166         return false;
167     base = reinterpret_cast<Value *>(p);
168     end = base + CAPACITY_VALS;
169 #endif
170     return true;
171 }
172
173 void
174 StackSpace::finish()
175 {
176 #ifdef XP_WIN
177     VirtualFree(base, (commitEnd - base) * sizeof(Value), MEM_DECOMMIT);
178     VirtualFree(base, 0, MEM_RELEASE);
179 #elif defined(XP_OS2)
180     DosFreeMem(base);
181 #else
182 #ifdef SOLARIS
183     munmap((caddr_t)base, CAPACITY_BYTES);
184 #else
185     munmap(base, CAPACITY_BYTES);
186 #endif
187 #endif
188 }
189
190 #ifdef XP_WIN
191 JS_FRIEND_API(bool)
192 StackSpace::bumpCommit(Value *from, ptrdiff_t nvals) const
193 {
194     JS_ASSERT(end - from >= nvals);
195     Value *newCommit = commitEnd;
196     Value *request = from + nvals;
197
198     /* Use a dumb loop; will probably execute once. */
199     JS_ASSERT((end - newCommit) % COMMIT_VALS == 0);
200     do {
201         newCommit += COMMIT_VALS;
202         JS_ASSERT((end - newCommit) >= 0);
203     } while (newCommit < request);
204
205     /* The cast is safe because CAPACITY_BYTES is small. */
206     int32 size = static_cast<int32>(newCommit - commitEnd) * sizeof(Value);
207
208     if (!VirtualAlloc(commitEnd, size, MEM_COMMIT, PAGE_READWRITE))
209         return false;
210     commitEnd = newCommit;
211     return true;
212 }
213 #endif
214
215 void
216 StackSpace::mark(JSTracer *trc)
217 {
218     /*
219      * The correctness/completeness of marking depends on the continuity
220      * invariants described by the StackSegment and StackSpace definitions.
221      *
222      * NB:
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).
226      */
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");
234
235             /* Mark slots/args trailing off of the last stack frame. */
236             JSStackFrame *fp = seg->getCurrentFrame();
237             MarkStackRangeConservatively(trc, fp->slots(), end);
238
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);
244             }
245
246             /* Mark initial stack frame and leading args. */
247             js_TraceStackFrame(trc, initial);
248             MarkStackRangeConservatively(trc, seg->valueRangeBegin(), (Value *)initial);
249         } else {
250             /* Mark slots/args trailing off segment. */
251             MarkValueRange(trc, seg->valueRangeBegin(), end, "stack");
252         }
253         end = (Value *)seg;
254     }
255 }
256
257 bool
258 StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
259 {
260     Value *start = firstUnused();
261     ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + 2 + argc;
262     if (!ensureSpace(cx, start, nvals))
263         return false;
264
265     StackSegment *seg = new(start) StackSegment;
266     seg->setPreviousInMemory(currentSegment);
267     currentSegment = seg;
268
269     ag->cx = cx;
270     ag->seg = seg;
271     ag->argv_ = seg->valueRangeBegin() + 2;
272     ag->argc_ = argc;
273
274     /* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
275 #ifdef DEBUG
276     ag->prevInvokeSegment = invokeSegment;
277     invokeSegment = seg;
278     ag->prevInvokeFrame = invokeFrame;
279     invokeFrame = NULL;
280 #endif
281     ag->prevInvokeArgEnd = invokeArgEnd;
282     invokeArgEnd = ag->argv() + ag->argc();
283     return true;
284 }
285
286 void
287 StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag)
288 {
289     JS_ASSERT(!currentSegment->inContext());
290     JS_ASSERT(ag.seg == currentSegment);
291     JS_ASSERT(invokeSegment == currentSegment);
292     JS_ASSERT(invokeArgEnd == ag.argv() + ag.argc());
293
294     currentSegment = currentSegment->getPreviousInMemory();
295
296 #ifdef DEBUG
297     invokeSegment = ag.prevInvokeSegment;
298     invokeFrame = ag.prevInvokeFrame;
299 #endif
300     invokeArgEnd = ag.prevInvokeArgEnd;
301 }
302
303 bool
304 StackSpace::getSegmentAndFrame(JSContext *cx, uintN vplen, uintN nslots,
305                                FrameGuard *fg) const
306 {
307     Value *start = firstUnused();
308     uintN nvals = VALUES_PER_STACK_SEGMENT + vplen + VALUES_PER_STACK_FRAME + nslots;
309     if (!ensureSpace(cx, start, nvals))
310         return false;
311
312     fg->seg_ = new(start) StackSegment;
313     fg->vp_ = start + VALUES_PER_STACK_SEGMENT;
314     fg->fp_ = reinterpret_cast<JSStackFrame *>(fg->vp() + vplen);
315     return true;
316 }
317
318 void
319 StackSpace::pushSegmentAndFrame(JSContext *cx, JSFrameRegs *regs, FrameGuard *fg)
320 {
321     /* Caller should have already initialized regs. */
322     JS_ASSERT(regs->fp == fg->fp());
323     StackSegment *seg = fg->segment();
324
325     /* Register new segment/frame with the context. */
326     cx->pushSegmentAndFrame(seg, *regs);
327
328     /* Officially push the segment/frame on the stack. */
329     seg->setPreviousInMemory(currentSegment);
330     currentSegment = seg;
331
332     /* Mark as 'pushed' in the guard. */
333     fg->cx_ = cx;
334 }
335
336 void
337 StackSpace::popSegmentAndFrame(JSContext *cx)
338 {
339     JS_ASSERT(isCurrentAndActive(cx));
340     JS_ASSERT(cx->hasActiveSegment());
341
342     /* Officially pop the segment/frame from the stack. */
343     currentSegment = currentSegment->getPreviousInMemory();
344
345     /* Unregister pushed segment/frame from the context. */
346     cx->popSegmentAndFrame();
347
348     /*
349      * N.B. This StackSpace should be GC-able without any operations after
350      * cx->popSegmentAndFrame executes since it can trigger GC.
351      */
352 }
353
354 FrameGuard::~FrameGuard()
355 {
356     if (!pushed())
357         return;
358     JS_ASSERT(cx_->activeSegment() == segment());
359     JS_ASSERT(cx_->maybefp() == fp());
360     cx_->stack().popSegmentAndFrame(cx_);
361 }
362
363 bool
364 StackSpace::getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const
365 {
366     return getSegmentAndFrame(cx, 2, script->nslots, fg);
367 }
368
369 void
370 StackSpace::pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg)
371 {
372     JSStackFrame *fp = fg->fp();
373     JSScript *script = fp->script();
374     fg->regs_.pc = script->code;
375     fg->regs_.fp = fp;
376     fg->regs_.sp = fp->base();
377     pushSegmentAndFrame(cx, &fg->regs_, fg);
378     fg->seg_->setInitialVarObj(initialVarObj);
379 }
380
381 bool
382 StackSpace::pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *fg)
383 {
384     if (!getSegmentAndFrame(cx, 0 /*vplen*/, 0 /*nslots*/, fg))
385         return false;
386     fg->fp()->initDummyFrame(cx, scopeChain);
387     fg->regs_.fp = fg->fp();
388     fg->regs_.pc = NULL;
389     fg->regs_.sp = fg->fp()->slots();
390     pushSegmentAndFrame(cx, &fg->regs_, fg);
391     return true;
392 }
393
394 bool
395 StackSpace::getGeneratorFrame(JSContext *cx, uintN vplen, uintN nslots, GeneratorFrameGuard *fg)
396 {
397     return getSegmentAndFrame(cx, vplen, nslots, fg);
398 }
399
400 void
401 StackSpace::pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameGuard *fg)
402 {
403     JS_ASSERT(regs->fp == fg->fp());
404     JS_ASSERT(regs->fp->prev() == cx->maybefp());
405     pushSegmentAndFrame(cx, regs, fg);
406 }
407
408 bool
409 StackSpace::bumpCommitAndLimit(JSStackFrame *base, Value *sp, uintN nvals, Value **limit) const
410 {
411     JS_ASSERT(sp >= firstUnused());
412     JS_ASSERT(sp + nvals >= *limit);
413 #ifdef XP_WIN
414     if (commitEnd <= *limit) {
415         Value *quotaEnd = (Value *)base + STACK_QUOTA;
416         if (sp + nvals < quotaEnd) {
417             if (!ensureSpace(NULL, sp, nvals))
418                 return false;
419             *limit = Min(quotaEnd, commitEnd);
420             return true;
421         }
422     }
423 #endif
424     return false;
425 }
426
427 void
428 FrameRegsIter::initSlow()
429 {
430     if (!curseg) {
431         curfp = NULL;
432         cursp = NULL;
433         curpc = NULL;
434         return;
435     }
436
437     JS_ASSERT(curseg->isSuspended());
438     curfp = curseg->getSuspendedFrame();
439     cursp = curseg->getSuspendedRegs()->sp;
440     curpc = curseg->getSuspendedRegs()->pc;
441 }
442
443 /*
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
447  * arguments.
448  */
449 void
450 FrameRegsIter::incSlow(JSStackFrame *fp, JSStackFrame *prev)
451 {
452     JS_ASSERT(prev);
453     JS_ASSERT(curpc == curfp->pc(cx, fp));
454     JS_ASSERT(fp == curseg->getInitialFrame());
455
456     /*
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.
462      */
463     curseg = curseg->getPreviousInContext();
464     cursp = curseg->getSuspendedRegs()->sp;
465     JSStackFrame *f = curseg->getSuspendedFrame();
466     while (f != prev) {
467         if (f == curseg->getInitialFrame()) {
468             curseg = curseg->getPreviousInContext();
469             cursp = curseg->getSuspendedRegs()->sp;
470             f = curseg->getSuspendedFrame();
471         } else {
472             cursp = f->formalArgsEnd();
473             f = f->prev();
474         }
475     }
476 }
477
478 AllFramesIter::AllFramesIter(JSContext *cx)
479   : curcs(cx->stack().getCurrentSegment()),
480     curfp(curcs ? curcs->getCurrentFrame() : NULL)
481 {
482 }
483
484 AllFramesIter&
485 AllFramesIter::operator++()
486 {
487     JS_ASSERT(!done());
488     if (curfp == curcs->getInitialFrame()) {
489         curcs = curcs->getPreviousInMemory();
490         curfp = curcs ? curcs->getCurrentFrame() : NULL;
491     } else {
492         curfp = curfp->prev();
493     }
494     return *this;
495 }
496
497 bool
498 JSThreadData::init()
499 {
500 #ifdef DEBUG
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);
504 #endif
505     if (!stackSpace.init())
506         return false;
507     dtoaState = js_NewDtoaState();
508     if (!dtoaState) {
509         finish();
510         return false;
511     }
512     nativeStackBase = GetNativeStackBase();
513
514 #ifdef JS_TRACER
515     /* Set the default size for the code cache to 16MB. */
516     maxCodeCacheBytes = 16 * 1024 * 1024;
517 #endif
518
519     return true;
520 }
521
522 void
523 JSThreadData::finish()
524 {
525     if (dtoaState)
526         js_DestroyDtoaState(dtoaState);
527
528     js_FinishGSNCache(&gsnCache);
529     propertyCache.~PropertyCache();
530     stackSpace.finish();
531 }
532
533 void
534 JSThreadData::mark(JSTracer *trc)
535 {
536     stackSpace.mark(trc);
537 }
538
539 void
540 JSThreadData::purge(JSContext *cx)
541 {
542     js_PurgeGSNCache(&gsnCache);
543
544     /* FIXME: bug 506341. */
545     propertyCache.purge(cx);
546 }
547
548 #ifdef JS_THREADSAFE
549
550 static JSThread *
551 NewThread(void *id)
552 {
553     JS_ASSERT(js_CurrentThreadId() == id);
554     JSThread *thread = (JSThread *) js_calloc(sizeof(JSThread));
555     if (!thread)
556         return NULL;
557     JS_INIT_CLIST(&thread->contextList);
558     thread->id = id;
559     if (!thread->data.init()) {
560         js_free(thread);
561         return NULL;
562     }
563     return thread;
564 }
565
566 static void
567 DestroyThread(JSThread *thread)
568 {
569     /* The thread must have zero contexts. */
570     JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
571
572     /*
573      * The conservative GC scanner should be disabled when the thread leaves
574      * the last request.
575      */
576     JS_ASSERT(!thread->data.conservativeGC.hasStackToScan());
577
578     thread->data.finish();
579     js_free(thread);
580 }
581
582 JSThread *
583 js_CurrentThread(JSRuntime *rt)
584 {
585     void *id = js_CurrentThreadId();
586     JS_LOCK_GC(rt);
587
588     /*
589      * We must not race with a GC that accesses cx->thread for JSContext
590      * instances on all threads, see bug 476934.
591      */
592     js_WaitForGC(rt);
593
594     JSThread *thread;
595     JSThread::Map::AddPtr p = rt->threads.lookupForAdd(id);
596     if (p) {
597         thread = p->value;
598
599         /*
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.
602          */
603         if (JS_CLIST_IS_EMPTY(&thread->contextList))
604             thread->data.nativeStackBase = GetNativeStackBase();
605     } else {
606         JS_UNLOCK_GC(rt);
607         thread = NewThread(id);
608         if (!thread)
609             return NULL;
610         JS_LOCK_GC(rt);
611         js_WaitForGC(rt);
612         if (!rt->threads.relookupOrAdd(p, id, thread)) {
613             JS_UNLOCK_GC(rt);
614             DestroyThread(thread);
615             return NULL;
616         }
617
618         /* Another thread cannot add an entry for the current thread id. */
619         JS_ASSERT(p->value == thread);
620     }
621     JS_ASSERT(thread->id == id);
622
623 #ifdef DEBUG
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);
630 #endif
631
632     return thread;
633 }
634
635 JSBool
636 js_InitContextThread(JSContext *cx)
637 {
638     JSThread *thread = js_CurrentThread(cx->runtime);
639     if (!thread)
640         return false;
641
642     JS_APPEND_LINK(&cx->threadLinks, &thread->contextList);
643     cx->thread = thread;
644     return true;
645 }
646
647 void
648 js_ClearContextThread(JSContext *cx)
649 {
650     JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
651     JS_REMOVE_AND_INIT_LINK(&cx->threadLinks);
652     cx->thread = NULL;
653 }
654
655 #endif /* JS_THREADSAFE */
656
657 JSThreadData *
658 js_CurrentThreadData(JSRuntime *rt)
659 {
660 #ifdef JS_THREADSAFE
661     JSThread *thread = js_CurrentThread(rt);
662     if (!thread)
663         return NULL;
664
665     return &thread->data;
666 #else
667     return &rt->threadData;
668 #endif
669 }
670
671 JSBool
672 js_InitThreads(JSRuntime *rt)
673 {
674 #ifdef JS_THREADSAFE
675     if (!rt->threads.init(4))
676         return false;
677 #else
678     if (!rt->threadData.init())
679         return false;
680 #endif
681     return true;
682 }
683
684 void
685 js_FinishThreads(JSRuntime *rt)
686 {
687 #ifdef JS_THREADSAFE
688     if (!rt->threads.initialized())
689         return;
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);
694     }
695     rt->threads.clear();
696 #else
697     rt->threadData.finish();
698 #endif
699 }
700
701 void
702 js_PurgeThreads(JSContext *cx)
703 {
704 #ifdef JS_THREADSAFE
705     for (JSThread::Map::Enum e(cx->runtime->threads);
706          !e.empty();
707          e.popFront()) {
708         JSThread *thread = e.front().value;
709
710         if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
711             JS_ASSERT(cx->thread != thread);
712
713             DestroyThread(thread);
714             e.removeFront();
715         } else {
716             thread->data.purge(cx);
717         }
718     }
719 #else
720     cx->runtime->threadData.purge(cx);
721 #endif
722 }
723
724 JSContext *
725 js_NewContext(JSRuntime *rt, size_t stackChunkSize)
726 {
727     JSContext *cx;
728     JSBool ok, first;
729     JSContextCallback cxCallback;
730
731     /*
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.
735      */
736     void *mem = js_calloc(sizeof *cx);
737     if (!mem)
738         return NULL;
739
740     cx = new (mem) JSContext(rt);
741     cx->debugHooks = &rt->globalDebugHooks;
742 #if JS_STACK_GROWTH_DIRECTION > 0
743     cx->stackLimit = (jsuword) -1;
744 #endif
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();
749
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);
754
755     JS_ASSERT(cx->resolveFlags == 0);
756
757     if (!cx->busyArrays.init()) {
758         FreeContext(cx);
759         return NULL;
760     }
761
762 #ifdef JS_THREADSAFE
763     if (!js_InitContextThread(cx)) {
764         FreeContext(cx);
765         return NULL;
766     }
767 #endif
768
769     /*
770      * Here the GC lock is still held after js_InitContextThread took it and
771      * the GC is not running on another thread.
772      */
773     for (;;) {
774         if (rt->state == JSRTS_UP) {
775             JS_ASSERT(!JS_CLIST_IS_EMPTY(&rt->contextList));
776             first = JS_FALSE;
777             break;
778         }
779         if (rt->state == JSRTS_DOWN) {
780             JS_ASSERT(JS_CLIST_IS_EMPTY(&rt->contextList));
781             first = JS_TRUE;
782             rt->state = JSRTS_LAUNCHING;
783             break;
784         }
785         JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT);
786
787         /*
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
792          * finished.
793          */
794         js_WaitForGC(rt);
795     }
796     JS_APPEND_LINK(&cx->link, &rt->contextList);
797     JS_UNLOCK_GC(rt);
798
799     js_InitRandom(cx);
800
801     /*
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".
808      */
809     if (first) {
810 #ifdef JS_THREADSAFE
811         JS_BeginRequest(cx);
812 #endif
813         ok = js_InitCommonAtoms(cx);
814
815         /*
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
818          * not necessary.
819          */
820         if (ok && !rt->scriptFilenameTable)
821             ok = js_InitRuntimeScriptState(rt);
822         if (ok)
823             ok = js_InitRuntimeNumberState(cx);
824
825 #ifdef JS_THREADSAFE
826         JS_EndRequest(cx);
827 #endif
828         if (!ok) {
829             js_DestroyContext(cx, JSDCM_NEW_FAILED);
830             return NULL;
831         }
832
833         AutoLockGC lock(rt);
834         rt->state = JSRTS_UP;
835         JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
836     }
837
838     cxCallback = rt->cxCallback;
839     if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) {
840         js_DestroyContext(cx, JSDCM_NEW_FAILED);
841         return NULL;
842     }
843
844     return cx;
845 }
846
847 #if defined DEBUG && defined XP_UNIX
848 # include <stdio.h>
849
850 class JSAutoFile {
851 public:
852     JSAutoFile() : mFile(NULL) {}
853
854     ~JSAutoFile() {
855         if (mFile)
856             fclose(mFile);
857     }
858
859     FILE *open(const char *fname, const char *mode) {
860         return mFile = fopen(fname, mode);
861     }
862     operator FILE *() {
863         return mFile;
864     }
865
866 private:
867     FILE *mFile;
868 };
869
870 static void
871 DumpEvalCacheMeter(JSContext *cx)
872 {
873     if (const char *filename = getenv("JS_EVALCACHE_STATFILE")) {
874         struct {
875             const char *name;
876             ptrdiff_t  offset;
877         } table[] = {
878 #define frob(x) { #x, offsetof(JSEvalCacheMeter, x) }
879             EVAL_CACHE_METER_LIST(frob)
880 #undef frob
881         };
882         JSEvalCacheMeter *ecm = &cx->compartment->evalCacheMeter;
883
884         static JSAutoFile fp;
885         if (!fp && !fp.open(filename, "w"))
886             return;
887
888         fprintf(fp, "eval cache meter (%p):\n",
889 #ifdef JS_THREADSAFE
890                 (void *) cx->thread
891 #else
892                 (void *) cx->runtime
893 #endif
894                 );
895         for (uintN i = 0; i < JS_ARRAY_LENGTH(table); ++i) {
896             fprintf(fp, "%-8.8s  %llu\n",
897                     table[i].name,
898                     (unsigned long long int) *(uint64 *)((uint8 *)ecm + table[i].offset));
899         }
900         fprintf(fp, "hit ratio %g%%\n", ecm->hit * 100. / ecm->probe);
901         fprintf(fp, "avg steps %g\n", double(ecm->step) / ecm->probe);
902         fflush(fp);
903     }
904 }
905 # define DUMP_EVAL_CACHE_METER(cx) DumpEvalCacheMeter(cx)
906
907 static void
908 DumpFunctionCountMap(const char *title, JSRuntime::FunctionCountMap &map, FILE *fp)
909 {
910     fprintf(fp, "\n%s count map:\n", title);
911
912     for (JSRuntime::FunctionCountMap::Range r = map.all(); !r.empty(); r.popFront()) {
913         JSFunction *fun = r.front().key;
914         int32 count = r.front().value;
915
916         fprintf(fp, "%10d %s:%u\n", count, fun->u.i.script->filename, fun->u.i.script->lineno);
917     }
918 }
919
920 static void
921 DumpFunctionMeter(JSContext *cx)
922 {
923     if (const char *filename = cx->runtime->functionMeterFilename) {
924         struct {
925             const char *name;
926             ptrdiff_t  offset;
927         } table[] = {
928 #define frob(x) { #x, offsetof(JSFunctionMeter, x) }
929             FUNCTION_KIND_METER_LIST(frob)
930 #undef frob
931         };
932         JSFunctionMeter *fm = &cx->runtime->functionMeter;
933
934         static JSAutoFile fp;
935         if (!fp && !fp.open(filename, "w"))
936             return;
937
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));
941
942         DumpFunctionCountMap("method read barrier", cx->runtime->methodReadBarrierCountMap, fp);
943         DumpFunctionCountMap("unjoined function", cx->runtime->unjoinedFunctionCountMap, fp);
944
945         putc('\n', fp);
946         fflush(fp);
947     }
948 }
949
950 # define DUMP_FUNCTION_METER(cx)   DumpFunctionMeter(cx)
951
952 #endif /* DEBUG && XP_UNIX */
953
954 #ifndef DUMP_EVAL_CACHE_METER
955 # define DUMP_EVAL_CACHE_METER(cx) ((void) 0)
956 #endif
957
958 #ifndef DUMP_FUNCTION_METER
959 # define DUMP_FUNCTION_METER(cx)   ((void) 0)
960 #endif
961
962 void
963 js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
964 {
965     JSRuntime *rt;
966     JSContextCallback cxCallback;
967     JSBool last;
968
969     JS_ASSERT(!cx->enumerators);
970
971     rt = cx->runtime;
972 #ifdef JS_THREADSAFE
973     /*
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.
977      */
978     JS_ASSERT(cx->thread && CURRENT_THREAD_IS_ME(cx->thread));
979     if (!cx->thread)
980         JS_SetContextThread(cx);
981
982     /*
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.
987      */
988     JS_ASSERT(cx->outstandingRequests <= cx->thread->data.requestDepth);
989 #endif
990
991     if (mode != JSDCM_NEW_FAILED) {
992         cxCallback = rt->cxCallback;
993         if (cxCallback) {
994             /*
995              * JSCONTEXT_DESTROY callback is not allowed to fail and must
996              * return true.
997              */
998 #ifdef DEBUG
999             JSBool callbackStatus =
1000 #endif
1001             cxCallback(cx, JSCONTEXT_DESTROY);
1002             JS_ASSERT(callbackStatus);
1003         }
1004     }
1005
1006     JS_LOCK_GC(rt);
1007     JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING);
1008 #ifdef JS_THREADSAFE
1009     /*
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.
1012      */
1013     if (cx->thread->data.requestDepth == 0)
1014         js_WaitForGC(rt);
1015 #endif
1016     JS_REMOVE_LINK(&cx->link);
1017     last = (rt->contextList.next == &rt->contextList);
1018     if (last)
1019         rt->state = JSRTS_LANDING;
1020     if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC
1021 #ifdef JS_THREADSAFE
1022         || cx->outstandingRequests != 0
1023 #endif
1024         ) {
1025         JS_ASSERT(!rt->gcRunning);
1026
1027         JS_UNLOCK_GC(rt);
1028
1029         if (last) {
1030 #ifdef JS_THREADSAFE
1031             /*
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.
1040              */
1041             if (cx->thread->data.requestDepth == 0)
1042                 JS_BeginRequest(cx);
1043 #endif
1044
1045             js_FinishRuntimeNumberState(cx);
1046
1047             /* Unpin all common atoms before final GC. */
1048             js_FinishCommonAtoms(cx);
1049
1050             /* Clear debugging state to remove GC roots. */
1051             JS_ClearAllTraps(cx);
1052             JS_ClearAllWatchPoints(cx);
1053         }
1054
1055 #ifdef JS_THREADSAFE
1056         /*
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.
1062          */
1063         while (cx->outstandingRequests != 0)
1064             JS_EndRequest(cx);
1065 #endif
1066
1067         if (last) {
1068             js_GC(cx, NULL, GC_LAST_CONTEXT);
1069             DUMP_EVAL_CACHE_METER(cx);
1070             DUMP_FUNCTION_METER(cx);
1071
1072             /* Take the runtime down, now that it has no contexts or atoms. */
1073             JS_LOCK_GC(rt);
1074             rt->state = JSRTS_DOWN;
1075             JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
1076         } else {
1077             if (mode == JSDCM_FORCE_GC)
1078                 js_GC(cx, NULL, GC_NORMAL);
1079             else if (mode == JSDCM_MAYBE_GC)
1080                 JS_MaybeGC(cx);
1081             JS_LOCK_GC(rt);
1082             js_WaitForGC(rt);
1083         }
1084     }
1085 #ifdef JS_THREADSAFE
1086 #ifdef DEBUG
1087     JSThread *t = cx->thread;
1088 #endif
1089     js_ClearContextThread(cx);
1090     JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
1091 #endif
1092 #ifdef JS_METER_DST_OFFSET_CACHING
1093     cx->dstOffsetCache.dumpStats();
1094 #endif
1095     JS_UNLOCK_GC(rt);
1096     FreeContext(cx);
1097 }
1098
1099 static void
1100 FreeContext(JSContext *cx)
1101 {
1102 #ifdef JS_THREADSAFE
1103     JS_ASSERT(!cx->thread);
1104 #endif
1105
1106     /* Free the stuff hanging off of cx. */
1107     VOUCH_DOES_NOT_REQUIRE_STACK();
1108     JS_FinishArenaPool(&cx->tempPool);
1109     JS_FinishArenaPool(&cx->regExpPool);
1110
1111     if (cx->lastMessage)
1112         js_free(cx->lastMessage);
1113
1114     /* Remove any argument formatters. */
1115     JSArgumentFormatMap *map = cx->argumentFormatMap;
1116     while (map) {
1117         JSArgumentFormatMap *temp = map;
1118         map = map->next;
1119         cx->free(temp);
1120     }
1121
1122     /* Destroy the resolve recursion damper. */
1123     if (cx->resolvingTable) {
1124         JS_DHashTableDestroy(cx->resolvingTable);
1125         cx->resolvingTable = NULL;
1126     }
1127
1128     /* Finally, free cx itself. */
1129     cx->~JSContext();
1130     js_free(cx);
1131 }
1132
1133 JSContext *
1134 js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
1135 {
1136     JSContext *cx = *iterp;
1137
1138     Conditionally<AutoLockGC> lockIf(!!unlocked, rt);
1139     cx = js_ContextFromLinkField(cx ? cx->link.next : rt->contextList.next);
1140     if (&cx->link == &rt->contextList)
1141         cx = NULL;
1142     *iterp = cx;
1143     return cx;
1144 }
1145
1146 JS_FRIEND_API(JSContext *)
1147 js_NextActiveContext(JSRuntime *rt, JSContext *cx)
1148 {
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)
1153             break;
1154     }
1155     return cx;
1156 #else
1157     return js_ContextIterator(rt, JS_FALSE, &iter);
1158 #endif
1159 }
1160
1161 static JSDHashNumber
1162 resolving_HashKey(JSDHashTable *table, const void *ptr)
1163 {
1164     const JSResolvingKey *key = (const JSResolvingKey *)ptr;
1165
1166     return (JSDHashNumber(uintptr_t(key->obj)) >> JS_GCTHING_ALIGN) ^ JSID_BITS(key->id);
1167 }
1168
1169 static JSBool
1170 resolving_MatchEntry(JSDHashTable *table,
1171                      const JSDHashEntryHdr *hdr,
1172                      const void *ptr)
1173 {
1174     const JSResolvingEntry *entry = (const JSResolvingEntry *)hdr;
1175     const JSResolvingKey *key = (const JSResolvingKey *)ptr;
1176
1177     return entry->key.obj == key->obj && entry->key.id == key->id;
1178 }
1179
1180 static const JSDHashTableOps resolving_dhash_ops = {
1181     JS_DHashAllocTable,
1182     JS_DHashFreeTable,
1183     resolving_HashKey,
1184     resolving_MatchEntry,
1185     JS_DHashMoveEntryStub,
1186     JS_DHashClearEntryStub,
1187     JS_DHashFinalizeStub,
1188     NULL
1189 };
1190
1191 JSBool
1192 js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
1193                   JSResolvingEntry **entryp)
1194 {
1195     JSDHashTable *table;
1196     JSResolvingEntry *entry;
1197
1198     table = cx->resolvingTable;
1199     if (!table) {
1200         table = JS_NewDHashTable(&resolving_dhash_ops, NULL,
1201                                  sizeof(JSResolvingEntry),
1202                                  JS_DHASH_MIN_SIZE);
1203         if (!table)
1204             goto outofmem;
1205         cx->resolvingTable = table;
1206     }
1207
1208     entry = (JSResolvingEntry *)
1209             JS_DHashTableOperate(table, key, JS_DHASH_ADD);
1210     if (!entry)
1211         goto outofmem;
1212
1213     if (entry->flags & flag) {
1214         /* An entry for (key, flag) exists already -- dampen recursion. */
1215         entry = NULL;
1216     } else {
1217         /* Fill in key if we were the first to add entry, then set flag. */
1218         if (!entry->key.obj)
1219             entry->key = *key;
1220         entry->flags |= flag;
1221     }
1222     *entryp = entry;
1223     return JS_TRUE;
1224
1225 outofmem:
1226     JS_ReportOutOfMemory(cx);
1227     return JS_FALSE;
1228 }
1229
1230 void
1231 js_StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
1232                  JSResolvingEntry *entry, uint32 generation)
1233 {
1234     JSDHashTable *table;
1235
1236     /*
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.
1240      */
1241     table = cx->resolvingTable;
1242     if (!entry || table->generation != generation) {
1243         entry = (JSResolvingEntry *)
1244                 JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP);
1245     }
1246     JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&entry->hdr));
1247     entry->flags &= ~flag;
1248     if (entry->flags)
1249         return;
1250
1251     /*
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.
1256      */
1257     if (table->removedCount < JS_DHASH_TABLE_SIZE(table) >> 2)
1258         JS_DHashTableRawRemove(table, &entry->hdr);
1259     else
1260         JS_DHashTableOperate(table, key, JS_DHASH_REMOVE);
1261 }
1262
1263 static void
1264 ReportError(JSContext *cx, const char *message, JSErrorReport *reportp,
1265             JSErrorCallback callback, void *userRef)
1266 {
1267     /*
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.
1272      */
1273     JS_ASSERT(reportp);
1274     if ((!callback || callback == js_GetErrorMessage) &&
1275         reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
1276         reportp->flags |= JSREPORT_EXCEPTION;
1277
1278     /*
1279      * Call the error reporter only if an exception wasn't raised.
1280      *
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.
1285      */
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 */
1292         if (hook)
1293             hook(cx, message, reportp, cx->debugHooks->debugErrorHookData);
1294     }
1295 }
1296
1297 /* The report must be initially zeroed. */
1298 static void
1299 PopulateReportBlame(JSContext *cx, JSErrorReport *report)
1300 {
1301     /*
1302      * Walk stack until we find a frame that is associated with some script
1303      * rather than a native frame.
1304      */
1305     for (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) {
1306         if (fp->pc(cx)) {
1307             report->filename = fp->script()->filename;
1308             report->lineno = js_FramePCToLineNumber(cx, fp);
1309             break;
1310         }
1311     }
1312 }
1313
1314 /*
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.
1320  */
1321 void
1322 js_ReportOutOfMemory(JSContext *cx)
1323 {
1324 #ifdef JS_TRACER
1325     /*
1326      * If we are in a builtin called directly from trace, don't report an
1327      * error. We will retry in the interpreter instead.
1328      */
1329     if (JS_ON_TRACE(cx) && !JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit)
1330         return;
1331 #endif
1332
1333     JSErrorReport report;
1334     JSErrorReporter onError = cx->errorReporter;
1335
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";
1340
1341     /* Fill out the report, but don't do anything that requires allocation. */
1342     PodZero(&report);
1343     report.flags = JSREPORT_ERROR;
1344     report.errorNumber = JSMSG_OUT_OF_MEMORY;
1345     PopulateReportBlame(cx, &report);
1346
1347     /*
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.
1352      */
1353     cx->clearPendingException();
1354     if (onError) {
1355         JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
1356         if (hook &&
1357             !hook(cx, msg, &report, cx->debugHooks->debugErrorHookData)) {
1358             onError = NULL;
1359         }
1360     }
1361
1362     if (onError)
1363         onError(cx, msg, &report);
1364 }
1365
1366 void
1367 js_ReportOutOfScriptQuota(JSContext *cx)
1368 {
1369     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1370                          JSMSG_SCRIPT_STACK_QUOTA);
1371 }
1372
1373 JS_FRIEND_API(void)
1374 js_ReportOverRecursed(JSContext *cx)
1375 {
1376     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
1377 }
1378
1379 void
1380 js_ReportAllocationOverflow(JSContext *cx)
1381 {
1382     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ALLOC_OVERFLOW);
1383 }
1384
1385 /*
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.
1390  */
1391 static bool
1392 checkReportFlags(JSContext *cx, uintN *flags)
1393 {
1394     if (JSREPORT_IS_STRICT_MODE_ERROR(*flags)) {
1395         /*
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.
1399          */
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;
1405         else
1406             return true;
1407     } else if (JSREPORT_IS_STRICT(*flags)) {
1408         /* Warning/error only when JSOPTION_STRICT is set. */
1409         if (!cx->hasStrictOption())
1410             return true;
1411     }
1412
1413     /* Warnings become errors when JSOPTION_WERROR is set. */
1414     if (JSREPORT_IS_WARNING(*flags) && cx->hasWErrorOption())
1415         *flags &= ~JSREPORT_WARNING;
1416
1417     return false;
1418 }
1419
1420 JSBool
1421 js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap)
1422 {
1423     char *message;
1424     jschar *ucmessage;
1425     size_t messagelen;
1426     JSErrorReport report;
1427     JSBool warning;
1428
1429     if (checkReportFlags(cx, &flags))
1430         return JS_TRUE;
1431
1432     message = JS_vsmprintf(format, ap);
1433     if (!message)
1434         return JS_FALSE;
1435     messagelen = strlen(message);
1436
1437     PodZero(&report);
1438     report.flags = flags;
1439     report.errorNumber = JSMSG_USER_DEFINED_ERROR;
1440     report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen);
1441     PopulateReportBlame(cx, &report);
1442
1443     warning = JSREPORT_IS_WARNING(report.flags);
1444
1445     ReportError(cx, message, &report, NULL, NULL);
1446     js_free(message);
1447     cx->free(ucmessage);
1448     return warning;
1449 }
1450
1451 /*
1452  * The arguments from ap need to be packaged up into an array and stored
1453  * into the report struct.
1454  *
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.
1459  *
1460  * Returns true if the expansion succeeds (can fail if out of memory).
1461  */
1462 JSBool
1463 js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
1464                         void *userRef, const uintN errorNumber,
1465                         char **messagep, JSErrorReport *reportp,
1466                         bool charArgs, va_list ap)
1467 {
1468     const JSErrorFormatString *efs;
1469     int i;
1470     int argCount;
1471
1472     *messagep = NULL;
1473
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);
1477     else
1478         efs = callback(userRef, NULL, errorNumber);
1479     if (efs) {
1480         size_t totalArgsLength = 0;
1481         size_t argLengths[10]; /* only {0} thru {9} supported */
1482         argCount = efs->argCount;
1483         JS_ASSERT(argCount <= 10);
1484         if (argCount > 0) {
1485             /*
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
1489              * pointers later.
1490              */
1491             reportp->messageArgs = (const jschar **)
1492                 cx->malloc(sizeof(jschar *) * (argCount + 1));
1493             if (!reportp->messageArgs)
1494                 return JS_FALSE;
1495             reportp->messageArgs[argCount] = NULL;
1496             for (i = 0; i < argCount; i++) {
1497                 if (charArgs) {
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])
1503                         goto error;
1504                 } else {
1505                     reportp->messageArgs[i] = va_arg(ap, jschar *);
1506                 }
1507                 argLengths[i] = js_strlen(reportp->messageArgs[i]);
1508                 totalArgsLength += argLengths[i];
1509             }
1510             /* NULL-terminate for easy copying. */
1511             reportp->messageArgs[i] = NULL;
1512         }
1513         /*
1514          * Parse the error format, substituting the argument X
1515          * for {X} in the format.
1516          */
1517         if (argCount > 0) {
1518             if (efs->format) {
1519                 jschar *buffer, *fmt, *out;
1520                 int expandedArgs = 0;
1521                 size_t expandedLength;
1522                 size_t len = strlen(efs->format);
1523
1524                 buffer = fmt = js_InflateString (cx, efs->format, &len);
1525                 if (!buffer)
1526                     goto error;
1527                 expandedLength = len
1528                                  - (3 * argCount)       /* exclude the {n} */
1529                                  + totalArgsLength;
1530
1531                 /*
1532                 * Note - the above calculation assumes that each argument
1533                 * is used once and only once in the expansion !!!
1534                 */
1535                 reportp->ucmessage = out = (jschar *)
1536                     cx->malloc((expandedLength + 1) * sizeof(jschar));
1537                 if (!out) {
1538                     cx->free(buffer);
1539                     goto error;
1540                 }
1541                 while (*fmt) {
1542                     if (*fmt == '{') {
1543                         if (isdigit(fmt[1])) {
1544                             int d = JS7_UNDEC(fmt[1]);
1545                             JS_ASSERT(d < argCount);
1546                             js_strncpy(out, reportp->messageArgs[d],
1547                                        argLengths[d]);
1548                             out += argLengths[d];
1549                             fmt += 3;
1550                             expandedArgs++;
1551                             continue;
1552                         }
1553                     }
1554                     *out++ = *fmt++;
1555                 }
1556                 JS_ASSERT(expandedArgs == argCount);
1557                 *out = 0;
1558                 cx->free(buffer);
1559                 *messagep =
1560                     js_DeflateString(cx, reportp->ucmessage,
1561                                      (size_t)(out - reportp->ucmessage));
1562                 if (!*messagep)
1563                     goto error;
1564             }
1565         } else {
1566             /*
1567              * Zero arguments: the format string (if it exists) is the
1568              * entire message.
1569              */
1570             if (efs->format) {
1571                 size_t len;
1572                 *messagep = JS_strdup(cx, efs->format);
1573                 if (!*messagep)
1574                     goto error;
1575                 len = strlen(*messagep);
1576                 reportp->ucmessage = js_InflateString(cx, *messagep, &len);
1577                 if (!reportp->ucmessage)
1578                     goto error;
1579             }
1580         }
1581     }
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);
1588         if (!*messagep)
1589             goto error;
1590         JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
1591     }
1592     return JS_TRUE;
1593
1594 error:
1595     if (reportp->messageArgs) {
1596         /* free the arguments only if we allocated them */
1597         if (charArgs) {
1598             i = 0;
1599             while (reportp->messageArgs[i])
1600                 cx->free((void *)reportp->messageArgs[i++]);
1601         }
1602         cx->free((void *)reportp->messageArgs);
1603         reportp->messageArgs = NULL;
1604     }
1605     if (reportp->ucmessage) {
1606         cx->free((void *)reportp->ucmessage);
1607         reportp->ucmessage = NULL;
1608     }
1609     if (*messagep) {
1610         cx->free((void *)*messagep);
1611         *messagep = NULL;
1612     }
1613     return JS_FALSE;
1614 }
1615
1616 JSBool
1617 js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
1618                        void *userRef, const uintN errorNumber,
1619                        JSBool charArgs, va_list ap)
1620 {
1621     JSErrorReport report;
1622     char *message;
1623     JSBool warning;
1624
1625     if (checkReportFlags(cx, &flags))
1626         return JS_TRUE;
1627     warning = JSREPORT_IS_WARNING(flags);
1628
1629     PodZero(&report);
1630     report.flags = flags;
1631     report.errorNumber = errorNumber;
1632     PopulateReportBlame(cx, &report);
1633
1634     if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
1635                                  &message, &report, !!charArgs, ap)) {
1636         return JS_FALSE;
1637     }
1638
1639     ReportError(cx, message, &report, callback, userRef);
1640
1641     if (message)
1642         cx->free(message);
1643     if (report.messageArgs) {
1644         /*
1645          * js_ExpandErrorArguments owns its messageArgs only if it had to
1646          * inflate the arguments (from regular |char *|s).
1647          */
1648         if (charArgs) {
1649             int i = 0;
1650             while (report.messageArgs[i])
1651                 cx->free((void *)report.messageArgs[i++]);
1652         }
1653         cx->free((void *)report.messageArgs);
1654     }
1655     if (report.ucmessage)
1656         cx->free((void *)report.ucmessage);
1657
1658     return warning;
1659 }
1660
1661 JS_FRIEND_API(void)
1662 js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp)
1663 {
1664     JSErrorReporter onError;
1665
1666     if (!message)
1667         return;
1668
1669     if (cx->lastMessage)
1670         js_free(cx->lastMessage);
1671     cx->lastMessage = JS_strdup(cx, message);
1672     if (!cx->lastMessage)
1673         return;
1674     onError = cx->errorReporter;
1675
1676     /*
1677      * If debugErrorHook is present then we give it a chance to veto
1678      * sending the error on to the regular ErrorReporter.
1679      */
1680     if (onError) {
1681         JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
1682         if (hook &&
1683             !hook(cx, cx->lastMessage, reportp,
1684                   cx->debugHooks->debugErrorHookData)) {
1685             onError = NULL;
1686         }
1687     }
1688     if (onError)
1689         onError(cx, cx->lastMessage, reportp);
1690 }
1691
1692 void
1693 js_ReportIsNotDefined(JSContext *cx, const char *name)
1694 {
1695     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name);
1696 }
1697
1698 JSBool
1699 js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, const Value &v,
1700                            JSString *fallback)
1701 {
1702     char *bytes;
1703     JSBool ok;
1704
1705     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
1706     if (!bytes)
1707         return JS_FALSE;
1708
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,
1714                                           NULL, NULL);
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);
1720     } else {
1721         JS_ASSERT(v.isNull());
1722         ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
1723                                           js_GetErrorMessage, NULL,
1724                                           JSMSG_UNEXPECTED_TYPE, bytes,
1725                                           js_null_str, NULL);
1726     }
1727
1728     cx->free(bytes);
1729     return ok;
1730 }
1731
1732 void
1733 js_ReportMissingArg(JSContext *cx, const Value &v, uintN arg)
1734 {
1735     char argbuf[11];
1736     char *bytes;
1737     JSAtom *atom;
1738
1739     JS_snprintf(argbuf, sizeof argbuf, "%u", arg);
1740     bytes = NULL;
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));
1745         if (!bytes)
1746             return;
1747     }
1748     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1749                          JSMSG_MISSING_FUN_ARG, argbuf,
1750                          bytes ? bytes : "");
1751     cx->free(bytes);
1752 }
1753
1754 JSBool
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)
1758 {
1759     char *bytes;
1760     JSBool ok;
1761
1762     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
1763     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
1764     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
1765     if (!bytes)
1766         return JS_FALSE;
1767
1768     ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage,
1769                                       NULL, errorNumber, bytes, arg1, arg2);
1770     cx->free(bytes);
1771     return ok;
1772 }
1773
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; }
1778 #endif
1779
1780 JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
1781 #define MSG_DEF(name, number, count, exception, format) \
1782     { format, count, exception } ,
1783 #include "js.msg"
1784 #undef MSG_DEF
1785 };
1786
1787 JS_FRIEND_API(const JSErrorFormatString *)
1788 js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber)
1789 {
1790     if ((errorNumber > 0) && (errorNumber < JSErr_Limit))
1791         return &js_ErrorFormatString[errorNumber];
1792     return NULL;
1793 }
1794
1795 JSBool
1796 js_InvokeOperationCallback(JSContext *cx)
1797 {
1798     JSRuntime *rt = cx->runtime;
1799     JSThreadData *td = JS_THREAD_DATA(cx);
1800
1801     JS_ASSERT_REQUEST_DEPTH(cx);
1802     JS_ASSERT(td->interruptFlags != 0);
1803
1804     /*
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.
1808      */
1809     JS_LOCK_GC(rt);
1810     td->interruptFlags = 0;
1811 #ifdef JS_THREADSAFE
1812     JS_ATOMIC_DECREMENT(&rt->interruptCounter);
1813 #endif
1814     JS_UNLOCK_GC(rt);
1815
1816     if (rt->gcIsNeeded) {
1817         js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL);
1818
1819         /*
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.
1822          */
1823         bool delayedOutOfMemory;
1824         JS_LOCK_GC(rt);
1825         delayedOutOfMemory = (rt->gcBytes > rt->gcMaxBytes);
1826         JS_UNLOCK_GC(rt);
1827         if (delayedOutOfMemory) {
1828             js_ReportOutOfMemory(cx);
1829             return false;
1830         }
1831     }
1832     
1833 #ifdef JS_THREADSAFE
1834     /*
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.
1840      *
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.
1843      */
1844     JS_YieldRequest(cx);
1845 #endif
1846
1847     JSOperationCallback cb = cx->operationCallback;
1848
1849     /*
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.
1853      */
1854
1855     return !cb || cb(cx);
1856 }
1857
1858 JSBool
1859 js_HandleExecutionInterrupt(JSContext *cx)
1860 {
1861     JSBool result = JS_TRUE;
1862     if (JS_THREAD_DATA(cx)->interruptFlags)
1863         result = js_InvokeOperationCallback(cx) && result;
1864     return result;
1865 }
1866
1867 namespace js {
1868
1869 void
1870 TriggerOperationCallback(JSContext *cx)
1871 {
1872     /*
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
1876      * GC-ed.
1877      */
1878     JSThreadData *td;
1879 #ifdef JS_THREADSAFE
1880     JSThread *thread = cx->thread;
1881     if (!thread)
1882         return;
1883     td = &thread->data;
1884 #else
1885     td = JS_THREAD_DATA(cx);
1886 #endif
1887     td->triggerOperationCallback(cx->runtime);
1888 }
1889
1890 void
1891 TriggerAllOperationCallbacks(JSRuntime *rt)
1892 {
1893     for (ThreadDataIter i(rt); !i.empty(); i.popFront())
1894         i.threadData()->triggerOperationCallback(rt);
1895 }
1896
1897 } /* namespace js */
1898
1899 JSStackFrame *
1900 js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
1901 {
1902     if (!fp)
1903         fp = js_GetTopStackFrame(cx);
1904     while (fp && fp->isDummyFrame())
1905         fp = fp->prev();
1906     JS_ASSERT_IF(fp, fp->isScriptFrame());
1907     return fp;
1908 }
1909
1910 jsbytecode*
1911 js_GetCurrentBytecodePC(JSContext* cx)
1912 {
1913     jsbytecode *pc, *imacpc;
1914
1915 #ifdef JS_TRACER
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;
1919     } else
1920 #endif
1921     {
1922         JS_ASSERT_NOT_ON_TRACE(cx);  /* for static analysis */
1923         pc = cx->regs ? cx->regs->pc : NULL;
1924         if (!pc)
1925             return NULL;
1926         imacpc = cx->fp()->maybeImacropc();
1927     }
1928
1929     /*
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.
1933      */
1934     return (*pc == JSOP_CALL && imacpc) ? imacpc : pc;
1935 }
1936
1937 bool
1938 js_CurrentPCIsInImacro(JSContext *cx)
1939 {
1940 #ifdef JS_TRACER
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();
1945 #else
1946     return false;
1947 #endif
1948 }
1949
1950 void
1951 DSTOffsetCache::purge()
1952 {
1953     /*
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!
1957      */
1958     offsetMilliseconds = 0;
1959     rangeStartSeconds = rangeEndSeconds = INT64_MIN;
1960     oldOffsetMilliseconds = 0;
1961     oldRangeStartSeconds = oldRangeEndSeconds = INT64_MIN;
1962
1963 #ifdef JS_METER_DST_OFFSET_CACHING
1964     totalCalculations = 0;
1965     hit = 0;
1966     missIncreasing = missDecreasing = 0;
1967     missIncreasingOffsetChangeExpand = missIncreasingOffsetChangeUpper = 0;
1968     missDecreasingOffsetChangeExpand = missDecreasingOffsetChangeLower = 0;
1969     missLargeIncrease = missLargeDecrease = 0;
1970 #endif
1971
1972     sanityCheck();
1973 }
1974
1975 /*
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.
1980  */
1981 DSTOffsetCache::DSTOffsetCache()
1982 {
1983     purge();
1984 }
1985
1986 JSContext::JSContext(JSRuntime *rt)
1987   : hasVersionOverride(false),
1988     runtime(rt),
1989     compartment(NULL),
1990     regs(NULL),
1991     busyArrays()
1992 {}
1993
1994 void
1995 JSContext::resetCompartment()
1996 {
1997     JSObject *scopeobj;
1998     if (hasfp()) {
1999         scopeobj = &fp()->scopeChain();
2000     } else {
2001         scopeobj = globalObject;
2002         if (!scopeobj)
2003             goto error;
2004
2005         /*
2006          * Innerize. Assert, but check anyway, that this succeeds. (It
2007          * can only fail due to bugs in the engine or embedding.)
2008          */
2009         OBJ_TO_INNER_OBJECT(this, scopeobj);
2010         if (!scopeobj)
2011             goto error;
2012     }
2013
2014     compartment = scopeobj->compartment();
2015
2016     if (isExceptionPending())
2017         wrapPendingException();
2018     return;
2019
2020 error:
2021
2022     /*
2023      * If we try to use the context without a selected compartment,
2024      * we will crash.
2025      */
2026     compartment = NULL;
2027 }
2028
2029 /*
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.
2033  */
2034 void
2035 JSContext::wrapPendingException()
2036 {
2037     Value v = getPendingException();
2038     clearPendingException();
2039     if (compartment->wrap(this, &v))
2040         setPendingException(v);
2041 }
2042
2043 void
2044 JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs)
2045 {
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);
2053 }
2054
2055 void
2056 JSContext::popSegmentAndFrame()
2057 {
2058     /*
2059      * NB: This function calls resetCompartment, which may GC, so the stack needs
2060      * to be in a GC-able state by that point.
2061      */
2062
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);
2070             resetCompartment();
2071         } else {
2072             setCurrentRegs(currentSegment->getSuspendedRegs());
2073             currentSegment->resume();
2074         }
2075     } else {
2076         JS_ASSERT(regs->fp->prev() == NULL);
2077         setCurrentRegs(NULL);
2078         resetCompartment();
2079     }
2080     maybeMigrateVersionOverride();
2081 }
2082
2083 void
2084 JSContext::saveActiveSegment()
2085 {
2086     JS_ASSERT(hasActiveSegment());
2087     currentSegment->save(regs);
2088     setCurrentRegs(NULL);
2089     resetCompartment();
2090 }
2091
2092 void
2093 JSContext::restoreSegment()
2094 {
2095     js::StackSegment *ccs = currentSegment;
2096     setCurrentRegs(ccs->getSuspendedRegs());
2097     ccs->restore();
2098     resetCompartment();
2099 }
2100
2101 JSGenerator *
2102 JSContext::generatorFor(JSStackFrame *fp) const
2103 {
2104     JS_ASSERT(stack().contains(fp) && fp->isGeneratorFrame());
2105     JS_ASSERT(!fp->isFloatingGenerator());
2106     JS_ASSERT(!genStack.empty());
2107
2108     if (JS_LIKELY(fp == genStack.back()->liveFrame()))
2109         return genStack.back();
2110
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)
2114             return genStack[i];
2115     }
2116     JS_NOT_REACHED("no matching generator");
2117     return NULL;
2118 }
2119
2120 StackSegment *
2121 JSContext::containingSegment(const JSStackFrame *target)
2122 {
2123     /* The context may have nothing running. */
2124     StackSegment *seg = currentSegment;
2125     if (!seg)
2126         return NULL;
2127
2128     /* The active segments's top frame is cx->regs->fp. */
2129     if (regs) {
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()) {
2135             if (f == target)
2136                 return seg;
2137         }
2138         seg = seg->getPreviousInContext();
2139     }
2140
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()) {
2146             if (f == target)
2147                 return seg;
2148         }
2149     }
2150
2151     return NULL;
2152 }
2153
2154 JS_FRIEND_API(void)
2155 JSRuntime::onTooMuchMalloc()
2156 {
2157 #ifdef JS_THREADSAFE
2158     AutoLockGC lock(this);
2159
2160     /*
2161      * We can be called outside a request and can race against a GC that
2162      * mutates the JSThread set during the sweeping phase.
2163      */
2164     js_WaitForGC(this);
2165 #endif
2166     TriggerGC(this);
2167 }
2168
2169 JS_FRIEND_API(void *)
2170 JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
2171 {
2172 #ifdef JS_THREADSAFE
2173     gcHelperThread.waitBackgroundSweepEnd(this);
2174     if (!p)
2175         p = ::js_malloc(nbytes);
2176     else if (p == reinterpret_cast<void *>(1))
2177         p = ::js_calloc(nbytes);
2178     else
2179       p = ::js_realloc(p, nbytes);
2180     if (p)
2181         return p;
2182 #endif
2183     if (cx)
2184         js_ReportOutOfMemory(cx);
2185     return NULL;
2186 }
2187
2188 /*
2189  * Release pool's arenas if the stackPool has existed for longer than the
2190  * limit specified by gcEmptyArenaPoolLifespan.
2191  */
2192 inline void
2193 FreeOldArenas(JSRuntime *rt, JSArenaPool *pool)
2194 {
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);
2200     }
2201 }
2202
2203 void
2204 JSContext::purge()
2205 {
2206     FreeOldArenas(runtime, &regExpPool);
2207 }
2208
2209 static bool
2210 ComputeIsJITBroken()
2211 {
2212 #ifndef ANDROID
2213     return false;
2214 #else  // ANDROID
2215     if (getenv("JS_IGNORE_JIT_BROKENNESS")) {
2216         return false;
2217     }
2218
2219     std::string line;
2220
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'",
2225                         line.c_str());
2226
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");
2230         return false;
2231     }
2232
2233     // We're using 2.6.29, and this causes trouble with the JITs on i9000.
2234     line = "";
2235     bool broken = false;
2236     std::ifstream cpuinfo("/proc/cpuinfo");
2237     do {
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
2245                 NULL
2246             };
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);
2251                     broken = true;
2252                     break;
2253                 }
2254             }
2255             break;
2256         }
2257         std::getline(cpuinfo, line);
2258     } while(!cpuinfo.fail() && !cpuinfo.eof());
2259
2260     __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are %sbroken",
2261                         broken ? "" : "not ");
2262
2263     return broken;
2264 #endif  // ifndef ANDROID
2265 }
2266
2267 static bool
2268 IsJITBrokenHere()
2269 {
2270     static bool computedIsBroken = false;
2271     static bool isBroken = false;
2272     if (!computedIsBroken) {
2273         isBroken = ComputeIsJITBroken();
2274         computedIsBroken = true;
2275     }
2276     return isBroken;
2277 }
2278
2279 void
2280 JSContext::updateJITEnabled()
2281 {
2282 #ifdef JS_TRACER
2283     traceJitEnabled = ((runOptions & JSOPTION_JIT) &&
2284                        !IsJITBrokenHere() &&
2285                        (debugHooks == &js_NullDebugHooks ||
2286                         (debugHooks == &runtime->globalDebugHooks &&
2287                          !runtime->debuggerInhibitsJIT())));
2288 #endif
2289 #ifdef JS_METHODJIT
2290     methodJitEnabled = (runOptions & JSOPTION_METHODJIT) &&
2291                        !IsJITBrokenHere()
2292 # if defined JS_CPU_X86 || defined JS_CPU_X64
2293                        && JSC::MacroAssemblerX86Common::getSSEState() >=
2294                           JSC::MacroAssemblerX86Common::HasSSE2
2295 # endif
2296                         ;
2297 #ifdef JS_TRACER
2298     profilingEnabled = (runOptions & JSOPTION_PROFILING) && traceJitEnabled && methodJitEnabled;
2299 #endif
2300 #endif
2301 }
2302
2303 namespace js {
2304
2305 JS_FORCES_STACK JS_FRIEND_API(void)
2306 LeaveTrace(JSContext *cx)
2307 {
2308 #ifdef JS_TRACER
2309     if (JS_ON_TRACE(cx))
2310         DeepBail(cx);
2311 #endif
2312 }
2313
2314 } /* namespace js */