Bug 1033442 - Remove non-pod malloc from MallocProvider and AllocPolicy; r=jonco
authorTerrence Cole <terrence@mozilla.com>
Fri, 08 Aug 2014 13:22:39 -0700
changeset 221547 9acca266d2c8ebc84e80e3eaaa0a43da32165d58
parent 221546 baea646f5a80c0cb1b3121b55471255ccffddc4a
child 221548 0b3ddcde7580a8a7a3c014fc334adacf62855826
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1033442
milestone34.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 1033442 - Remove non-pod malloc from MallocProvider and AllocPolicy; r=jonco
js/src/builtin/MapObject.cpp
js/src/ctypes/CTypes.cpp
js/src/ds/LifoAlloc.h
js/src/gc/ForkJoinNursery.cpp
js/src/gc/ForkJoinNursery.h
js/src/gc/Nursery.cpp
js/src/jit/BaselineJIT.cpp
js/src/jit/Ion.cpp
js/src/jit/IonAllocPolicy.h
js/src/jit/JitcodeMap.cpp
js/src/jit/shared/CodeGenerator-shared.cpp
js/src/jsalloc.h
js/src/jsapi.cpp
js/src/jscntxt.h
js/src/jsgcinlines.h
js/src/jsiter.cpp
js/src/jsopcode.cpp
js/src/jsscript.cpp
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/MallocProvider.h
js/src/vm/Runtime.h
js/src/vm/SelfHosting.cpp
js/src/vm/String.cpp
js/src/vm/StringBuffer.cpp
js/src/vm/StringBuffer.h
js/src/vm/TypedArrayObject.cpp
memory/replace/dmd/DMD.cpp
mfbt/AllocPolicy.h
mfbt/Vector.h
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -103,24 +103,24 @@ class OrderedHashTable
   public:
     explicit OrderedHashTable(AllocPolicy &ap)
         : hashTable(nullptr), data(nullptr), dataLength(0), ranges(nullptr), alloc(ap) {}
 
     bool init() {
         MOZ_ASSERT(!hashTable, "init must be called at most once");
 
         uint32_t buckets = initialBuckets();
-        Data **tableAlloc = static_cast<Data **>(alloc.malloc_(buckets * sizeof(Data *)));
+        Data **tableAlloc = alloc.template pod_malloc<Data *>(buckets);
         if (!tableAlloc)
             return false;
         for (uint32_t i = 0; i < buckets; i++)
             tableAlloc[i] = nullptr;
 
         uint32_t capacity = uint32_t(buckets * fillFactor());
-        Data *dataAlloc = static_cast<Data *>(alloc.malloc_(capacity * sizeof(Data)));
+        Data *dataAlloc = alloc.template pod_malloc<Data>(capacity);
         if (!dataAlloc) {
             alloc.free_(tableAlloc);
             return false;
         }
 
         // clear() requires that members are assigned only after all allocation
         // has succeeded, and that this->ranges is left untouched.
         hashTable = tableAlloc;
@@ -620,24 +620,24 @@ class OrderedHashTable
         // If the size of the table is not changing, rehash in place to avoid
         // allocating memory.
         if (newHashShift == hashShift) {
             rehashInPlace();
             return true;
         }
 
         size_t newHashBuckets = 1 << (HashNumberSizeBits - newHashShift);
-        Data **newHashTable = static_cast<Data **>(alloc.malloc_(newHashBuckets * sizeof(Data *)));
+        Data **newHashTable = alloc.template pod_malloc<Data *>(newHashBuckets);
         if (!newHashTable)
             return false;
         for (uint32_t i = 0; i < newHashBuckets; i++)
             newHashTable[i] = nullptr;
 
         uint32_t newCapacity = uint32_t(newHashBuckets * fillFactor());
-        Data *newData = static_cast<Data *>(alloc.malloc_(newCapacity * sizeof(Data)));
+        Data *newData = alloc.template pod_malloc<Data>(newCapacity);
         if (!newData) {
             alloc.free_(newHashTable);
             return false;
         }
 
         Data *wp = newData;
         for (Data *p = data, *end = data + dataLength; p != end; p++) {
             if (!Ops::isEmpty(Ops::getKey(p->element))) {
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -33,16 +33,17 @@
 
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsnum.h"
 #include "jsprf.h"
 
 #include "builtin/TypedObject.h"
 #include "ctypes/Library.h"
+#include "gc/Zone.h"
 
 using namespace std;
 using mozilla::NumericLimits;
 
 using JS::AutoCheckCannotGC;
 
 namespace js {
 namespace ctypes {
@@ -6092,17 +6093,17 @@ CClosure::Create(JSContext* cx,
     }
 
     // With the exception of void, the FunctionType constructor ensures that
     // the return type has a defined size.
     JS_ASSERT(CType::IsSizeDefined(fninfo->mReturnType));
 
     // Allocate a buffer for the return value.
     size_t rvSize = CType::GetSize(fninfo->mReturnType);
-    cinfo->errResult = cx->malloc_(rvSize);
+    cinfo->errResult = result->zone()->pod_malloc<uint8_t>(rvSize);
     if (!cinfo->errResult)
       return nullptr;
 
     // Do the value conversion. This might fail, in which case we throw.
     if (!ImplicitConvert(cx, errVal, fninfo->mReturnType, cinfo->errResult,
                          false, nullptr))
       return nullptr;
   } else {
@@ -6377,17 +6378,17 @@ CData::Create(JSContext* cx,
   }
 
   char* data;
   if (!ownResult) {
     data = static_cast<char*>(source);
   } else {
     // Initialize our own buffer.
     size_t size = CType::GetSize(typeObj);
-    data = (char*)cx->malloc_(size);
+    data = dataObj->zone()->pod_malloc<char>(size);
     if (!data) {
       // Report a catchable allocation error.
       JS_ReportAllocationOverflow(cx);
       js_free(buffer);
       return nullptr;
     }
 
     if (!source)
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -511,35 +511,38 @@ template <Fallibility fb>
 class LifoAllocPolicy
 {
     LifoAlloc &alloc_;
 
   public:
     MOZ_IMPLICIT LifoAllocPolicy(LifoAlloc &alloc)
       : alloc_(alloc)
     {}
-    void *malloc_(size_t bytes) {
-        return fb == Fallible ? alloc_.alloc(bytes) : alloc_.allocInfallible(bytes);
+    template <typename T>
+    T *pod_malloc(size_t numElems) {
+        if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
+            return nullptr;
+        size_t bytes = numElems * sizeof(T);
+        void *p = fb == Fallible ? alloc_.alloc(bytes) : alloc_.allocInfallible(bytes);
+        return static_cast<T *>(p);
     }
     template <typename T>
     T *pod_calloc(size_t numElems) {
-        if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
-            return nullptr;
-        T *p = (T *)malloc_(numElems * sizeof(T));
+        T *p = pod_malloc<T>(numElems);
         if (fb == Fallible && !p)
             return nullptr;
         memset(p, 0, numElems * sizeof(T));
         return p;
     }
     void *realloc_(void *p, size_t oldBytes, size_t bytes) {
-        void *n = malloc_(bytes);
+        uint8_t *n = pod_malloc<uint8_t>(bytes);
         if (fb == Fallible && !n)
             return nullptr;
         memcpy(n, p, Min(oldBytes, bytes));
-        return n;
+        return static_cast<void *>(n);
     }
     void free_(void *p) {
     }
     void reportAllocOverflow() const {
     }
 };
 
 } // namespace js
--- a/js/src/gc/ForkJoinNursery.cpp
+++ b/js/src/gc/ForkJoinNursery.cpp
@@ -134,27 +134,16 @@
 //   other, never a combination.  After gc the fromspace is always
 //   discarded.
 //
 // - If the gc copies objects into a nursery tospace then this tospace
 //   becomes known as the "newspace" following gc.  Otherwise, a new
 //   newspace won't be needed (if the parallel section is finished) or
 //   can be created empty (if the gc just needed to evacuate).
 //
-//
-// Style note:
-//
-// - Use js_memcpy, malloc_, realloc_, and js_free uniformly, do not
-//   use PodCopy or pod_malloc: the type information for the latter is
-//   not always correct and surrounding code usually operates in terms
-//   of bytes, anyhow.
-//
-//   With power comes responsibility, etc: code that used pod_malloc
-//   gets safe size computation built-in; here we must handle that
-//   manually.
 
 namespace js {
 namespace gc {
 
 ForkJoinNursery::ForkJoinNursery(ForkJoinContext *cx, ForkJoinGCShared *shared, Allocator *tenured)
   : cx_(cx)
   , tenured_(tenured)
   , shared_(shared)
@@ -558,29 +547,29 @@ ForkJoinNursery::allocateObject(size_t b
 HeapSlot *
 ForkJoinNursery::allocateSlots(JSObject *obj, uint32_t nslots)
 {
     JS_ASSERT(obj);
     JS_ASSERT(nslots > 0);
 
     if (nslots & mozilla::tl::MulOverflowMask<sizeof(HeapSlot)>::value)
         return nullptr;
-    size_t size = nslots * sizeof(HeapSlot);
 
     if (!isInsideNewspace(obj))
-        return reinterpret_cast<HeapSlot *>(cx_->malloc_(size));
+        return obj->zone()->pod_malloc<HeapSlot>(nslots);
 
     if (nslots > MaxNurserySlots)
-        return allocateHugeSlots(nslots);
+        return allocateHugeSlots(obj, nslots);
 
+    size_t size = nslots * sizeof(HeapSlot);
     HeapSlot *slots = static_cast<HeapSlot *>(allocate(size));
     if (slots)
         return slots;
 
-    return allocateHugeSlots(nslots);
+    return allocateHugeSlots(obj, nslots);
 }
 
 HeapSlot *
 ForkJoinNursery::reallocateSlots(JSObject *obj, HeapSlot *oldSlots,
                                  uint32_t oldCount, uint32_t newCount)
 {
     if (newCount & mozilla::tl::MulOverflowMask<sizeof(HeapSlot)>::value)
         return nullptr;
@@ -629,23 +618,22 @@ ForkJoinNursery::freeSlots(HeapSlot *slo
 {
     if (!isInsideNewspace(slots)) {
         hugeSlots[hugeSlotsNew].remove(slots);
         js_free(slots);
     }
 }
 
 HeapSlot *
-ForkJoinNursery::allocateHugeSlots(size_t nslots)
+ForkJoinNursery::allocateHugeSlots(JSObject *obj, size_t nslots)
 {
     if (nslots & mozilla::tl::MulOverflowMask<sizeof(HeapSlot)>::value)
         return nullptr;
 
-    size_t size = nslots * sizeof(HeapSlot);
-    HeapSlot *slots = reinterpret_cast<HeapSlot *>(cx_->malloc_(size));
+    HeapSlot *slots = obj->zone()->pod_malloc<HeapSlot>(nslots);
     if (!slots)
         return slots;
 
     // If this put fails, we will only leak the slots.
     (void)hugeSlots[hugeSlotsNew].put(slots);
     return slots;
 }
 
@@ -772,22 +760,23 @@ ForkJoinNursery::allocateInTospace(gc::A
         // either because memory is exhausted or if the allocation
         // budget is used up.  There is a guard in
         // Chunk::allocateArena() against the latter case.
         return tenured_->arenas.allocateFromArena(evacuationZone_, thingKind);
     }
     return allocateInTospaceInfallible(thingSize);
 }
 
-void *
-ForkJoinNursery::allocateInTospace(size_t nelem, size_t elemSize)
+template <typename T>
+T *
+ForkJoinNursery::allocateInTospace(size_t nelem)
 {
     if (isEvacuating_)
-        return evacuationZone_->malloc_(nelem * elemSize);
-    return allocateInTospaceInfallible(nelem * elemSize);
+        return evacuationZone_->pod_malloc<T>(nelem);
+    return static_cast<T *>(allocateInTospaceInfallible(nelem * sizeof(T)));
 }
 
 MOZ_ALWAYS_INLINE void
 ForkJoinNursery::insertIntoFixupList(RelocationOverlay *entry)
 {
     *tail_ = entry;
     tail_ = &entry->next_;
     *tail_ = nullptr;
@@ -845,17 +834,17 @@ ForkJoinNursery::copySlotsToTospace(JSOb
     if (!isInsideFromspace(src->slots)) {
         hugeSlots[hugeSlotsFrom].remove(src->slots);
         if (!isEvacuating_)
             hugeSlots[hugeSlotsNew].put(src->slots);
         return 0;
     }
 
     size_t count = src->numDynamicSlots();
-    dst->slots = reinterpret_cast<HeapSlot *>(allocateInTospace(count, sizeof(HeapSlot)));
+    dst->slots = allocateInTospace<HeapSlot>(count);
     if (!dst->slots)
         CrashAtUnhandlableOOM("Failed to allocate slots while moving object.");
     js_memcpy(dst->slots, src->slots, count * sizeof(HeapSlot));
     setSlotsForwardingPointer(src->slots, dst->slots, count);
     return count * sizeof(HeapSlot);
 }
 
 size_t
@@ -884,17 +873,17 @@ ForkJoinNursery::copyElementsToTospace(J
         dst->setFixedElements();
         dstHeader = dst->getElementsHeader();
         js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
         setElementsForwardingPointer(srcHeader, dstHeader, nslots);
         return nslots * sizeof(HeapSlot);
     }
 
     JS_ASSERT(nslots >= 2);
-    dstHeader = reinterpret_cast<ObjectElements *>(allocateInTospace(nslots, sizeof(HeapSlot)));
+    dstHeader = reinterpret_cast<ObjectElements *>(allocateInTospace<HeapSlot>(nslots));
     if (!dstHeader)
         CrashAtUnhandlableOOM("Failed to allocate elements while moving object.");
     js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
     setElementsForwardingPointer(srcHeader, dstHeader, nslots);
     dst->elements = dstHeader->elements();
     return nslots * sizeof(HeapSlot);
 }
 
--- a/js/src/gc/ForkJoinNursery.h
+++ b/js/src/gc/ForkJoinNursery.h
@@ -200,17 +200,17 @@ class ForkJoinNursery
     static const int NurseryLoadFactor = 3;
 
     // Allocate an object in the nursery's newspace.  Return nullptr
     // when allocation fails (ie the object can't fit in the current
     // chunk and the number of chunks it at its maximum).
     void *allocate(size_t size);
 
     // Allocate an external slot array and register it with this nursery.
-    HeapSlot *allocateHugeSlots(size_t nslots);
+    HeapSlot *allocateHugeSlots(JSObject *obj, size_t nslots);
 
     // Reallocate an external slot array, unregister the old array and
     // register the new array.  If the allocation fails then leave
     // everything unchanged.
     HeapSlot *reallocateHugeSlots(HeapSlot *oldSlots, uint32_t oldSize, uint32_t newSize);
 
     // Walk the list of registered slot arrays and free them all.
     void sweepHugeSlots();
@@ -235,19 +235,19 @@ class ForkJoinNursery
     void forwardFromStack(ForkJoinNurseryCollectionTracer *trc);
     void forwardFromTenured(ForkJoinNurseryCollectionTracer *trc);
     void forwardFromRematerializedFrames(ForkJoinNurseryCollectionTracer *trc);
     void collectToFixedPoint(ForkJoinNurseryCollectionTracer *trc);
     void freeFromspace();
     void computeNurserySizeAfterGC(size_t live, const char **msg);
 
     AllocKind getObjectAllocKind(JSObject *src);
+    void *allocateInTospaceInfallible(size_t thingSize);
     void *allocateInTospace(AllocKind thingKind);
-    void *allocateInTospace(size_t nelem, size_t elemSize);
-    void *allocateInTospaceInfallible(size_t thingSize);
+    template <typename T> T *allocateInTospace(size_t nelem);
     MOZ_ALWAYS_INLINE bool shouldMoveObject(void **thingp);
     void *moveObjectToTospace(JSObject *src);
     size_t copyObjectToTospace(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
     size_t copyElementsToTospace(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
     size_t copySlotsToTospace(JSObject *dst, JSObject *src, gc::AllocKind dstKind);
     MOZ_ALWAYS_INLINE void insertIntoFixupList(RelocationOverlay *entry);
 
     void setSlotsForwardingPointer(HeapSlot *oldSlots, HeapSlot *newSlots, uint32_t nslots);
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -690,18 +690,17 @@ js::Nursery::moveElementsToTenured(JSObj
         dst->setFixedElements();
         dstHeader = dst->getElementsHeader();
         js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
         setElementsForwardingPointer(srcHeader, dstHeader, nslots);
         return nslots * sizeof(HeapSlot);
     }
 
     JS_ASSERT(nslots >= 2);
-    size_t nbytes = nslots * sizeof(HeapValue);
-    dstHeader = static_cast<ObjectElements *>(zone->malloc_(nbytes));
+    dstHeader = reinterpret_cast<ObjectElements *>(zone->pod_malloc<HeapSlot>(nslots));
     if (!dstHeader)
         CrashAtUnhandlableOOM("Failed to allocate elements while tenuring.");
     js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
     setElementsForwardingPointer(srcHeader, dstHeader, nslots);
     dst->elements = dstHeader->elements();
     return nslots * sizeof(HeapSlot);
 }
 
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -368,17 +368,17 @@ BaselineScript::New(JSContext *cx, uint3
     size_t paddedBytecodeTypesMapSize = AlignBytes(bytecodeTypeMapSize, DataAlignment);
 
     size_t allocBytes = paddedBaselineScriptSize +
         paddedICEntriesSize +
         paddedPCMappingIndexEntriesSize +
         paddedPCMappingSize +
         paddedBytecodeTypesMapSize;
 
-    uint8_t *buffer = (uint8_t *)cx->malloc_(allocBytes);
+    uint8_t *buffer = cx->zone()->pod_malloc<uint8_t>(allocBytes);
     if (!buffer)
         return nullptr;
 
     BaselineScript *script = reinterpret_cast<BaselineScript *>(buffer);
     new (script) BaselineScript(prologueOffset, epilogueOffset,
                                 spsPushToggleOffset, postDebugPrologueOffset);
 
     size_t offsetCursor = paddedBaselineScriptSize;
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -895,17 +895,17 @@ IonScript::New(JSContext *cx, types::Rec
                    paddedConstantsSize +
                    paddedSafepointIndicesSize+
                    paddedOsiIndicesSize +
                    paddedCacheEntriesSize +
                    paddedRuntimeSize +
                    paddedSafepointSize +
                    paddedCallTargetSize +
                    paddedBackedgeSize;
-    uint8_t *buffer = (uint8_t *)cx->malloc_(sizeof(IonScript) + bytes);
+    uint8_t *buffer = cx->zone()->pod_malloc<uint8_t>(sizeof(IonScript) + bytes);
     if (!buffer)
         return nullptr;
 
     IonScript *script = reinterpret_cast<IonScript *>(buffer);
     new (script) IonScript();
 
     uint32_t offsetCursor = sizeof(IonScript);
 
--- a/js/src/jit/IonAllocPolicy.h
+++ b/js/src/jit/IonAllocPolicy.h
@@ -95,57 +95,52 @@ class AutoTempAllocatorRooter : private 
 class IonAllocPolicy
 {
     TempAllocator &alloc_;
 
   public:
     MOZ_IMPLICIT IonAllocPolicy(TempAllocator &alloc)
       : alloc_(alloc)
     {}
-    void *malloc_(size_t bytes) {
-        return alloc_.allocate(bytes);
+    template <typename T>
+    T *pod_malloc(size_t numElems) {
+        if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
+            return nullptr;
+        return static_cast<T *>(alloc_.allocate(numElems * sizeof(T)));
     }
     template <typename T>
     T *pod_calloc(size_t numElems) {
-        if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
-            return nullptr;
-        T *p = (T *)alloc_.allocate(numElems * sizeof(T));
+        T *p = pod_malloc<T>(numElems);
         if (p)
             memset(p, 0, numElems * sizeof(T));
         return p;
     }
     void *realloc_(void *p, size_t oldBytes, size_t bytes) {
-        void *n = malloc_(bytes);
+        void *n = static_cast<void *>(pod_malloc<uint8_t>(bytes));
         if (!n)
             return n;
         memcpy(n, p, Min(oldBytes, bytes));
         return n;
     }
     void free_(void *p) {
     }
     void reportAllocOverflow() const {
     }
 };
 
-// Deprecated. Don't use this. Will be removed after everything has been
-// converted to IonAllocPolicy.
 class OldIonAllocPolicy
 {
   public:
     OldIonAllocPolicy()
     {}
-    void *malloc_(size_t bytes) {
-        return GetIonContext()->temp->allocate(bytes);
-    }
-    void *realloc_(void *p, size_t oldBytes, size_t bytes) {
-        void *n = malloc_(bytes);
-        if (!n)
-            return n;
-        memcpy(n, p, Min(oldBytes, bytes));
-        return n;
+    template <typename T>
+    T *pod_malloc(size_t numElems) {
+        if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
+            return nullptr;
+        return static_cast<T *>(GetIonContext()->temp->allocate(numElems * sizeof(T)));
     }
     void free_(void *p) {
     }
     void reportAllocOverflow() const {
     }
 };
 
 class AutoIonContextAlloc
--- a/js/src/jit/JitcodeMap.cpp
+++ b/js/src/jit/JitcodeMap.cpp
@@ -547,17 +547,17 @@ JitcodeIonTable::makeIonEntry(JSContext 
     }
 
     if (numScripts < uint32_t(JitcodeGlobalEntry::IonEntry::Multi)) {
         out.init(code->raw(), code->raw() + code->instructionsSize(), numScripts, scripts, this);
         return true;
     }
 
     // Create SizedScriptList
-    void *mem = cx->malloc_(SizedScriptList::AllocSizeFor(numScripts));
+    void *mem = (void *)cx->pod_malloc<uint8_t>(SizedScriptList::AllocSizeFor(numScripts));
     if (!mem)
         return false;
     SizedScriptList *scriptList = new (mem) SizedScriptList(numScripts, scripts);
     out.init(code->raw(), code->raw() + code->instructionsSize(), scriptList, this);
     return true;
 }
 
 uint32_t
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -583,17 +583,17 @@ CodeGeneratorShared::createNativeToBytec
         }
 
         // Otherwise, we must have reached the top without finding any siblings.
         JS_ASSERT(tree->isOutermostCaller());
         break;
     }
 
     // Allocate array for list.
-    JSScript **data = (JSScript **) cx->malloc_(scriptList.length() * sizeof(JSScript **));
+    JSScript **data = cx->runtime()->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();
@@ -637,17 +637,17 @@ CodeGeneratorShared::generateCompactNati
     {
         return false;
     }
 
     JS_ASSERT(tableOffset > 0);
     JS_ASSERT(numRegions > 0);
 
     // Writer is done, copy it to sized buffer.
-    uint8_t *data = (uint8_t *) cx->malloc_(writer.length());
+    uint8_t *data = cx->runtime()->pod_malloc<uint8_t>(writer.length());
     if (!data)
         return false;
 
     memcpy(data, writer.buffer(), writer.length());
     nativeToBytecodeMap_ = data;
     nativeToBytecodeMapSize_ = writer.length();
     nativeToBytecodeTableOffset_ = tableOffset;
     nativeToBytecodeNumRegions_ = numRegions;
--- a/js/src/jsalloc.h
+++ b/js/src/jsalloc.h
@@ -20,17 +20,17 @@
 namespace js {
 
 struct ContextFriendFields;
 
 /* Policy for using system memory functions and doing no error reporting. */
 class SystemAllocPolicy
 {
   public:
-    void *malloc_(size_t bytes) { return js_malloc(bytes); }
+    template <typename T> T *pod_malloc(size_t numElems) { return js_pod_malloc<T>(numElems); }
     template <typename T> T *pod_calloc(size_t numElems) { return js_pod_calloc<T>(numElems); }
     void *realloc_(void *p, size_t oldBytes, size_t bytes) { return js_realloc(p, bytes); }
     void free_(void *p) { js_free(p); }
     void reportAllocOverflow() const {}
 };
 
 /*
  * Allocation policy that calls the system memory functions and reports errors
@@ -50,28 +50,29 @@ class TempAllocPolicy
      * code bloat.
      */
     JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes);
 
   public:
     MOZ_IMPLICIT TempAllocPolicy(JSContext *cx) : cx_((ContextFriendFields *) cx) {} // :(
     MOZ_IMPLICIT TempAllocPolicy(ContextFriendFields *cx) : cx_(cx) {}
 
-    void *malloc_(size_t bytes) {
-        void *p = js_malloc(bytes);
+    template <typename T>
+    T *pod_malloc(size_t numElems) {
+        T *p = js_pod_malloc<T>(numElems);
         if (MOZ_UNLIKELY(!p))
-            p = onOutOfMemory(nullptr, bytes);
+            p = static_cast<T *>(onOutOfMemory(nullptr, numElems * sizeof(T)));
         return p;
     }
 
     template <typename T>
     T *pod_calloc(size_t numElems) {
         T *p = js_pod_calloc<T>(numElems);
         if (MOZ_UNLIKELY(!p))
-            p = (T *)onOutOfMemory(reinterpret_cast<void *>(1), numElems * sizeof(T));
+            p = static_cast<T *>(onOutOfMemory(reinterpret_cast<void *>(1), numElems * sizeof(T)));
         return p;
     }
 
     void *realloc_(void *p, size_t oldBytes, size_t bytes) {
         void *p2 = js_realloc(p, bytes);
         if (MOZ_UNLIKELY(!p2))
             p2 = onOutOfMemory(p2, bytes);
         return p2;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1406,17 +1406,17 @@ JS_ComputeThis(JSContext *cx, jsval *vp)
     return call.thisv();
 }
 
 JS_PUBLIC_API(void *)
 JS_malloc(JSContext *cx, size_t nbytes)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return cx->malloc_(nbytes);
+    return static_cast<void *>(cx->runtime()->pod_malloc<uint8_t>(nbytes));
 }
 
 JS_PUBLIC_API(void *)
 JS_realloc(JSContext *cx, void *p, size_t nbytes)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return cx->realloc_(p, nbytes);
@@ -1453,17 +1453,17 @@ JS_strdup(JSContext *cx, const char *s)
     return DuplicateString(cx, s).release();
 }
 
 JS_PUBLIC_API(char *)
 JS_strdup(JSRuntime *rt, const char *s)
 {
     AssertHeapIsIdle(rt);
     size_t n = strlen(s) + 1;
-    void *p = rt->malloc_(n);
+    char *p = rt->pod_malloc<char>(n);
     if (!p)
         return nullptr;
     return static_cast<char*>(js_memcpy(p, s, n));
 }
 
 #undef JS_AddRoot
 
 JS_PUBLIC_API(bool)
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -988,32 +988,16 @@ class AutoAssertNoException
     }
 
     ~AutoAssertNoException()
     {
         JS_ASSERT_IF(!hadException, !cx->isExceptionPending());
     }
 };
 
-/*
- * FIXME bug 647103 - replace these *AllocPolicy names.
- */
-class ContextAllocPolicy
-{
-    ThreadSafeContext *const cx_;
-
-  public:
-    MOZ_IMPLICIT ContextAllocPolicy(ThreadSafeContext *cx) : cx_(cx) {}
-    ThreadSafeContext *context() const { return cx_; }
-    void *malloc_(size_t bytes) { return cx_->malloc_(bytes); }
-    void *realloc_(void *p, size_t oldBytes, size_t bytes) { return cx_->realloc_(p, oldBytes, bytes); }
-    void free_(void *p) { js_free(p); }
-    void reportAllocOverflow() const { js_ReportAllocationOverflow(cx_); }
-};
-
 /* Exposed intrinsics so that Ion may inline them. */
 bool intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_IsObject(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_ToInteger(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_ToString(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp);
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -190,16 +190,17 @@ class ArenaCellIterImpl
             span = *span.nextSpan();
         }
     }
 
   public:
     ArenaCellIterImpl()
       : firstThingOffset(0)     // Squelch
       , thingSize(0)            //   warnings
+      , limit(0)
     {
     }
 
     void initUnsynchronized(ArenaHeader *aheader) {
         AllocKind kind = aheader->getAllocKind();
 #ifdef DEBUG
         isInited = true;
 #endif
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -376,17 +376,17 @@ Snapshot(JSContext *cx, JSObject *pobj_,
 
 bool
 js::VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap)
 {
     JS_STATIC_ASSERT(sizeof(JSIdArray) > sizeof(jsid));
     size_t len = props.length();
     size_t idsz = len * sizeof(jsid);
     size_t sz = (sizeof(JSIdArray) - sizeof(jsid)) + idsz;
-    JSIdArray *ida = static_cast<JSIdArray *>(cx->malloc_(sz));
+    JSIdArray *ida = reinterpret_cast<JSIdArray *>(cx->zone()->pod_malloc<uint8_t>(sz));
     if (!ida)
         return false;
 
     ida->length = static_cast<int>(len);
     jsid *v = props.begin();
     for (int i = 0; i < ida->length; i++)
         ida->vector[i].init(v[i]);
     *idap = ida;
@@ -494,22 +494,24 @@ NewPropertyIteratorObject(JSContext *cx,
 
     return &obj->as<PropertyIteratorObject>();
 }
 
 NativeIterator *
 NativeIterator::allocateIterator(JSContext *cx, uint32_t slength, const AutoIdVector &props)
 {
     size_t plength = props.length();
-    NativeIterator *ni = (NativeIterator *)
-        cx->malloc_(sizeof(NativeIterator)
-                    + plength * sizeof(JSString *)
-                    + slength * sizeof(Shape *));
-    if (!ni)
+    size_t nbytes = sizeof(NativeIterator) +
+                    plength * sizeof(JSString *) +
+                    slength * sizeof(Shape *);
+    uint8_t *bytes = cx->zone()->pod_malloc<uint8_t>(nbytes);
+    if (!bytes)
         return nullptr;
+
+    NativeIterator *ni = (NativeIterator *)bytes;
     AutoValueVector strings(cx);
     ni->props_array = ni->props_cursor = (HeapPtrFlatString *) (ni + 1);
     ni->props_end = ni->props_array + plength;
     if (plength) {
         for (size_t i = 0; i < plength; i++) {
             JSFlatString *str = IdToString(cx, props[i]);
             if (!str || !strings.append(StringValue(str)))
                 return nullptr;
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -2075,17 +2075,17 @@ js::GetPCCountScriptSummary(JSContext *c
         return nullptr;
     }
 
     const ScriptAndCounts &sac = (*rt->scriptAndCountsVector)[index];
     RootedScript script(cx, sac.script);
 
     /*
      * OOM on buffer appends here will not be caught immediately, but since
-     * StringBuffer uses a ContextAllocPolicy will trigger an exception on the
+     * StringBuffer uses a TempAllocPolicy will trigger an exception on the
      * context if they occur, which we'll catch before returning.
      */
     StringBuffer buf(cx);
 
     buf.append('{');
 
     AppendJSONProperty(buf, "file", NO_COMMA);
     JSString *str = JS_NewStringCopyZ(cx, script->filename());
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1603,17 +1603,17 @@ ScriptSource::updateCompressedSourceSet(
 
 bool
 ScriptSource::ensureOwnsSource(ExclusiveContext *cx)
 {
     JS_ASSERT(dataType == DataUncompressed);
     if (ownsUncompressedChars())
         return true;
 
-    jschar *uncompressed = (jschar *) cx->malloc_(sizeof(jschar) * Max<size_t>(length_, 1));
+    jschar *uncompressed = cx->zone()->pod_malloc<jschar>(Max<size_t>(length_, 1));
     if (!uncompressed)
         return false;
     PodCopy(uncompressed, uncompressedChars(), length_);
 
     data.uncompressed.chars = uncompressed;
     data.uncompressed.ownsChars = true;
     return true;
 }
@@ -1813,17 +1813,17 @@ ScriptSource::performXDR(XDRState<mode> 
             if (!xdr->codeUint8(&argumentsNotIncluded))
                 return false;
             if (mode == XDR_DECODE)
                 argumentsNotIncluded_ = argumentsNotIncluded;
         }
 
         size_t byteLen = compressedLength ? compressedLength : (length_ * sizeof(jschar));
         if (mode == XDR_DECODE) {
-            void *p = xdr->cx()->malloc_(Max<size_t>(byteLen, 1));
+            uint8_t *p = xdr->cx()->template pod_malloc<uint8_t>(Max<size_t>(byteLen, 1));
             if (!p || !xdr->codeBytes(p, byteLen)) {
                 js_free(p);
                 return false;
             }
 
             if (compressedLength)
                 setCompressedSource(xdr->cx()->runtime(), p, compressedLength,
                                     CompressedSourceHasher::computeHash(p, compressedLength));
@@ -1903,17 +1903,17 @@ ScriptSource::performXDR(XDRState<mode> 
             return false;
         if (mode == XDR_DECODE && !setFilename(xdr->cx(), fn))
             return false;
     }
 
     return true;
 }
 
-// Format and return a cx->malloc_'ed URL for a generated script like:
+// Format and return a cx->zone()->pod_malloc'ed URL for a generated script like:
 //   {filename} line {lineno} > {introducer}
 // For example:
 //   foo.js line 7 > eval
 // indicating code compiled by the call to 'eval' on line 7 of foo.js.
 static char *
 FormatIntroducedFilename(ExclusiveContext *cx, const char *filename, unsigned lineno,
                          const char *introducer)
 {
@@ -1928,17 +1928,17 @@ FormatIntroducedFilename(ExclusiveContex
     size_t linenoLen = JS_snprintf(linenoBuf, 15, "%u", lineno);
     size_t introducerLen = strlen(introducer);
     size_t len = filenameLen                    +
                  6 /* == strlen(" line ") */    +
                  linenoLen                      +
                  3 /* == strlen(" > ") */       +
                  introducerLen                  +
                  1 /* \0 */;
-    char *formatted = cx->pod_malloc<char>(len);
+    char *formatted = cx->zone()->pod_malloc<char>(len);
     if (!formatted)
         return nullptr;
     mozilla::DebugOnly<size_t> checkLen = JS_snprintf(formatted, len, "%s line %s > %s",
                                                       filename, linenoBuf, introducer);
     JS_ASSERT(checkLen == len - 1);
 
     return formatted;
 }
@@ -2056,17 +2056,18 @@ js::SharedScriptData::new_(ExclusiveCont
      */
     const uint32_t pointerSize = sizeof(JSAtom *);
     const uint32_t pointerMask = pointerSize - 1;
     const uint32_t dataOffset = offsetof(SharedScriptData, data);
     uint32_t baseLength = codeLength + srcnotesLength;
     uint32_t padding = (pointerSize - ((baseLength + dataOffset) & pointerMask)) & pointerMask;
     uint32_t length = baseLength + padding + pointerSize * natoms;
 
-    SharedScriptData *entry = (SharedScriptData *)cx->malloc_(length + dataOffset);
+    SharedScriptData *entry = reinterpret_cast<SharedScriptData *>(
+            cx->zone()->pod_malloc<uint8_t>(length + dataOffset));
     if (!entry)
         return nullptr;
 
     entry->length = length;
     entry->natoms = natoms;
     entry->marked = false;
     memset(entry->data + baseLength, 0, padding);
 
@@ -3649,17 +3650,17 @@ LazyScript::CreateRaw(ExclusiveContext *
 
     // Reset runtime flags to obtain a fresh LazyScript.
     p.hasBeenCloned = false;
     p.treatAsRunOnce = false;
 
     size_t bytes = (p.numFreeVariables * sizeof(HeapPtrAtom))
                  + (p.numInnerFunctions * sizeof(HeapPtrFunction));
 
-    ScopedJSFreePtr<void> table(bytes ? cx->malloc_(bytes) : nullptr);
+    ScopedJSFreePtr<uint8_t> table(bytes ? fun->zone()->pod_malloc<uint8_t>(bytes) : nullptr);
     if (bytes && !table)
         return nullptr;
 
     LazyScript *res = js_NewGCLazyScript(cx);
     if (!res)
         return nullptr;
 
     cx->compartment()->scheduleDelazificationForDebugMode();
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -494,17 +494,17 @@ ReadEvalPrintLoop(JSContext *cx, Handle<
     do {
         /*
          * Accumulate lines until we get a 'compilable unit' - one that either
          * generates an error (before running out of source) or that compiles
          * cleanly.  This should be whenever we get a complete statement that
          * coincides with the end of a line.
          */
         int startline = lineno;
-        typedef Vector<char, 32, ContextAllocPolicy> CharBuffer;
+        typedef Vector<char, 32> CharBuffer;
         CharBuffer buffer(cx);
         do {
             ScheduleWatchdog(cx->runtime(), -1);
             gServiceInterrupt = false;
             errno = 0;
 
             char *line = GetLine(in, startline == lineno ? "js> " : "");
             if (!line) {
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -152,18 +152,18 @@ struct CopyScriptFrameIterArgs
     void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) {
         if (!iter_.isIon())
             ArgumentsObject::MaybeForwardToCallObject(iter_.abstractFramePtr(), obj, data);
     }
 };
 
 template <typename CopyArgs>
 /* static */ ArgumentsObject *
-ArgumentsObject::create(JSContext *cx, HandleScript script, HandleFunction callee, unsigned numActuals,
-                        CopyArgs &copy)
+ArgumentsObject::create(JSContext *cx, HandleScript script, HandleFunction callee,
+                        unsigned numActuals, CopyArgs &copy)
 {
     RootedObject proto(cx, callee->global().getOrCreateObjectPrototype(cx));
     if (!proto)
         return nullptr;
 
     bool strict = callee->strict();
     const Class *clasp = strict ? &StrictArgumentsObject::class_ : &NormalArgumentsObject::class_;
 
@@ -183,17 +183,18 @@ ArgumentsObject::create(JSContext *cx, H
 
     unsigned numFormals = callee->nargs();
     unsigned numDeletedWords = NumWordsForBitArrayOfLength(numActuals);
     unsigned numArgs = Max(numActuals, numFormals);
     unsigned numBytes = offsetof(ArgumentsData, args) +
                         numDeletedWords * sizeof(size_t) +
                         numArgs * sizeof(Value);
 
-    ArgumentsData *data = (ArgumentsData *)cx->malloc_(numBytes);
+    ArgumentsData *data = reinterpret_cast<ArgumentsData *>(
+            cx->zone()->pod_malloc<uint8_t>(numBytes));
     if (!data)
         return nullptr;
 
     JSObject *obj = JSObject::create(cx, FINALIZE_KIND, GetInitialHeap(GenericObject, clasp),
                                      shape, type);
     if (!obj) {
         js_free(data);
         return nullptr;
--- a/js/src/vm/MallocProvider.h
+++ b/js/src/vm/MallocProvider.h
@@ -47,21 +47,80 @@
 
 #include "js/Utility.h"
 
 namespace js {
 
 template<class Client>
 struct MallocProvider
 {
-    void *malloc_(size_t bytes) {
-        Client *client = static_cast<Client *>(this);
-        client->updateMallocCounter(bytes);
-        void *p = js_malloc(bytes);
-        return MOZ_LIKELY(!!p) ? p : client->onOutOfMemory(nullptr, bytes);
+    template <class T>
+    T *pod_malloc() {
+        T *p = js_pod_malloc<T>();
+        if (MOZ_LIKELY(p)) {
+            client()->updateMallocCounter(sizeof(T));
+            return p;
+        }
+        client()->onOutOfMemory(nullptr, sizeof(T));
+        return nullptr;
+    }
+
+    template <class T>
+    T *pod_malloc(size_t numElems) {
+        T *p = js_pod_malloc<T>(numElems);
+        if (MOZ_LIKELY(p)) {
+            client()->updateMallocCounter(numElems * sizeof(T));
+            return p;
+        }
+        if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
+            client()->reportAllocationOverflow();
+            return nullptr;
+        }
+        client()->onOutOfMemory(nullptr, numElems * sizeof(T));
+        return nullptr;
+    }
+
+    template <class T>
+    mozilla::UniquePtr<T[], JS::FreePolicy>
+    make_pod_array(size_t numElems) {
+        return mozilla::UniquePtr<T[], JS::FreePolicy>(pod_malloc<T>(numElems));
+    }
+
+    template <class T>
+    T *pod_calloc() {
+        T *p = js_pod_calloc<T>();
+        if (MOZ_LIKELY(p)) {
+            client()->updateMallocCounter(sizeof(T));
+            return p;
+        }
+        client()->onOutOfMemory(reinterpret_cast<void *>(1), sizeof(T));
+        return nullptr;
+    }
+
+    template <class T>
+    T *
+    pod_calloc(size_t numElems) {
+        T *p = js_pod_calloc<T>(numElems);
+        if (MOZ_LIKELY(p)) {
+            client()->updateMallocCounter(numElems * sizeof(T));
+            return p;
+        }
+        if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
+            client()->reportAllocationOverflow();
+            return nullptr;
+        }
+        client()->onOutOfMemory(reinterpret_cast<void *>(1), sizeof(T));
+        return nullptr;
+    }
+
+    template <class T>
+    mozilla::UniquePtr<T[], JS::FreePolicy>
+    make_zeroed_pod_array(size_t numElems)
+    {
+        return mozilla::UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems));
     }
 
     void *realloc_(void *p, size_t oldBytes, size_t newBytes) {
         Client *client = static_cast<Client *>(this);
         /*
          * For compatibility we do not account for realloc that decreases
          * previously allocated memory.
          */
@@ -79,79 +138,22 @@ struct MallocProvider
          */
         if (!p)
             client->updateMallocCounter(bytes);
         void *p2 = js_realloc(p, bytes);
         return MOZ_LIKELY(!!p2) ? p2 : client->onOutOfMemory(p, bytes);
     }
 
     template <class T>
-    T *pod_malloc() {
-        return (T *)malloc_(sizeof(T));
-    }
-
-    template <class T>
-    T *pod_calloc() {
-        Client *client = static_cast<Client *>(this);
-        client->updateMallocCounter(sizeof(T));
-        T *p = js_pod_calloc<T>();
-        if (MOZ_UNLIKELY(!p)) {
-            client->onOutOfMemory(reinterpret_cast<void *>(1), sizeof(T));
-            return nullptr;
-        }
-        return p;
-    }
-
-    template <class T>
-    T *pod_malloc(size_t numElems) {
-        if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
-            Client *client = static_cast<Client *>(this);
-            client->reportAllocationOverflow();
-            return nullptr;
-        }
-        return (T *)malloc_(numElems * sizeof(T));
-    }
-
-    template <class T>
-    mozilla::UniquePtr<T[], JS::FreePolicy>
-    make_pod_array(size_t numElems) {
-        return mozilla::UniquePtr<T[], JS::FreePolicy>(pod_malloc<T>(numElems));
-    }
-
-    template <class T>
-    T *
-    pod_calloc(size_t numElems, JSCompartment *comp = nullptr, JSContext *cx = nullptr) {
-        if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
-            Client *client = static_cast<Client *>(this);
-            client->reportAllocationOverflow();
-            return nullptr;
-        }
-        Client *client = static_cast<Client *>(this);
-        client->updateMallocCounter(numElems * sizeof(T));
-        T *p = js_pod_calloc<T>(numElems);
-        if (MOZ_UNLIKELY(!p)) {
-            client->onOutOfMemory(reinterpret_cast<void *>(1), sizeof(T));
-            return nullptr;
-        }
-        return p;
-    }
-
-    template <class T>
-    mozilla::UniquePtr<T[], JS::FreePolicy>
-    make_zeroed_pod_array(size_t numElems,
-                          JSCompartment *comp = nullptr,
-                          JSContext *cx = nullptr)
-    {
-        return mozilla::UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems, comp, cx));
-    }
-
-    template <class T>
     T *pod_realloc(T *prior, size_t oldSize, size_t newSize) {
         return (T *)realloc_(prior, oldSize * sizeof(T), newSize * sizeof(T));
     }
 
-    JS_DECLARE_NEW_METHODS(new_, malloc_, MOZ_ALWAYS_INLINE)
+    JS_DECLARE_NEW_METHODS(new_, pod_malloc<uint8_t>, MOZ_ALWAYS_INLINE)
     JS_DECLARE_MAKE_METHODS(make_unique, new_, MOZ_ALWAYS_INLINE)
+
+  private:
+    Client *client() { return static_cast<Client *>(this); }
 };
 
 } /* namespace js */
 
 #endif /* vm_MallocProvider_h */
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -1644,33 +1644,37 @@ SetValueRangeToNull(Value *beg, Value *e
 
 static MOZ_ALWAYS_INLINE void
 SetValueRangeToNull(Value *vec, size_t len)
 {
     SetValueRangeToNull(vec, vec + len);
 }
 
 /*
- * Allocation policy that uses JSRuntime::malloc_ and friends, so that
+ * Allocation policy that uses JSRuntime::pod_malloc and friends, so that
  * memory pressure is properly accounted for. This is suitable for
  * long-lived objects owned by the JSRuntime.
  *
  * Since it doesn't hold a JSContext (those may not live long enough), it
  * can't report out-of-memory conditions itself; the caller must check for
  * OOM and take the appropriate action.
  *
  * FIXME bug 647103 - replace these *AllocPolicy names.
  */
 class RuntimeAllocPolicy
 {
     JSRuntime *const runtime;
 
   public:
     MOZ_IMPLICIT RuntimeAllocPolicy(JSRuntime *rt) : runtime(rt) {}
-    void *malloc_(size_t bytes) { return runtime->malloc_(bytes); }
+
+    template <typename T>
+    T *pod_malloc(size_t numElems) {
+        return runtime->pod_malloc<T>(numElems);
+    }
 
     template <typename T>
     T *pod_calloc(size_t numElems) {
         return runtime->pod_calloc<T>(numElems);
     }
 
     void *realloc_(void *p, size_t bytes) { return runtime->realloc_(p, bytes); }
     void free_(void *p) { js_free(p); }
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1018,17 +1018,17 @@ JSRuntime::initSelfHosting(JSContext *cx
         RootedScript script(cx);
         if (Compile(cx, shg, options, filename, &script))
             ok = Execute(cx, script, *shg.get(), rv.address());
     } else {
         uint32_t srcLen = GetRawScriptsSize();
 
         const unsigned char *compressed = compressedSources;
         uint32_t compressedLen = GetCompressedSize();
-        ScopedJSFreePtr<char> src(reinterpret_cast<char *>(cx->malloc_(srcLen)));
+        ScopedJSFreePtr<char> src(selfHostingGlobal_->zone()->pod_malloc<char>(srcLen));
         if (!src || !DecompressString(compressed, compressedLen,
                                       reinterpret_cast<unsigned char *>(src.get()), srcLen))
         {
             return false;
         }
 
         ok = Evaluate(cx, shg, options, src, srcLen, &rv);
     }
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -147,17 +147,17 @@ JSString::equals(const char *s)
     }
 
     return StringEqualsAscii(linear, s);
 }
 #endif /* DEBUG */
 
 template <typename CharT>
 static MOZ_ALWAYS_INLINE bool
-AllocChars(ThreadSafeContext *maybecx, size_t length, CharT **chars, size_t *capacity)
+AllocChars(JSString *str, size_t length, CharT **chars, size_t *capacity)
 {
     /*
      * String length doesn't include the null char, so include it here before
      * doubling. Adding the null char after doubling would interact poorly with
      * round-up malloc schemes.
      */
     size_t numChars = length + 1;
 
@@ -168,18 +168,17 @@ AllocChars(ThreadSafeContext *maybecx, s
      */
     static const size_t DOUBLING_MAX = 1024 * 1024;
     numChars = numChars > DOUBLING_MAX ? numChars + (numChars / 8) : RoundUpPow2(numChars);
 
     /* Like length, capacity does not include the null char, so take it out. */
     *capacity = numChars - 1;
 
     JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(CharT) < UINT32_MAX);
-    size_t bytes = numChars * sizeof(CharT);
-    *chars = (CharT *)(maybecx ? maybecx->malloc_(bytes) : js_malloc(bytes));
+    *chars = str->zone()->pod_malloc<CharT>(numChars);
     return *chars != nullptr;
 }
 
 bool
 JSRope::copyLatin1CharsZ(ThreadSafeContext *cx, ScopedJSFreePtr<Latin1Char> &out) const
 {
     return copyCharsInternal<Latin1Char>(cx, out, true);
 }
@@ -374,17 +373,17 @@ JSRope::flattenInternal(ExclusiveContext
             left.d.u1.flags ^= (EXTENSIBLE_FLAGS | DEPENDENT_FLAGS);
             left.d.s.u3.base = (JSLinearString *)this;  /* will be true on exit */
             StringWriteBarrierPostRemove(maybecx, &left.d.s.u2.left);
             StringWriteBarrierPost(maybecx, (JSString **)&left.d.s.u3.base);
             goto visit_right_child;
         }
     }
 
-    if (!AllocChars(maybecx, wholeLength, &wholeChars, &wholeCapacity))
+    if (!AllocChars(this, wholeLength, &wholeChars, &wholeCapacity))
         return nullptr;
 
     pos = wholeChars;
     first_visit_node: {
         if (b == WithIncrementalBarrier) {
             JSString::writeBarrierPre(str->d.s.u2.left);
             JSString::writeBarrierPre(str->d.s.u3.right);
         }
--- a/js/src/vm/StringBuffer.cpp
+++ b/js/src/vm/StringBuffer.cpp
@@ -83,16 +83,22 @@ FinishStringFlat(ExclusiveContext *cx, S
     ScopedJSFreePtr<CharT> buf(ExtractWellSized<CharT>(cx, cb));
     if (!buf)
         return nullptr;
 
     JSFlatString *str = NewStringDontDeflate<CanGC>(cx, buf.get(), len);
     if (!str)
         return nullptr;
 
+    /*
+     * The allocation was made on a TempAllocPolicy, so account for the string
+     * data on the string's zone.
+     */
+    str->zone()->updateMallocCounter(sizeof(CharT) * len);
+
     buf.forget();
     return str;
 }
 
 JSFlatString *
 StringBuffer::finishString()
 {
     size_t len = length();
--- a/js/src/vm/StringBuffer.h
+++ b/js/src/vm/StringBuffer.h
@@ -25,21 +25,21 @@ namespace js {
  *
  * Well-sized extractions (which waste no more than 1/4 of their char
  * buffer space) are guaranteed for strings built by this interface.
  * See |extractWellSized|.
  */
 class StringBuffer
 {
     /*
-     * The Vector's buffer is taken by the new string so use
-     * ContextAllocPolicy.
+     * The Vector's buffer may be either stolen or copied, so we need to use
+     * TempAllocPolicy and account for the memory manually when stealing.
      */
-    typedef Vector<Latin1Char, 64, ContextAllocPolicy> Latin1CharBuffer;
-    typedef Vector<jschar, 32, ContextAllocPolicy> TwoByteCharBuffer;
+    typedef Vector<Latin1Char, 64> Latin1CharBuffer;
+    typedef Vector<jschar, 32> TwoByteCharBuffer;
 
     ExclusiveContext *cx;
 
     /*
      * If Latin1 strings are enabled, cb starts out as a Latin1CharBuffer. When
      * a TwoByte char is appended, inflateChars() constructs a TwoByteCharBuffer
      * and copies the Latin1 chars.
      */
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1061,17 +1061,17 @@ class TypedArrayObjectTemplate : public 
 
         if (tarray->type() == self->type()) {
             memmove(dest, tarray->viewData(), byteLength);
             return true;
         }
 
         // We have to make a copy of the source array here, since
         // there's overlap, and we have to convert types.
-        void *srcbuf = cx->malloc_(byteLength);
+        uint8_t *srcbuf = self->zone()->pod_malloc<uint8_t>(byteLength);
         if (!srcbuf)
             return false;
         js_memcpy(srcbuf, tarray->viewData(), byteLength);
 
         uint32_t len = tarray->length();
         switch (tarray->type()) {
           case Scalar::Int8: {
             int8_t *src = (int8_t*) srcbuf;
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -97,16 +97,26 @@ class InfallibleAllocPolicy
 public:
   static void* malloc_(size_t aSize)
   {
     void* p = gMallocTable->malloc(aSize);
     ExitOnFailure(p);
     return p;
   }
 
+  template <typename T>
+  static T* pod_malloc(size_t aNumElems)
+  {
+    if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
+      return nullptr;
+    void* p = gMallocTable->malloc(aNumElems * sizeof(T));
+    ExitOnFailure(p);
+    return (T*)p;
+  }
+
   static void* calloc_(size_t aSize)
   {
     void* p = gMallocTable->calloc(1, aSize);
     ExitOnFailure(p);
     return p;
   }
 
   template <typename T>
--- a/mfbt/AllocPolicy.h
+++ b/mfbt/AllocPolicy.h
@@ -7,29 +7,32 @@
 /*
  * An allocation policy concept, usable for structures and algorithms to
  * control how memory is allocated and how failures are handled.
  */
 
 #ifndef mozilla_AllocPolicy_h
 #define mozilla_AllocPolicy_h
 
+#include "mozilla/NullPtr.h"
+#include "mozilla/TemplateLib.h"
+
 #include <stddef.h>
 #include <stdlib.h>
 
 namespace mozilla {
 
 /*
  * Allocation policies are used to implement the standard allocation behaviors
  * in a customizable way.  Additionally, custom behaviors may be added to these
  * behaviors, such as additionally reporting an error through an out-of-band
  * mechanism when OOM occurs.  The concept modeled here is as follows:
  *
  *  - public copy constructor, assignment, destructor
- *  - void* malloc_(size_t)
+ *  - template <typename T> T* pod_malloc(size_t)
  *      Responsible for OOM reporting when null is returned.
  *  - template <typename T> T* pod_calloc(size_t)
  *      Responsible for OOM reporting when null is returned.
  *  - void* realloc_(void*, size_t, size_t)
  *      Responsible for OOM reporting when null is returned.  The *used* bytes
  *      of the previous buffer is passed in (rather than the old allocation
  *      size), in addition to the *new* allocation size requested.
  *  - void free_(void*)
@@ -45,19 +48,22 @@ namespace mozilla {
 
 /*
  * A policy that straightforwardly uses malloc/calloc/realloc/free and adds no
  * extra behaviors.
  */
 class MallocAllocPolicy
 {
 public:
-  void* malloc_(size_t aBytes)
+  template <typename T>
+  T* pod_malloc(size_t aNumElems)
   {
-    return malloc(aBytes);
+    if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
+        return nullptr;
+    return static_cast<T*>(malloc(aNumElems * sizeof(T)));
   }
 
   template <typename T>
   T* pod_calloc(size_t aNumElems)
   {
     return static_cast<T*>(calloc(aNumElems, sizeof(T)));
   }
 
--- a/mfbt/Vector.h
+++ b/mfbt/Vector.h
@@ -119,17 +119,17 @@ struct VectorImpl
    * aNewCap has not overflowed, and (2) multiplying aNewCap by sizeof(T) will
    * not overflow.
    */
   static inline bool
   growTo(VectorBase<T, N, AP, ThisVector>& aV, size_t aNewCap)
   {
     MOZ_ASSERT(!aV.usingInlineStorage());
     MOZ_ASSERT(!CapacityHasExcessSpace<T>(aNewCap));
-    T* newbuf = reinterpret_cast<T*>(aV.malloc_(aNewCap * sizeof(T)));
+    T* newbuf = aV.template pod_malloc<T>(aNewCap);
     if (!newbuf) {
       return false;
     }
     T* dst = newbuf;
     T* src = aV.beginNoCheck();
     for (; src < aV.endNoCheck(); ++dst, ++src) {
       new(dst) T(Move(*src));
     }
@@ -699,17 +699,17 @@ VectorBase<T, N, AP, TV>::~VectorBase()
 template<typename T, size_t N, class AP, class TV>
 inline bool
 VectorBase<T, N, AP, TV>::convertToHeapStorage(size_t aNewCap)
 {
   MOZ_ASSERT(usingInlineStorage());
 
   /* Allocate buffer. */
   MOZ_ASSERT(!detail::CapacityHasExcessSpace<T>(aNewCap));
-  T* newBuf = reinterpret_cast<T*>(this->malloc_(aNewCap * sizeof(T)));
+  T* newBuf = this->template pod_malloc<T>(aNewCap);
   if (!newBuf) {
     return false;
   }
 
   /* Copy inline elements into heap buffer. */
   Impl::moveConstruct(newBuf, beginNoCheck(), endNoCheck());
   Impl::destroy(beginNoCheck(), endNoCheck());
 
@@ -808,17 +808,17 @@ template<typename T, size_t N, class AP,
 inline bool
 VectorBase<T, N, AP, TV>::initCapacity(size_t aRequest)
 {
   MOZ_ASSERT(empty());
   MOZ_ASSERT(usingInlineStorage());
   if (aRequest == 0) {
     return true;
   }
-  T* newbuf = reinterpret_cast<T*>(this->malloc_(aRequest * sizeof(T)));
+  T* newbuf = this->template pod_malloc<T>(aRequest);
   if (!newbuf) {
     return false;
   }
   mBegin = newbuf;
   mCapacity = aRequest;
 #ifdef DEBUG
   mReserved = aRequest;
 #endif
@@ -1132,17 +1132,17 @@ VectorBase<T, N, AP, TV>::popCopy()
 }
 
 template<typename T, size_t N, class AP, class TV>
 inline T*
 VectorBase<T, N, AP, TV>::extractRawBuffer()
 {
   T* ret;
   if (usingInlineStorage()) {
-    ret = reinterpret_cast<T*>(this->malloc_(mLength * sizeof(T)));
+    ret = this->template pod_malloc<T>(mLength);
     if (!ret) {
       return nullptr;
     }
     Impl::copyConstruct(ret, beginNoCheck(), endNoCheck());
     Impl::destroy(beginNoCheck(), endNoCheck());
     /* mBegin, mCapacity are unchanged. */
     mLength = 0;
   } else {