Bug 1199216 - Implement JS::ubi::Node::size for JSScript referents; r=sfink
authorNick Fitzgerald <fitzgen@gmail.com>
Tue, 22 Sep 2015 12:15:23 -0700
changeset 263871 e46f4a5bd5583b7ab09ccfafd1c0f5e895e380ad
parent 263870 ba36f2cc953e842d787a9ea1707a7360abc806b6
child 263872 e90db4a949ae7ff2701ece8261c84d07de71397e
push id29422
push usercbook@mozilla.com
push dateWed, 23 Sep 2015 10:32:35 +0000
treeherdermozilla-central@abe43c30d78d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1199216
milestone44.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 1199216 - Implement JS::ubi::Node::size for JSScript referents; r=sfink
js/public/UbiNode.h
js/src/builtin/TestingFunctions.cpp
js/src/jit-test/tests/heap-analysis/byteSize-of-scripts.js
js/src/jsscript.cpp
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -1015,16 +1015,17 @@ struct Concrete<JS::Symbol> : TracerConc
   public:
     static void construct(void* storage, JS::Symbol* ptr) {
         new (storage) Concrete(ptr);
     }
 };
 
 template<> struct Concrete<JSScript> : TracerConcreteWithCompartment<JSScript> {
     CoarseType coarseType() const final { return CoarseType::Script; }
+    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
 
   protected:
     explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment<JSScript>(ptr) { }
 
   public:
     static void construct(void *storage, JSScript *ptr) { new (storage) Concrete(ptr); }
 };
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2459,16 +2459,44 @@ ByteSize(JSContext* cx, unsigned argc, V
             args.rval().setNumber(uint32_t(node.size(mallocSizeOf)));
         else
             args.rval().setUndefined();
     }
     return true;
 }
 
 static bool
+ByteSizeOfScript(JSContext*cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (!args.requireAtLeast(cx, "byteSizeOfScript", 1))
+        return false;
+    if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
+        JS_ReportError(cx, "Argument must be a Function object");
+        return false;
+    }
+
+    RootedScript script(cx, args[0].toObject().as<JSFunction>().getOrCreateScript(cx));
+    mozilla::MallocSizeOf mallocSizeOf = cx->runtime()->debuggerMallocSizeOf;
+
+    {
+        // We can't tolerate the GC moving things around while we're using a
+        // ubi::Node. Check that nothing we do causes a GC.
+        JS::AutoCheckCannotGC autoCannotGC;
+
+        JS::ubi::Node node = script;
+        if (node)
+            args.rval().setNumber(uint32_t(node.size(mallocSizeOf)));
+        else
+            args.rval().setUndefined();
+    }
+    return true;
+}
+
+static bool
 ImmutablePrototypesEnabled(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     args.rval().setBoolean(JS_ImmutablePrototypesEnabled());
     return true;
 }
 
@@ -3219,16 +3247,20 @@ gc::ZealModeHelpText),
 "    options.locals - show local variables in each frame\n"
 "    options.thisprops - show the properties of the 'this' object of each frame\n"),
 
     JS_FN_HELP("byteSize", ByteSize, 1, 0,
 "byteSize(value)",
 "  Return the size in bytes occupied by |value|, or |undefined| if value\n"
 "  is not allocated in memory.\n"),
 
+    JS_FN_HELP("byteSizeOfScript", ByteSizeOfScript, 1, 0,
+"byteSizeOfScript(f)",
+"  Return the size in bytes occupied by the function |f|'s JSScript.\n"),
+
     JS_FN_HELP("immutablePrototypesEnabled", ImmutablePrototypesEnabled, 0, 0,
 "immutablePrototypesEnabled()",
 "  Returns true if immutable-prototype behavior (triggered by setImmutablePrototype)\n"
 "  is enabled, such that modifying an immutable prototype will fail."),
 
     JS_FN_HELP("setImmutablePrototype", SetImmutablePrototype, 1, 0,
 "setImmutablePrototype(obj)",
 "  Try to make obj's [[Prototype]] immutable, such that subsequent attempts to\n"
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/heap-analysis/byteSize-of-scripts.js
@@ -0,0 +1,46 @@
+// Check JS::ubi::Node::size results for scripts. We don't attempt to check
+// exact sizes in this test (deemed to difficult and non-deterministic), just
+// some sanity checks.
+
+function f1() {
+  return 42;
+}
+
+print("byteSizeOfScript(f1) = " + byteSizeOfScript(f1));
+assertEq(byteSizeOfScript(f1) > 1, true);
+
+function f2(n) {
+  var obj = {
+    x: 1,
+    y: 2,
+    z: 3,
+  };
+
+  if (i % 2 == 0) {
+    for (var i = 0; i < n; i++) {
+      this.x += i;
+      print(uneval(i));
+      obj[i] = i * i;
+      if (i > 10) {
+        f2(i / f1());
+      }
+    }
+  }
+
+  if (i % 3 == 0) {
+    for (var i = 0; i < n; i++) {
+      this.x *= i;
+      print(uneval(i));
+      obj[i] = i * i;
+      if (i > 10) {
+        f2(i / f1());
+      }
+    }
+  }
+
+  return this.x;
+}
+
+print("byteSizeOfScript(f2) = " + byteSizeOfScript(f2));
+assertEq(byteSizeOfScript(f2) > 1, true);
+assertEq(byteSizeOfScript(f2) > byteSizeOfScript(f1), true);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -4314,8 +4314,28 @@ void
 JSScript::AutoDelazify::dropScript()
 {
     // Don't touch script_ if it's in the self-hosting compartment, see the
     // comment in holdScript.
     if (script_ && !script_->compartment()->isSelfHosting)
         script_->setDoNotRelazify(oldDoNotRelazify_);
     script_ = nullptr;
 }
+
+JS::ubi::Node::Size
+JS::ubi::Concrete<JSScript>::size(mozilla::MallocSizeOf mallocSizeOf) const
+{
+    Size size = Arena::thingSize(get().asTenured().getAllocKind());
+
+    size += get().sizeOfData(mallocSizeOf);
+    size += get().sizeOfTypeScript(mallocSizeOf);
+
+    size_t baselineSize = 0;
+    size_t baselineStubsSize = 0;
+    jit::AddSizeOfBaselineData(&get(), mallocSizeOf, &baselineSize, &baselineStubsSize);
+    size += baselineSize;
+    size += baselineStubsSize;
+
+    size += jit::SizeOfIonData(&get(), mallocSizeOf);
+
+    MOZ_ASSERT(size > 0);
+    return size;
+}