jscompartment.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "jscompartmentinlines.h"
  6. #include "mozilla/DebugOnly.h"
  7. #include "mozilla/MemoryReporting.h"
  8. #include "jscntxt.h"
  9. #include "jsfriendapi.h"
  10. #include "jsgc.h"
  11. #include "jsiter.h"
  12. #include "jswrapper.h"
  13. #include "gc/Marking.h"
  14. #include "gc/Policy.h"
  15. #include "jit/JitCompartment.h"
  16. #include "jit/JitOptions.h"
  17. #include "js/Date.h"
  18. #include "js/Proxy.h"
  19. #include "js/RootingAPI.h"
  20. #include "proxy/DeadObjectProxy.h"
  21. #include "vm/Debugger.h"
  22. #include "vm/StopIterationObject.h"
  23. #include "vm/WrapperObject.h"
  24. #include "jsatominlines.h"
  25. #include "jsfuninlines.h"
  26. #include "jsgcinlines.h"
  27. #include "jsobjinlines.h"
  28. #include "jsscriptinlines.h"
  29. #include "vm/NativeObject-inl.h"
  30. using namespace js;
  31. using namespace js::gc;
  32. using namespace js::jit;
  33. using mozilla::DebugOnly;
  34. JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = JS::CompartmentOptions())
  35. : creationOptions_(options.creationOptions()),
  36. behaviors_(options.behaviors()),
  37. zone_(zone),
  38. runtime_(zone->runtimeFromMainThread()),
  39. principals_(nullptr),
  40. isSystem_(false),
  41. isAtomsCompartment_(false),
  42. isSelfHosting(false),
  43. marked(true),
  44. warnedAboutExprClosure(false),
  45. warnedAboutForEach(false),
  46. #ifdef DEBUG
  47. firedOnNewGlobalObject(false),
  48. #endif
  49. global_(nullptr),
  50. enterCompartmentDepth(0),
  51. performanceMonitoring(runtime_),
  52. data(nullptr),
  53. allocationMetadataBuilder(nullptr),
  54. lastAnimationTime(0),
  55. regExps(runtime_),
  56. globalWriteBarriered(0),
  57. detachedTypedObjects(0),
  58. objectMetadataState(ImmediateMetadata()),
  59. selfHostingScriptSource(nullptr),
  60. objectMetadataTable(nullptr),
  61. innerViews(zone, InnerViewTable()),
  62. lazyArrayBuffers(nullptr),
  63. wasm(zone),
  64. nonSyntacticLexicalEnvironments_(nullptr),
  65. gcIncomingGrayPointers(nullptr),
  66. debugModeBits(0),
  67. randomKeyGenerator_(runtime_->forkRandomKeyGenerator()),
  68. scriptCountsMap(nullptr),
  69. debugScriptMap(nullptr),
  70. debugEnvs(nullptr),
  71. enumerators(nullptr),
  72. lastCachedNativeIterator(nullptr),
  73. compartmentStats_(nullptr),
  74. scheduledForDestruction(false),
  75. maybeAlive(true),
  76. jitCompartment_(nullptr),
  77. mappedArgumentsTemplate_(nullptr),
  78. unmappedArgumentsTemplate_(nullptr),
  79. lcovOutput()
  80. {
  81. runtime_->numCompartments++;
  82. MOZ_ASSERT_IF(creationOptions_.mergeable(),
  83. creationOptions_.invisibleToDebugger());
  84. }
  85. JSCompartment::~JSCompartment()
  86. {
  87. // Write the code coverage information in a file.
  88. JSRuntime* rt = runtimeFromMainThread();
  89. if (rt->lcovOutput.isEnabled())
  90. rt->lcovOutput.writeLCovResult(lcovOutput);
  91. js_delete(jitCompartment_);
  92. js_delete(scriptCountsMap);
  93. js_delete(debugScriptMap);
  94. js_delete(debugEnvs);
  95. js_delete(objectMetadataTable);
  96. js_delete(lazyArrayBuffers);
  97. js_delete(nonSyntacticLexicalEnvironments_),
  98. js_free(enumerators);
  99. runtime_->numCompartments--;
  100. }
  101. bool
  102. JSCompartment::init(JSContext* maybecx)
  103. {
  104. /*
  105. * maybecx is null when called to create the atoms compartment from
  106. * JSRuntime::init().
  107. *
  108. * As a hack, we clear our timezone cache every time we create a new
  109. * compartment. This ensures that the cache is always relatively fresh, but
  110. * shouldn't interfere with benchmarks that create tons of date objects
  111. * (unless they also create tons of iframes, which seems unlikely).
  112. */
  113. JS::ResetTimeZone();
  114. if (!crossCompartmentWrappers.init(0)) {
  115. if (maybecx)
  116. ReportOutOfMemory(maybecx);
  117. return false;
  118. }
  119. if (!regExps.init(maybecx))
  120. return false;
  121. enumerators = NativeIterator::allocateSentinel(maybecx);
  122. if (!enumerators)
  123. return false;
  124. if (!savedStacks_.init() || !varNames_.init()) {
  125. if (maybecx)
  126. ReportOutOfMemory(maybecx);
  127. return false;
  128. }
  129. return true;
  130. }
  131. jit::JitRuntime*
  132. JSRuntime::createJitRuntime(JSContext* cx)
  133. {
  134. // The shared stubs are created in the atoms compartment, which may be
  135. // accessed by other threads with an exclusive context.
  136. AutoLockForExclusiveAccess atomsLock(cx);
  137. MOZ_ASSERT(!jitRuntime_);
  138. if (!CanLikelyAllocateMoreExecutableMemory()) {
  139. // Report OOM instead of potentially hitting the MOZ_CRASH below.
  140. ReportOutOfMemory(cx);
  141. return nullptr;
  142. }
  143. jit::JitRuntime* jrt = cx->new_<jit::JitRuntime>(cx->runtime());
  144. if (!jrt)
  145. return nullptr;
  146. // Protect jitRuntime_ from being observed (by InterruptRunningJitCode)
  147. // while it is being initialized. Unfortunately, initialization depends on
  148. // jitRuntime_ being non-null, so we can't just wait to assign jitRuntime_.
  149. JitRuntime::AutoPreventBackedgePatching apbp(cx->runtime(), jrt);
  150. jitRuntime_ = jrt;
  151. AutoEnterOOMUnsafeRegion noOOM;
  152. if (!jitRuntime_->initialize(cx, atomsLock)) {
  153. // Handling OOM here is complicated: if we delete jitRuntime_ now, we
  154. // will destroy the ExecutableAllocator, even though there may still be
  155. // JitCode instances holding references to ExecutablePools.
  156. noOOM.crash("OOM in createJitRuntime");
  157. }
  158. return jitRuntime_;
  159. }
  160. bool
  161. JSCompartment::ensureJitCompartmentExists(JSContext* cx)
  162. {
  163. using namespace js::jit;
  164. if (jitCompartment_)
  165. return true;
  166. if (!zone()->getJitZone(cx))
  167. return false;
  168. /* Set the compartment early, so linking works. */
  169. jitCompartment_ = cx->new_<JitCompartment>();
  170. if (!jitCompartment_)
  171. return false;
  172. if (!jitCompartment_->initialize(cx)) {
  173. js_delete(jitCompartment_);
  174. jitCompartment_ = nullptr;
  175. return false;
  176. }
  177. return true;
  178. }
  179. #ifdef JSGC_HASH_TABLE_CHECKS
  180. namespace {
  181. struct CheckGCThingAfterMovingGCFunctor {
  182. template <class T> void operator()(T* t) { CheckGCThingAfterMovingGC(*t); }
  183. };
  184. } // namespace (anonymous)
  185. void
  186. JSCompartment::checkWrapperMapAfterMovingGC()
  187. {
  188. /*
  189. * Assert that the postbarriers have worked and that nothing is left in
  190. * wrapperMap that points into the nursery, and that the hash table entries
  191. * are discoverable.
  192. */
  193. for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
  194. e.front().mutableKey().applyToWrapped(CheckGCThingAfterMovingGCFunctor());
  195. e.front().mutableKey().applyToDebugger(CheckGCThingAfterMovingGCFunctor());
  196. WrapperMap::Ptr ptr = crossCompartmentWrappers.lookup(e.front().key());
  197. MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
  198. }
  199. }
  200. #endif
  201. bool
  202. JSCompartment::putWrapper(JSContext* cx, const CrossCompartmentKey& wrapped,
  203. const js::Value& wrapper)
  204. {
  205. MOZ_ASSERT(wrapped.is<JSString*>() == wrapper.isString());
  206. MOZ_ASSERT_IF(!wrapped.is<JSString*>(), wrapper.isObject());
  207. if (!crossCompartmentWrappers.put(wrapped, wrapper)) {
  208. ReportOutOfMemory(cx);
  209. return false;
  210. }
  211. return true;
  212. }
  213. static JSString*
  214. CopyStringPure(JSContext* cx, JSString* str)
  215. {
  216. /*
  217. * Directly allocate the copy in the destination compartment, rather than
  218. * first flattening it (and possibly allocating in source compartment),
  219. * because we don't know whether the flattening will pay off later.
  220. */
  221. size_t len = str->length();
  222. JSString* copy;
  223. if (str->isLinear()) {
  224. /* Only use AutoStableStringChars if the NoGC allocation fails. */
  225. if (str->hasLatin1Chars()) {
  226. JS::AutoCheckCannotGC nogc;
  227. copy = NewStringCopyN<NoGC>(cx, str->asLinear().latin1Chars(nogc), len);
  228. } else {
  229. JS::AutoCheckCannotGC nogc;
  230. copy = NewStringCopyNDontDeflate<NoGC>(cx, str->asLinear().twoByteChars(nogc), len);
  231. }
  232. if (copy)
  233. return copy;
  234. AutoStableStringChars chars(cx);
  235. if (!chars.init(cx, str))
  236. return nullptr;
  237. return chars.isLatin1()
  238. ? NewStringCopyN<CanGC>(cx, chars.latin1Range().begin().get(), len)
  239. : NewStringCopyNDontDeflate<CanGC>(cx, chars.twoByteRange().begin().get(), len);
  240. }
  241. if (str->hasLatin1Chars()) {
  242. ScopedJSFreePtr<Latin1Char> copiedChars;
  243. if (!str->asRope().copyLatin1CharsZ(cx, copiedChars))
  244. return nullptr;
  245. return NewString<CanGC>(cx, copiedChars.forget(), len);
  246. }
  247. ScopedJSFreePtr<char16_t> copiedChars;
  248. if (!str->asRope().copyTwoByteCharsZ(cx, copiedChars))
  249. return nullptr;
  250. return NewStringDontDeflate<CanGC>(cx, copiedChars.forget(), len);
  251. }
  252. bool
  253. JSCompartment::wrap(JSContext* cx, MutableHandleString strp)
  254. {
  255. MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(this));
  256. MOZ_ASSERT(cx->compartment() == this);
  257. /* If the string is already in this compartment, we are done. */
  258. JSString* str = strp;
  259. if (str->zoneFromAnyThread() == zone())
  260. return true;
  261. /* If the string is an atom, we don't have to copy. */
  262. if (str->isAtom()) {
  263. MOZ_ASSERT(str->isPermanentAtom() || str->zone()->isAtomsZone());
  264. return true;
  265. }
  266. /* Check the cache. */
  267. RootedValue key(cx, StringValue(str));
  268. if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(CrossCompartmentKey(key))) {
  269. strp.set(p->value().get().toString());
  270. return true;
  271. }
  272. /* No dice. Make a copy, and cache it. */
  273. JSString* copy = CopyStringPure(cx, str);
  274. if (!copy)
  275. return false;
  276. if (!putWrapper(cx, CrossCompartmentKey(key), StringValue(copy)))
  277. return false;
  278. strp.set(copy);
  279. return true;
  280. }
  281. bool
  282. JSCompartment::getNonWrapperObjectForCurrentCompartment(JSContext* cx, MutableHandleObject obj)
  283. {
  284. // Ensure that we have entered a compartment.
  285. MOZ_ASSERT(cx->global());
  286. // If we have a cross-compartment wrapper, make sure that the cx isn't
  287. // associated with the self-hosting global. We don't want to create
  288. // wrappers for objects in other runtimes, which may be the case for the
  289. // self-hosting global.
  290. MOZ_ASSERT(!cx->runtime()->isSelfHostingGlobal(cx->global()));
  291. MOZ_ASSERT(!cx->runtime()->isSelfHostingGlobal(&obj->global()));
  292. // The object is already in the right compartment. Normally same-
  293. // compartment returns the object itself, however, windows are always
  294. // wrapped by a proxy, so we have to check for that case here manually.
  295. if (obj->compartment() == this) {
  296. obj.set(ToWindowProxyIfWindow(obj));
  297. return true;
  298. }
  299. // Note that if the object is same-compartment, but has been wrapped into a
  300. // different compartment, we need to unwrap it and return the bare same-
  301. // compartment object. Note again that windows are always wrapped by a
  302. // WindowProxy even when same-compartment so take care not to strip this
  303. // particular wrapper.
  304. RootedObject objectPassedToWrap(cx, obj);
  305. obj.set(UncheckedUnwrap(obj, /* stopAtWindowProxy = */ true));
  306. if (obj->compartment() == this) {
  307. MOZ_ASSERT(!IsWindow(obj));
  308. return true;
  309. }
  310. // Translate StopIteration singleton.
  311. if (obj->is<StopIterationObject>()) {
  312. // StopIteration isn't a constructor, but it's stored in GlobalObject
  313. // as one, out of laziness. Hence the GetBuiltinConstructor call here.
  314. RootedObject stopIteration(cx);
  315. if (!GetBuiltinConstructor(cx, JSProto_StopIteration, &stopIteration))
  316. return false;
  317. obj.set(stopIteration);
  318. return true;
  319. }
  320. // Invoke the prewrap callback. The prewrap callback is responsible for
  321. // doing similar reification as above, but can account for any additional
  322. // embedder requirements.
  323. //
  324. // We're a bit worried about infinite recursion here, so we do a check -
  325. // see bug 809295.
  326. auto preWrap = cx->runtime()->wrapObjectCallbacks->preWrap;
  327. JS_CHECK_SYSTEM_RECURSION(cx, return false);
  328. if (preWrap) {
  329. preWrap(cx, cx->global(), obj, objectPassedToWrap, obj);
  330. if (!obj)
  331. return false;
  332. }
  333. MOZ_ASSERT(!IsWindow(obj));
  334. return true;
  335. }
  336. bool
  337. JSCompartment::getOrCreateWrapper(JSContext* cx, HandleObject existing, MutableHandleObject obj)
  338. {
  339. // If we already have a wrapper for this value, use it.
  340. RootedValue key(cx, ObjectValue(*obj));
  341. if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(CrossCompartmentKey(key))) {
  342. obj.set(&p->value().get().toObject());
  343. MOZ_ASSERT(obj->is<CrossCompartmentWrapperObject>());
  344. return true;
  345. }
  346. // Ensure that the wrappee is exposed in case we are creating a new wrapper
  347. // for a gray object.
  348. ExposeObjectToActiveJS(obj);
  349. // Create a new wrapper for the object.
  350. auto wrap = cx->runtime()->wrapObjectCallbacks->wrap;
  351. RootedObject wrapper(cx, wrap(cx, existing, obj));
  352. if (!wrapper)
  353. return false;
  354. // We maintain the invariant that the key in the cross-compartment wrapper
  355. // map is always directly wrapped by the value.
  356. MOZ_ASSERT(Wrapper::wrappedObject(wrapper) == &key.get().toObject());
  357. if (!putWrapper(cx, CrossCompartmentKey(key), ObjectValue(*wrapper))) {
  358. // Enforce the invariant that all cross-compartment wrapper object are
  359. // in the map by nuking the wrapper if we couldn't add it.
  360. // Unfortunately it's possible for the wrapper to still be marked if we
  361. // took this path, for example if the object metadata callback stashes a
  362. // reference to it.
  363. if (wrapper->is<CrossCompartmentWrapperObject>())
  364. NukeCrossCompartmentWrapper(cx, wrapper);
  365. return false;
  366. }
  367. obj.set(wrapper);
  368. return true;
  369. }
  370. bool
  371. JSCompartment::wrap(JSContext* cx, MutableHandleObject obj)
  372. {
  373. MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(this));
  374. MOZ_ASSERT(cx->compartment() == this);
  375. if (!obj)
  376. return true;
  377. AutoDisableProxyCheck adpc(cx->runtime());
  378. // Anything we're wrapping has already escaped into script, so must have
  379. // been unmarked-gray at some point in the past.
  380. MOZ_ASSERT(!ObjectIsMarkedGray(obj));
  381. // The passed object may already be wrapped, or may fit a number of special
  382. // cases that we need to check for and manually correct.
  383. if (!getNonWrapperObjectForCurrentCompartment(cx, obj))
  384. return false;
  385. // If the reification above did not result in a same-compartment object,
  386. // get or create a new wrapper object in this compartment for it.
  387. if (obj->compartment() != this) {
  388. if (!getOrCreateWrapper(cx, nullptr, obj))
  389. return false;
  390. }
  391. // Ensure that the wrapper is also exposed.
  392. ExposeObjectToActiveJS(obj);
  393. return true;
  394. }
  395. bool
  396. JSCompartment::rewrap(JSContext* cx, MutableHandleObject obj, HandleObject existingArg)
  397. {
  398. MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(this));
  399. MOZ_ASSERT(cx->compartment() == this);
  400. MOZ_ASSERT(obj);
  401. MOZ_ASSERT(existingArg);
  402. MOZ_ASSERT(existingArg->compartment() == cx->compartment());
  403. MOZ_ASSERT(IsDeadProxyObject(existingArg));
  404. AutoDisableProxyCheck adpc(cx->runtime());
  405. // It may not be possible to re-use existing; if so, clear it so that we
  406. // are forced to create a new wrapper. Note that this cannot call out to
  407. // |wrap| because of the different gray unmarking semantics.
  408. RootedObject existing(cx, existingArg);
  409. if (existing->hasStaticPrototype() ||
  410. // Note: Class asserted above, so all that's left to check is callability
  411. existing->isCallable() ||
  412. obj->isCallable())
  413. {
  414. existing.set(nullptr);
  415. }
  416. // The passed object may already be wrapped, or may fit a number of special
  417. // cases that we need to check for and manually correct.
  418. if (!getNonWrapperObjectForCurrentCompartment(cx, obj))
  419. return false;
  420. // If the reification above resulted in a same-compartment object, we do
  421. // not need to create or return an existing wrapper.
  422. if (obj->compartment() == this)
  423. return true;
  424. return getOrCreateWrapper(cx, existing, obj);
  425. }
  426. bool
  427. JSCompartment::wrap(JSContext* cx, MutableHandle<PropertyDescriptor> desc)
  428. {
  429. if (!wrap(cx, desc.object()))
  430. return false;
  431. if (desc.hasGetterObject()) {
  432. if (!wrap(cx, desc.getterObject()))
  433. return false;
  434. }
  435. if (desc.hasSetterObject()) {
  436. if (!wrap(cx, desc.setterObject()))
  437. return false;
  438. }
  439. return wrap(cx, desc.value());
  440. }
  441. bool
  442. JSCompartment::wrap(JSContext* cx, MutableHandle<GCVector<Value>> vec)
  443. {
  444. for (size_t i = 0; i < vec.length(); ++i) {
  445. if (!wrap(cx, vec[i]))
  446. return false;
  447. }
  448. return true;
  449. }
  450. LexicalEnvironmentObject*
  451. JSCompartment::getOrCreateNonSyntacticLexicalEnvironment(JSContext* cx, HandleObject enclosing)
  452. {
  453. if (!nonSyntacticLexicalEnvironments_) {
  454. nonSyntacticLexicalEnvironments_ = cx->new_<ObjectWeakMap>(cx);
  455. if (!nonSyntacticLexicalEnvironments_ || !nonSyntacticLexicalEnvironments_->init())
  456. return nullptr;
  457. }
  458. // If a wrapped WithEnvironmentObject was passed in, unwrap it, as we may
  459. // be creating different WithEnvironmentObject wrappers each time.
  460. RootedObject key(cx, enclosing);
  461. if (enclosing->is<WithEnvironmentObject>()) {
  462. MOZ_ASSERT(!enclosing->as<WithEnvironmentObject>().isSyntactic());
  463. key = &enclosing->as<WithEnvironmentObject>().object();
  464. }
  465. RootedObject lexicalEnv(cx, nonSyntacticLexicalEnvironments_->lookup(key));
  466. if (!lexicalEnv) {
  467. lexicalEnv = LexicalEnvironmentObject::createNonSyntactic(cx, enclosing);
  468. if (!lexicalEnv)
  469. return nullptr;
  470. if (!nonSyntacticLexicalEnvironments_->add(cx, key, lexicalEnv))
  471. return nullptr;
  472. }
  473. return &lexicalEnv->as<LexicalEnvironmentObject>();
  474. }
  475. LexicalEnvironmentObject*
  476. JSCompartment::getNonSyntacticLexicalEnvironment(JSObject* enclosing) const
  477. {
  478. if (!nonSyntacticLexicalEnvironments_)
  479. return nullptr;
  480. // If a wrapped WithEnvironmentObject was passed in, unwrap it as in
  481. // getOrCreateNonSyntacticLexicalEnvironment.
  482. JSObject* key = enclosing;
  483. if (enclosing->is<WithEnvironmentObject>()) {
  484. MOZ_ASSERT(!enclosing->as<WithEnvironmentObject>().isSyntactic());
  485. key = &enclosing->as<WithEnvironmentObject>().object();
  486. }
  487. JSObject* lexicalEnv = nonSyntacticLexicalEnvironments_->lookup(key);
  488. if (!lexicalEnv)
  489. return nullptr;
  490. return &lexicalEnv->as<LexicalEnvironmentObject>();
  491. }
  492. bool
  493. JSCompartment::addToVarNames(JSContext* cx, JS::Handle<JSAtom*> name)
  494. {
  495. MOZ_ASSERT(name);
  496. MOZ_ASSERT(!isAtomsCompartment());
  497. if (varNames_.put(name))
  498. return true;
  499. ReportOutOfMemory(cx);
  500. return false;
  501. }
  502. void
  503. JSCompartment::traceOutgoingCrossCompartmentWrappers(JSTracer* trc)
  504. {
  505. MOZ_ASSERT(trc->runtime()->isHeapMajorCollecting());
  506. MOZ_ASSERT(!zone()->isCollecting() || trc->runtime()->gc.isHeapCompacting());
  507. for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
  508. Value v = e.front().value().unbarrieredGet();
  509. if (e.front().key().is<JSObject*>()) {
  510. ProxyObject* wrapper = &v.toObject().as<ProxyObject>();
  511. /*
  512. * We have a cross-compartment wrapper. Its private pointer may
  513. * point into the compartment being collected, so we should mark it.
  514. */
  515. TraceEdge(trc, wrapper->slotOfPrivate(), "cross-compartment wrapper");
  516. }
  517. }
  518. }
  519. /* static */ void
  520. JSCompartment::traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc)
  521. {
  522. gcstats::AutoPhase ap(trc->runtime()->gc.stats, gcstats::PHASE_MARK_CCWS);
  523. MOZ_ASSERT(trc->runtime()->isHeapMajorCollecting());
  524. for (CompartmentsIter c(trc->runtime(), SkipAtoms); !c.done(); c.next()) {
  525. if (!c->zone()->isCollecting())
  526. c->traceOutgoingCrossCompartmentWrappers(trc);
  527. }
  528. Debugger::markIncomingCrossCompartmentEdges(trc);
  529. }
  530. void
  531. JSCompartment::trace(JSTracer* trc)
  532. {
  533. savedStacks_.trace(trc);
  534. // Atoms are always tenured.
  535. if (!trc->runtime()->isHeapMinorCollecting())
  536. varNames_.trace(trc);
  537. }
  538. void
  539. JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime traceOrMark)
  540. {
  541. if (objectMetadataState.is<PendingMetadata>()) {
  542. TraceRoot(trc,
  543. &objectMetadataState.as<PendingMetadata>(),
  544. "on-stack object pending metadata");
  545. }
  546. if (!trc->runtime()->isHeapMinorCollecting()) {
  547. // JIT code and the global are never nursery allocated, so we only need
  548. // to trace them when not doing a minor collection.
  549. if (jitCompartment_)
  550. jitCompartment_->mark(trc, this);
  551. // If a compartment is on-stack, we mark its global so that
  552. // JSContext::global() remains valid.
  553. if (enterCompartmentDepth && global_.unbarrieredGet())
  554. TraceRoot(trc, global_.unsafeUnbarrieredForTracing(), "on-stack compartment global");
  555. }
  556. // Nothing below here needs to be treated as a root if we aren't marking
  557. // this zone for a collection.
  558. if (traceOrMark == js::gc::GCRuntime::MarkRuntime && !zone()->isCollecting())
  559. return;
  560. /* Mark debug scopes, if present */
  561. if (debugEnvs)
  562. debugEnvs->mark(trc);
  563. if (lazyArrayBuffers)
  564. lazyArrayBuffers->trace(trc);
  565. if (objectMetadataTable)
  566. objectMetadataTable->trace(trc);
  567. // If code coverage is only enabled with the Debugger or the LCovOutput,
  568. // then the following comment holds.
  569. //
  570. // The scriptCountsMap maps JSScript weak-pointers to ScriptCounts
  571. // structures. It uses a HashMap instead of a WeakMap, so that we can keep
  572. // the data alive for the JSScript::finalize call. Thus, we do not trace the
  573. // keys of the HashMap to avoid adding a strong reference to the JSScript
  574. // pointers.
  575. //
  576. // If the code coverage is either enabled with the --dump-bytecode command
  577. // line option, or with the PCCount JSFriend API functions, then we mark the
  578. // keys of the map to hold the JSScript alive.
  579. if (scriptCountsMap &&
  580. trc->runtime()->profilingScripts &&
  581. !trc->runtime()->isHeapMinorCollecting())
  582. {
  583. MOZ_ASSERT_IF(!trc->runtime()->isBeingDestroyed(), collectCoverage());
  584. for (ScriptCountsMap::Range r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
  585. JSScript* script = const_cast<JSScript*>(r.front().key());
  586. MOZ_ASSERT(script->hasScriptCounts());
  587. TraceRoot(trc, &script, "profilingScripts");
  588. MOZ_ASSERT(script == r.front().key(), "const_cast is only a work-around");
  589. }
  590. }
  591. if (nonSyntacticLexicalEnvironments_)
  592. nonSyntacticLexicalEnvironments_->trace(trc);
  593. wasm.trace(trc);
  594. }
  595. void
  596. JSCompartment::finishRoots()
  597. {
  598. if (debugEnvs)
  599. debugEnvs->finish();
  600. if (lazyArrayBuffers)
  601. lazyArrayBuffers->clear();
  602. if (objectMetadataTable)
  603. objectMetadataTable->clear();
  604. clearScriptCounts();
  605. if (nonSyntacticLexicalEnvironments_)
  606. nonSyntacticLexicalEnvironments_->clear();
  607. }
  608. void
  609. JSCompartment::sweepAfterMinorGC(JSTracer* trc)
  610. {
  611. globalWriteBarriered = 0;
  612. if (innerViews.needsSweepAfterMinorGC())
  613. innerViews.sweepAfterMinorGC();
  614. crossCompartmentWrappers.sweepAfterMinorGC(trc);
  615. }
  616. void
  617. JSCompartment::sweepSavedStacks()
  618. {
  619. savedStacks_.sweep();
  620. }
  621. void
  622. JSCompartment::sweepGlobalObject(FreeOp* fop)
  623. {
  624. if (global_ && IsAboutToBeFinalized(&global_)) {
  625. if (isDebuggee())
  626. Debugger::detachAllDebuggersFromGlobal(fop, global_.unbarrieredGet());
  627. global_.set(nullptr);
  628. }
  629. }
  630. void
  631. JSCompartment::sweepSelfHostingScriptSource()
  632. {
  633. if (selfHostingScriptSource.unbarrieredGet() &&
  634. IsAboutToBeFinalized(&selfHostingScriptSource))
  635. {
  636. selfHostingScriptSource.set(nullptr);
  637. }
  638. }
  639. void
  640. JSCompartment::sweepJitCompartment(FreeOp* fop)
  641. {
  642. if (jitCompartment_)
  643. jitCompartment_->sweep(fop, this);
  644. }
  645. void
  646. JSCompartment::sweepRegExps()
  647. {
  648. /*
  649. * JIT code increments activeWarmUpCounter for any RegExpShared used by jit
  650. * code for the lifetime of the JIT script. Thus, we must perform
  651. * sweeping after clearing jit code.
  652. */
  653. regExps.sweep(runtimeFromAnyThread());
  654. }
  655. void
  656. JSCompartment::sweepDebugEnvironments()
  657. {
  658. JSRuntime* rt = runtimeFromAnyThread();
  659. if (debugEnvs)
  660. debugEnvs->sweep(rt);
  661. }
  662. void
  663. JSCompartment::sweepNativeIterators()
  664. {
  665. /* Sweep list of native iterators. */
  666. NativeIterator* ni = enumerators->next();
  667. while (ni != enumerators) {
  668. JSObject* iterObj = ni->iterObj();
  669. NativeIterator* next = ni->next();
  670. if (gc::IsAboutToBeFinalizedUnbarriered(&iterObj))
  671. ni->unlink();
  672. ni = next;
  673. }
  674. }
  675. /*
  676. * Remove dead wrappers from the table. We must sweep all compartments, since
  677. * string entries in the crossCompartmentWrappers table are not marked during
  678. * markCrossCompartmentWrappers.
  679. */
  680. void
  681. JSCompartment::sweepCrossCompartmentWrappers()
  682. {
  683. crossCompartmentWrappers.sweep();
  684. }
  685. void
  686. JSCompartment::sweepVarNames()
  687. {
  688. varNames_.sweep();
  689. }
  690. namespace {
  691. struct TraceRootFunctor {
  692. JSTracer* trc;
  693. const char* name;
  694. TraceRootFunctor(JSTracer* trc, const char* name) : trc(trc), name(name) {}
  695. template <class T> void operator()(T* t) { return TraceRoot(trc, t, name); }
  696. };
  697. struct NeedsSweepUnbarrieredFunctor {
  698. template <class T> bool operator()(T* t) const { return IsAboutToBeFinalizedUnbarriered(t); }
  699. };
  700. } // namespace (anonymous)
  701. void
  702. CrossCompartmentKey::trace(JSTracer* trc)
  703. {
  704. applyToWrapped(TraceRootFunctor(trc, "CrossCompartmentKey::wrapped"));
  705. applyToDebugger(TraceRootFunctor(trc, "CrossCompartmentKey::debugger"));
  706. }
  707. bool
  708. CrossCompartmentKey::needsSweep()
  709. {
  710. return applyToWrapped(NeedsSweepUnbarrieredFunctor()) ||
  711. applyToDebugger(NeedsSweepUnbarrieredFunctor());
  712. }
  713. void
  714. JSCompartment::sweepTemplateObjects()
  715. {
  716. if (mappedArgumentsTemplate_ && IsAboutToBeFinalized(&mappedArgumentsTemplate_))
  717. mappedArgumentsTemplate_.set(nullptr);
  718. if (unmappedArgumentsTemplate_ && IsAboutToBeFinalized(&unmappedArgumentsTemplate_))
  719. unmappedArgumentsTemplate_.set(nullptr);
  720. }
  721. /* static */ void
  722. JSCompartment::fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc)
  723. {
  724. MOZ_ASSERT(trc->runtime()->gc.isHeapCompacting());
  725. for (CompartmentsIter comp(trc->runtime(), SkipAtoms); !comp.done(); comp.next()) {
  726. // Sweep the wrapper map to update its pointers to the wrappers.
  727. comp->sweepCrossCompartmentWrappers();
  728. // Trace the wrappers in the map to update their edges to their referents.
  729. comp->traceOutgoingCrossCompartmentWrappers(trc);
  730. }
  731. }
  732. void
  733. JSCompartment::fixupAfterMovingGC()
  734. {
  735. purge();
  736. fixupGlobal();
  737. objectGroups.fixupTablesAfterMovingGC();
  738. fixupScriptMapsAfterMovingGC();
  739. }
  740. void
  741. JSCompartment::fixupGlobal()
  742. {
  743. GlobalObject* global = *global_.unsafeGet();
  744. if (global)
  745. global_.set(MaybeForwarded(global));
  746. }
  747. void
  748. JSCompartment::fixupScriptMapsAfterMovingGC()
  749. {
  750. // Map entries are removed by JSScript::finalize, but we need to update the
  751. // script pointers here in case they are moved by the GC.
  752. if (scriptCountsMap) {
  753. for (ScriptCountsMap::Enum e(*scriptCountsMap); !e.empty(); e.popFront()) {
  754. JSScript* script = e.front().key();
  755. if (!IsAboutToBeFinalizedUnbarriered(&script) && script != e.front().key())
  756. e.rekeyFront(script);
  757. }
  758. }
  759. if (debugScriptMap) {
  760. for (DebugScriptMap::Enum e(*debugScriptMap); !e.empty(); e.popFront()) {
  761. JSScript* script = e.front().key();
  762. if (!IsAboutToBeFinalizedUnbarriered(&script) && script != e.front().key())
  763. e.rekeyFront(script);
  764. }
  765. }
  766. }
  767. #ifdef JSGC_HASH_TABLE_CHECKS
  768. void
  769. JSCompartment::checkScriptMapsAfterMovingGC()
  770. {
  771. if (scriptCountsMap) {
  772. for (auto r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
  773. JSScript* script = r.front().key();
  774. CheckGCThingAfterMovingGC(script);
  775. auto ptr = scriptCountsMap->lookup(script);
  776. MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
  777. }
  778. }
  779. if (debugScriptMap) {
  780. for (auto r = debugScriptMap->all(); !r.empty(); r.popFront()) {
  781. JSScript* script = r.front().key();
  782. CheckGCThingAfterMovingGC(script);
  783. DebugScript* ds = r.front().value();
  784. for (uint32_t i = 0; i < ds->numSites; i++) {
  785. BreakpointSite* site = ds->breakpoints[i];
  786. if (site)
  787. CheckGCThingAfterMovingGC(site->script);
  788. }
  789. auto ptr = debugScriptMap->lookup(script);
  790. MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
  791. }
  792. }
  793. }
  794. #endif
  795. void
  796. JSCompartment::purge()
  797. {
  798. dtoaCache.purge();
  799. lastCachedNativeIterator = nullptr;
  800. }
  801. void
  802. JSCompartment::clearTables()
  803. {
  804. global_.set(nullptr);
  805. // No scripts should have run in this compartment. This is used when
  806. // merging a compartment that has been used off thread into another
  807. // compartment and zone.
  808. MOZ_ASSERT(crossCompartmentWrappers.empty());
  809. MOZ_ASSERT(!jitCompartment_);
  810. MOZ_ASSERT(!debugEnvs);
  811. MOZ_ASSERT(enumerators->next() == enumerators);
  812. MOZ_ASSERT(regExps.empty());
  813. objectGroups.clearTables();
  814. if (savedStacks_.initialized())
  815. savedStacks_.clear();
  816. if (varNames_.initialized())
  817. varNames_.clear();
  818. }
  819. void
  820. JSCompartment::setAllocationMetadataBuilder(const js::AllocationMetadataBuilder *builder)
  821. {
  822. // Clear any jitcode in the runtime, which behaves differently depending on
  823. // whether there is a creation callback.
  824. ReleaseAllJITCode(runtime_->defaultFreeOp());
  825. allocationMetadataBuilder = builder;
  826. }
  827. void
  828. JSCompartment::clearObjectMetadata()
  829. {
  830. js_delete(objectMetadataTable);
  831. objectMetadataTable = nullptr;
  832. }
  833. void
  834. JSCompartment::setNewObjectMetadata(JSContext* cx, HandleObject obj)
  835. {
  836. assertSameCompartment(cx, this, obj);
  837. AutoEnterOOMUnsafeRegion oomUnsafe;
  838. if (JSObject* metadata = allocationMetadataBuilder->build(cx, obj, oomUnsafe)) {
  839. assertSameCompartment(cx, metadata);
  840. if (!objectMetadataTable) {
  841. objectMetadataTable = cx->new_<ObjectWeakMap>(cx);
  842. if (!objectMetadataTable || !objectMetadataTable->init())
  843. oomUnsafe.crash("setNewObjectMetadata");
  844. }
  845. if (!objectMetadataTable->add(cx, obj, metadata))
  846. oomUnsafe.crash("setNewObjectMetadata");
  847. }
  848. }
  849. static bool
  850. AddInnerLazyFunctionsFromScript(JSScript* script, AutoObjectVector& lazyFunctions)
  851. {
  852. if (!script->hasObjects())
  853. return true;
  854. ObjectArray* objects = script->objects();
  855. for (size_t i = 0; i < objects->length; i++) {
  856. JSObject* obj = objects->vector[i];
  857. if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpretedLazy()) {
  858. if (!lazyFunctions.append(obj))
  859. return false;
  860. }
  861. }
  862. return true;
  863. }
  864. static bool
  865. AddLazyFunctionsForCompartment(JSContext* cx, AutoObjectVector& lazyFunctions, AllocKind kind)
  866. {
  867. // Find all live root lazy functions in the compartment: those which have a
  868. // source object, indicating that they have a parent, and which do not have
  869. // an uncompiled enclosing script. The last condition is so that we don't
  870. // compile lazy scripts whose enclosing scripts failed to compile,
  871. // indicating that the lazy script did not escape the script.
  872. //
  873. // Some LazyScripts have a non-null |JSScript* script| pointer. We still
  874. // want to delazify in that case: this pointer is weak so the JSScript
  875. // could be destroyed at the next GC.
  876. for (auto i = cx->zone()->cellIter<JSObject>(kind); !i.done(); i.next()) {
  877. JSFunction* fun = &i->as<JSFunction>();
  878. // Sweeping is incremental; take care to not delazify functions that
  879. // are about to be finalized. GC things referenced by objects that are
  880. // about to be finalized (e.g., in slots) may already be freed.
  881. if (gc::IsAboutToBeFinalizedUnbarriered(&fun) ||
  882. fun->compartment() != cx->compartment())
  883. {
  884. continue;
  885. }
  886. if (fun->isInterpretedLazy()) {
  887. LazyScript* lazy = fun->lazyScriptOrNull();
  888. if (lazy && lazy->sourceObject() && !lazy->hasUncompiledEnclosingScript()) {
  889. if (!lazyFunctions.append(fun))
  890. return false;
  891. }
  892. }
  893. }
  894. return true;
  895. }
  896. static bool
  897. CreateLazyScriptsForCompartment(JSContext* cx)
  898. {
  899. AutoObjectVector lazyFunctions(cx);
  900. if (!AddLazyFunctionsForCompartment(cx, lazyFunctions, AllocKind::FUNCTION))
  901. return false;
  902. // Methods, for instance {get method() {}}, are extended functions that can
  903. // be relazified, so we need to handle those as well.
  904. if (!AddLazyFunctionsForCompartment(cx, lazyFunctions, AllocKind::FUNCTION_EXTENDED))
  905. return false;
  906. // Create scripts for each lazy function, updating the list of functions to
  907. // process with any newly exposed inner functions in created scripts.
  908. // A function cannot be delazified until its outer script exists.
  909. RootedFunction fun(cx);
  910. for (size_t i = 0; i < lazyFunctions.length(); i++) {
  911. fun = &lazyFunctions[i]->as<JSFunction>();
  912. // lazyFunctions may have been populated with multiple functions for
  913. // a lazy script.
  914. if (!fun->isInterpretedLazy())
  915. continue;
  916. bool lazyScriptHadNoScript = !fun->lazyScript()->maybeScript();
  917. JSScript* script = JSFunction::getOrCreateScript(cx, fun);
  918. if (!script)
  919. return false;
  920. if (lazyScriptHadNoScript && !AddInnerLazyFunctionsFromScript(script, lazyFunctions))
  921. return false;
  922. }
  923. return true;
  924. }
  925. bool
  926. JSCompartment::ensureDelazifyScriptsForDebugger(JSContext* cx)
  927. {
  928. MOZ_ASSERT(cx->compartment() == this);
  929. if (needsDelazificationForDebugger() && !CreateLazyScriptsForCompartment(cx))
  930. return false;
  931. debugModeBits &= ~DebuggerNeedsDelazification;
  932. return true;
  933. }
  934. void
  935. JSCompartment::updateDebuggerObservesFlag(unsigned flag)
  936. {
  937. MOZ_ASSERT(isDebuggee());
  938. MOZ_ASSERT(flag == DebuggerObservesAllExecution ||
  939. flag == DebuggerObservesCoverage ||
  940. flag == DebuggerObservesAsmJS);
  941. GlobalObject* global = zone()->runtimeFromMainThread()->gc.isForegroundSweeping()
  942. ? unsafeUnbarrieredMaybeGlobal()
  943. : maybeGlobal();
  944. const GlobalObject::DebuggerVector* v = global->getDebuggers();
  945. for (auto p = v->begin(); p != v->end(); p++) {
  946. Debugger* dbg = *p;
  947. if (flag == DebuggerObservesAllExecution ? dbg->observesAllExecution() :
  948. flag == DebuggerObservesCoverage ? dbg->observesCoverage() :
  949. dbg->observesAsmJS())
  950. {
  951. debugModeBits |= flag;
  952. return;
  953. }
  954. }
  955. debugModeBits &= ~flag;
  956. }
  957. void
  958. JSCompartment::unsetIsDebuggee()
  959. {
  960. if (isDebuggee()) {
  961. debugModeBits &= ~DebuggerObservesMask;
  962. DebugEnvironments::onCompartmentUnsetIsDebuggee(this);
  963. }
  964. }
  965. void
  966. JSCompartment::updateDebuggerObservesCoverage()
  967. {
  968. bool previousState = debuggerObservesCoverage();
  969. updateDebuggerObservesFlag(DebuggerObservesCoverage);
  970. if (previousState == debuggerObservesCoverage())
  971. return;
  972. if (debuggerObservesCoverage()) {
  973. // Interrupt any running interpreter frame. The scriptCounts are
  974. // allocated on demand when a script resume its execution.
  975. for (ActivationIterator iter(runtimeFromMainThread()); !iter.done(); ++iter) {
  976. if (iter->isInterpreter())
  977. iter->asInterpreter()->enableInterruptsUnconditionally();
  978. }
  979. return;
  980. }
  981. // If code coverage is enabled by any other means, keep it.
  982. if (collectCoverage())
  983. return;
  984. clearScriptCounts();
  985. }
  986. bool
  987. JSCompartment::collectCoverage() const
  988. {
  989. return collectCoverageForPGO() ||
  990. collectCoverageForDebug();
  991. }
  992. bool
  993. JSCompartment::collectCoverageForPGO() const
  994. {
  995. return !JitOptions.disablePgo;
  996. }
  997. bool
  998. JSCompartment::collectCoverageForDebug() const
  999. {
  1000. return debuggerObservesCoverage() ||
  1001. runtimeFromAnyThread()->profilingScripts ||
  1002. runtimeFromAnyThread()->lcovOutput.isEnabled();
  1003. }
  1004. void
  1005. JSCompartment::clearScriptCounts()
  1006. {
  1007. if (!scriptCountsMap)
  1008. return;
  1009. // Clear all hasScriptCounts_ flags of JSScript, in order to release all
  1010. // ScriptCounts entry of the current compartment.
  1011. for (ScriptCountsMap::Range r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
  1012. ScriptCounts* value = r.front().value();
  1013. r.front().key()->takeOverScriptCountsMapEntry(value);
  1014. js_delete(value);
  1015. }
  1016. js_delete(scriptCountsMap);
  1017. scriptCountsMap = nullptr;
  1018. }
  1019. void
  1020. JSCompartment::clearBreakpointsIn(FreeOp* fop, js::Debugger* dbg, HandleObject handler)
  1021. {
  1022. for (auto script = zone()->cellIter<JSScript>(); !script.done(); script.next()) {
  1023. if (script->compartment() == this && script->hasAnyBreakpointsOrStepMode())
  1024. script->clearBreakpointsIn(fop, dbg, handler);
  1025. }
  1026. }
  1027. void
  1028. JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
  1029. size_t* tiAllocationSiteTables,
  1030. size_t* tiArrayTypeTables,
  1031. size_t* tiObjectTypeTables,
  1032. size_t* compartmentObject,
  1033. size_t* compartmentTables,
  1034. size_t* innerViewsArg,
  1035. size_t* lazyArrayBuffersArg,
  1036. size_t* objectMetadataTablesArg,
  1037. size_t* crossCompartmentWrappersArg,
  1038. size_t* regexpCompartment,
  1039. size_t* savedStacksSet,
  1040. size_t* varNamesSet,
  1041. size_t* nonSyntacticLexicalEnvironmentsArg,
  1042. size_t* jitCompartment,
  1043. size_t* privateData)
  1044. {
  1045. *compartmentObject += mallocSizeOf(this);
  1046. objectGroups.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
  1047. tiArrayTypeTables, tiObjectTypeTables,
  1048. compartmentTables);
  1049. wasm.addSizeOfExcludingThis(mallocSizeOf, compartmentTables);
  1050. *innerViewsArg += innerViews.sizeOfExcludingThis(mallocSizeOf);
  1051. if (lazyArrayBuffers)
  1052. *lazyArrayBuffersArg += lazyArrayBuffers->sizeOfIncludingThis(mallocSizeOf);
  1053. if (objectMetadataTable)
  1054. *objectMetadataTablesArg += objectMetadataTable->sizeOfIncludingThis(mallocSizeOf);
  1055. *crossCompartmentWrappersArg += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf);
  1056. *regexpCompartment += regExps.sizeOfExcludingThis(mallocSizeOf);
  1057. *savedStacksSet += savedStacks_.sizeOfExcludingThis(mallocSizeOf);
  1058. *varNamesSet += varNames_.sizeOfExcludingThis(mallocSizeOf);
  1059. if (nonSyntacticLexicalEnvironments_)
  1060. *nonSyntacticLexicalEnvironmentsArg +=
  1061. nonSyntacticLexicalEnvironments_->sizeOfIncludingThis(mallocSizeOf);
  1062. if (jitCompartment_)
  1063. *jitCompartment += jitCompartment_->sizeOfIncludingThis(mallocSizeOf);
  1064. auto callback = runtime_->sizeOfIncludingThisCompartmentCallback;
  1065. if (callback)
  1066. *privateData += callback(mallocSizeOf, this);
  1067. }
  1068. HashNumber
  1069. JSCompartment::randomHashCode()
  1070. {
  1071. ensureRandomNumberGenerator();
  1072. return HashNumber(randomNumberGenerator.ref().next());
  1073. }
  1074. mozilla::HashCodeScrambler
  1075. JSCompartment::randomHashCodeScrambler()
  1076. {
  1077. return mozilla::HashCodeScrambler(randomKeyGenerator_.next(),
  1078. randomKeyGenerator_.next());
  1079. }
  1080. AutoSetNewObjectMetadata::AutoSetNewObjectMetadata(ExclusiveContext* ecx
  1081. MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
  1082. : CustomAutoRooter(ecx)
  1083. , cx_(ecx->maybeJSContext())
  1084. , prevState_(ecx->compartment()->objectMetadataState)
  1085. {
  1086. MOZ_GUARD_OBJECT_NOTIFIER_INIT;
  1087. if (cx_)
  1088. cx_->compartment()->objectMetadataState = NewObjectMetadataState(DelayMetadata());
  1089. }
  1090. AutoSetNewObjectMetadata::~AutoSetNewObjectMetadata()
  1091. {
  1092. // If we don't have a cx, we didn't change the metadata state, so no need to
  1093. // reset it here.
  1094. if (!cx_)
  1095. return;
  1096. if (!cx_->isExceptionPending() && cx_->compartment()->hasObjectPendingMetadata()) {
  1097. // This destructor often runs upon exit from a function that is
  1098. // returning an unrooted pointer to a Cell. The allocation metadata
  1099. // callback often allocates; if it causes a GC, then the Cell pointer
  1100. // being returned won't be traced or relocated.
  1101. //
  1102. // The only extant callbacks are those internal to SpiderMonkey that
  1103. // capture the JS stack. In fact, we're considering removing general
  1104. // callbacks altogther in bug 1236748. Since it's not running arbitrary
  1105. // code, it's adequate to simply suppress GC while we run the callback.
  1106. AutoSuppressGC autoSuppressGC(cx_);
  1107. JSObject* obj = cx_->compartment()->objectMetadataState.as<PendingMetadata>();
  1108. // Make sure to restore the previous state before setting the object's
  1109. // metadata. SetNewObjectMetadata asserts that the state is not
  1110. // PendingMetadata in order to ensure that metadata callbacks are called
  1111. // in order.
  1112. cx_->compartment()->objectMetadataState = prevState_;
  1113. obj = SetNewObjectMetadata(cx_, obj);
  1114. } else {
  1115. cx_->compartment()->objectMetadataState = prevState_;
  1116. }
  1117. }