Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / js / src / jscompartment.h
blob639a96bc7d5cd0a4558da2a10d4406d5a744ff2c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is SpiderMonkey code.
18 * The Initial Developer of the Original Code is
19 * Mozilla Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 2010
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #ifndef jscompartment_h___
41 #define jscompartment_h___
43 #include "jscntxt.h"
44 #include "jsgc.h"
45 #include "jsmath.h"
46 #include "jsobj.h"
47 #include "jsfun.h"
48 #include "jsgcstats.h"
49 #include "jsclist.h"
50 #include "jsxml.h"
52 #ifdef _MSC_VER
53 #pragma warning(push)
54 #pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
55 #endif
57 namespace JSC {
59 class ExecutableAllocator;
63 namespace js {
65 /* Holds the number of recording attemps for an address. */
66 typedef HashMap<jsbytecode*,
67 size_t,
68 DefaultHasher<jsbytecode*>,
69 SystemAllocPolicy> RecordAttemptMap;
71 /* Holds the profile data for loops. */
72 typedef HashMap<jsbytecode*,
73 LoopProfile*,
74 DefaultHasher<jsbytecode*>,
75 SystemAllocPolicy> LoopProfileMap;
77 class Oracle;
79 typedef HashSet<JSScript *,
80 DefaultHasher<JSScript *>,
81 SystemAllocPolicy> TracedScriptSet;
83 typedef HashMap<JSFunction *,
84 JSString *,
85 DefaultHasher<JSFunction *>,
86 SystemAllocPolicy> ToSourceCache;
88 struct TraceMonitor;
90 /* Holds the execution state during trace execution. */
91 struct TracerState
93 JSContext* cx; // current VM context handle
94 TraceMonitor* traceMonitor; // current TM
95 double* stackBase; // native stack base
96 double* sp; // native stack pointer, stack[0] is spbase[0]
97 double* eos; // first unusable word after the native stack / begin of globals
98 FrameInfo** callstackBase; // call stack base
99 void* sor; // start of rp stack
100 FrameInfo** rp; // call stack pointer
101 void* eor; // first unusable word after the call stack
102 VMSideExit* lastTreeExitGuard; // guard we exited on during a tree call
103 VMSideExit* lastTreeCallGuard; // guard we want to grow from if the tree
104 // call exit guard mismatched
105 void* rpAtLastTreeCall; // value of rp at innermost tree call guard
106 VMSideExit* outermostTreeExitGuard; // the last side exit returned by js_CallTree
107 TreeFragment* outermostTree; // the outermost tree we initially invoked
108 uintN* inlineCallCountp; // inline call count counter
109 VMSideExit** innermostNestedGuardp;
110 VMSideExit* innermost;
111 uint64 startTime;
112 TracerState* prev;
114 // Used by _FAIL builtins; see jsbuiltins.h. The builtin sets the
115 // JSBUILTIN_BAILED bit if it bails off trace and the JSBUILTIN_ERROR bit
116 // if an error or exception occurred.
117 uint32 builtinStatus;
119 // Used to communicate the location of the return value in case of a deep bail.
120 double* deepBailSp;
122 // Used when calling natives from trace to root the vp vector.
123 uintN nativeVpLen;
124 js::Value* nativeVp;
126 TracerState(JSContext *cx, TraceMonitor *tm, TreeFragment *ti,
127 uintN &inlineCallCountp, VMSideExit** innermostNestedGuardp);
128 ~TracerState();
132 * Storage for the execution state and store during trace execution. Generated
133 * code depends on the fact that the globals begin |MAX_NATIVE_STACK_SLOTS|
134 * doubles after the stack begins. Thus, on trace, |TracerState::eos| holds a
135 * pointer to the first global.
137 struct TraceNativeStorage
139 double stack_global_buf[MAX_NATIVE_STACK_SLOTS + GLOBAL_SLOTS_BUFFER_SIZE];
140 FrameInfo *callstack_buf[MAX_CALL_STACK_ENTRIES];
142 double *stack() { return stack_global_buf; }
143 double *global() { return stack_global_buf + MAX_NATIVE_STACK_SLOTS; }
144 FrameInfo **callstack() { return callstack_buf; }
147 /* Holds data to track a single globa. */
148 struct GlobalState {
149 JSObject* globalObj;
150 uint32 globalShape;
151 SlotList* globalSlots;
155 * Trace monitor. Every JSCompartment has an associated trace monitor
156 * that keeps track of loop frequencies for all JavaScript code loaded
157 * into that runtime.
159 struct TraceMonitor {
161 * The context currently executing JIT-compiled code in this compartment, or
162 * NULL if none. Among other things, this can in certain cases prevent
163 * last-ditch GC and suppress calls to JS_ReportOutOfMemory.
165 * !tracecx && !recorder: not on trace
166 * !tracecx && recorder: recording
167 * tracecx && !recorder: executing a trace
168 * tracecx && recorder: executing inner loop, recording outer loop
170 JSContext *tracecx;
173 * State for the current tree execution. bailExit is valid if the tree has
174 * called back into native code via a _FAIL builtin and has not yet bailed,
175 * else garbage (NULL in debug builds).
177 js::TracerState *tracerState;
178 js::VMSideExit *bailExit;
180 /* Counts the number of iterations run by the currently executing trace. */
181 unsigned iterationCounter;
184 * Cached storage to use when executing on trace. While we may enter nested
185 * traces, we always reuse the outer trace's storage, so never need more
186 * than of these.
188 TraceNativeStorage *storage;
191 * There are 4 allocators here. This might seem like overkill, but they
192 * have different lifecycles, and by keeping them separate we keep the
193 * amount of retained memory down significantly. They are flushed (ie.
194 * all the allocated memory is freed) periodically.
196 * - dataAlloc has the lifecycle of the monitor. It's flushed only when
197 * the monitor is flushed. It's used for fragments.
199 * - traceAlloc has the same flush lifecycle as the dataAlloc, but it is
200 * also *marked* when a recording starts and rewinds to the mark point
201 * if recording aborts. So you can put things in it that are only
202 * reachable on a successful record/compile cycle like GuardRecords and
203 * SideExits.
205 * - tempAlloc is flushed after each recording, successful or not. It's
206 * used to store LIR code and for all other elements in the LIR
207 * pipeline.
209 * - codeAlloc has the same lifetime as dataAlloc, but its API is
210 * different (CodeAlloc vs. VMAllocator). It's used for native code.
211 * It's also a good idea to keep code and data separate to avoid I-cache
212 * vs. D-cache issues.
214 VMAllocator* dataAlloc;
215 VMAllocator* traceAlloc;
216 VMAllocator* tempAlloc;
217 nanojit::CodeAlloc* codeAlloc;
218 nanojit::Assembler* assembler;
219 FrameInfoCache* frameCache;
221 /* This gets incremented every time the monitor is flushed. */
222 uintN flushEpoch;
224 Oracle* oracle;
225 TraceRecorder* recorder;
227 /* If we are profiling a loop, this tracks the current profile. Otherwise NULL. */
228 LoopProfile* profile;
230 GlobalState globalStates[MONITOR_N_GLOBAL_STATES];
231 TreeFragment *vmfragments[FRAGMENT_TABLE_SIZE];
232 RecordAttemptMap* recordAttempts;
234 /* A hashtable mapping PC values to loop profiles for those loops. */
235 LoopProfileMap* loopProfiles;
238 * Maximum size of the code cache before we start flushing. 1/16 of this
239 * size is used as threshold for the regular expression code cache.
241 uint32 maxCodeCacheBytes;
244 * If nonzero, do not flush the JIT cache after a deep bail. That would
245 * free JITted code pages that we will later return to. Instead, set the
246 * needFlush flag so that it can be flushed later.
248 JSBool needFlush;
250 // Cached temporary typemap to avoid realloc'ing every time we create one.
251 // This must be used in only one place at a given time. It must be cleared
252 // before use.
253 TypeMap* cachedTempTypeMap;
255 /* Scripts with recorded fragments. */
256 TracedScriptSet tracedScripts;
258 #ifdef DEBUG
259 /* Fields needed for fragment/guard profiling. */
260 nanojit::Seq<nanojit::Fragment*>* branches;
261 uint32 lastFragID;
263 * profAlloc has a lifetime which spans exactly from InitJIT to
264 * FinishJIT.
266 VMAllocator* profAlloc;
267 FragStatsMap* profTab;
268 #endif
270 bool ontrace() const {
271 return !!tracecx;
274 /* Flush the JIT cache. */
275 void flush();
277 /* Sweep any cache entry pointing to dead GC things. */
278 void sweep(JSContext *cx);
280 /* Mark any tracer stacks that are active. */
281 void mark(JSTracer *trc);
283 bool outOfMemory() const;
286 namespace mjit {
287 class JaegerCompartment;
291 /* Number of potentially reusable scriptsToGC to search for the eval cache. */
292 #ifndef JS_EVAL_CACHE_SHIFT
293 # define JS_EVAL_CACHE_SHIFT 6
294 #endif
295 #define JS_EVAL_CACHE_SIZE JS_BIT(JS_EVAL_CACHE_SHIFT)
297 #ifdef DEBUG
298 # define EVAL_CACHE_METER_LIST(_) _(probe), _(hit), _(step), _(noscope)
299 # define identity(x) x
301 struct JSEvalCacheMeter {
302 uint64 EVAL_CACHE_METER_LIST(identity);
305 # undef identity
306 #endif
308 namespace js {
310 class NativeIterCache {
311 static const size_t SIZE = size_t(1) << 8;
313 /* Cached native iterators. */
314 JSObject *data[SIZE];
316 static size_t getIndex(uint32 key) {
317 return size_t(key) % SIZE;
320 public:
321 /* Native iterator most recently started. */
322 JSObject *last;
324 NativeIterCache()
325 : last(NULL) {
326 PodArrayZero(data);
329 void purge() {
330 PodArrayZero(data);
331 last = NULL;
334 JSObject *get(uint32 key) const {
335 return data[getIndex(key)];
338 void set(uint32 key, JSObject *iterobj) {
339 data[getIndex(key)] = iterobj;
344 * A single-entry cache for some base-10 double-to-string conversions. This
345 * helps date-format-xparb.js. It also avoids skewing the results for
346 * v8-splay.js when measured by the SunSpider harness, where the splay tree
347 * initialization (which includes many repeated double-to-string conversions)
348 * is erroneously included in the measurement; see bug 562553.
350 class DtoaCache {
351 double d;
352 jsint base;
353 JSString *s; // if s==NULL, d and base are not valid
354 public:
355 DtoaCache() : s(NULL) {}
356 void purge() { s = NULL; }
358 JSString *lookup(jsint base, double d) {
359 return this->s && base == this->base && d == this->d ? this->s : NULL;
362 void cache(jsint base, double d, JSString *s) {
363 this->base = base;
364 this->d = d;
365 this->s = s;
370 } /* namespace js */
372 struct JS_FRIEND_API(JSCompartment) {
373 JSRuntime *rt;
374 JSPrincipals *principals;
375 js::gc::Chunk *chunk;
377 js::gc::ArenaList arenas[js::gc::FINALIZE_LIMIT];
378 js::gc::FreeLists freeLists;
380 size_t gcBytes;
381 size_t gcTriggerBytes;
382 size_t gcLastBytes;
384 #ifdef JS_GCMETER
385 js::gc::JSGCArenaStats compartmentStats[js::gc::FINALIZE_LIMIT];
386 #endif
388 #ifdef JS_TRACER
389 /* Trace-tree JIT recorder/interpreter state. */
390 js::TraceMonitor traceMonitor;
391 #endif
393 /* Hashed lists of scripts created by eval to garbage-collect. */
394 JSScript *scriptsToGC[JS_EVAL_CACHE_SIZE];
396 #ifdef DEBUG
397 JSEvalCacheMeter evalCacheMeter;
398 #endif
400 void *data;
401 bool active; // GC flag, whether there are active frames
402 js::WrapperMap crossCompartmentWrappers;
404 #ifdef JS_METHODJIT
405 js::mjit::JaegerCompartment *jaegerCompartment;
406 #endif
409 * Shared scope property tree, and arena-pool for allocating its nodes.
411 js::PropertyTree propertyTree;
413 #ifdef DEBUG
414 /* Property metering. */
415 jsrefcount livePropTreeNodes;
416 jsrefcount totalPropTreeNodes;
417 jsrefcount propTreeKidsChunks;
418 jsrefcount liveDictModeNodes;
419 #endif
422 * Runtime-shared empty scopes for well-known built-in objects that lack
423 * class prototypes (the usual locus of an emptyShape). Mnemonic: ABCDEW
425 js::EmptyShape *emptyArgumentsShape;
426 js::EmptyShape *emptyBlockShape;
427 js::EmptyShape *emptyCallShape;
428 js::EmptyShape *emptyDeclEnvShape;
429 js::EmptyShape *emptyEnumeratorShape;
430 js::EmptyShape *emptyWithShape;
432 typedef js::HashSet<js::EmptyShape *,
433 js::DefaultHasher<js::EmptyShape *>,
434 js::SystemAllocPolicy> EmptyShapeSet;
436 EmptyShapeSet emptyShapes;
438 bool debugMode; // true iff debug mode on
439 JSCList scripts; // scripts in this compartment
441 JSC::ExecutableAllocator *regExpAllocator;
443 js::NativeIterCache nativeIterCache;
445 js::ToSourceCache toSourceCache;
447 JSCompartment(JSRuntime *rt);
448 ~JSCompartment();
450 bool init();
452 /* Mark cross-compartment pointers. */
453 void markCrossCompartment(JSTracer *trc);
455 /* Mark this compartment's local roots. */
456 void mark(JSTracer *trc);
458 bool wrap(JSContext *cx, js::Value *vp);
459 bool wrap(JSContext *cx, JSString **strp);
460 bool wrap(JSContext *cx, JSObject **objp);
461 bool wrapId(JSContext *cx, jsid *idp);
462 bool wrap(JSContext *cx, js::PropertyOp *op);
463 bool wrap(JSContext *cx, js::StrictPropertyOp *op);
464 bool wrap(JSContext *cx, js::PropertyDescriptor *desc);
465 bool wrap(JSContext *cx, js::AutoIdVector &props);
467 void sweep(JSContext *cx, uint32 releaseInterval);
468 void purge(JSContext *cx);
469 void finishArenaLists();
470 void finalizeObjectArenaLists(JSContext *cx);
471 void finalizeStringArenaLists(JSContext *cx);
472 bool arenaListsAreEmpty();
474 void setGCLastBytes(size_t lastBytes);
476 js::DtoaCache dtoaCache;
478 private:
479 js::MathCache *mathCache;
481 js::MathCache *allocMathCache(JSContext *cx);
483 bool marked;
485 typedef js::HashMap<jsbytecode*,
486 size_t,
487 js::DefaultHasher<jsbytecode*>,
488 js::SystemAllocPolicy> BackEdgeMap;
490 BackEdgeMap backEdgeTable;
492 public:
493 js::MathCache *getMathCache(JSContext *cx) {
494 return mathCache ? mathCache : allocMathCache(cx);
497 bool isMarked() { return marked; }
498 void clearMark() { marked = false; }
500 size_t backEdgeCount(jsbytecode *pc) const;
501 size_t incBackEdgeCount(jsbytecode *pc);
504 #define JS_SCRIPTS_TO_GC(cx) ((cx)->compartment->scriptsToGC)
505 #define JS_PROPERTY_TREE(cx) ((cx)->compartment->propertyTree)
507 #ifdef DEBUG
508 #define JS_COMPARTMENT_METER(x) x
509 #else
510 #define JS_COMPARTMENT_METER(x)
511 #endif
514 * N.B. JS_ON_TRACE(cx) is true if JIT code is on the stack in the current
515 * thread, regardless of whether cx is the context in which that trace is
516 * executing. cx must be a context on the current thread.
518 static inline bool
519 JS_ON_TRACE(JSContext *cx)
521 #ifdef JS_TRACER
522 if (JS_THREAD_DATA(cx)->onTraceCompartment)
523 return JS_THREAD_DATA(cx)->onTraceCompartment->traceMonitor.ontrace();
524 #endif
525 return false;
528 #ifdef JS_TRACER
529 static inline js::TraceMonitor *
530 JS_TRACE_MONITOR_ON_TRACE(JSContext *cx)
532 JS_ASSERT(JS_ON_TRACE(cx));
533 return &JS_THREAD_DATA(cx)->onTraceCompartment->traceMonitor;
537 * Only call this directly from the interpreter loop or the method jit.
538 * Otherwise, we may get the wrong compartment, and thus the wrong
539 * TraceMonitor.
541 static inline js::TraceMonitor *
542 JS_TRACE_MONITOR_FROM_CONTEXT(JSContext *cx)
544 return &cx->compartment->traceMonitor;
546 #endif
548 static inline js::TraceRecorder *
549 TRACE_RECORDER(JSContext *cx)
551 #ifdef JS_TRACER
552 if (JS_THREAD_DATA(cx)->recordingCompartment)
553 return JS_THREAD_DATA(cx)->recordingCompartment->traceMonitor.recorder;
554 #endif
555 return NULL;
558 static inline js::LoopProfile *
559 TRACE_PROFILER(JSContext *cx)
561 #ifdef JS_TRACER
562 if (JS_THREAD_DATA(cx)->profilingCompartment)
563 return JS_THREAD_DATA(cx)->profilingCompartment->traceMonitor.profile;
564 #endif
565 return NULL;
568 namespace js {
569 static inline MathCache *
570 GetMathCache(JSContext *cx)
572 return cx->compartment->getMathCache(cx);
576 #ifdef DEBUG
577 # define EVAL_CACHE_METER(x) (cx->compartment->evalCacheMeter.x++)
578 #else
579 # define EVAL_CACHE_METER(x) ((void) 0)
580 #endif
582 #ifdef _MSC_VER
583 #pragma warning(pop)
584 #endif
586 namespace js {
588 class PreserveCompartment {
589 protected:
590 JSContext *cx;
591 private:
592 JSCompartment *oldCompartment;
593 JS_DECL_USE_GUARD_OBJECT_NOTIFIER
594 public:
595 PreserveCompartment(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) : cx(cx) {
596 JS_GUARD_OBJECT_NOTIFIER_INIT;
597 oldCompartment = cx->compartment;
600 ~PreserveCompartment() {
601 cx->compartment = oldCompartment;
605 class SwitchToCompartment : public PreserveCompartment {
606 public:
607 SwitchToCompartment(JSContext *cx, JSCompartment *newCompartment) : PreserveCompartment(cx) {
608 cx->compartment = newCompartment;
611 SwitchToCompartment(JSContext *cx, JSObject *target) : PreserveCompartment(cx) {
612 cx->compartment = target->getCompartment();
616 class AssertCompartmentUnchanged {
617 protected:
618 JSContext * const cx;
619 JSCompartment * const oldCompartment;
620 JS_DECL_USE_GUARD_OBJECT_NOTIFIER
621 public:
622 AssertCompartmentUnchanged(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM)
623 : cx(cx), oldCompartment(cx->compartment) {
624 JS_GUARD_OBJECT_NOTIFIER_INIT;
627 ~AssertCompartmentUnchanged() {
628 JS_ASSERT(cx->compartment == oldCompartment);
634 #endif /* jscompartment_h___ */