Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jscompartment.h
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
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/
10  *
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.
15  *
16  * The Original Code is SpiderMonkey code.
17  *
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.
22  *
23  * Contributor(s):
24  *
25  *
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.
37  *
38  * ***** END LICENSE BLOCK ***** */
39
40 #ifndef jscompartment_h___
41 #define jscompartment_h___
42
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"
51
52 #ifdef _MSC_VER
53 #pragma warning(push)
54 #pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
55 #endif
56
57 namespace JSC {
58
59 class ExecutableAllocator;
60
61 }
62
63 namespace js {
64
65 /* Holds the number of recording attemps for an address. */
66 typedef HashMap<jsbytecode*,
67                 size_t,
68                 DefaultHasher<jsbytecode*>,
69                 SystemAllocPolicy> RecordAttemptMap;
70
71 /* Holds the profile data for loops. */
72 typedef HashMap<jsbytecode*,
73                 LoopProfile*,
74                 DefaultHasher<jsbytecode*>,
75                 SystemAllocPolicy> LoopProfileMap;
76
77 class Oracle;
78
79 typedef HashSet<JSScript *,
80                 DefaultHasher<JSScript *>,
81                 SystemAllocPolicy> TracedScriptSet;
82
83 typedef HashMap<JSFunction *,
84                 JSString *,
85                 DefaultHasher<JSFunction *>,
86                 SystemAllocPolicy> ToSourceCache;
87
88 struct TraceMonitor;
89
90 /* Holds the execution state during trace execution. */
91 struct TracerState
92 {
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;
113
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;
118
119     // Used to communicate the location of the return value in case of a deep bail.
120     double*        deepBailSp;
121
122     // Used when calling natives from trace to root the vp vector.
123     uintN          nativeVpLen;
124     js::Value*     nativeVp;
125
126     TracerState(JSContext *cx, TraceMonitor *tm, TreeFragment *ti,
127                 uintN &inlineCallCountp, VMSideExit** innermostNestedGuardp);
128     ~TracerState();
129 };
130
131 /*
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.
136  */
137 struct TraceNativeStorage
138 {
139     double stack_global_buf[MAX_NATIVE_STACK_SLOTS + GLOBAL_SLOTS_BUFFER_SIZE];
140     FrameInfo *callstack_buf[MAX_CALL_STACK_ENTRIES];
141
142     double *stack() { return stack_global_buf; }
143     double *global() { return stack_global_buf + MAX_NATIVE_STACK_SLOTS; }
144     FrameInfo **callstack() { return callstack_buf; }
145 };
146
147 /* Holds data to track a single globa. */
148 struct GlobalState {
149     JSObject*               globalObj;
150     uint32                  globalShape;
151     SlotList*               globalSlots;
152 };
153
154 /*
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.
158  */
159 struct TraceMonitor {
160     /*
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.
164      *
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
169      */
170     JSContext               *tracecx;
171
172     /*
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).
176      */
177     js::TracerState     *tracerState;
178     js::VMSideExit      *bailExit;
179
180     /* Counts the number of iterations run by the currently executing trace. */
181     unsigned                iterationCounter;
182
183     /*
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.
187      */
188     TraceNativeStorage      *storage;
189
190     /*
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.
195      *
196      * - dataAlloc has the lifecycle of the monitor.  It's flushed only when
197      *   the monitor is flushed.  It's used for fragments.
198      *
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.
204      *
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.
208      *
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.
213      */
214     VMAllocator*            dataAlloc;
215     VMAllocator*            traceAlloc;
216     VMAllocator*            tempAlloc;
217     nanojit::CodeAlloc*     codeAlloc;
218     nanojit::Assembler*     assembler;
219     FrameInfoCache*         frameCache;
220
221     /* This gets incremented every time the monitor is flushed. */
222     uintN                   flushEpoch;
223
224     Oracle*                 oracle;
225     TraceRecorder*          recorder;
226
227     /* If we are profiling a loop, this tracks the current profile. Otherwise NULL. */
228     LoopProfile*            profile;
229
230     GlobalState             globalStates[MONITOR_N_GLOBAL_STATES];
231     TreeFragment            *vmfragments[FRAGMENT_TABLE_SIZE];
232     RecordAttemptMap*       recordAttempts;
233
234     /* A hashtable mapping PC values to loop profiles for those loops. */
235     LoopProfileMap*         loopProfiles;
236
237     /*
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.
240      */
241     uint32                  maxCodeCacheBytes;
242
243     /*
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.
247      */
248     JSBool                  needFlush;
249
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;
254
255     /* Scripts with recorded fragments. */
256     TracedScriptSet         tracedScripts;
257
258 #ifdef DEBUG
259     /* Fields needed for fragment/guard profiling. */
260     nanojit::Seq<nanojit::Fragment*>* branches;
261     uint32                  lastFragID;
262     /*
263      * profAlloc has a lifetime which spans exactly from InitJIT to
264      * FinishJIT.
265      */
266     VMAllocator*            profAlloc;
267     FragStatsMap*           profTab;
268 #endif
269
270     bool ontrace() const {
271         return !!tracecx;
272     }
273
274     /* Flush the JIT cache. */
275     void flush();
276
277     /* Sweep any cache entry pointing to dead GC things. */
278     void sweep(JSContext *cx);
279
280     /* Mark any tracer stacks that are active. */
281     void mark(JSTracer *trc);
282
283     bool outOfMemory() const;
284 };
285
286 namespace mjit {
287 class JaegerCompartment;
288 }
289 }
290
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)
296
297 #ifdef DEBUG
298 # define EVAL_CACHE_METER_LIST(_)   _(probe), _(hit), _(step), _(noscope)
299 # define identity(x)                x
300
301 struct JSEvalCacheMeter {
302     uint64 EVAL_CACHE_METER_LIST(identity);
303 };
304
305 # undef identity
306 #endif
307
308 namespace js {
309
310 class NativeIterCache {
311     static const size_t SIZE = size_t(1) << 8;
312     
313     /* Cached native iterators. */
314     JSObject            *data[SIZE];
315
316     static size_t getIndex(uint32 key) {
317         return size_t(key) % SIZE;
318     }
319
320   public:
321     /* Native iterator most recently started. */
322     JSObject            *last;
323
324     NativeIterCache()
325       : last(NULL) {
326         PodArrayZero(data);
327     }
328
329     void purge() {
330         PodArrayZero(data);
331         last = NULL;
332     }
333
334     JSObject *get(uint32 key) const {
335         return data[getIndex(key)];
336     }
337
338     void set(uint32 key, JSObject *iterobj) {
339         data[getIndex(key)] = iterobj;
340     }
341 };
342
343 /*
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.
349  */
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; }
357
358     JSString *lookup(jsint base, double d) {
359         return this->s && base == this->base && d == this->d ? this->s : NULL;
360     }
361
362     void cache(jsint base, double d, JSString *s) {
363         this->base = base;
364         this->d = d;
365         this->s = s;
366     }
367
368 };
369
370 } /* namespace js */
371
372 struct JS_FRIEND_API(JSCompartment) {
373     JSRuntime                    *rt;
374     JSPrincipals                 *principals;
375     js::gc::Chunk                *chunk;
376
377     js::gc::ArenaList            arenas[js::gc::FINALIZE_LIMIT];
378     js::gc::FreeLists            freeLists;
379
380     size_t                       gcBytes;
381     size_t                       gcTriggerBytes;
382     size_t                       gcLastBytes;
383
384 #ifdef JS_GCMETER
385     js::gc::JSGCArenaStats       compartmentStats[js::gc::FINALIZE_LIMIT];
386 #endif
387
388 #ifdef JS_TRACER
389     /* Trace-tree JIT recorder/interpreter state. */
390     js::TraceMonitor             traceMonitor;
391 #endif
392
393     /* Hashed lists of scripts created by eval to garbage-collect. */
394     JSScript                     *scriptsToGC[JS_EVAL_CACHE_SIZE];
395
396 #ifdef DEBUG
397     JSEvalCacheMeter             evalCacheMeter;
398 #endif
399
400     void                         *data;
401     bool                         active;  // GC flag, whether there are active frames
402     js::WrapperMap               crossCompartmentWrappers;
403
404 #ifdef JS_METHODJIT
405     js::mjit::JaegerCompartment  *jaegerCompartment;
406 #endif
407
408     /*
409      * Shared scope property tree, and arena-pool for allocating its nodes.
410      */
411     js::PropertyTree             propertyTree;
412
413 #ifdef DEBUG
414     /* Property metering. */
415     jsrefcount                   livePropTreeNodes;
416     jsrefcount                   totalPropTreeNodes;
417     jsrefcount                   propTreeKidsChunks;
418     jsrefcount                   liveDictModeNodes;
419 #endif
420
421     /*
422      * Runtime-shared empty scopes for well-known built-in objects that lack
423      * class prototypes (the usual locus of an emptyShape). Mnemonic: ABCDEW
424      */
425     js::EmptyShape               *emptyArgumentsShape;
426     js::EmptyShape               *emptyBlockShape;
427     js::EmptyShape               *emptyCallShape;
428     js::EmptyShape               *emptyDeclEnvShape;
429     js::EmptyShape               *emptyEnumeratorShape;
430     js::EmptyShape               *emptyWithShape;
431
432     typedef js::HashSet<js::EmptyShape *,
433                         js::DefaultHasher<js::EmptyShape *>,
434                         js::SystemAllocPolicy> EmptyShapeSet;
435
436     EmptyShapeSet                emptyShapes;
437
438     bool                         debugMode;  // true iff debug mode on
439     JSCList                      scripts;    // scripts in this compartment
440
441     JSC::ExecutableAllocator     *regExpAllocator;
442
443     js::NativeIterCache          nativeIterCache;
444
445     js::ToSourceCache            toSourceCache;
446
447     JSCompartment(JSRuntime *rt);
448     ~JSCompartment();
449
450     bool init();
451
452     /* Mark cross-compartment wrappers. */
453     void markCrossCompartment(JSTracer *trc);
454
455     /* Mark this compartment's local roots. */
456     void mark(JSTracer *trc);
457
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);
466
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();
473
474     void setGCLastBytes(size_t lastBytes);
475
476     js::DtoaCache dtoaCache;
477
478   private:
479     js::MathCache                *mathCache;
480
481     js::MathCache *allocMathCache(JSContext *cx);
482
483     bool                         marked;
484     
485     typedef js::HashMap<jsbytecode*,
486                         size_t,
487                         js::DefaultHasher<jsbytecode*>,
488                         js::SystemAllocPolicy> BackEdgeMap;
489
490     BackEdgeMap                  backEdgeTable;
491
492     JSCompartment *thisForCtor() { return this; }
493   public:
494     js::MathCache *getMathCache(JSContext *cx) {
495         return mathCache ? mathCache : allocMathCache(cx);
496     }
497
498     bool isMarked() { return marked; }
499     void clearMark() { marked = false; }
500
501     size_t backEdgeCount(jsbytecode *pc) const;
502     size_t incBackEdgeCount(jsbytecode *pc);
503 };
504
505 #define JS_SCRIPTS_TO_GC(cx)    ((cx)->compartment->scriptsToGC)
506 #define JS_PROPERTY_TREE(cx)    ((cx)->compartment->propertyTree)
507
508 #ifdef DEBUG
509 #define JS_COMPARTMENT_METER(x) x
510 #else
511 #define JS_COMPARTMENT_METER(x)
512 #endif
513
514 /*
515  * N.B. JS_ON_TRACE(cx) is true if JIT code is on the stack in the current
516  * thread, regardless of whether cx is the context in which that trace is
517  * executing. cx must be a context on the current thread.
518  */
519 static inline bool
520 JS_ON_TRACE(JSContext *cx)
521 {
522 #ifdef JS_TRACER
523     if (JS_THREAD_DATA(cx)->onTraceCompartment)
524         return JS_THREAD_DATA(cx)->onTraceCompartment->traceMonitor.ontrace();
525 #endif
526     return false;
527 }
528
529 #ifdef JS_TRACER
530 static inline js::TraceMonitor *
531 JS_TRACE_MONITOR_ON_TRACE(JSContext *cx)
532 {
533     JS_ASSERT(JS_ON_TRACE(cx));
534     return &JS_THREAD_DATA(cx)->onTraceCompartment->traceMonitor;
535 }
536
537 /*
538  * Only call this directly from the interpreter loop or the method jit.
539  * Otherwise, we may get the wrong compartment, and thus the wrong
540  * TraceMonitor.
541  */
542 static inline js::TraceMonitor *
543 JS_TRACE_MONITOR_FROM_CONTEXT(JSContext *cx)
544 {
545     return &cx->compartment->traceMonitor;
546 }
547 #endif
548
549 static inline js::TraceRecorder *
550 TRACE_RECORDER(JSContext *cx)
551 {
552 #ifdef JS_TRACER
553     if (JS_THREAD_DATA(cx)->recordingCompartment)
554         return JS_THREAD_DATA(cx)->recordingCompartment->traceMonitor.recorder;
555 #endif
556     return NULL;
557 }
558
559 static inline js::LoopProfile *
560 TRACE_PROFILER(JSContext *cx)
561 {
562 #ifdef JS_TRACER
563     if (JS_THREAD_DATA(cx)->profilingCompartment)
564         return JS_THREAD_DATA(cx)->profilingCompartment->traceMonitor.profile;
565 #endif
566     return NULL;
567 }
568
569 namespace js {
570 static inline MathCache *
571 GetMathCache(JSContext *cx)
572 {
573     return cx->compartment->getMathCache(cx);
574 }
575 }
576
577 #ifdef DEBUG
578 # define EVAL_CACHE_METER(x)    (cx->compartment->evalCacheMeter.x++)
579 #else
580 # define EVAL_CACHE_METER(x)    ((void) 0)
581 #endif
582
583 #ifdef _MSC_VER
584 #pragma warning(pop)
585 #endif
586
587 namespace js {
588
589 class PreserveCompartment {
590   protected:
591     JSContext *cx;
592   private:
593     JSCompartment *oldCompartment;
594     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
595   public:
596      PreserveCompartment(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) : cx(cx) {
597         JS_GUARD_OBJECT_NOTIFIER_INIT;
598         oldCompartment = cx->compartment;
599     }
600
601     ~PreserveCompartment() {
602         cx->compartment = oldCompartment;
603     }
604 };
605
606 class SwitchToCompartment : public PreserveCompartment {
607   public:
608     SwitchToCompartment(JSContext *cx, JSCompartment *newCompartment) : PreserveCompartment(cx) {
609         cx->compartment = newCompartment;
610     }
611
612     SwitchToCompartment(JSContext *cx, JSObject *target) : PreserveCompartment(cx) {
613         cx->compartment = target->getCompartment();
614     }
615 };
616
617 class AssertCompartmentUnchanged {
618   protected:
619     JSContext * const cx;
620     JSCompartment * const oldCompartment;
621     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
622   public:
623      AssertCompartmentUnchanged(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM)
624      : cx(cx), oldCompartment(cx->compartment) {
625         JS_GUARD_OBJECT_NOTIFIER_INIT;
626     }
627
628     ~AssertCompartmentUnchanged() {
629         JS_ASSERT(cx->compartment == oldCompartment);
630     }
631 };
632
633 }
634
635 #endif /* jscompartment_h___ */