Bug 1395509 - Track malloc memory used by wasm objects, part 1 r=luke
authorJon Coppeard <jcoppeard@mozilla.com>
Thu, 20 Jun 2019 15:19:18 -0700
changeset 542769 b396c73d8978b5c1b381cc56aa02762b8c8dca8a
parent 542768 442d11bc5876b0134ede7abd20c812b9d4ee40a1
child 542770 893a79647962f1917bdde65957fed18e5afd1d5a
child 542786 ec4aac5a6c9f6b0172894a44bed7ad3393bfbae0
push id2131
push userffxbld-merge
push dateMon, 26 Aug 2019 18:30:20 +0000
treeherdermozilla-release@b19ffb3ca153 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1395509
milestone69.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 1395509 - Track malloc memory used by wasm objects, part 1 r=luke This adds tracking of malloc memory to WasmInstanceObject, WasmGlobalObject, WasmMemoryObject and ResolveResponseClosure (the straightforward cases). Differential Revision: https://phabricator.services.mozilla.com/D35485
js/public/GCVector.h
js/src/gc/GCEnum.h
js/src/wasm/WasmJS.cpp
js/src/wasm/WasmJS.h
--- a/js/public/GCVector.h
+++ b/js/public/GCVector.h
@@ -31,16 +31,18 @@ namespace JS {
 // it does not itself know when to barrier or trace items. To function properly
 // it must either be used with Rooted, or barriered and traced manually.
 template <typename T, size_t MinInlineCapacity = 0,
           typename AllocPolicy = js::TempAllocPolicy>
 class GCVector {
   mozilla::Vector<T, MinInlineCapacity, AllocPolicy> vector;
 
  public:
+  using ElementType = T;
+
   explicit GCVector(AllocPolicy alloc = AllocPolicy()) : vector(alloc) {}
 
   GCVector(GCVector&& vec) : vector(std::move(vec.vector)) {}
 
   GCVector& operator=(GCVector&& vec) {
     vector = std::move(vec.vector);
     return *this;
   }
--- a/js/src/gc/GCEnum.h
+++ b/js/src/gc/GCEnum.h
@@ -114,17 +114,24 @@ enum class ZealMode {
   _(TypedArrayElements)                    \
   _(TypeDescrTraceList)                    \
   _(NativeIterator)                        \
   _(JitScript)                             \
   _(ObjectGroupAddendum)                   \
   _(ScriptDebugScript)                     \
   _(BreakpointSite)                        \
   _(ForOfPIC)                              \
-  _(ForOfPICStub)
+  _(ForOfPICStub)                          \
+  _(WasmInstanceExports)                   \
+  _(WasmInstanceScopes)                    \
+  _(WasmInstanceGlobals)                   \
+  _(WasmInstanceInstance)                  \
+  _(WasmMemoryObservers)                   \
+  _(WasmGlobalCell)                        \
+  _(WasmResolveResponseClosure)
 
 #define JS_FOR_EACH_MEMORY_USE(_)  \
   JS_FOR_EACH_PUBLIC_MEMORY_USE(_) \
   JS_FOR_EACH_INTERNAL_MEMORY_USE(_)
 
 enum class MemoryUse : uint8_t {
 #define DEFINE_MEMORY_USE(Name) Name,
   JS_FOR_EACH_MEMORY_USE(DEFINE_MEMORY_USE)
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -1218,21 +1218,22 @@ const JSFunctionSpec WasmInstanceObject:
 
 bool WasmInstanceObject::isNewborn() const {
   MOZ_ASSERT(is<WasmInstanceObject>());
   return getReservedSlot(INSTANCE_SLOT).isUndefined();
 }
 
 /* static */
 void WasmInstanceObject::finalize(FreeOp* fop, JSObject* obj) {
-  fop->delete_(&obj->as<WasmInstanceObject>().exports());
-  fop->delete_(&obj->as<WasmInstanceObject>().scopes());
-  fop->delete_(&obj->as<WasmInstanceObject>().indirectGlobals());
-  if (!obj->as<WasmInstanceObject>().isNewborn()) {
-    fop->delete_(&obj->as<WasmInstanceObject>().instance());
+  WasmInstanceObject& instance = obj->as<WasmInstanceObject>();
+  fop->delete_(obj, &instance.exports(), MemoryUse::WasmInstanceExports);
+  fop->delete_(obj, &instance.scopes(), MemoryUse::WasmInstanceScopes);
+  fop->delete_(obj, &instance.indirectGlobals(), MemoryUse::WasmInstanceGlobals);
+  if (!instance.isNewborn()) {
+    fop->delete_(obj, &instance.instance(), MemoryUse::WasmInstanceInstance);
   }
 }
 
 /* static */
 void WasmInstanceObject::trace(JSTracer* trc, JSObject* obj) {
   WasmInstanceObject& instanceObj = obj->as<WasmInstanceObject>();
   instanceObj.exports().trace(trc);
   instanceObj.indirectGlobals().trace(trc);
@@ -1246,38 +1247,38 @@ WasmInstanceObject* WasmInstanceObject::
     JSContext* cx, SharedCode code, const DataSegmentVector& dataSegments,
     const ElemSegmentVector& elemSegments, UniqueTlsData tlsData,
     HandleWasmMemoryObject memory, SharedTableVector&& tables,
     StructTypeDescrVector&& structTypeDescrs,
     const JSFunctionVector& funcImports, const GlobalDescVector& globals,
     const ValVector& globalImportValues,
     const WasmGlobalObjectVector& globalObjs, HandleObject proto,
     UniqueDebugState maybeDebug) {
-  UniquePtr<ExportMap> exports = js::MakeUnique<ExportMap>();
+  UniquePtr<ExportMap> exports = js::MakeUnique<ExportMap>(cx->zone());
   if (!exports) {
     ReportOutOfMemory(cx);
     return nullptr;
   }
 
-  UniquePtr<ScopeMap> scopes = js::MakeUnique<ScopeMap>(cx->zone());
+  UniquePtr<ScopeMap> scopes = js::MakeUnique<ScopeMap>(cx->zone(), cx->zone());
   if (!scopes) {
     ReportOutOfMemory(cx);
     return nullptr;
   }
 
   uint32_t indirectGlobals = 0;
 
   for (uint32_t i = 0; i < globalObjs.length(); i++) {
     if (globalObjs[i] && globals[i].isIndirect()) {
       indirectGlobals++;
     }
   }
 
-  Rooted<UniquePtr<WasmGlobalObjectVector>> indirectGlobalObjs(
-      cx, js::MakeUnique<WasmGlobalObjectVector>());
+  Rooted<UniquePtr<GlobalObjectVector>> indirectGlobalObjs(
+      cx, js::MakeUnique<GlobalObjectVector>(cx->zone()));
   if (!indirectGlobalObjs || !indirectGlobalObjs->resize(indirectGlobals)) {
     ReportOutOfMemory(cx);
     return nullptr;
   }
 
   {
     uint32_t next = 0;
     for (uint32_t i = 0; i < globalObjs.length(); i++) {
@@ -1292,36 +1293,42 @@ WasmInstanceObject* WasmInstanceObject::
       cx, NewObjectWithGivenProto<WasmInstanceObject>(cx, proto));
   if (!obj) {
     return nullptr;
   }
 
   MOZ_ASSERT(obj->isTenured(), "assumed by WasmTableObject write barriers");
 
   // Finalization assumes these slots are always initialized:
-  obj->initReservedSlot(EXPORTS_SLOT, PrivateValue(exports.release()));
-  obj->initReservedSlot(SCOPES_SLOT, PrivateValue(scopes.release()));
-  obj->initReservedSlot(GLOBALS_SLOT,
-                        PrivateValue(indirectGlobalObjs.release()));
+  InitReservedSlot(obj, EXPORTS_SLOT, exports.release(),
+                   MemoryUse::WasmInstanceExports);
+
+  InitReservedSlot(obj, SCOPES_SLOT, scopes.release(),
+                   MemoryUse::WasmInstanceScopes);
+
+  InitReservedSlot(obj, GLOBALS_SLOT, indirectGlobalObjs.release(),
+                   MemoryUse::WasmInstanceGlobals);
+
   obj->initReservedSlot(INSTANCE_SCOPE_SLOT, UndefinedValue());
 
   // The INSTANCE_SLOT may not be initialized if Instance allocation fails,
   // leading to an observable "newborn" state in tracing/finalization.
   MOZ_ASSERT(obj->isNewborn());
 
   // Root the Instance via WasmInstanceObject before any possible GC.
   auto* instance = cx->new_<Instance>(
       cx, obj, code, std::move(tlsData), memory, std::move(tables),
       std::move(structTypeDescrs), funcImports, globalImportValues, globalObjs,
       std::move(maybeDebug));
   if (!instance) {
     return nullptr;
   }
 
-  obj->initReservedSlot(INSTANCE_SLOT, PrivateValue(instance));
+  InitReservedSlot(obj, INSTANCE_SLOT, instance,
+                   MemoryUse::WasmInstanceInstance);
   MOZ_ASSERT(!obj->isNewborn());
 
   if (!instance->init(cx, dataSegments, elemSegments)) {
     return nullptr;
   }
 
   return obj;
 }
@@ -1399,18 +1406,19 @@ JSObject& WasmInstanceObject::exportsObj
 WasmInstanceObject::ExportMap& WasmInstanceObject::exports() const {
   return *(ExportMap*)getReservedSlot(EXPORTS_SLOT).toPrivate();
 }
 
 WasmInstanceObject::ScopeMap& WasmInstanceObject::scopes() const {
   return *(ScopeMap*)getReservedSlot(SCOPES_SLOT).toPrivate();
 }
 
-WasmGlobalObjectVector& WasmInstanceObject::indirectGlobals() const {
-  return *(WasmGlobalObjectVector*)getReservedSlot(GLOBALS_SLOT).toPrivate();
+WasmInstanceObject::GlobalObjectVector& WasmInstanceObject::indirectGlobals()
+    const {
+  return *(GlobalObjectVector*)getReservedSlot(GLOBALS_SLOT).toPrivate();
 }
 
 static bool WasmCall(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   RootedFunction callee(cx, &args.callee().as<JSFunction>());
 
   Instance& instance = ExportedFunctionToInstance(callee);
   uint32_t funcIndex = ExportedFunctionToFuncIndex(callee);
@@ -1601,17 +1609,17 @@ const Class WasmMemoryObject::class_ = {
         JSCLASS_HAS_RESERVED_SLOTS(WasmMemoryObject::RESERVED_SLOTS) |
         JSCLASS_FOREGROUND_FINALIZE,
     &WasmMemoryObject::classOps_};
 
 /* static */
 void WasmMemoryObject::finalize(FreeOp* fop, JSObject* obj) {
   WasmMemoryObject& memory = obj->as<WasmMemoryObject>();
   if (memory.hasObservers()) {
-    fop->delete_(&memory.observers());
+    fop->delete_(obj, &memory.observers(), MemoryUse::WasmMemoryObservers);
   }
 }
 
 /* static */
 WasmMemoryObject* WasmMemoryObject::create(
     JSContext* cx, HandleArrayBufferObjectMaybeShared buffer,
     HandleObject proto) {
   AutoSetNewObjectMetadata metadata(cx);
@@ -1784,23 +1792,24 @@ WasmMemoryObject::InstanceSet& WasmMemor
   MOZ_ASSERT(hasObservers());
   return *reinterpret_cast<InstanceSet*>(
       getReservedSlot(OBSERVERS_SLOT).toPrivate());
 }
 
 WasmMemoryObject::InstanceSet* WasmMemoryObject::getOrCreateObservers(
     JSContext* cx) {
   if (!hasObservers()) {
-    auto observers = MakeUnique<InstanceSet>(cx->zone());
+    auto observers = MakeUnique<InstanceSet>(cx->zone(), cx->zone());
     if (!observers) {
       ReportOutOfMemory(cx);
       return nullptr;
     }
 
-    setReservedSlot(OBSERVERS_SLOT, PrivateValue(observers.release()));
+    InitReservedSlot(this, OBSERVERS_SLOT, observers.release(),
+                     MemoryUse::WasmMemoryObservers);
   }
 
   return &observers();
 }
 
 bool WasmMemoryObject::movingGrowable() const {
 #ifdef WASM_HUGE_MEMORY
   return false;
@@ -2347,17 +2356,17 @@ void WasmGlobalObject::trace(JSTracer* t
       MOZ_CRASH("NullRef not expressible");
   }
 }
 
 /* static */
 void WasmGlobalObject::finalize(FreeOp* fop, JSObject* obj) {
   WasmGlobalObject* global = reinterpret_cast<WasmGlobalObject*>(obj);
   if (!global->isNewborn()) {
-    fop->delete_(global->cell());
+    fop->delete_(obj, global->cell(), MemoryUse::WasmGlobalCell);
   }
 }
 
 /* static */
 WasmGlobalObject* WasmGlobalObject::create(JSContext* cx, HandleVal hval,
                                            bool isMutable) {
   RootedObject proto(
       cx, &cx->global()->getPrototype(JSProto_WasmGlobal).toObject());
@@ -2411,17 +2420,17 @@ WasmGlobalObject* WasmGlobalObject::crea
       MOZ_CRASH("Ref NYI");
     case ValType::NullRef:
       MOZ_CRASH("NullRef not expressible");
   }
 
   obj->initReservedSlot(TYPE_SLOT,
                         Int32Value(int32_t(val.type().bitsUnsafe())));
   obj->initReservedSlot(MUTABLE_SLOT, JS::BooleanValue(isMutable));
-  obj->initReservedSlot(CELL_SLOT, PrivateValue(cell));
+  InitReservedSlot(obj, CELL_SLOT, cell, MemoryUse::WasmGlobalCell);
 
   MOZ_ASSERT(!obj->isNewborn());
 
   return obj;
 }
 
 /* static */
 bool WasmGlobalObject::construct(JSContext* cx, unsigned argc, Value* vp) {
@@ -3400,17 +3409,19 @@ class CompileStreamTask : public Promise
 class ResolveResponseClosure : public NativeObject {
   static const unsigned COMPILE_ARGS_SLOT = 0;
   static const unsigned PROMISE_OBJ_SLOT = 1;
   static const unsigned INSTANTIATE_SLOT = 2;
   static const unsigned IMPORT_OBJ_SLOT = 3;
   static const ClassOps classOps_;
 
   static void finalize(FreeOp* fop, JSObject* obj) {
-    obj->as<ResolveResponseClosure>().compileArgs().Release();
+    auto& closure = obj->as<ResolveResponseClosure>();
+    fop->release(obj, &closure.compileArgs(),
+                 MemoryUse::WasmResolveResponseClosure);
   }
 
  public:
   static const unsigned RESERVED_SLOTS = 4;
   static const Class class_;
 
   static ResolveResponseClosure* create(JSContext* cx, const CompileArgs& args,
                                         HandleObject promise, bool instantiate,
@@ -3419,17 +3430,18 @@ class ResolveResponseClosure : public Na
 
     AutoSetNewObjectMetadata metadata(cx);
     auto* obj = NewObjectWithGivenProto<ResolveResponseClosure>(cx, nullptr);
     if (!obj) {
       return nullptr;
     }
 
     args.AddRef();
-    obj->setReservedSlot(COMPILE_ARGS_SLOT, PrivateValue((void*)&args));
+    InitReservedSlot(obj, COMPILE_ARGS_SLOT, const_cast<CompileArgs*>(&args),
+                     MemoryUse::WasmResolveResponseClosure);
     obj->setReservedSlot(PROMISE_OBJ_SLOT, ObjectValue(*promise));
     obj->setReservedSlot(INSTANTIATE_SLOT, BooleanValue(instantiate));
     obj->setReservedSlot(IMPORT_OBJ_SLOT, ObjectOrNullValue(importObj));
     return obj;
   }
 
   CompileArgs& compileArgs() const {
     return *(CompileArgs*)getReservedSlot(COMPILE_ARGS_SLOT).toPrivate();
--- a/js/src/wasm/WasmJS.h
+++ b/js/src/wasm/WasmJS.h
@@ -15,16 +15,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef wasm_js_h
 #define wasm_js_h
 
 #include "gc/Policy.h"
+#include "gc/ZoneAllocator.h"
 #include "vm/NativeObject.h"
 #include "wasm/WasmTypes.h"
 
 namespace js {
 
 class ArrayBufferObjectMaybeShared;
 class GlobalObject;
 class StructTypeDescr;
@@ -220,25 +221,25 @@ class WasmInstanceObject : public Native
   static void finalize(FreeOp* fop, JSObject* obj);
   static void trace(JSTracer* trc, JSObject* obj);
 
   // ExportMap maps from function index to exported function object.
   // This allows the instance to lazily create exported function
   // objects on demand (instead up-front for all table elements) while
   // correctly preserving observable function object identity.
   using ExportMap = GCHashMap<uint32_t, HeapPtr<JSFunction*>,
-                              DefaultHasher<uint32_t>, SystemAllocPolicy>;
+                              DefaultHasher<uint32_t>, ZoneAllocPolicy>;
   ExportMap& exports() const;
 
   // WeakScopeMap maps from function index to js::Scope. This maps is weak
   // to avoid holding scope objects alive. The scopes are normally created
   // during debugging.
   using ScopeMap =
       JS::WeakCache<GCHashMap<uint32_t, WeakHeapPtr<WasmFunctionScope*>,
-                              DefaultHasher<uint32_t>, SystemAllocPolicy>>;
+                              DefaultHasher<uint32_t>, ZoneAllocPolicy>>;
   ScopeMap& scopes() const;
 
  public:
   static const unsigned RESERVED_SLOTS = 6;
   static const Class class_;
   static const JSPropertySpec properties[];
   static const JSFunctionSpec methods[];
   static const JSFunctionSpec static_methods[];
@@ -270,17 +271,18 @@ class WasmInstanceObject : public Native
   const wasm::CodeRange& getExportedFunctionCodeRange(JSFunction* fun,
                                                       wasm::Tier tier);
 
   static WasmInstanceScope* getScope(JSContext* cx,
                                      HandleWasmInstanceObject instanceObj);
   static WasmFunctionScope* getFunctionScope(
       JSContext* cx, HandleWasmInstanceObject instanceObj, uint32_t funcIndex);
 
-  WasmGlobalObjectVector& indirectGlobals() const;
+  using GlobalObjectVector = GCVector<WasmGlobalObject*, 0, ZoneAllocPolicy>;
+  GlobalObjectVector& indirectGlobals() const;
 };
 
 // The class of WebAssembly.Memory. A WasmMemoryObject references an ArrayBuffer
 // or SharedArrayBuffer object which owns the actual memory.
 
 class WasmMemoryObject : public NativeObject {
   static const unsigned BUFFER_SLOT = 0;
   static const unsigned OBSERVERS_SLOT = 1;
@@ -290,17 +292,17 @@ class WasmMemoryObject : public NativeOb
   static bool bufferGetter(JSContext* cx, unsigned argc, Value* vp);
   static bool growImpl(JSContext* cx, const CallArgs& args);
   static bool grow(JSContext* cx, unsigned argc, Value* vp);
   static uint32_t growShared(HandleWasmMemoryObject memory, uint32_t delta);
 
   using InstanceSet =
       JS::WeakCache<GCHashSet<WeakHeapPtrWasmInstanceObject,
                               MovableCellHasher<WeakHeapPtrWasmInstanceObject>,
-                              SystemAllocPolicy>>;
+                              ZoneAllocPolicy>>;
   bool hasObservers() const;
   InstanceSet& observers() const;
   InstanceSet* getOrCreateObservers(JSContext* cx);
 
  public:
   static const unsigned RESERVED_SLOTS = 2;
   static const Class class_;
   static const JSPropertySpec properties[];