Bug 1063247: Let embeddings tell Debugger how to find the size of a malloc'd block of memory. r=terrence

This commit is contained in:
Jim Blandy 2014-09-19 15:10:01 -07:00
parent e3b9515c0f
commit 53ec639c97
8 changed files with 85 additions and 3 deletions

View File

@ -11,6 +11,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Move.h"
#include "jspubtd.h"
@ -249,6 +250,19 @@ class BuilderOrigin : public Builder {
JSObject *unwrap(Object &object) { return unwrapAny(object); }
};
// Finding the size of blocks allocated with malloc
// ------------------------------------------------
//
// Debugger.Memory wants to be able to report how many bytes items in memory are
// consuming. To do this, it needs a function that accepts a pointer to a block,
// and returns the number of bytes allocated to that block. SpiderMonkey itself
// doesn't know which function is appropriate to use, but the embedding does.
// Tell Debuggers in |runtime| to use |mallocSizeOf| to find the size of
// malloc'd blocks.
void SetDebuggerMallocSizeOf(JSRuntime *runtime, mozilla::MallocSizeOf mallocSizeOf);
} // namespace dbg
} // namespace JS

View File

@ -2012,6 +2012,19 @@ IsSimdAvailable(JSContext *cx, unsigned argc, Value *vp)
return true;
}
static bool
ByteSize(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
mozilla::MallocSizeOf mallocSizeOf = cx->runtime()->debuggerMallocSizeOf;
JS::ubi::Node node = args.get(0);
if (node)
args.rval().set(NumberValue(node.size(mallocSizeOf)));
else
args.rval().setUndefined();
return true;
}
static const JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gc", ::GC, 0, 0,
"gc([obj] | 'compartment' [, 'shrinking'])",
@ -2334,6 +2347,11 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
" 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_FS_HELP_END
};

View File

@ -1736,6 +1736,7 @@ ia64*-hpux*)
LDFLAGS="$LDFLAGS -DYNAMICBASE"
fi
AC_DEFINE(HAVE_SNPRINTF)
AC_DEFINE(HAVE__MSIZE)
AC_DEFINE(_WINDOWS)
AC_DEFINE(WIN32)
AC_DEFINE(XP_WIN)
@ -3912,8 +3913,8 @@ dnl ========================================================
dnl JavaScript shell
dnl ========================================================
AC_HAVE_FUNCS(setlocale)
AC_HAVE_FUNCS(localeconv)
AC_CHECK_HEADERS(malloc.h malloc/malloc.h)
AC_CHECK_FUNCS(setlocale localeconv malloc_size malloc_usable_size)
AC_SUBST(MOZILLA_VERSION)

View File

@ -22,6 +22,12 @@
# include <io.h> /* for isatty() */
#endif
#include <locale.h>
#ifdef HAVE_MALLOC_H /* for malloc_usable_size on Linux, _msize on Windows */
#include <malloc.h>
#endif
#ifdef HAVE_MALLOC_MALLOC_H
#include <malloc/malloc.h> /* for malloc_size on OSX */
#endif
#include <math.h>
#include <signal.h>
#include <stdio.h>
@ -57,6 +63,7 @@
#include "frontend/Parser.h"
#include "jit/arm/Simulator-arm.h"
#include "jit/Ion.h"
#include "js/Debug.h"
#include "js/OldDebugAPI.h"
#include "js/StructuredClone.h"
#include "perf/jsperf.h"
@ -5848,6 +5855,26 @@ DummyPreserveWrapperCallback(JSContext *cx, JSObject *obj)
return true;
}
size_t
ShellMallocSizeOf(const void *constPtr)
{
// Match the type that all the library functions we might use here expect.
void *ptr = (void *) constPtr;
if (!ptr)
return 0;
#if defined(HAVE_MALLOC_USABLE_SIZE)
return malloc_usable_size(ptr);
#elif defined(HAVE_MALLOC_SIZE)
return malloc_size(ptr);
#elif HAVE__MSIZE
return _msize(ptr);
#else
return 0;
#endif
}
int
main(int argc, char **argv, char **envp)
{
@ -6095,6 +6122,8 @@ main(int argc, char **argv, char **envp)
JS_SetNativeStackQuota(rt, gMaxStackSize);
JS::dbg::SetDebuggerMallocSizeOf(rt, ShellMallocSizeOf);
if (!offThreadState.init())
return 1;

View File

@ -15,6 +15,7 @@
#include "jscompartment.h"
#include "gc/Marking.h"
#include "js/Debug.h"
#include "js/UbiNode.h"
#include "js/UbiNodeTraverse.h"
#include "vm/Debugger.h"
@ -249,6 +250,11 @@ DebuggerMemory::setMaxAllocationsLogLength(JSContext *cx, unsigned argc, Value *
/* Debugger.Memory.prototype.takeCensus */
void
JS::dbg::SetDebuggerMallocSizeOf(JSRuntime *rt, mozilla::MallocSizeOf mallocSizeOf) {
rt->debuggerMallocSizeOf = mallocSizeOf;
}
namespace js {
namespace dbg {

View File

@ -121,6 +121,12 @@ static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
nullptr
};
static size_t
ReturnZeroSize(const void *p)
{
return 0;
}
JSRuntime::JSRuntime(JSRuntime *parentRuntime)
: JS::shadow::Runtime(
#ifdef JSGC_GENERATIONAL
@ -223,7 +229,8 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
enteredPolicy(nullptr),
#endif
largeAllocationFailureCallback(nullptr),
oomCallback(nullptr)
oomCallback(nullptr),
debuggerMallocSizeOf(ReturnZeroSize)
{
liveRuntimesCount++;

View File

@ -1402,6 +1402,12 @@ struct JSRuntime : public JS::shadow::Runtime,
}
return (T *)onOutOfMemoryCanGC(p, newSize * sizeof(T));
}
/*
* Debugger.Memory functions like takeCensus use this embedding-provided
* function to assess the size of malloc'd blocks of memory.
*/
mozilla::MallocSizeOf debuggerMallocSizeOf;
};
namespace js {

View File

@ -27,6 +27,7 @@
#include "jsobjinlines.h"
using JS::HandleValue;
using JS::Value;
using JS::ubi::Concrete;
using JS::ubi::Edge;