Bug 1543997 - Move default free op from JSRuntime to JSContext r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Fri, 12 Apr 2019 16:51:42 +0100
changeset 469595 03b7cf8b0c18
parent 469594 974f32848a0d
child 469596 4aeaae90b1a1
push id35875
push userccoroiu@mozilla.com
push dateTue, 16 Apr 2019 04:06:16 +0000
treeherdermozilla-central@a83cab75b00d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1543997
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1543997 - Move default free op from JSRuntime to JSContext r=sfink Differential Revision: https://phabricator.services.mozilla.com/D27332
js/src/gc/FreeOp.h
js/src/gc/GC.cpp
js/src/vm/JSContext.cpp
js/src/vm/JSContext.h
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
--- a/js/src/gc/FreeOp.h
+++ b/js/src/gc/FreeOp.h
@@ -24,32 +24,33 @@ namespace js {
  * convenience methods that also call destructors.
  *
  * FreeOp is passed to finalizers and other sweep-phase hooks so that we do not
  * need to pass a JSContext to those hooks.
  */
 class FreeOp : public JSFreeOp {
   Vector<void*, 0, SystemAllocPolicy> freeLaterList;
   jit::JitPoisonRangeVector jitPoisonRanges;
+  const bool isDefault;
 
  public:
   static FreeOp* get(JSFreeOp* fop) { return static_cast<FreeOp*>(fop); }
 
-  explicit FreeOp(JSRuntime* maybeRuntime);
+  explicit FreeOp(JSRuntime* maybeRuntime, bool isDefault = false);
   ~FreeOp();
 
   bool onMainThread() const { return runtime_ != nullptr; }
 
   bool maybeOnHelperThread() const {
     // Sometimes background finalization happens on the main thread so
     // runtime_ being null doesn't always mean we are off thread.
     return !runtime_;
   }
 
-  bool isDefaultFreeOp() const;
+  bool isDefaultFreeOp() const { return isDefault; }
 
   void free_(void* p) { js_free(p); }
 
   void freeLater(void* p) {
     // FreeOps other than the defaultFreeOp() are constructed on the stack,
     // and won't hold onto the pointers to free indefinitely.
     MOZ_ASSERT(!isDefaultFreeOp());
 
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -3724,19 +3724,20 @@ void GCRuntime::freeFromBackgroundThread
 
     Nursery::BufferSet buffers;
     mozilla::Swap(buffers, buffersToFreeAfterMinorGC.ref());
 
     AutoUnlockHelperThreadState unlock(lock);
 
     lifoBlocks.freeAll();
 
+    FreeOp* fop = TlsContext.get()->defaultFreeOp();
     for (Nursery::BufferSet::Range r = buffers.all(); !r.empty();
          r.popFront()) {
-      rt->defaultFreeOp()->free_(r.front());
+      fop->free_(r.front());
     }
   } while (!lifoBlocksToFree.ref().isEmpty() ||
            !buffersToFreeAfterMinorGC.ref().empty());
 }
 
 void GCRuntime::waitBackgroundFreeEnd() { freeTask.join(); }
 
 /* static */
--- a/js/src/vm/JSContext.cpp
+++ b/js/src/vm/JSContext.cpp
@@ -1219,16 +1219,17 @@ mozilla::GenericErrorResult<JS::Error&> 
 }
 
 JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
     : runtime_(runtime),
       kind_(ContextKind::HelperThread),
       helperThread_(nullptr),
       options_(options),
       freeLists_(nullptr),
+      defaultFreeOp_(runtime, true),
       jitActivation(nullptr),
       activation_(nullptr),
       profilingActivation_(nullptr),
       nativeStackBase(GetNativeStackBase()),
       entryMonitor(nullptr),
       noExecuteDebuggerTop(nullptr),
 #ifdef DEBUG
       inUnsafeCallWithABI(false),
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -169,16 +169,18 @@ struct JSContext : public JS::RootingCon
   // This is reset each time we switch zone, then added to the variable in the
   // zone when we switch away from it.  This would be a js::ThreadData but we
   // need to take its address.
   uint32_t allocsThisZoneSinceMinorGC_;
 
   // Free lists for parallel allocation in the atoms zone on helper threads.
   js::ThreadData<js::gc::FreeLists*> atomsZoneFreeLists_;
 
+  js::ThreadData<js::FreeOp> defaultFreeOp_;
+
  public:
   // This is used by helper threads to change the runtime their context is
   // currently operating on.
   void setRuntime(JSRuntime* rt);
 
   bool isMainThreadContext() const {
     return kind_ == js::ContextKind::MainThread;
   }
@@ -264,17 +266,17 @@ struct JSContext : public JS::RootingCon
   bool permanentAtomsPopulated() { return runtime_->permanentAtomsPopulated(); }
   const js::FrozenAtomSet& permanentAtoms() {
     return *runtime_->permanentAtoms();
   }
   js::WellKnownSymbols& wellKnownSymbols() {
     return *runtime_->wellKnownSymbols;
   }
   js::PropertyName* emptyString() { return runtime_->emptyString; }
-  js::FreeOp* defaultFreeOp() { return runtime_->defaultFreeOp(); }
+  js::FreeOp* defaultFreeOp() { return &defaultFreeOp_.ref(); }
   void* stackLimitAddress(JS::StackKind kind) {
     return &nativeStackLimit[kind];
   }
   void* stackLimitAddressForJitCode(JS::StackKind kind);
   uintptr_t stackLimit(JS::StackKind kind) { return nativeStackLimit[kind]; }
   uintptr_t stackLimitForJitCode(JS::StackKind kind);
   size_t gcSystemPageSize() { return js::gc::SystemPageSize(); }
   bool jitSupportsFloatingPoint() const {
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -196,20 +196,17 @@ bool JSRuntime::init(JSContext* cx, uint
 #endif
 
   if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized()) {
     return false;
   }
 
   mainContext_ = cx;
 
-  defaultFreeOp_ = js_new<js::FreeOp>(this);
-  if (!defaultFreeOp_) {
-    return false;
-  }
+  defaultFreeOp_ = cx->defaultFreeOp();
 
   if (!gc.init(maxbytes, maxNurseryBytes)) {
     return false;
   }
 
   UniquePtr<Zone> atomsZone = MakeUnique<Zone>(this);
   if (!atomsZone || !atomsZone->init(true)) {
     return false;
@@ -298,18 +295,16 @@ void JSRuntime::destroyRuntime() {
   FreeScriptData(this);
 
 #if !EXPOSE_INTL_API
   FinishRuntimeNumberState(this);
 #endif
 
   gc.finish();
 
-  js_delete(defaultFreeOp_.ref());
-
   defaultLocale = nullptr;
   js_delete(jitRuntime_.ref());
 
 #ifdef DEBUG
   initialized_ = false;
 #endif
 }
 
@@ -568,34 +563,31 @@ const char* JSRuntime::getDefaultLocale(
   defaultLocale.ref() = std::move(lang);
   return defaultLocale.ref().get();
 }
 
 void JSRuntime::traceSharedIntlData(JSTracer* trc) {
   sharedIntlData.ref().trace(trc);
 }
 
-FreeOp::FreeOp(JSRuntime* maybeRuntime) : JSFreeOp(maybeRuntime) {
+FreeOp::FreeOp(JSRuntime* maybeRuntime, bool isDefault)
+    : JSFreeOp(maybeRuntime), isDefault(isDefault) {
   MOZ_ASSERT_IF(maybeRuntime, CurrentThreadCanAccessRuntime(maybeRuntime));
 }
 
 FreeOp::~FreeOp() {
   for (size_t i = 0; i < freeLaterList.length(); i++) {
     free_(freeLaterList[i]);
   }
 
   if (!jitPoisonRanges.empty()) {
     jit::ExecutableAllocator::poisonCode(runtime(), jitPoisonRanges);
   }
 }
 
-bool FreeOp::isDefaultFreeOp() const {
-  return runtime_ && runtime_->defaultFreeOp() == this;
-}
-
 GlobalObject* JSRuntime::getIncumbentGlobal(JSContext* cx) {
   MOZ_ASSERT(cx->jobQueue);
 
   JSObject* obj = cx->jobQueue->getIncumbentGlobal(cx);
   if (!obj) {
     return nullptr;
   }
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -639,17 +639,17 @@ struct JSRuntime : public js::MallocProv
   /* Well-known numbers. */
   const js::Value NaNValue;
   const js::Value negativeInfinityValue;
   const js::Value positiveInfinityValue;
 
   js::WriteOnceData<js::PropertyName*> emptyString;
 
  private:
-  js::WriteOnceData<js::FreeOp*> defaultFreeOp_;
+  js::MainThreadData<js::FreeOp*> defaultFreeOp_;
 
  public:
   js::FreeOp* defaultFreeOp() {
     MOZ_ASSERT(defaultFreeOp_);
     return defaultFreeOp_;
   }
 
 #if !EXPOSE_INTL_API