Remove DUMP_CALL_TABLE (preliminary patch for 365851, r=igor).

This commit is contained in:
brendan@mozilla.org 2007-12-14 13:36:02 -08:00
parent b38ae8cb70
commit e19d051052
5 changed files with 3 additions and 414 deletions

View File

@ -2553,14 +2553,6 @@ restart:
/* Finalize watch points associated with unreachable objects. */
js_SweepWatchPoints(cx);
#ifdef DUMP_CALL_TABLE
/*
* Call js_DumpCallTable here so it can meter and then clear weak refs to
* GC-things that are about to be finalized.
*/
js_DumpCallTable(cx);
#endif
/*
* Here we need to ensure that JSObject instances are finalized before GC-
* allocated JSString and jsdouble instances so object's finalizer can

View File

@ -666,339 +666,6 @@ NoSuchMethod(JSContext *cx, uintN argc, jsval *vp, uint32 flags)
#endif /* JS_HAS_NO_SUCH_METHOD */
#ifdef DUMP_CALL_TABLE
#include "jsclist.h"
#include "jshash.h"
#include "jsdtoa.h"
typedef struct CallKey {
jsval callee; /* callee value */
const char *filename; /* function filename or null */
uintN lineno; /* function lineno or 0 */
} CallKey;
/* Compensate for typeof null == "object" brain damage. */
#define JSTYPE_NULL JSTYPE_LIMIT
#define TYPEOF(cx,v) (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
#define TYPENAME(t) (((t) == JSTYPE_NULL) ? js_null_str : JS_TYPE_STR(t))
#define NTYPEHIST (JSTYPE_LIMIT + 1)
typedef struct CallValue {
uint32 total; /* total call count */
uint32 recycled; /* LRU-recycled calls lost */
uint16 minargc; /* minimum argument count */
uint16 maxargc; /* maximum argument count */
struct ArgInfo {
uint32 typeHist[NTYPEHIST]; /* histogram by type */
JSCList lruList; /* top 10 values LRU list */
struct ArgValCount {
JSCList lruLink; /* LRU list linkage */
jsval value; /* recently passed value */
uint32 count; /* number of times passed */
char strbuf[112]; /* string conversion buffer */
} topValCounts[10]; /* top 10 value storage */
} argInfo[8];
} CallValue;
typedef struct CallEntry {
JSHashEntry entry;
CallKey key;
CallValue value;
char name[32]; /* function name copy */
} CallEntry;
static void *
AllocCallTable(void *pool, size_t size)
{
return malloc(size);
}
static void
FreeCallTable(void *pool, void *item)
{
free(item);
}
static JSHashEntry *
AllocCallEntry(void *pool, const void *key)
{
return (JSHashEntry*) calloc(1, sizeof(CallEntry));
}
static void
FreeCallEntry(void *pool, JSHashEntry *he, uintN flag)
{
JS_ASSERT(flag == HT_FREE_ENTRY);
free(he);
}
static JSHashAllocOps callTableAllocOps = {
AllocCallTable, FreeCallTable,
AllocCallEntry, FreeCallEntry
};
JS_STATIC_DLL_CALLBACK(JSHashNumber)
js_hash_call_key(const void *key)
{
CallKey *ck = (CallKey *) key;
JSHashNumber hash = (jsuword)ck->callee >> 3;
if (ck->filename) {
hash = (hash << 4) ^ JS_HashString(ck->filename);
hash = (hash << 4) ^ ck->lineno;
}
return hash;
}
JS_STATIC_DLL_CALLBACK(intN)
js_compare_call_keys(const void *k1, const void *k2)
{
CallKey *ck1 = (CallKey *)k1, *ck2 = (CallKey *)k2;
return ck1->callee == ck2->callee &&
((ck1->filename && ck2->filename)
? strcmp(ck1->filename, ck2->filename) == 0
: ck1->filename == ck2->filename) &&
ck1->lineno == ck2->lineno;
}
JSHashTable *js_CallTable;
size_t js_LogCallToSourceLimit;
JS_STATIC_DLL_CALLBACK(intN)
CallTableDumper(JSHashEntry *he, intN k, void *arg)
{
CallEntry *ce = (CallEntry *)he;
FILE *fp = (FILE *)arg;
uintN argc, i, n;
struct ArgInfo *ai;
JSType save, type;
JSCList *cl;
struct ArgValCount *avc;
jsval argval;
if (ce->key.filename) {
/* We're called at the end of the mark phase, so mark our filenames. */
js_MarkScriptFilename(ce->key.filename);
fprintf(fp, "%s:%u ", ce->key.filename, ce->key.lineno);
} else {
fprintf(fp, "@%p ", (void *) ce->key.callee);
}
if (ce->name[0])
fprintf(fp, "name %s ", ce->name);
fprintf(fp, "calls %lu (%lu) argc %u/%u\n",
(unsigned long) ce->value.total,
(unsigned long) ce->value.recycled,
ce->value.minargc, ce->value.maxargc);
argc = JS_MIN(ce->value.maxargc, 8);
for (i = 0; i < argc; i++) {
ai = &ce->value.argInfo[i];
n = 0;
save = -1;
for (type = JSTYPE_VOID; type <= JSTYPE_LIMIT; type++) {
if (ai->typeHist[type]) {
save = type;
++n;
}
}
if (n == 1) {
fprintf(fp, " arg %u type %s: %lu\n",
i, TYPENAME(save), (unsigned long) ai->typeHist[save]);
} else {
fprintf(fp, " arg %u type histogram:\n", i);
for (type = JSTYPE_VOID; type <= JSTYPE_LIMIT; type++) {
fprintf(fp, " %9s: %8lu ",
TYPENAME(type), (unsigned long) ai->typeHist[type]);
for (n = (uintN) JS_HOWMANY(ai->typeHist[type], 10); n > 0; --n)
fputc('*', fp);
fputc('\n', fp);
}
}
fprintf(fp, " arg %u top 10 values:\n", i);
n = 1;
for (cl = ai->lruList.prev; cl != &ai->lruList; cl = cl->prev) {
avc = (struct ArgValCount *)cl;
if (!avc->count)
break;
argval = avc->value;
fprintf(fp, " %9u: %8lu %.*s (%#lx)\n",
n, (unsigned long) avc->count,
(int) sizeof avc->strbuf, avc->strbuf,
argval);
++n;
}
}
return HT_ENUMERATE_NEXT;
}
void
js_DumpCallTable(JSContext *cx)
{
char name[24];
FILE *fp;
static uintN dumpCount;
if (!js_CallTable)
return;
JS_snprintf(name, sizeof name, "/tmp/calltable.dump.%u", dumpCount & 7);
dumpCount++;
fp = fopen(name, "w");
if (!fp)
return;
JS_HashTableEnumerateEntries(js_CallTable, CallTableDumper, fp);
fclose(fp);
}
static void
LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv)
{
CallKey key;
const char *name, *cstr;
JSFunction *fun;
JSHashNumber keyHash;
JSHashEntry **hep, *he;
CallEntry *ce;
uintN i, j;
jsval argval;
JSType type;
struct ArgInfo *ai;
struct ArgValCount *avc;
JSString *str;
if (!js_CallTable) {
js_CallTable = JS_NewHashTable(1024, js_hash_call_key,
js_compare_call_keys, NULL,
&callTableAllocOps, NULL);
if (!js_CallTable)
return;
}
key.callee = callee;
key.filename = NULL;
key.lineno = 0;
name = "";
if (VALUE_IS_FUNCTION(cx, callee)) {
fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(callee));
if (fun->atom)
name = js_AtomToPrintableString(cx, fun->atom);
if (FUN_INTERPRETED(fun)) {
key.filename = fun->u.i.script->filename;
key.lineno = fun->u.i.script->lineno;
}
}
keyHash = js_hash_call_key(&key);
hep = JS_HashTableRawLookup(js_CallTable, keyHash, &key);
he = *hep;
if (he) {
ce = (CallEntry *) he;
JS_ASSERT(strncmp(ce->name, name, sizeof ce->name) == 0);
} else {
he = JS_HashTableRawAdd(js_CallTable, hep, keyHash, &key, NULL);
if (!he)
return;
ce = (CallEntry *) he;
ce->entry.key = &ce->key;
ce->entry.value = &ce->value;
ce->key = key;
for (i = 0; i < 8; i++) {
ai = &ce->value.argInfo[i];
JS_INIT_CLIST(&ai->lruList);
for (j = 0; j < 10; j++)
JS_APPEND_LINK(&ai->topValCounts[j].lruLink, &ai->lruList);
}
strncpy(ce->name, name, sizeof ce->name);
}
++ce->value.total;
if (ce->value.minargc < argc)
ce->value.minargc = argc;
if (ce->value.maxargc < argc)
ce->value.maxargc = argc;
if (argc > 8)
argc = 8;
for (i = 0; i < argc; i++) {
ai = &ce->value.argInfo[i];
argval = argv[i];
type = TYPEOF(cx, argval);
++ai->typeHist[type];
for (j = 0; ; j++) {
if (j == 10) {
avc = (struct ArgValCount *) ai->lruList.next;
ce->value.recycled += avc->count;
avc->value = argval;
avc->count = 1;
break;
}
avc = &ai->topValCounts[j];
if (avc->value == argval) {
++avc->count;
break;
}
}
/* Move avc to the back of the LRU list. */
JS_REMOVE_LINK(&avc->lruLink);
JS_APPEND_LINK(&avc->lruLink, &ai->lruList);
str = NULL;
cstr = "";
switch (TYPEOF(cx, argval)) {
case JSTYPE_VOID:
cstr = js_undefined_str;
break;
case JSTYPE_NULL:
cstr = js_null_str;
break;
case JSTYPE_BOOLEAN:
cstr = JS_BOOLEAN_STR(JSVAL_TO_BOOLEAN(argval));
break;
case JSTYPE_NUMBER:
if (JSVAL_IS_INT(argval)) {
JS_snprintf(avc->strbuf, sizeof avc->strbuf, "%ld",
JSVAL_TO_INT(argval));
} else {
JS_dtostr(avc->strbuf, sizeof avc->strbuf, DTOSTR_STANDARD, 0,
*JSVAL_TO_DOUBLE(argval));
}
continue;
case JSTYPE_STRING:
str = js_QuoteString(cx, JSVAL_TO_STRING(argval), (jschar)'"');
break;
case JSTYPE_FUNCTION:
if (VALUE_IS_FUNCTION(cx, argval)) {
fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(argval));
if (fun->atom) {
str = ATOM_TO_STRING(fun->atom);
break;
}
}
/* FALL THROUGH */
case JSTYPE_OBJECT:
js_LogCallToSourceLimit = sizeof avc->strbuf;
cx->options |= JSOPTION_LOGCALL_TOSOURCE;
str = js_ValueToSource(cx, argval);
cx->options &= ~JSOPTION_LOGCALL_TOSOURCE;
break;
}
if (str)
js_PutEscapedString(avc->strbuf, sizeof avc->strbuf, str, 0);
else
strncpy(avc->strbuf, cstr, sizeof avc->strbuf);
}
}
#endif /* DUMP_CALL_TABLE */
/*
* Conditional assert to detect failure to clear a pending exception that is
* suppressed (or unintentional suppression of a wanted exception).
@ -1361,9 +1028,6 @@ have_fun:
ASSERT_NOT_THROWING(cx);
#endif
} else if (script) {
#ifdef DUMP_CALL_TABLE
LogCall(cx, *vp, argc, frame.argv);
#endif
/* Use parent scope so js_GetCallObject can find the right "Call". */
frame.scopeChain = parent;
if (JSFUN_HEAVYWEIGHT_TEST(fun->flags)) {
@ -4046,9 +3710,6 @@ interrupt:
JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags));
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
newifp->frame.thisp = (JSObject *)vp[1];
#ifdef DUMP_CALL_TABLE
LogCall(cx, *vp, argc, vp + 2);
#endif
/* Push void to initialize local variables. */
sp = newsp;

View File

@ -118,15 +118,6 @@ js_AllocStack(JSContext *cx, uintN nslots, void **markp);
extern JS_FRIEND_API(void)
js_FreeStack(JSContext *cx, void *mark);
#ifdef DUMP_CALL_TABLE
# define JSOPTION_LOGCALL_TOSOURCE JS_BIT(15)
extern JSHashTable *js_CallTable;
extern size_t js_LogCallToSourceLimit;
extern void js_DumpCallTable(JSContext *cx);
#endif
/*
* Refresh and return fp->scopeChain. It may be stale if block scopes are
* active but not yet reflected by objects in the scope chain. If a block

View File

@ -796,47 +796,6 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
}
}
#ifdef DUMP_CALL_TABLE
if (cx->options & JSOPTION_LOGCALL_TOSOURCE) {
const char *classname = OBJ_GET_CLASS(cx, obj)->name;
size_t classnchars = strlen(classname);
static const char classpropid[] = "C";
const char *cp;
#ifdef DEBUG
size_t onchars = nchars;
#endif
/* 2 for ': ', 2 quotes around classname, 2 for ', ' after. */
classnchars += sizeof classpropid - 1 + 2 + 2;
if (ida->length)
classnchars += 2;
/* 2 for the braces, 1 for the terminator */
chars = (jschar *)
realloc((ochars = chars),
(nchars + classnchars + 2 + 1) * sizeof(jschar));
if (!chars) {
free(ochars);
goto error;
}
chars[nchars++] = '{'; /* 1 from the 2 braces */
for (cp = classpropid; *cp; cp++)
chars[nchars++] = (jschar) *cp;
chars[nchars++] = ':';
chars[nchars++] = ' '; /* 2 for ': ' */
chars[nchars++] = '"';
for (cp = classname; *cp; cp++)
chars[nchars++] = (jschar) *cp;
chars[nchars++] = '"'; /* 2 quotes */
if (ida->length) {
chars[nchars++] = ',';
chars[nchars++] = ' '; /* 2 for ', ' */
}
JS_ASSERT(nchars - onchars == 1 + classnchars);
} else
#endif
chars[nchars++] = '{';
comma = NULL;
@ -1113,10 +1072,6 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
if (vsharp)
JS_free(cx, vsharp);
#ifdef DUMP_CALL_TABLE
if (outermost && nchars >= js_LogCallToSourceLimit)
break;
#endif
}
}
@ -4127,11 +4082,7 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
/* Object has a private scope; Enumerate all props in scope. */
for (sprop = lastProp = SCOPE_LAST_PROP(scope); sprop;
sprop = sprop->parent) {
if ((
#ifdef DUMP_CALL_TABLE
(cx->options & JSOPTION_LOGCALL_TOSOURCE) ||
#endif
(sprop->attrs & JSPROP_ENUMERATE)) &&
if ((sprop->attrs & JSPROP_ENUMERATE) &&
!(sprop->flags & SPROP_IS_ALIAS) &&
(!SCOPE_HAD_MIDDLE_DELETE(scope) ||
SCOPE_HAS_PROPERTY(scope, sprop))) {
@ -4145,11 +4096,7 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
}
i = length;
for (sprop = lastProp; sprop; sprop = sprop->parent) {
if ((
#ifdef DUMP_CALL_TABLE
(cx->options & JSOPTION_LOGCALL_TOSOURCE) ||
#endif
(sprop->attrs & JSPROP_ENUMERATE)) &&
if ((sprop->attrs & JSPROP_ENUMERATE) &&
!(sprop->flags & SPROP_IS_ALIAS) &&
(!SCOPE_HAD_MIDDLE_DELETE(scope) ||
SCOPE_HAS_PROPERTY(scope, sprop))) {

View File

@ -4925,9 +4925,7 @@ Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
return ucs4Char;
}
#if defined(DEBUG) || \
defined(DUMP_CALL_TABLE) || \
defined(DUMP_SCOPE_STATS)
#if defined(DEBUG) || defined(DUMP_SCOPE_STATS)
JS_FRIEND_API(size_t)
js_PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp,