зеркало из https://github.com/mozilla/gecko-dev.git
Remove DUMP_CALL_TABLE (preliminary patch for 365851, r=igor).
This commit is contained in:
Родитель
b38ae8cb70
Коммит
e19d051052
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))) {
|
||||
|
|
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче