Bug 692277 - Part a: Introduce an unstable public API for JS memory measurements to be used in XPCJSRuntime; r=njn sr=dmandelin
authorMs2ger <ms2ger@gmail.com>
Sat, 24 Dec 2011 09:27:39 +0100
changeset 85727 53c2fc22835b43d2fe60a5fce7e2e9cec97ecc1d
parent 85726 a16ef2789fc3f2422a6a215f2ba94207b3547f16
child 85728 f4d8adba8d7494ff58e16b66c27512a87b44e210
push idunknown
push userunknown
push dateunknown
reviewersnjn, dmandelin
bugs692277
milestone12.0a1
Bug 692277 - Part a: Introduce an unstable public API for JS memory measurements to be used in XPCJSRuntime; r=njn sr=dmandelin
js/public/MemoryMetrics.h
js/src/Makefile.in
js/src/jsapi-tests/testIntTypesABI.cpp
js/src/jsapi.cpp
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsinfer.cpp
js/src/jsobj.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/methodjit/MethodJIT.cpp
js/src/shell/js.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcpublic.h
new file mode 100644
--- /dev/null
+++ b/js/public/MemoryMetrics.h
@@ -0,0 +1,104 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is about:memory glue.
+ *
+ * The Initial Developer of the Original Code is
+ * Ms2ger <ms2ger@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef js_MemoryMetrics_h
+#define js_MemoryMetrics_h
+
+/*
+ * These declarations are not within jsapi.h because they are highly likely
+ * to change in the future. Depend on them at your own risk.
+ */
+
+#include "jspubtd.h"
+
+#include "js/Utility.h"
+
+namespace JS {
+
+/* Data for tracking analysis/inference memory usage. */
+struct TypeInferenceMemoryStats
+{
+    int64_t scripts;
+    int64_t objects;
+    int64_t tables;
+    int64_t temporary;
+};
+
+extern JS_PUBLIC_API(void)
+SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment,
+                                   TypeInferenceMemoryStats *stats,
+                                   JSMallocSizeOfFun mallocSizeOf);
+
+extern JS_PUBLIC_API(void)
+SizeOfObjectTypeInferenceData(/*TypeObject*/ void *object,
+                              TypeInferenceMemoryStats *stats,
+                              JSMallocSizeOfFun mallocSizeOf);
+
+extern JS_PUBLIC_API(size_t)
+SizeOfObjectDynamicSlots(JSObject *obj, JSMallocSizeOfFun mallocSizeOf);
+
+extern JS_PUBLIC_API(size_t)
+SizeOfCompartmentShapeTable(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf);
+
+extern JS_PUBLIC_API(size_t)
+SizeOfCompartmentMjitCode(const JSCompartment *c);
+
+extern JS_PUBLIC_API(bool)
+IsShapeInDictionary(const void *shape);
+
+extern JS_PUBLIC_API(size_t)
+SizeOfShapePropertyTable(const void *shape, JSMallocSizeOfFun mallocSizeOf);
+
+extern JS_PUBLIC_API(size_t)
+SizeOfShapeKids(const void *shape, JSMallocSizeOfFun mallocSizeOf);
+
+extern JS_PUBLIC_API(size_t)
+SizeOfScriptData(JSScript *script, JSMallocSizeOfFun mallocSizeOf);
+
+#ifdef JS_METHODJIT
+extern JS_PUBLIC_API(size_t)
+SizeOfScriptJitData(JSScript *script, JSMallocSizeOfFun mallocSizeOf);
+#endif
+
+extern JS_PUBLIC_API(size_t)
+SystemCompartmentCount(const JSRuntime *rt);
+
+extern JS_PUBLIC_API(size_t)
+UserCompartmentCount(const JSRuntime *rt);
+
+} // namespace JS
+
+#endif // js_MemoryMetrics_h
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -264,16 +264,17 @@ VPATH		+= \
 EXPORTS_NAMESPACES += js
 
 # If you add a header here, add it to js/src/jsapi-tests/testIntTypesABI.cpp so
 # that we ensure we don't over-expose our internal integer typedefs.  Note that
 # LegacyIntTypes.h below is deliberately exempted from this requirement.
 EXPORTS_js = \
 		HashTable.h \
 		LegacyIntTypes.h \
+		MemoryMetrics.h \
 		TemplateLib.h \
 		Utility.h \
 		Vector.h \
 		$(NULL)
 
 ###############################################
 # BEGIN include sources for low-level code shared with mfbt
 #
--- a/js/src/jsapi-tests/testIntTypesABI.cpp
+++ b/js/src/jsapi-tests/testIntTypesABI.cpp
@@ -13,16 +13,17 @@
 #include "jscpucfg.h"
 #include "jspubtd.h"
 #include "jsstdint.h"
 #include "jstypes.h"
 #include "jsval.h"
 #include "jsxdrapi.h"
 
 #include "js/HashTable.h"
+#include "js/MemoryMetrics.h"
 #include "js/TemplateLib.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 
 /*
  * Verify that our public (and intended to be public, versus being that way
  * because we haven't made them private yet) headers don't define
  * {u,}int{8,16,32,64} or JS{Ui,I}nt{8,16,32,64} types.  If any do, they will
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -81,16 +81,17 @@
 #include "jsweakmap.h"
 #include "jswrapper.h"
 #include "jstypedarray.h"
 
 #include "ds/LifoAlloc.h"
 #include "builtin/RegExp.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
+#include "js/MemoryMetrics.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/RegExpObject-inl.h"
@@ -918,16 +919,40 @@ JS_GetRuntimePrivate(JSRuntime *rt)
 }
 
 JS_PUBLIC_API(void)
 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
 {
     rt->data = data;
 }
 
+JS_PUBLIC_API(size_t)
+JS::SystemCompartmentCount(const JSRuntime *rt)
+{
+    size_t n = 0;
+    for (size_t i = 0; i < rt->compartments.length(); i++) {
+        if (rt->compartments[i]->isSystemCompartment) {
+            ++n;
+        }
+    }
+    return n;
+}
+
+JS_PUBLIC_API(size_t)
+JS::UserCompartmentCount(const JSRuntime *rt)
+{
+    size_t n = 0;
+    for (size_t i = 0; i < rt->compartments.length(); i++) {
+        if (!rt->compartments[i]->isSystemCompartment) {
+            ++n;
+        }
+    }
+    return n;
+}
+
 #ifdef JS_THREADSAFE
 static void
 StartRequest(JSContext *cx)
 {
     JSThread *t = cx->thread();
     JS_ASSERT(CURRENT_THREAD_IS_ME(t));
 
     if (t->data.requestDepth) {
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -43,22 +43,24 @@
 #include "jsgc.h"
 #include "jsgcmark.h"
 #include "jsiter.h"
 #include "jsmath.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jswatchpoint.h"
 #include "jswrapper.h"
+
 #include "assembler/wtf/Platform.h"
-#include "yarr/BumpPointerAllocator.h"
+#include "js/MemoryMetrics.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/PolyIC.h"
 #include "methodjit/MonoIC.h"
 #include "vm/Debugger.h"
+#include "yarr/BumpPointerAllocator.h"
 
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 
 #if ENABLE_YARR_JIT
 #include "assembler/jit/ExecutableAllocator.h"
 #endif
@@ -137,27 +139,34 @@ JSCompartment::ensureJaegerCompartmentEx
     if (!jc->Initialize()) {
         cx->delete_(jc);
         return false;
     }
     jaegerCompartment_ = jc;
     return true;
 }
 
-void
-JSCompartment::sizeOfCode(size_t *method, size_t *regexp, size_t *unused) const
+size_t
+JSCompartment::sizeOfMjitCode() const
 {
-    if (jaegerCompartment_) {
-        jaegerCompartment_->execAlloc()->sizeOfCode(method, regexp, unused);
-    } else {
-        *method = 0;
-        *regexp = 0;
-        *unused = 0;
-    }
+    if (!jaegerCompartment_)
+        return 0;
+
+    size_t method, regexp, unused;
+    jaegerCompartment_->execAlloc()->sizeOfCode(&method, &regexp, &unused);
+    JS_ASSERT(regexp == 0);
+    return method + unused;
 }
+
+JS_PUBLIC_API(size_t)
+JS::SizeOfCompartmentMjitCode(const JSCompartment *c)
+{
+    return c->sizeOfMjitCode();
+}
+
 #endif
 
 bool
 JSCompartment::wrap(JSContext *cx, Value *vp)
 {
     JS_ASSERT(cx->compartment == this);
 
     uintN flags = 0;
@@ -735,8 +744,17 @@ JSCompartment::sweepBreakpoints(JSContex
 }
 
 GCMarker *
 JSCompartment::createBarrierTracer()
 {
     JS_ASSERT(!gcIncrementalTracer);
     return NULL;
 }
+
+JS_PUBLIC_API(size_t)
+JS::SizeOfCompartmentShapeTable(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf)
+{
+    return c->baseShapes.sizeOfExcludingThis(mallocSizeOf)
+         + c->initialShapes.sizeOfExcludingThis(mallocSizeOf)
+         + c->newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
+         + c->lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
+}
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -230,17 +230,17 @@ struct JS_FRIEND_API(JSCompartment) {
 
     js::mjit::JaegerCompartment *jaegerCompartment() const {
         JS_ASSERT(jaegerCompartment_);
         return jaegerCompartment_;
     }
 
     bool ensureJaegerCompartmentExists(JSContext *cx);
 
-    void sizeOfCode(size_t *method, size_t *regexp, size_t *unused) const;
+    size_t sizeOfMjitCode() const;
 #endif
 
     /*
      * Shared scope property tree, and arena-pool for allocating its nodes.
      */
     js::PropertyTree             propertyTree;
 
 #ifdef DEBUG
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -179,31 +179,16 @@ AutoSwitchCompartment::AutoSwitchCompart
 }
 
 AutoSwitchCompartment::~AutoSwitchCompartment()
 {
     /* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
     cx->compartment = oldCompartment;
 }
 
-JS_FRIEND_API(size_t)
-js::GetObjectDynamicSlotSize(JSObject *obj, JSMallocSizeOfFun mallocSizeOf)
-{
-    return obj->dynamicSlotSize(mallocSizeOf);
-}
-
-JS_FRIEND_API(size_t)
-js::GetCompartmentShapeTableSize(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf)
-{
-    return c->baseShapes.sizeOfExcludingThis(mallocSizeOf)
-         + c->initialShapes.sizeOfExcludingThis(mallocSizeOf)
-         + c->newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
-         + c->lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
-}
-
 JS_FRIEND_API(bool)
 js::IsScopeObject(const JSObject *obj)
 {
     return obj->isInternalScope();
 }
 
 JS_FRIEND_API(JSObject *)
 js::GetObjectParentMaybeScope(const JSObject *obj)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -109,35 +109,16 @@ extern JS_FRIEND_API(void)
 JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback);
 
 typedef void
 (* JSGCFinishedCallback)(JSRuntime *rt, JSCompartment *comp, const char *description);
 
 extern JS_FRIEND_API(void)
 JS_SetGCFinishedCallback(JSRuntime *rt, JSGCFinishedCallback callback);
 
-/* Data for tracking analysis/inference memory usage. */
-typedef struct TypeInferenceMemoryStats
-{
-    int64_t scripts;
-    int64_t objects;
-    int64_t tables;
-    int64_t temporary;
-} TypeInferenceMemoryStats;
-
-extern JS_FRIEND_API(void)
-JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
-                               TypeInferenceMemoryStats *stats,
-                               JSMallocSizeOfFun mallocSizeOf);
-
-extern JS_FRIEND_API(void)
-JS_GetTypeInferenceObjectStats(/*TypeObject*/ void *object,
-                               TypeInferenceMemoryStats *stats,
-                               JSMallocSizeOfFun mallocSizeOf);
-
 extern JS_FRIEND_API(JSPrincipals *)
 JS_GetCompartmentPrincipals(JSCompartment *compartment);
 
 /* Safe to call with input obj == NULL. Returns non-NULL iff obj != NULL. */
 extern JS_FRIEND_API(JSObject *)
 JS_ObjectToInnerObject(JSContext *cx, JSObject *obj);
 
 /* Requires obj != NULL. */
@@ -204,22 +185,16 @@ class JS_FRIEND_API(AutoSwitchCompartmen
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 #ifdef OLD_GETTER_SETTER_METHODS
 JS_FRIEND_API(JSBool) obj_defineGetter(JSContext *cx, uintN argc, js::Value *vp);
 JS_FRIEND_API(JSBool) obj_defineSetter(JSContext *cx, uintN argc, js::Value *vp);
 #endif
 
-extern JS_FRIEND_API(size_t)
-GetObjectDynamicSlotSize(JSObject *obj, JSMallocSizeOfFun mallocSizeOf);
-
-extern JS_FRIEND_API(size_t)
-GetCompartmentShapeTableSize(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf);
-
 /*
  * Check whether it is OK to assign an undeclared property with name
  * propname of the global object in the current script on cx.  Reports
  * an error if one needs to be reported (in particular in all cases
  * when it returns false).
  */
 extern JS_FRIEND_API(bool)
 CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -51,16 +51,17 @@
 #include "jsobj.h"
 #include "jsscript.h"
 #include "jscntxt.h"
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jsiter.h"
 
 #include "frontend/TokenStream.h"
+#include "js/MemoryMetrics.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Retcon.h"
 
 #include "jsatominlines.h"
 #include "jsgcinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
@@ -6289,30 +6290,30 @@ GetScriptMemoryStats(JSScript *script, T
     TypeResult *result = typeScript->dynamicList;
     while (result) {
         stats->scripts += mallocSizeOf(result, sizeof(TypeResult));
         result = result->next;
     }
 
     /*
      * This counts memory that is in the temp pool but gets attributed
-     * elsewhere.  See JS_GetTypeInferenceMemoryStats for more details.
+     * elsewhere.  See JS::SizeOfCompartmentTypeInferenceData for more details.
      */
     TypeSet *typeArray = typeScript->typeArray();
     for (unsigned i = 0; i < count; i++) {
         size_t bytes = typeArray[i].dynamicSize();
         stats->scripts += bytes;
         stats->temporary -= bytes;
     }
 }
 
-JS_FRIEND_API(void)
-JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
-                               TypeInferenceMemoryStats *stats,
-                               JSMallocSizeOfFun mallocSizeOf)
+JS_PUBLIC_API(void)
+JS::SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment,
+                                       TypeInferenceMemoryStats *stats,
+                                       JSMallocSizeOfFun mallocSizeOf)
 {
     /*
      * Note: not all data in the pool is temporary, and some will survive GCs
      * by being copied to the replacement pool. This memory will be counted
      * elsewhere and deducted from the amount of temporary data.
      */
     stats->temporary += compartment->typeLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
 
@@ -6345,18 +6346,18 @@ JS_GetTypeInferenceMemoryStats(JSContext
 
             /* key.ids and values.types have the same length. */
             stats->tables += mallocSizeOf(key.ids, key.nslots * sizeof(jsid)) +
                              mallocSizeOf(value.types, key.nslots * sizeof(Type));
         }
     }
 }
 
-JS_FRIEND_API(void)
-JS_GetTypeInferenceObjectStats(void *object_, TypeInferenceMemoryStats *stats, JSMallocSizeOfFun mallocSizeOf)
+JS_PUBLIC_API(void)
+JS::SizeOfObjectTypeInferenceData(void *object_, TypeInferenceMemoryStats *stats, JSMallocSizeOfFun mallocSizeOf)
 {
     TypeObject *object = (TypeObject *) object_;
 
     if (object->singleton) {
         /*
          * Properties and associated type sets for singletons are cleared on
          * every GC. The type object is normally destroyed too, but we don't
          * charge this to 'temporary' as this is not for GC heap values.
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -77,16 +77,17 @@
 #include "jsdbgapi.h"
 #include "json.h"
 #include "jswatchpoint.h"
 #include "jswrapper.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
+#include "js/MemoryMetrics.h"
 
 #include "jsarrayinlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jsstrinlines.h"
 
@@ -7125,16 +7126,22 @@ js::HandleNonGenericMethodClassMismatch(
         if (thisObj.isProxy())
             return Proxy::nativeCall(cx, &thisObj, clasp, native, args);
     }
 
     ReportIncompatibleMethod(cx, args, clasp);
     return false;
 }
 
+JS_PUBLIC_API(size_t)
+JS::SizeOfObjectDynamicSlots(JSObject *obj, JSMallocSizeOfFun mallocSizeOf)
+{
+    return obj->dynamicSlotSize(mallocSizeOf);
+}
+
 #ifdef DEBUG
 
 /*
  * Routines to print out values during debugging.  These are FRIEND_API to help
  * the debugger find them and to support temporarily hacking js_Dump* calls
  * into other code.
  */
 
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -54,16 +54,18 @@
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsscope.h"
 #include "jsstr.h"
 
+#include "js/MemoryMetrics.h"
+
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 bool
@@ -1444,8 +1446,26 @@ JSCompartment::sweepInitialShapeTable(JS
     if (initialShapes.initialized()) {
         for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) {
             const InitialShapeEntry &entry = e.front();
             if (!entry.shape->isMarked() || (entry.proto && !entry.proto->isMarked()))
                 e.removeFront();
         }
     }
 }
+
+JS_PUBLIC_API(bool)
+JS::IsShapeInDictionary(const void *shape)
+{
+    return static_cast<const Shape*>(shape)->inDictionary();
+}
+
+JS_PUBLIC_API(size_t)
+JS::SizeOfShapePropertyTable(const void *shape, JSMallocSizeOfFun mallocSizeOf)
+{
+    return static_cast<const Shape*>(shape)->sizeOfPropertyTable(mallocSizeOf);
+}
+
+JS_PUBLIC_API(size_t)
+JS::SizeOfShapeKids(const void *shape, JSMallocSizeOfFun mallocSizeOf)
+{
+    return static_cast<const Shape*>(shape)->sizeOfKids(mallocSizeOf);
+}
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -63,16 +63,17 @@
 #include "jsscope.h"
 #include "jsscript.h"
 #if JS_HAS_XDR
 #include "jsxdrapi.h"
 #endif
 
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
+#include "js/MemoryMetrics.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Retcon.h"
 #include "vm/Debugger.h"
 
 #include "jsinferinlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
@@ -1306,16 +1307,22 @@ JSScript::dataSize(JSMallocSizeOfFun mal
 #if JS_SCRIPT_INLINE_DATA_LIMIT
     if (data == inlineData)
         return 0;
 #endif
 
     return mallocSizeOf(data, dataSize());
 }
 
+JS_PUBLIC_API(size_t)
+JS::SizeOfScriptData(JSScript *script, JSMallocSizeOfFun mallocSizeOf)
+{
+    return script->dataSize(mallocSizeOf);
+}
+
 /*
  * Nb: srcnotes are variable-length.  This function computes the number of
  * srcnote *slots*, which may be greater than the number of srcnotes.
  */
 uint32_t
 JSScript::numNotes()
 {
     jssrcnote *sn;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -646,18 +646,18 @@ struct JSScript : public js::gc::Cell {
         void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal;
         if (addr == NULL)
             return JITScript_None;
         if (addr == JS_UNJITTABLE_SCRIPT)
             return JITScript_Invalid;
         return JITScript_Valid;
     }
 
-    /* Size of the JITScript and all sections.  (This method is implemented in MethodJIT.h.) */
-    JS_FRIEND_API(size_t) jitDataSize(JSMallocSizeOfFun mallocSizeOf);
+    /* Size of the JITScript and all sections.  (This method is implemented in MethodJIT.cpp.) */
+    size_t jitDataSize(JSMallocSizeOfFun mallocSizeOf);
 
 #endif
 
     /* Counter accessors. */
     js::OpcodeCounts getCounts(jsbytecode *pc) {
         JS_ASSERT(size_t(pc - code) < length);
         return pcCounters.counts[pc - code];
     }
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -35,16 +35,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "MethodJIT.h"
 #include "Logging.h"
 #include "assembler/jit/ExecutableAllocator.h"
 #include "assembler/assembler/RepatchBuffer.h"
+#include "js/MemoryMetrics.h"
 #include "jsgcmark.h"
 #include "BaseAssembler.h"
 #include "Compiler.h"
 #include "MonoIC.h"
 #include "PolyIC.h"
 #include "TrampolineCompiler.h"
 #include "jscntxtinlines.h"
 #include "jscompartment.h"
@@ -1307,16 +1308,22 @@ JSScript::jitDataSize(JSMallocSizeOfFun 
     size_t n = 0;
     if (jitNormal)
         n += jitNormal->scriptDataSize(mallocSizeOf); 
     if (jitCtor)
         n += jitCtor->scriptDataSize(mallocSizeOf); 
     return n;
 }
 
+JS_PUBLIC_API(size_t)
+JS::SizeOfScriptJitData(JSScript *script, JSMallocSizeOfFun mallocSizeOf)
+{
+    return script->jitDataSize(mallocSizeOf);
+}
+
 /* Please keep in sync with Compiler::finishThisUp! */
 size_t
 mjit::JITScript::scriptDataSize(JSMallocSizeOfFun mallocSizeOf)
 {
     size_t computedSize =
         sizeof(JITScript) +
         sizeof(NativeMapEntry) * nNmapPairs +
         sizeof(InlineFrame) * nInlineFrames +
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3820,21 +3820,19 @@ Deserialize(JSContext *cx, uintN argc, j
 }
 
 JSBool
 MJitCodeStats(JSContext *cx, uintN argc, jsval *vp)
 {
 #ifdef JS_METHODJIT
     JSRuntime *rt = cx->runtime;
     AutoLockGC lock(rt);
-    size_t n = 0, method, regexp, unused;
-    for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
-    {
-        (*c)->sizeOfCode(&method, &regexp, &unused);
-        n += method + regexp + unused;
+    size_t n = 0;
+    for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
+        n += (*c)->sizeOfMjitCode();
     }
     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(n));
 #else
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
 #endif
     return true;
 }
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -44,27 +44,27 @@
 #include "mozilla/Util.h"
 
 #include "xpcprivate.h"
 #include "xpcpublic.h"
 #include "WrapperFactory.h"
 #include "dom_quickstubs.h"
 
 #include "jscompartment.h"
-#include "jsgcchunk.h"
-#include "jsscope.h"
 #include "nsIMemoryReporter.h"
 #include "nsPrintfCString.h"
 #include "mozilla/FunctionTimer.h"
 #include "prsystem.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsContentUtils.h"
 
+#include "js/MemoryMetrics.h"
+
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::xpconnect::memory;
 
 /***************************************************************************/
@@ -1235,36 +1235,34 @@ XPCJSRuntime::~XPCJSRuntime()
     XPCPerThreadData::ShutDown();
 }
 
 namespace {
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
 
 void
-CompartmentCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
+CompartmentMemoryCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
 {
     // Append a new CompartmentStats to the vector.
     IterateData *data = static_cast<IterateData *>(vdata);
     CompartmentStats compartmentStats(cx, compartment);
     CompartmentStats *curr =
         data->compartmentStatsVector.AppendElement(compartmentStats);
     data->currCompartmentStats = curr;
 
     // Get the compartment-level numbers.
 #ifdef JS_METHODJIT
-    size_t method, regexp, unused;
-    compartment->sizeOfCode(&method, &regexp, &unused);
-    JS_ASSERT(regexp == 0);     /* this execAlloc is only used for method code */
-    curr->mjitCode = method + unused;
+    curr->mjitCode = JS::SizeOfCompartmentMjitCode(compartment);
 #endif
-    JS_GetTypeInferenceMemoryStats(cx, compartment, &curr->typeInferenceMemory,
-                                   JsMallocSizeOf);
+    JS::SizeOfCompartmentTypeInferenceData(cx, compartment,
+                                           &curr->typeInferenceMemory,
+                                           JsMallocSizeOf);
     curr->shapesCompartmentTables =
-        js::GetCompartmentShapeTableSize(compartment, JsMallocSizeOf);
+        JS::SizeOfCompartmentShapeTable(compartment, JsMallocSizeOf);
 }
 
 void
 ChunkCallback(JSContext *cx, void *vdata, js::gc::Chunk *chunk)
 {
     // Nb: This function is only called for dirty chunks, which is why we
     // increment gcHeapChunkDirtyDecommitted.
     IterateData *data = static_cast<IterateData *>(vdata);
@@ -1301,63 +1299,62 @@ CellCallback(JSContext *cx, void *vdata,
         case JSTRACE_OBJECT:
         {
             JSObject *obj = static_cast<JSObject *>(thing);
             if (JS_ObjectIsFunction(cx, obj)) {
                 curr->gcHeapObjectsFunction += thingSize;
             } else {
                 curr->gcHeapObjectsNonFunction += thingSize;
             }
-            curr->objectSlots += js::GetObjectDynamicSlotSize(obj, JsMallocSizeOf);
+            curr->objectSlots += JS::SizeOfObjectDynamicSlots(obj, JsMallocSizeOf);
             break;
         }
         case JSTRACE_STRING:
         {
             JSString *str = static_cast<JSString *>(thing);
             curr->gcHeapStrings += thingSize;
             curr->stringChars += str->charsHeapSize(JsMallocSizeOf);
             break;
         }
         case JSTRACE_SHAPE:
         {
-            js::Shape *shape = static_cast<js::Shape *>(thing);
-            if (shape->inDictionary()) {
+            if (JS::IsShapeInDictionary(thing)) {
                 curr->gcHeapShapesDict += thingSize;
                 curr->shapesExtraDictTables +=
-                    shape->sizeOfPropertyTable(JsMallocSizeOf);
+                    JS::SizeOfShapePropertyTable(thing, JsMallocSizeOf);
             } else {
                 curr->gcHeapShapesTree += thingSize;
                 curr->shapesExtraTreeTables +=
-                    shape->sizeOfPropertyTable(JsMallocSizeOf);
+                    JS::SizeOfShapePropertyTable(thing, JsMallocSizeOf);
                 curr->shapesExtraTreeShapeKids +=
-                    shape->sizeOfKids(JsMallocSizeOf);
+                    JS::SizeOfShapeKids(thing, JsMallocSizeOf);
             }
             break;
         }
         case JSTRACE_BASE_SHAPE:
         {
             curr->gcHeapShapesBase += thingSize;
             break;
         }
         case JSTRACE_SCRIPT:
         {
             JSScript *script = static_cast<JSScript *>(thing);
             curr->gcHeapScripts += thingSize;
-            curr->scriptData += script->dataSize(JsMallocSizeOf);
+            curr->scriptData += JS::SizeOfScriptData(script, JsMallocSizeOf);
 #ifdef JS_METHODJIT
-            curr->mjitData += script->jitDataSize(JsMallocSizeOf);
+            curr->mjitData += JS::SizeOfScriptJitData(script, JsMallocSizeOf);
 #endif
             break;
         }
         case JSTRACE_TYPE_OBJECT:
         {
             js::types::TypeObject *obj = static_cast<js::types::TypeObject *>(thing);
             curr->gcHeapTypeObjects += thingSize;
-            JS_GetTypeInferenceObjectStats(obj, &curr->typeInferenceMemory,
-                                           JsMallocSizeOf);
+            JS::SizeOfObjectTypeInferenceData(obj, &curr->typeInferenceMemory,
+                                              JsMallocSizeOf);
             break;
         }
         case JSTRACE_XML:
         {
             curr->gcHeapXML += thingSize;
             break;
         }
     }
@@ -1459,37 +1456,23 @@ NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJS
                              KIND_OTHER,
                              nsIMemoryReporter::UNITS_BYTES,
                              GetGCChunkTotalBytes,
                              "Memory used by the garbage-collected JavaScript heap.")
 
 static PRInt64
 GetJSSystemCompartmentCount()
 {
-    JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
-    size_t n = 0;
-    for (size_t i = 0; i < rt->compartments.length(); i++) {
-        if (rt->compartments[i]->isSystemCompartment) {
-            n++;
-        }
-    }
-    return n;
+    return JS::SystemCompartmentCount(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
 }
 
 static PRInt64
 GetJSUserCompartmentCount()
 {
-    JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
-    size_t n = 0;
-    for (size_t i = 0; i < rt->compartments.length(); i++) {
-        if (!rt->compartments[i]->isSystemCompartment) {
-            n++;
-        }
-    }
-    return n;
+    return JS::UserCompartmentCount(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
 }
 
 // Nb: js-system-compartment-count + js-user-compartment-count could be
 // different to the number of compartments reported by
 // XPConnectJSCompartmentsMultiReporter if a garbage collection occurred
 // between them being consulted.  We could move these reporters into
 // XPConnectJSCompartmentCount to avoid that problem, but then we couldn't
 // easily report them via telemetry, so we live with the small risk of
@@ -1576,17 +1559,17 @@ CollectCompartmentStatsForRuntime(JSRunt
         data->gcHeapChunkCleanUnused =
             PRInt64(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) *
             js::gc::ChunkSize -
             data->gcHeapChunkCleanDecommitted;
         data->gcHeapChunkTotal =
             PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
             js::gc::ChunkSize;
 
-        js::IterateCompartmentsArenasCells(cx, data, CompartmentCallback,
+        js::IterateCompartmentsArenasCells(cx, data, CompartmentMemoryCallback,
                                            ArenaCallback, CellCallback);
         js::IterateChunks(cx, data, ChunkCallback);
 
         data->runtimeObject = JsMallocSizeOf(rt, sizeof(JSRuntime));
 
         // Nb: we use sizeOfExcludingThis() because atomState.atoms is within
         // JSRuntime, and so counted when JSRuntime is counted.
         data->runtimeAtomsTable =
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -36,16 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef xpcpublic_h
 #define xpcpublic_h
 
 #include "jsapi.h"
+#include "js/MemoryMetrics.h"
 #include "jsclass.h"
 #include "jsfriendapi.h"
 #include "jsgc.h"
 #include "jspubtd.h"
 #include "jsproxy.h"
 
 #include "nsISupports.h"
 #include "nsIPrincipal.h"
@@ -234,17 +235,17 @@ struct CompartmentStats
     PRInt64 shapesExtraTreeShapeKids;
     PRInt64 shapesCompartmentTables;
     PRInt64 scriptData;
 
 #ifdef JS_METHODJIT
     PRInt64 mjitCode;
     PRInt64 mjitData;
 #endif
-    TypeInferenceMemoryStats typeInferenceMemory;
+    JS::TypeInferenceMemoryStats typeInferenceMemory;
 };
 
 struct IterateData
 {
     IterateData()
       : runtimeObject(0),
         runtimeAtomsTable(0),
         runtimeContexts(0),