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