Bug 1400278 - Replace runtime allocation with system or zone allocation where possible r=jandem
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 20 Sep 2017 13:19:32 +0100
changeset 381876 29b2e8acf5f925c4ee2c5534f02bc9608afd674a
parent 381875 065aebfbdd75820c73419a3173dbf1c5bca1ab00
child 381877 5e2869a877a66bcf7f4b52a9769b0761f964f597
push id95218
push userjcoppeard@mozilla.com
push dateWed, 20 Sep 2017 12:19:58 +0000
treeherdermozilla-inbound@29b2e8acf5f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1400278
milestone57.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 1400278 - Replace runtime allocation with system or zone allocation where possible r=jandem
js/public/MemoryMetrics.h
js/src/gc/Zone.h
js/src/jit/CodeGenerator.cpp
js/src/jit/CompileWrappers.cpp
js/src/jit/CompileWrappers.h
js/src/jit/Ion.cpp
js/src/jit/JitCompartment.h
js/src/jit/MacroAssembler.cpp
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/jit/shared/CodeGenerator-shared.cpp
js/src/jsapi.cpp
js/src/jsatom.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscompartment.h
js/src/jsobj.cpp
js/src/jsscript.cpp
js/src/vm/ArrayBufferObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/MemoryMetrics.cpp
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
js/src/vm/WeakMapPtr.cpp
js/src/wasm/WasmDebug.cpp
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -683,17 +683,17 @@ struct ZoneStats
 
     ~ZoneStats() {
         // |allStrings| is usually deleted and set to nullptr before this
         // destructor runs. But there are failure cases due to OOMs that may
         // prevent that, so it doesn't hurt to try again here.
         js_delete(allStrings);
     }
 
-    bool initStrings(JSRuntime* rt);
+    bool initStrings();
 
     void addSizes(const ZoneStats& other) {
         MOZ_ASSERT(isTotals);
         FOR_EACH_SIZE(ADD_OTHER_SIZE)
         unusedGCThings.addSizes(other.unusedGCThings);
         stringInfo.add(other.stringInfo);
         shapeInfo.add(other.shapeInfo);
     }
@@ -803,17 +803,17 @@ struct CompartmentStats
 
     ~CompartmentStats() {
         // |allClasses| is usually deleted and set to nullptr before this
         // destructor runs. But there are failure cases due to OOMs that may
         // prevent that, so it doesn't hurt to try again here.
         js_delete(allClasses);
     }
 
-    bool initClasses(JSRuntime* rt);
+    bool initClasses();
 
     void addSizes(const CompartmentStats& other) {
         MOZ_ASSERT(isTotals);
         FOR_EACH_SIZE(ADD_OTHER_SIZE)
         classInfo.add(other.classInfo);
     }
 
     size_t sizeOfLiveGCThings() const {
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -247,17 +247,17 @@ struct Zone : public JS::shadow::Zone,
     void changeGCState(GCState prev, GCState next) {
         MOZ_ASSERT(CurrentThreadIsHeapBusy());
         MOZ_ASSERT(gcState() == prev);
         MOZ_ASSERT_IF(next != NoGC, canCollect());
         gcState_ = next;
     }
 
     bool isCollecting() const {
-        MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
+        MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
         return isCollectingFromAnyThread();
     }
 
     bool isCollectingFromAnyThread() const {
         if (CurrentThreadIsHeapCollecting())
             return gcState_ != NoGC;
         else
             return needsIncrementalBarrier();
@@ -430,17 +430,17 @@ struct Zone : public JS::shadow::Zone,
 
     JS::WeakCache<TypeDescrObjectSet>& typeDescrObjects() { return typeDescrObjects_.ref(); }
 
     bool addTypeDescrObject(JSContext* cx, HandleObject obj);
 
     bool triggerGCForTooMuchMalloc() {
         JSRuntime* rt = runtimeFromAnyThread();
 
-        if (CurrentThreadCanAccessRuntime(rt)) {
+        if (js::CurrentThreadCanAccessRuntime(rt)) {
             return rt->gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC,
                                         gcMallocCounter.bytes(), gcMallocCounter.maxBytes());
         }
         return false;
     }
 
     void resetGCMallocBytes() { gcMallocCounter.reset(); }
     void setGCMaxMallocBytes(size_t value) { gcMallocCounter.setMax(value); }
@@ -615,17 +615,17 @@ struct Zone : public JS::shadow::Zone,
         return uniqueIds().has(cell);
     }
 
     // Transfer an id from another cell. This must only be called on behalf of a
     // moving GC. This method is infallible.
     void transferUniqueId(js::gc::Cell* tgt, js::gc::Cell* src) {
         MOZ_ASSERT(src != tgt);
         MOZ_ASSERT(!IsInsideNursery(tgt));
-        MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
+        MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
         MOZ_ASSERT(!uniqueIds().has(tgt));
         uniqueIds().rekeyIfMoved(src, tgt);
     }
 
     // Remove any unique id associated with this Cell.
     void removeUniqueId(js::gc::Cell* cell) {
         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
@@ -654,16 +654,38 @@ struct Zone : public JS::shadow::Zone,
     }
     void setKeepShapeTables(bool b) {
         keepShapeTables_ = b;
     }
 
     // Delete an empty compartment after its contents have been merged.
     void deleteEmptyCompartment(JSCompartment* comp);
 
+    /*
+     * This variation of calloc will call the large-allocation-failure callback
+     * on OOM and retry the allocation.
+     */
+    template <typename T>
+    T* pod_callocCanGC(size_t numElems) {
+        T* p = pod_calloc<T>(numElems);
+        if (MOZ_LIKELY(!!p))
+            return p;
+        size_t bytes;
+        if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
+            reportAllocationOverflow();
+            return nullptr;
+        }
+        JSRuntime* rt = runtimeFromActiveCooperatingThread();
+        p = static_cast<T*>(rt->onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes));
+        if (!p)
+            return nullptr;
+        updateMallocCounter(bytes);
+        return p;
+    }
+
   private:
     js::ZoneGroupData<js::jit::JitZone*> jitZone_;
 
     js::ActiveThreadData<bool> gcScheduled_;
     js::ZoneGroupData<bool> gcPreserveCode_;
     js::ZoneGroupData<bool> keepShapeTables_;
 
     // Allow zones to be linked into a list
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -7907,38 +7907,38 @@ JitCompartment::generateStringConcatStub
 #ifdef MOZ_VTUNE
     vtune::MarkStub(code, "StringConcatStub");
 #endif
 
     return code;
 }
 
 JitCode*
-JitRuntime::generateMallocStub(JSContext* cx)
+JitZone::generateMallocStub(JSContext* cx)
 {
     const Register regReturn = CallTempReg0;
     const Register regNBytes = CallTempReg0;
 
     MacroAssembler masm(cx);
 
     AllocatableRegisterSet regs(RegisterSet::Volatile());
 #ifdef JS_USE_LINK_REGISTER
     masm.pushReturnAddress();
 #endif
     regs.takeUnchecked(regNBytes);
     LiveRegisterSet save(regs.asLiveSet());
     masm.PushRegsInMask(save);
 
     const Register regTemp = regs.takeAnyGeneral();
-    const Register regRuntime = regTemp;
+    const Register regZone = regTemp;
     MOZ_ASSERT(regTemp != regNBytes);
 
     masm.setupUnalignedABICall(regTemp);
-    masm.movePtr(ImmPtr(cx->runtime()), regRuntime);
-    masm.passABIArg(regRuntime);
+    masm.movePtr(ImmPtr(cx->zone()), regZone);
+    masm.passABIArg(regZone);
     masm.passABIArg(regNBytes);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, MallocWrapper));
     masm.storeCallWordResult(regReturn);
 
     masm.PopRegsInMask(save);
     masm.ret();
 
     Linker linker(masm);
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -136,16 +136,22 @@ CompileZone::get(Zone* zone)
 }
 
 CompileRuntime*
 CompileZone::runtime()
 {
     return CompileRuntime::get(zone()->runtimeFromAnyThread());
 }
 
+JitCode*
+CompileZone::mallocStub()
+{
+    return zone()->jitZone()->mallocStub();
+}
+
 bool
 CompileZone::isAtomsZone()
 {
     return zone()->isAtomsZone();
 }
 
 #ifdef DEBUG
 const void*
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -63,16 +63,18 @@ class CompileZone
     Zone* zone();
 
   public:
     static CompileZone* get(Zone* zone);
 
     CompileRuntime* runtime();
     bool isAtomsZone();
 
+    JitCode* mallocStub();
+
 #ifdef DEBUG
     const void* addressOfIonBailAfter();
 #endif
 
     const void* addressOfJSContext();
     const void* addressOfNeedsIncrementalBarrier();
     const void* addressOfFreeList(gc::AllocKind allocKind);
     const void* addressOfNurseryPosition();
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -315,21 +315,16 @@ JitRuntime::initialize(JSContext* cx, Au
     if (!shapePreBarrier_)
         return false;
 
     JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for ObjectGroup");
     objectGroupPreBarrier_ = generatePreBarrier(cx, MIRType::ObjectGroup);
     if (!objectGroupPreBarrier_)
         return false;
 
-    JitSpew(JitSpew_Codegen, "# Emitting malloc stub");
-    mallocStub_ = generateMallocStub(cx);
-    if (!mallocStub_)
-        return false;
-
     JitSpew(JitSpew_Codegen, "# Emitting free stub");
     freeStub_ = generateFreeStub(cx);
     if (!freeStub_)
         return false;
 
     JitSpew(JitSpew_Codegen, "# Emitting VM function wrappers");
     for (VMFunction* fun = VMFunction::functions; fun; fun = fun->next) {
         JitSpew(JitSpew_Codegen, "# VM function wrapper");
@@ -465,16 +460,23 @@ JitCompartment::ensureIonStubsExist(JSCo
 bool
 JitZone::init(JSContext* cx)
 {
     if (!baselineCacheIRStubCodes_.init()) {
         ReportOutOfMemory(cx);
         return false;
     }
 
+    JitSpew(JitSpew_Codegen, "# Emitting malloc stub");
+    mallocStub_ = generateMallocStub(cx);
+    if (!mallocStub_) {
+        ReportOutOfMemory(cx);
+        return false;
+    }
+
     return true;
 }
 
 void
 jit::FreeIonBuilder(IonBuilder* builder)
 {
     // The builder is allocated into its LifoAlloc, so destroying that will
     // destroy the builder and all other data accumulated during compilation,
--- a/js/src/jit/JitCompartment.h
+++ b/js/src/jit/JitCompartment.h
@@ -124,18 +124,17 @@ class JitRuntime
 
     // Thunk that calls the GC pre barrier.
     ExclusiveAccessLockWriteOnceData<JitCode*> valuePreBarrier_;
     ExclusiveAccessLockWriteOnceData<JitCode*> stringPreBarrier_;
     ExclusiveAccessLockWriteOnceData<JitCode*> objectPreBarrier_;
     ExclusiveAccessLockWriteOnceData<JitCode*> shapePreBarrier_;
     ExclusiveAccessLockWriteOnceData<JitCode*> objectGroupPreBarrier_;
 
-    // Thunk to call malloc/free.
-    ExclusiveAccessLockWriteOnceData<JitCode*> mallocStub_;
+    // Thunk to call free.
     ExclusiveAccessLockWriteOnceData<JitCode*> freeStub_;
 
     // Thunk called to finish compilation of an IonScript.
     ExclusiveAccessLockWriteOnceData<JitCode*> lazyLinkStub_;
 
     // Thunk used by the debugger for breakpoint and step mode.
     ExclusiveAccessLockWriteOnceData<JitCode*> debugTrapHandler_;
 
@@ -160,17 +159,16 @@ class JitRuntime
     JitCode* generateExceptionTailStub(JSContext* cx, void* handler);
     JitCode* generateBailoutTailStub(JSContext* cx);
     JitCode* generateEnterJIT(JSContext* cx, EnterJitType type);
     JitCode* generateArgumentsRectifier(JSContext* cx, void** returnAddrOut);
     JitCode* generateBailoutTable(JSContext* cx, uint32_t frameClass);
     JitCode* generateBailoutHandler(JSContext* cx);
     JitCode* generateInvalidator(JSContext* cx);
     JitCode* generatePreBarrier(JSContext* cx, MIRType type);
-    JitCode* generateMallocStub(JSContext* cx);
     JitCode* generateFreeStub(JSContext* cx);
     JitCode* generateDebugTrapHandler(JSContext* cx);
     JitCode* generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrameRegPopOffsetOut);
     JitCode* generateVMWrapper(JSContext* cx, const VMFunction& f);
 
     bool generateTLEventVM(JSContext* cx, MacroAssembler& masm, const VMFunction& f, bool enter);
 
     inline bool generateTLEnterVM(JSContext* cx, MacroAssembler& masm, const VMFunction& f) {
@@ -281,20 +279,16 @@ class JitRuntime
           case MIRType::String: return stringPreBarrier_;
           case MIRType::Object: return objectPreBarrier_;
           case MIRType::Shape: return shapePreBarrier_;
           case MIRType::ObjectGroup: return objectGroupPreBarrier_;
           default: MOZ_CRASH();
         }
     }
 
-    JitCode* mallocStub() const {
-        return mallocStub_;
-    }
-
     JitCode* freeStub() const {
         return freeStub_;
     }
 
     JitCode* lazyLinkStub() const {
         return lazyLinkStub_;
     }
 
@@ -415,16 +409,19 @@ class JitZone
     // Map CacheIRStubKey to shared JitCode objects.
     using BaselineCacheIRStubCodeMap = GCHashMap<CacheIRStubKey,
                                                  ReadBarrieredJitCode,
                                                  CacheIRStubKey,
                                                  SystemAllocPolicy,
                                                  IcStubCodeMapGCPolicy<CacheIRStubKey>>;
     BaselineCacheIRStubCodeMap baselineCacheIRStubCodes_;
 
+    // Thunk to call malloc.
+    WriteOnceData<JitCode*> mallocStub_;
+
   public:
     MOZ_MUST_USE bool init(JSContext* cx);
     void sweep(FreeOp* fop);
 
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t* jitZone,
                                 size_t* baselineStubsOptimized,
                                 size_t* cachedCFG) const;
@@ -468,16 +465,23 @@ class JitZone
             return false;
         IonCacheIRStubInfoSet::AddPtr p = ionCacheIRStubInfoSet_.lookupForAdd(lookup);
         MOZ_ASSERT(!p);
         return ionCacheIRStubInfoSet_.add(p, Move(key));
     }
     void purgeIonCacheIRStubInfo() {
         ionCacheIRStubInfoSet_.finish();
     }
+
+    JitCode* mallocStub() const {
+        return mallocStub_;
+    }
+
+  private:
+    JitCode* generateMallocStub(JSContext* cx);
 };
 
 enum class BailoutReturnStub {
     GetProp,
     GetPropSuper,
     SetProp,
     Call,
     New,
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -847,17 +847,17 @@ MacroAssembler::callMallocStub(size_t nb
     const Register regNBytes = CallTempReg0;
 
     MOZ_ASSERT(nbytes > 0);
     MOZ_ASSERT(nbytes <= INT32_MAX);
 
     if (regNBytes != result)
         push(regNBytes);
     move32(Imm32(nbytes), regNBytes);
-    call(GetJitContext()->runtime->jitRuntime()->mallocStub());
+    call(GetJitContext()->compartment->zone()->mallocStub());
     if (regNBytes != result) {
         movePtr(regNBytes, result);
         pop(regNBytes);
     }
     branchTest32(Assembler::Zero, result, result, fail);
 }
 
 void
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -537,20 +537,20 @@ InterruptCheck(JSContext* cx)
         JitRuntime::AutoPreventBackedgePatching apbp(rt);
         cx->zone()->group()->jitZoneGroup->patchIonBackedges(cx, JitZoneGroup::BackedgeLoopHeader);
     }
 
     return CheckForInterrupt(cx);
 }
 
 void*
-MallocWrapper(JSRuntime* rt, size_t nbytes)
+MallocWrapper(JS::Zone* zone, size_t nbytes)
 {
     AutoUnsafeCallWithABI unsafe;
-    return rt->pod_malloc<uint8_t>(nbytes);
+    return zone->pod_malloc<uint8_t>(nbytes);
 }
 
 JSObject*
 NewCallObject(JSContext* cx, HandleShape shape, HandleObjectGroup group)
 {
     JSObject* obj = CallObject::create(cx, shape, group);
     if (!obj)
         return nullptr;
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -674,17 +674,17 @@ JSString* StringFromCodePoint(JSContext*
 
 MOZ_MUST_USE bool
 SetProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value,
             bool strict, jsbytecode* pc);
 
 MOZ_MUST_USE bool
 InterruptCheck(JSContext* cx);
 
-void* MallocWrapper(JSRuntime* rt, size_t nbytes);
+void* MallocWrapper(JS::Zone* zone, size_t nbytes);
 JSObject* NewCallObject(JSContext* cx, HandleShape shape, HandleObjectGroup group);
 JSObject* NewSingletonCallObject(JSContext* cx, HandleShape shape);
 JSObject* NewStringObject(JSContext* cx, HandleString str);
 
 bool OperatorIn(JSContext* cx, HandleValue key, HandleObject obj, bool* out);
 bool OperatorInI(JSContext* cx, uint32_t index, HandleObject obj, bool* out);
 
 MOZ_MUST_USE bool
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -706,17 +706,17 @@ CodeGeneratorShared::createNativeToBytec
         }
 
         // Otherwise, we must have reached the top without finding any siblings.
         MOZ_ASSERT(tree->isOutermostCaller());
         break;
     }
 
     // Allocate array for list.
-    JSScript** data = cx->runtime()->pod_malloc<JSScript*>(scriptList.length());
+    JSScript** data = cx->zone()->pod_malloc<JSScript*>(scriptList.length());
     if (!data)
         return false;
 
     for (uint32_t i = 0; i < scriptList.length(); i++)
         data[i] = scriptList[i];
 
     // Success.
     nativeToBytecodeScriptListLength_ = scriptList.length();
@@ -753,17 +753,17 @@ CodeGeneratorShared::generateCompactNati
         js_free(nativeToBytecodeScriptList_);
         return false;
     }
 
     MOZ_ASSERT(tableOffset > 0);
     MOZ_ASSERT(numRegions > 0);
 
     // Writer is done, copy it to sized buffer.
-    uint8_t* data = cx->runtime()->pod_malloc<uint8_t>(writer.length());
+    uint8_t* data = cx->zone()->pod_malloc<uint8_t>(writer.length());
     if (!data) {
         js_free(nativeToBytecodeScriptList_);
         return false;
     }
 
     memcpy(data, writer.buffer(), writer.length());
     nativeToBytecodeMap_ = data;
     nativeToBytecodeMapSize_ = writer.length();
@@ -909,17 +909,17 @@ CodeGeneratorShared::generateCompactTrac
 
     MOZ_ASSERT(regionTableOffset > 0);
     MOZ_ASSERT(typesTableOffset > 0);
     MOZ_ASSERT(attemptsTableOffset > 0);
     MOZ_ASSERT(typesTableOffset > regionTableOffset);
     MOZ_ASSERT(attemptsTableOffset > typesTableOffset);
 
     // Copy over the table out of the writer's buffer.
-    uint8_t* data = cx->runtime()->pod_malloc<uint8_t>(writer.length());
+    uint8_t* data = cx->zone()->pod_malloc<uint8_t>(writer.length());
     if (!data)
         return false;
 
     memcpy(data, writer.buffer(), writer.length());
     trackedOptimizationsMap_ = data;
     trackedOptimizationsMapSize_ = writer.length();
     trackedOptimizationsRegionTableOffset_ = regionTableOffset;
     trackedOptimizationsTypesTableOffset_ = typesTableOffset;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1329,17 +1329,17 @@ JS::detail::ComputeThis(JSContext* cx, V
     return thisv;
 }
 
 JS_PUBLIC_API(void*)
 JS_malloc(JSContext* cx, size_t nbytes)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    return static_cast<void*>(cx->runtime()->pod_malloc<uint8_t>(nbytes));
+    return static_cast<void*>(cx->zone()->pod_malloc<uint8_t>(nbytes));
 }
 
 JS_PUBLIC_API(void*)
 JS_realloc(JSContext* cx, void* p, size_t oldBytes, size_t newBytes)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     return static_cast<void*>(cx->zone()->pod_realloc<uint8_t>(static_cast<uint8_t*>(p), oldBytes,
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -76,33 +76,33 @@ struct CommonNameInfo
 {
     const char* str;
     size_t length;
 };
 
 bool
 JSRuntime::initializeAtoms(JSContext* cx)
 {
-    atoms_ = cx->new_<AtomSet>();
+    atoms_ = js_new<AtomSet>();
     if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
         return false;
 
     // |permanentAtoms| hasn't been created yet.
     MOZ_ASSERT(!permanentAtoms);
 
     if (parentRuntime) {
         staticStrings = parentRuntime->staticStrings;
         commonNames = parentRuntime->commonNames;
         emptyString = parentRuntime->emptyString;
         permanentAtoms = parentRuntime->permanentAtoms;
         wellKnownSymbols = parentRuntime->wellKnownSymbols;
         return true;
     }
 
-    staticStrings = cx->new_<StaticStrings>();
+    staticStrings = js_new<StaticStrings>();
     if (!staticStrings || !staticStrings->init(cx))
         return false;
 
     static const CommonNameInfo cachedNames[] = {
 #define COMMON_NAME_INFO(idpart, id, text) { js_##idpart##_str, sizeof(text) - 1 },
         FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INFO)
 #undef COMMON_NAME_INFO
 #define COMMON_NAME_INFO(name, init, clasp) { js_##name##_str, sizeof(#name) - 1 },
@@ -111,33 +111,33 @@ JSRuntime::initializeAtoms(JSContext* cx
 #define COMMON_NAME_INFO(name) { #name, sizeof(#name) - 1 },
         JS_FOR_EACH_WELL_KNOWN_SYMBOL(COMMON_NAME_INFO)
 #undef COMMON_NAME_INFO
 #define COMMON_NAME_INFO(name) { "Symbol." #name, sizeof("Symbol." #name) - 1 },
         JS_FOR_EACH_WELL_KNOWN_SYMBOL(COMMON_NAME_INFO)
 #undef COMMON_NAME_INFO
     };
 
-    commonNames = cx->new_<JSAtomState>();
+    commonNames = js_new<JSAtomState>();
     if (!commonNames)
         return false;
 
     ImmutablePropertyNamePtr* names = reinterpret_cast<ImmutablePropertyNamePtr*>(commonNames.ref());
     for (size_t i = 0; i < ArrayLength(cachedNames); i++, names++) {
         JSAtom* atom = Atomize(cx, cachedNames[i].str, cachedNames[i].length, PinAtom);
         if (!atom)
             return false;
         names->init(atom->asPropertyName());
     }
     MOZ_ASSERT(uintptr_t(names) == uintptr_t(commonNames + 1));
 
     emptyString = commonNames->empty;
 
     // Create the well-known symbols.
-    wellKnownSymbols = cx->new_<WellKnownSymbols>();
+    wellKnownSymbols = js_new<WellKnownSymbols>();
     if (!wellKnownSymbols)
         return false;
 
     ImmutablePropertyNamePtr* descriptions = commonNames->wellKnownSymbolDescriptions();
     ImmutableSymbolPtr* symbols = reinterpret_cast<ImmutableSymbolPtr*>(wellKnownSymbols.ref());
     for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++) {
         JS::Symbol* symbol = JS::Symbol::new_(cx, JS::SymbolCode(i), descriptions[i]);
         if (!symbol) {
@@ -237,19 +237,19 @@ bool
 JSRuntime::transformToPermanentAtoms(JSContext* cx)
 {
     MOZ_ASSERT(!parentRuntime);
 
     // All static strings were created as permanent atoms, now move the contents
     // of the atoms table into permanentAtoms and mark each as permanent.
 
     MOZ_ASSERT(!permanentAtoms);
-    permanentAtoms = cx->new_<FrozenAtomSet>(atoms_);   // takes ownership of atoms_
+    permanentAtoms = js_new<FrozenAtomSet>(atoms_);   // takes ownership of atoms_
 
-    atoms_ = cx->new_<AtomSet>();
+    atoms_ = js_new<AtomSet>();
     if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
         return false;
 
     for (FrozenAtomSet::Range r(permanentAtoms->all()); !r.empty(); r.popFront()) {
         AtomStateEntry entry = r.front();
         JSAtom* atom = entry.asPtr(cx);
         atom->morphIntoPermanentAtom();
     }
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1145,17 +1145,17 @@ class MOZ_STACK_CLASS ReportExceptionClo
 JS_FRIEND_API(bool)
 js::UseInternalJobQueues(JSContext* cx)
 {
     // Internal job queue handling must be set up very early. Self-hosting
     // initialization is as good a marker for that as any.
     MOZ_RELEASE_ASSERT(!cx->runtime()->hasInitializedSelfHosting(),
                        "js::UseInternalJobQueues must be called early during runtime startup.");
     MOZ_ASSERT(!cx->jobQueue);
-    auto* queue = cx->new_<PersistentRooted<JobQueue>>(cx, JobQueue(SystemAllocPolicy()));
+    auto* queue = js_new<PersistentRooted<JobQueue>>(cx, JobQueue(SystemAllocPolicy()));
     if (!queue)
         return false;
 
     cx->jobQueue = queue;
     cx->runtime()->offThreadPromiseState.ref().initInternalDispatchQueue();
 
     JS::SetEnqueuePromiseJobCallback(cx, InternalEnqueuePromiseJobCallback);
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -138,17 +138,16 @@ struct JSContext : public JS::RootingCon
         }
         return runtime_->onOutOfMemory(allocFunc, nbytes, reallocPtr, this);
     }
 
     /* Clear the pending exception (if any) due to OOM. */
     void recoverFromOutOfMemory();
 
     inline void updateMallocCounter(size_t nbytes) {
-        // Note: this is racy.
         runtime()->updateMallocCounter(zone(), nbytes);
     }
 
     void reportAllocationOverflow() {
         js::ReportAllocationOverflow(this);
     }
 
     // Accessors for immutable runtime data.
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -657,17 +657,17 @@ struct JSCompartment
     JS::Zone* zone() { return zone_; }
     const JS::Zone* zone() const { return zone_; }
 
     const JS::CompartmentCreationOptions& creationOptions() const { return creationOptions_; }
     JS::CompartmentBehaviors& behaviors() { return behaviors_; }
     const JS::CompartmentBehaviors& behaviors() const { return behaviors_; }
 
     JSRuntime* runtimeFromActiveCooperatingThread() const {
-        MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
+        MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
         return runtime_;
     }
 
     // Note: Unrestricted access to the zone's runtime from an arbitrary
     // thread can easily lead to races. Use this method very carefully.
     JSRuntime* runtimeFromAnyThread() const {
         return runtime_;
     }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2971,17 +2971,17 @@ js::WatchGuts(JSContext* cx, JS::HandleO
         if (!NativeObject::sparsifyDenseElements(cx, obj.as<NativeObject>()))
             return false;
 
         MarkTypePropertyNonData(cx, obj, id);
     }
 
     WatchpointMap* wpmap = cx->compartment()->watchpointMap;
     if (!wpmap) {
-        wpmap = cx->runtime()->new_<WatchpointMap>();
+        wpmap = cx->zone()->new_<WatchpointMap>();
         if (!wpmap || !wpmap->init()) {
             ReportOutOfMemory(cx);
             js_delete(wpmap);
             return false;
         }
         cx->compartment()->watchpointMap = wpmap;
     }
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3907,17 +3907,17 @@ JSScript::getOrCreateBreakpointSite(JSCo
 {
     if (!ensureHasDebugScript(cx))
         return nullptr;
 
     DebugScript* debug = debugScript();
     BreakpointSite*& site = debug->breakpoints[pcToOffset(pc)];
 
     if (!site) {
-        site = cx->runtime()->new_<JSBreakpointSite>(this, pc);
+        site = cx->zone()->new_<JSBreakpointSite>(this, pc);
         if (!site) {
             ReportOutOfMemory(cx);
             return nullptr;
         }
         debug->numSites++;
     }
 
     return site;
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -299,17 +299,17 @@ ArrayBufferObject::class_constructor(JSC
         return false;
     args.rval().setObject(*bufobj);
     return true;
 }
 
 static ArrayBufferObject::BufferContents
 AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes)
 {
-    uint8_t* p = cx->runtime()->pod_callocCanGC<uint8_t>(nbytes);
+    uint8_t* p = cx->zone()->pod_callocCanGC<uint8_t>(nbytes);
     if (!p)
         ReportOutOfMemory(cx);
 
     return ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(p);
 }
 
 static void
 NoteViewBufferWasDetached(ArrayBufferViewObject* view,
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -6522,34 +6522,34 @@ struct DebuggerScriptSetBreakpointMatche
         if (!dbg_->ensureExecutionObservabilityOfScript(cx_, script))
             return false;
 
         jsbytecode* pc = script->offsetToPC(offset_);
         BreakpointSite* site = script->getOrCreateBreakpointSite(cx_, pc);
         if (!site)
             return false;
         site->inc(cx_->runtime()->defaultFreeOp());
-        if (cx_->runtime()->new_<Breakpoint>(dbg_, site, handler_))
+        if (cx_->zone()->new_<Breakpoint>(dbg_, site, handler_))
             return true;
         site->dec(cx_->runtime()->defaultFreeOp());
         site->destroyIfEmpty(cx_->runtime()->defaultFreeOp());
         return false;
     }
 
     ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
         wasm::Instance& instance = wasmInstance->instance();
         if (!instance.debug().hasBreakpointTrapAtOffset(offset_)) {
             JS_ReportErrorNumberASCII(cx_, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_OFFSET);
             return false;
         }
         WasmBreakpointSite* site = instance.debug().getOrCreateBreakpointSite(cx_, offset_);
         if (!site)
             return false;
         site->inc(cx_->runtime()->defaultFreeOp());
-        if (cx_->runtime()->new_<WasmBreakpoint>(dbg_, site, handler_, instance.object()))
+        if (cx_->zone()->new_<WasmBreakpoint>(dbg_, site, handler_, instance.object()))
             return true;
         site->dec(cx_->runtime()->defaultFreeOp());
         site->destroyIfEmpty(cx_->runtime()->defaultFreeOp());
         return false;
     }
 };
 
 static bool
@@ -11646,17 +11646,17 @@ Debugger::isDebuggerCrossCompartmentEdge
 /*** JS::dbg::GarbageCollectionEvent **************************************************************/
 
 namespace JS {
 namespace dbg {
 
 /* static */ GarbageCollectionEvent::Ptr
 GarbageCollectionEvent::Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t gcNumber)
 {
-    auto data = rt->make_unique<GarbageCollectionEvent>(gcNumber);
+    auto data = MakeUnique<GarbageCollectionEvent>(gcNumber);
     if (!data)
         return nullptr;
 
     data->nonincrementalReason = stats.nonincrementalReason();
 
     for (auto& slice : stats.slices()) {
         if (!data->reason) {
             // There is only one GC reason for the whole cycle, but for legacy
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -311,17 +311,17 @@ static void
 StatsZoneCallback(JSRuntime* rt, void* data, Zone* zone)
 {
     // Append a new CompartmentStats to the vector.
     RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
 
     // CollectRuntimeStats reserves enough space.
     MOZ_ALWAYS_TRUE(rtStats->zoneStatsVector.growBy(1));
     ZoneStats& zStats = rtStats->zoneStatsVector.back();
-    if (!zStats.initStrings(rt))
+    if (!zStats.initStrings())
         MOZ_CRASH("oom");
     rtStats->initExtraZoneStats(zone, &zStats);
     rtStats->currZoneStats = &zStats;
 
     zone->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
                                  &zStats.typePool,
                                  &zStats.regexpZone,
                                  &zStats.jitZone,
@@ -336,17 +336,17 @@ static void
 StatsCompartmentCallback(JSContext* cx, void* data, JSCompartment* compartment)
 {
     // Append a new CompartmentStats to the vector.
     RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
 
     // CollectRuntimeStats reserves enough space.
     MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
     CompartmentStats& cStats = rtStats->compartmentStatsVector.back();
-    if (!cStats.initClasses(cx->runtime()))
+    if (!cStats.initClasses())
         MOZ_CRASH("oom");
     rtStats->initExtraCompartmentStats(compartment, &cStats);
 
     compartment->setCompartmentStats(&cStats);
 
     // Measure the compartment object itself, and things hanging off it.
     compartment->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
                                         &cStats.typeInferenceAllocationSiteTables,
@@ -615,33 +615,33 @@ StatsCellCallback(JSRuntime* rt, void* d
         MOZ_CRASH("invalid traceKind in StatsCellCallback");
     }
 
     // Yes, this is a subtraction:  see StatsArenaCallback() for details.
     zStats->unusedGCThings.addToKind(traceKind, -thingSize);
 }
 
 bool
-ZoneStats::initStrings(JSRuntime* rt)
+ZoneStats::initStrings()
 {
     isTotals = false;
-    allStrings = rt->new_<StringsHashMap>();
+    allStrings = js_new<StringsHashMap>();
     if (!allStrings || !allStrings->init()) {
         js_delete(allStrings);
         allStrings = nullptr;
         return false;
     }
     return true;
 }
 
 bool
-CompartmentStats::initClasses(JSRuntime* rt)
+CompartmentStats::initClasses()
 {
     isTotals = false;
-    allClasses = rt->new_<ClassesHashMap>();
+    allClasses = js_new<ClassesHashMap>();
     if (!allClasses || !allClasses->init()) {
         js_delete(allClasses);
         allClasses = nullptr;
         return false;
     }
     return true;
 }
 
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -213,22 +213,22 @@ JSRuntime::init(JSContext* cx, uint32_t 
 
     defaultFreeOp_ = js_new<js::FreeOp>(this);
     if (!defaultFreeOp_)
         return false;
 
     if (!gc.init(maxbytes, maxNurseryBytes))
         return false;
 
-    ScopedJSDeletePtr<Zone> atomsZone(new_<Zone>(this, nullptr));
+    ScopedJSDeletePtr<Zone> atomsZone(js_new<Zone>(this, nullptr));
     if (!atomsZone || !atomsZone->init(true))
         return false;
 
     JS::CompartmentOptions options;
-    ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get(), options));
+    ScopedJSDeletePtr<JSCompartment> atomsCompartment(js_new<JSCompartment>(atomsZone.get(), options));
     if (!atomsCompartment || !atomsCompartment->init(nullptr))
         return false;
 
     gc.atomsZone = atomsZone.get();
     if (!atomsZone->compartments().append(atomsCompartment.get()))
         return false;
 
     atomsCompartment->setIsSystem(true);
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -43,17 +43,16 @@
 #include "js/UniquePtr.h"
 #include "js/Vector.h"
 #include "threading/Thread.h"
 #include "vm/Caches.h"
 #include "vm/CodeCoverage.h"
 #include "vm/CommonPropertyNames.h"
 #include "vm/DateTime.h"
 #include "vm/GeckoProfiler.h"
-#include "vm/MallocProvider.h"
 #include "vm/Scope.h"
 #include "vm/SharedImmutableStringsCache.h"
 #include "vm/Stack.h"
 #include "vm/Stopwatch.h"
 #include "vm/Symbol.h"
 
 #ifdef _MSC_VER
 #pragma warning(push)
@@ -976,16 +975,18 @@ struct JSRuntime : public js::MallocProv
      */
     JS_FRIEND_API(void*) onOutOfMemory(js::AllocFunction allocator, size_t nbytes,
                                        void* reallocPtr = nullptr, JSContext* maybecx = nullptr);
 
     /*  onOutOfMemory but can call OnLargeAllocationFailure. */
     JS_FRIEND_API(void*) onOutOfMemoryCanGC(js::AllocFunction allocator, size_t nbytes,
                                             void* reallocPtr = nullptr);
 
+    static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
+
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* runtime);
 
   private:
     // Settings for how helper threads can be used.
     mozilla::Atomic<bool> offthreadIonCompilationEnabled_;
     mozilla::Atomic<bool> parallelParsingEnabled_;
 
     js::ActiveThreadData<bool> autoWritableJitCodeActive_;
@@ -1012,48 +1013,16 @@ struct JSRuntime : public js::MallocProv
         autoWritableJitCodeActive_ = b;
     }
 
     /* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
     js::ActiveThreadData<JS::OutOfMemoryCallback> oomCallback;
     js::ActiveThreadData<void*> oomCallbackData;
 
     /*
-     * These variations of malloc/calloc/realloc will call the
-     * large-allocation-failure callback on OOM and retry the allocation.
-     */
-    static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
-
-    template <typename T>
-    T* pod_callocCanGC(size_t numElems) {
-        T* p = pod_calloc<T>(numElems);
-        if (MOZ_LIKELY(!!p))
-            return p;
-        size_t bytes;
-        if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
-            reportAllocationOverflow();
-            return nullptr;
-        }
-        return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes));
-    }
-
-    template <typename T>
-    T* pod_reallocCanGC(T* p, size_t oldSize, size_t newSize) {
-        T* p2 = pod_realloc<T>(p, oldSize, newSize);
-        if (MOZ_LIKELY(!!p2))
-            return p2;
-        size_t bytes;
-        if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes))) {
-            reportAllocationOverflow();
-            return nullptr;
-        }
-        return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Realloc, bytes, p));
-    }
-
-    /*
      * Debugger.Memory functions like takeCensus use this embedding-provided
      * function to assess the size of malloc'd blocks of memory.
      */
     js::ActiveThreadData<mozilla::MallocSizeOf> debuggerMallocSizeOf;
 
     /* Last time at which an animation was played for this runtime. */
     mozilla::Atomic<int64_t> lastAnimationTime;
 
--- a/js/src/vm/WeakMapPtr.cpp
+++ b/js/src/vm/WeakMapPtr.cpp
@@ -59,17 +59,18 @@ JS::WeakMapPtr<K, V>::destroy()
     ptr = nullptr;
 }
 
 template <typename K, typename V>
 bool
 JS::WeakMapPtr<K, V>::init(JSContext* cx)
 {
     MOZ_ASSERT(!initialized());
-    typename details::Utils<K, V>::PtrType map = cx->runtime()->new_<typename details::Utils<K,V>::Type>(cx);
+    typename details::Utils<K, V>::PtrType map =
+        cx->zone()->new_<typename details::Utils<K,V>::Type>(cx);
     if (!map || !map->init())
         return false;
     ptr = map;
     return true;
 }
 
 template <typename K, typename V>
 void
--- a/js/src/wasm/WasmDebug.cpp
+++ b/js/src/wasm/WasmDebug.cpp
@@ -412,17 +412,17 @@ DebugState::getOrCreateBreakpointSite(JS
     WasmBreakpointSite* site;
     if (!breakpointSites_.initialized() && !breakpointSites_.init()) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     WasmBreakpointSiteMap::AddPtr p = breakpointSites_.lookupForAdd(offset);
     if (!p) {
-        site = cx->runtime()->new_<WasmBreakpointSite>(this, offset);
+        site = cx->zone()->new_<WasmBreakpointSite>(this, offset);
         if (!site || !breakpointSites_.add(p, offset, site)) {
             js_delete(site);
             ReportOutOfMemory(cx);
             return nullptr;
         }
     } else {
         site = p->value();
     }