PageRenderTime 53ms CodeModel.GetById 18ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 1ms

/js/src/jscompartment.h

http://github.com/zpao/v8monkey
C Header | 554 lines | 344 code | 110 blank | 100 comment | 11 complexity | 76291842653b39afbbe7505d26fdacc8 MD5 | raw file
  1/* -*- Mode: C++; tab-width: 4; 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 "mozilla/Attributes.h"
 44
 45#include "jsclist.h"
 46#include "jscntxt.h"
 47#include "jsfun.h"
 48#include "jsgc.h"
 49#include "jsgcstats.h"
 50#include "jsobj.h"
 51#include "jsscope.h"
 52#include "vm/GlobalObject.h"
 53#include "vm/RegExpObject.h"
 54
 55#ifdef _MSC_VER
 56#pragma warning(push)
 57#pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
 58#endif
 59
 60namespace js {
 61
 62typedef HashMap<JSFunction *,
 63                JSString *,
 64                DefaultHasher<JSFunction *>,
 65                SystemAllocPolicy> ToSourceCache;
 66
 67namespace mjit {
 68class JaegerCompartment;
 69}
 70
 71/* Defined in jsapi.cpp */
 72extern Class dummy_class;
 73
 74} /* namespace js */
 75
 76#ifndef JS_EVAL_CACHE_SHIFT
 77# define JS_EVAL_CACHE_SHIFT        6
 78#endif
 79
 80/* Number of buckets in the hash of eval scripts. */
 81#define JS_EVAL_CACHE_SIZE          JS_BIT(JS_EVAL_CACHE_SHIFT)
 82
 83namespace js {
 84
 85class NativeIterCache {
 86    static const size_t SIZE = size_t(1) << 8;
 87    
 88    /* Cached native iterators. */
 89    JSObject            *data[SIZE];
 90
 91    static size_t getIndex(uint32_t key) {
 92        return size_t(key) % SIZE;
 93    }
 94
 95  public:
 96    /* Native iterator most recently started. */
 97    JSObject            *last;
 98
 99    NativeIterCache()
100      : last(NULL) {
101        PodArrayZero(data);
102    }
103
104    void purge() {
105        PodArrayZero(data);
106        last = NULL;
107    }
108
109    JSObject *get(uint32_t key) const {
110        return data[getIndex(key)];
111    }
112
113    void set(uint32_t key, JSObject *iterobj) {
114        data[getIndex(key)] = iterobj;
115    }
116};
117
118class MathCache;
119
120/*
121 * A single-entry cache for some base-10 double-to-string conversions. This
122 * helps date-format-xparb.js.  It also avoids skewing the results for
123 * v8-splay.js when measured by the SunSpider harness, where the splay tree
124 * initialization (which includes many repeated double-to-string conversions)
125 * is erroneously included in the measurement; see bug 562553.
126 */
127class DtoaCache {
128    double        d;
129    jsint         base;
130    JSFixedString *s;      // if s==NULL, d and base are not valid
131  public:
132    DtoaCache() : s(NULL) {}
133    void purge() { s = NULL; }
134
135    JSFixedString *lookup(jsint base, double d) {
136        return this->s && base == this->base && d == this->d ? this->s : NULL;
137    }
138
139    void cache(jsint base, double d, JSFixedString *s) {
140        this->base = base;
141        this->d = d;
142        this->s = s;
143    }
144
145};
146
147struct ScriptFilenameEntry
148{
149    bool marked;
150    char filename[1];
151};
152
153struct ScriptFilenameHasher
154{
155    typedef const char *Lookup;
156    static HashNumber hash(const char *l) { return JS_HashString(l); }
157    static bool match(const ScriptFilenameEntry *e, const char *l) {
158        return strcmp(e->filename, l) == 0;
159    }
160};
161
162typedef HashSet<ScriptFilenameEntry *,
163                ScriptFilenameHasher,
164                SystemAllocPolicy> ScriptFilenameTable;
165
166} /* namespace js */
167
168namespace JS {
169struct TypeInferenceSizes;
170}
171
172struct JSCompartment
173{
174    JSRuntime                    *rt;
175    JSPrincipals                 *principals;
176
177    js::gc::ArenaLists           arenas;
178
179    bool                         needsBarrier_;
180    js::GCMarker                 *gcIncrementalTracer;
181
182    bool needsBarrier() {
183        return needsBarrier_;
184    }
185
186    js::GCMarker *barrierTracer() {
187        JS_ASSERT(needsBarrier_);
188        if (gcIncrementalTracer)
189            return gcIncrementalTracer;
190        return createBarrierTracer();
191    }
192
193    size_t                       gcBytes;
194    size_t                       gcTriggerBytes;
195    size_t                       gcLastBytes;
196    size_t                       gcMaxMallocBytes;
197
198    bool                         hold;
199    bool                         isSystemCompartment;
200
201    /*
202     * Pool for analysis and intermediate type information in this compartment.
203     * Cleared on every GC, unless the GC happens during analysis (indicated
204     * by activeAnalysis, which is implied by activeInference).
205     */
206    static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 128 * 1024;
207    js::LifoAlloc                typeLifoAlloc;
208    bool                         activeAnalysis;
209    bool                         activeInference;
210
211    /* Type information about the scripts and objects in this compartment. */
212    js::types::TypeCompartment   types;
213
214  public:
215    /* Hashed lists of scripts created by eval to garbage-collect. */
216    JSScript                     *evalCache[JS_EVAL_CACHE_SIZE];
217
218    void                         *data;
219    bool                         active;  // GC flag, whether there are active frames
220    bool                         hasDebugModeCodeToDrop;
221    js::WrapperMap               crossCompartmentWrappers;
222
223#ifdef JS_METHODJIT
224  private:
225    /* This is created lazily because many compartments don't need it. */
226    js::mjit::JaegerCompartment  *jaegerCompartment_;
227    /*
228     * This function is here so that xpconnect/src/xpcjsruntime.cpp doesn't
229     * need to see the declaration of JaegerCompartment, which would require
230     * #including MethodJIT.h into xpconnect/src/xpcjsruntime.cpp, which is
231     * difficult due to reasons explained in bug 483677.
232     */
233  public:
234    bool hasJaegerCompartment() {
235        return !!jaegerCompartment_;
236    }
237
238    js::mjit::JaegerCompartment *jaegerCompartment() const {
239        JS_ASSERT(jaegerCompartment_);
240        return jaegerCompartment_;
241    }
242
243    bool ensureJaegerCompartmentExists(JSContext *cx);
244
245    size_t sizeOfMjitCode() const;
246#endif
247
248    js::RegExpCompartment        regExps;
249
250    size_t sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf);
251    void sizeOfTypeInferenceData(JSContext *cx, JS::TypeInferenceSizes *stats,
252                                 JSMallocSizeOfFun mallocSizeOf);
253
254    /*
255     * Shared scope property tree, and arena-pool for allocating its nodes.
256     */
257    js::PropertyTree             propertyTree;
258
259#ifdef DEBUG
260    /* Property metering. */
261    jsrefcount                   livePropTreeNodes;
262    jsrefcount                   totalPropTreeNodes;
263    jsrefcount                   propTreeKidsChunks;
264    jsrefcount                   liveDictModeNodes;
265#endif
266
267    /* Set of all unowned base shapes in the compartment. */
268    js::BaseShapeSet             baseShapes;
269    void sweepBaseShapeTable(JSContext *cx);
270
271    /* Set of initial shapes in the compartment. */
272    js::InitialShapeSet          initialShapes;
273    void sweepInitialShapeTable(JSContext *cx);
274
275    /* Set of default 'new' or lazy types in the compartment. */
276    js::types::TypeObjectSet     newTypeObjects;
277    js::types::TypeObjectSet     lazyTypeObjects;
278    void sweepNewTypeObjectTable(JSContext *cx, js::types::TypeObjectSet &table);
279
280    js::types::TypeObject        *emptyTypeObject;
281
282    /* Get the default 'new' type for objects with a NULL prototype. */
283    inline js::types::TypeObject *getEmptyType(JSContext *cx);
284
285    js::types::TypeObject *getLazyType(JSContext *cx, JSObject *proto);
286
287    /* Cache to speed up object creation. */
288    js::NewObjectCache           newObjectCache;
289
290  private:
291    enum { DebugFromC = 1, DebugFromJS = 2 };
292
293    uintN                        debugModeBits;  // see debugMode() below
294    
295    /*
296     * Malloc counter to measure memory pressure for GC scheduling. It runs
297     * from gcMaxMallocBytes down to zero.
298     */
299    volatile ptrdiff_t           gcMallocBytes;
300
301  public:
302    js::NativeIterCache          nativeIterCache;
303
304    typedef js::Maybe<js::ToSourceCache> LazyToSourceCache;
305    LazyToSourceCache            toSourceCache;
306
307    js::ScriptFilenameTable      scriptFilenameTable;
308
309    JSCompartment(JSRuntime *rt);
310    ~JSCompartment();
311
312    bool init(JSContext *cx);
313
314    /* Mark cross-compartment wrappers. */
315    void markCrossCompartmentWrappers(JSTracer *trc);
316
317    bool wrap(JSContext *cx, js::Value *vp);
318    bool wrap(JSContext *cx, JSString **strp);
319    bool wrap(JSContext *cx, js::HeapPtrString *strp);
320    bool wrap(JSContext *cx, JSObject **objp);
321    bool wrapId(JSContext *cx, jsid *idp);
322    bool wrap(JSContext *cx, js::PropertyOp *op);
323    bool wrap(JSContext *cx, js::StrictPropertyOp *op);
324    bool wrap(JSContext *cx, js::PropertyDescriptor *desc);
325    bool wrap(JSContext *cx, js::AutoIdVector &props);
326
327    void markTypes(JSTracer *trc);
328    void sweep(JSContext *cx, bool releaseTypes);
329    void purge(JSContext *cx);
330
331    void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
332    void reduceGCTriggerBytes(size_t amount);
333    
334    void resetGCMallocBytes();
335    void setGCMaxMallocBytes(size_t value);
336    void updateMallocCounter(size_t nbytes) {
337        ptrdiff_t oldCount = gcMallocBytes;
338        ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes);
339        gcMallocBytes = newCount;
340        if (JS_UNLIKELY(newCount <= 0 && oldCount > 0))
341            onTooMuchMalloc();
342    }
343    
344    void onTooMuchMalloc();
345
346    js::DtoaCache dtoaCache;
347
348  private:
349    js::MathCache                *mathCache;
350
351    js::MathCache *allocMathCache(JSContext *cx);
352
353    /*
354     * Weak reference to each global in this compartment that is a debuggee.
355     * Each global has its own list of debuggers.
356     */
357    js::GlobalObjectSet              debuggees;
358
359  private:
360    JSCompartment *thisForCtor() { return this; }
361
362  public:
363    js::MathCache *getMathCache(JSContext *cx) {
364        return mathCache ? mathCache : allocMathCache(cx);
365    }
366
367    /*
368     * There are dueling APIs for debug mode. It can be enabled or disabled via
369     * JS_SetDebugModeForCompartment. It is automatically enabled and disabled
370     * by Debugger objects. Therefore debugModeBits has the DebugFromC bit set
371     * if the C API wants debug mode and the DebugFromJS bit set if debuggees
372     * is non-empty.
373     */
374    bool debugMode() const { return !!debugModeBits; }
375
376    /*
377     * True if any scripts from this compartment are on the JS stack in the
378     * calling thread. cx is a context in the calling thread, and it is assumed
379     * that no other thread is using this compartment.
380     */
381    bool hasScriptsOnStack(JSContext *cx);
382
383  private:
384    /* This is called only when debugMode() has just toggled. */
385    void updateForDebugMode(JSContext *cx);
386
387  public:
388    js::GlobalObjectSet &getDebuggees() { return debuggees; }
389    bool addDebuggee(JSContext *cx, js::GlobalObject *global);
390    void removeDebuggee(JSContext *cx, js::GlobalObject *global,
391                        js::GlobalObjectSet::Enum *debuggeesEnum = NULL);
392    bool setDebugModeFromC(JSContext *cx, bool b);
393
394    void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler);
395    void clearTraps(JSContext *cx);
396
397  private:
398    void sweepBreakpoints(JSContext *cx);
399
400    js::GCMarker *createBarrierTracer();
401
402  public:
403    js::WatchpointMap *watchpointMap;
404};
405
406#define JS_PROPERTY_TREE(cx)    ((cx)->compartment->propertyTree)
407
408namespace js {
409static inline MathCache *
410GetMathCache(JSContext *cx)
411{
412    return cx->compartment->getMathCache(cx);
413}
414}
415
416inline void
417JSContext::setCompartment(JSCompartment *compartment)
418{
419    this->compartment = compartment;
420    this->inferenceEnabled = compartment ? compartment->types.inferenceEnabled : false;
421}
422
423#ifdef _MSC_VER
424#pragma warning(pop)
425#endif
426
427namespace js {
428
429class PreserveCompartment {
430  protected:
431    JSContext *cx;
432  private:
433    JSCompartment *oldCompartment;
434    bool oldInferenceEnabled;
435    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
436  public:
437     PreserveCompartment(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) : cx(cx) {
438        JS_GUARD_OBJECT_NOTIFIER_INIT;
439        oldCompartment = cx->compartment;
440        oldInferenceEnabled = cx->inferenceEnabled;
441    }
442
443    ~PreserveCompartment() {
444        /* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
445        cx->compartment = oldCompartment;
446        cx->inferenceEnabled = oldInferenceEnabled;
447    }
448};
449
450class SwitchToCompartment : public PreserveCompartment {
451  public:
452    SwitchToCompartment(JSContext *cx, JSCompartment *newCompartment
453                        JS_GUARD_OBJECT_NOTIFIER_PARAM)
454        : PreserveCompartment(cx)
455    {
456        JS_GUARD_OBJECT_NOTIFIER_INIT;
457        cx->setCompartment(newCompartment);
458    }
459
460    SwitchToCompartment(JSContext *cx, JSObject *target JS_GUARD_OBJECT_NOTIFIER_PARAM)
461        : PreserveCompartment(cx)
462    {
463        JS_GUARD_OBJECT_NOTIFIER_INIT;
464        cx->setCompartment(target->compartment());
465    }
466
467    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
468};
469
470class AssertCompartmentUnchanged {
471  protected:
472    JSContext * const cx;
473    JSCompartment * const oldCompartment;
474    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
475  public:
476     AssertCompartmentUnchanged(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM)
477     : cx(cx), oldCompartment(cx->compartment) {
478        JS_GUARD_OBJECT_NOTIFIER_INIT;
479    }
480
481    ~AssertCompartmentUnchanged() {
482        JS_ASSERT(cx->compartment == oldCompartment);
483    }
484};
485
486class AutoCompartment
487{
488  public:
489    JSContext * const context;
490    JSCompartment * const origin;
491    JSObject * const target;
492    JSCompartment * const destination;
493  private:
494    Maybe<DummyFrameGuard> frame;
495    bool entered;
496
497  public:
498    AutoCompartment(JSContext *cx, JSObject *target);
499    ~AutoCompartment();
500
501    bool enter();
502    void leave();
503
504  private:
505    AutoCompartment(const AutoCompartment &) MOZ_DELETE;
506    AutoCompartment & operator=(const AutoCompartment &) MOZ_DELETE;
507};
508
509/*
510 * Use this to change the behavior of an AutoCompartment slightly on error. If
511 * the exception happens to be an Error object, copy it to the origin compartment
512 * instead of wrapping it.
513 */
514class ErrorCopier
515{
516    AutoCompartment &ac;
517    JSObject *scope;
518
519  public:
520    ErrorCopier(AutoCompartment &ac, JSObject *scope) : ac(ac), scope(scope) {
521        JS_ASSERT(scope->compartment() == ac.origin);
522    }
523    ~ErrorCopier();
524};
525
526class CompartmentsIter {
527  private:
528    JSCompartment **it, **end;
529
530  public:
531    CompartmentsIter(JSRuntime *rt) {
532        it = rt->compartments.begin();
533        end = rt->compartments.end();
534    }
535
536    bool done() const { return it == end; }
537
538    void next() {
539        JS_ASSERT(!done());
540        it++;
541    }
542
543    JSCompartment *get() const {
544        JS_ASSERT(!done());
545        return *it;
546    }
547
548    operator JSCompartment *() const { return get(); }
549    JSCompartment *operator->() const { return get(); }
550};
551
552} /* namespace js */
553
554#endif /* jscompartment_h___ */