# HG changeset patch # User Atul Varma # Date 1245716658 25200 # Node ID 193ff16b013a11931fed70e34cca4f6e6c78de9d # Parent be05a91e7b0aacdaad1b69d4d95363b9e95ffbee Added a dumpHeap() function to the TCB global object, which can be used even w/o debug builds of SpiderMonkey. diff -r be05a91e7b0a -r 193ff16b013a spidermonkey-playground.cpp --- a/spidermonkey-playground.cpp Mon Jun 22 15:54:37 2009 -0700 +++ b/spidermonkey-playground.cpp Mon Jun 22 17:24:18 2009 -0700 @@ -41,6 +41,7 @@ #include "string.h" #include "jsapi.h" #include "jsdbgapi.h" +#include "jsdhash.h" #include "wrapper.h" @@ -80,6 +81,79 @@ return JS_TRUE; } +// Private structure to track the state of tracing the JS heap. + +typedef struct TracingState { + // Keeps track of what objects we've visited so far. + JSDHashTable visited; + + // Whether the tracing operation is successful or failed. + JSBool result; +}; + +// Static singleton for tracking the state of tracing the JS heap. +static TracingState tracingState; + +// JSTraceCallback for heap dumping and other operations. + +static void traceCallback(JSTracer *trc, void *thing, uint32 kind) +{ + switch (kind) { + case JSTRACE_OBJECT: + JSDHashEntryStub *entry = (JSDHashEntryStub *) + JS_DHashTableOperate(&tracingState.visited, + thing, + JS_DHASH_LOOKUP); + if (JS_DHASH_ENTRY_IS_FREE((JSDHashEntryHdr *)entry)) { + entry = (JSDHashEntryStub *) JS_DHashTableOperate(&tracingState.visited, + thing, + JS_DHASH_ADD); + if (entry == NULL) { + JS_ReportOutOfMemory(trc->context); + tracingState.result = JS_FALSE; + return; + } + entry->key = thing; + JS_TraceChildren(trc, thing, kind); + } + break; + case JSTRACE_DOUBLE: + break; + case JSTRACE_STRING: + const char *str = JS_GetStringBytes((JSString *)thing); + printf("string: %s\n", str); + break; + } +} + +// This native JS function dumps the heap to stdout. It's available even on +// non-debug builds of SpiderMonkey, but it's also not terribly robust. + +static JSBool dumpHeap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + JSTracer tracer; + + if (!JS_DHashTableInit(&tracingState.visited, JS_DHashGetStubOps(), + NULL, sizeof(JSDHashEntryStub), + JS_DHASH_DEFAULT_CAPACITY(100))) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + tracingState.result = JS_TRUE; + tracer.context = cx; + tracer.callback = traceCallback; + JS_TraceRuntime(&tracer); + + JS_DHashTableFinish(&tracingState.visited); + + if (!tracingState.result) + return JS_FALSE; + *rval = JSVAL_VOID; + return JS_TRUE; +} + // This native JS function forces garbage collection. static JSBool forceGC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, @@ -378,6 +452,7 @@ JS_FS("functionInfo", functionInfo, 1, 0, 0), JS_FS("enumerate", enumerate, 1, 0, 0), JS_FS("forceGC", forceGC, 0, 0, 0), + JS_FS("dumpHeap", dumpHeap, 0, 0, 0), JS_FS_END };