зеркало из https://github.com/mozilla/gecko-dev.git
Remove JS_FrameIterator (bug 732653, r=luke,mrbkap).
This commit is contained in:
Родитель
58e1815704
Коммит
e83e82b9dd
|
@ -2257,8 +2257,8 @@ nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx,
|
|||
if (cx)
|
||||
{
|
||||
// Get principals from innermost JavaScript frame.
|
||||
JSStackFrame *fp = nullptr; // tell JS_FrameIterator to start at innermost
|
||||
for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp))
|
||||
JSStackFrame *fp = nullptr; // tell JS_BrokenFrameIterator to start at innermost
|
||||
for (fp = JS_BrokenFrameIterator(cx, &fp); fp; fp = JS_BrokenFrameIterator(cx, &fp))
|
||||
{
|
||||
nsIPrincipal* result = GetFramePrincipal(cx, fp, rv);
|
||||
if (result)
|
||||
|
@ -2286,7 +2286,7 @@ nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx,
|
|||
if (result)
|
||||
{
|
||||
JSStackFrame *inner = nullptr;
|
||||
*frameResult = JS_FrameIterator(cx, &inner);
|
||||
*frameResult = JS_BrokenFrameIterator(cx, &inner);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -2451,7 +2451,7 @@ nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
|
|||
nsresult rv;
|
||||
JSStackFrame *fp = nullptr;
|
||||
JSContext *cx = GetCurrentJSContext();
|
||||
fp = cx ? JS_FrameIterator(cx, &fp) : nullptr;
|
||||
fp = cx ? JS_BrokenFrameIterator(cx, &fp) : nullptr;
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
|
@ -2502,7 +2502,7 @@ nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
|
|||
// the JS engine via JS_EvaluateScript or similar APIs.
|
||||
if (JS_IsGlobalFrame(cx, fp))
|
||||
break;
|
||||
} while ((fp = JS_FrameIterator(cx, &fp)) != nullptr);
|
||||
} while ((fp = JS_BrokenFrameIterator(cx, &fp)) != nullptr);
|
||||
|
||||
if (!previousPrincipal)
|
||||
{
|
||||
|
|
|
@ -289,7 +289,7 @@ jsd_FindOrCreateJSDScript(JSDContext *jsdc,
|
|||
|
||||
/* Fallback for unknown scripts: create a new script. */
|
||||
if (!fp)
|
||||
JS_FrameIterator(cx, &fp);
|
||||
JS_BrokenFrameIterator(cx, &fp);
|
||||
if (fp)
|
||||
jsdscript = _newJSDScript(jsdc, cx, script);
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ jsd_NewThreadState(JSDContext* jsdc, JSContext *cx )
|
|||
jsdthreadstate->stackDepth = 0;
|
||||
|
||||
JS_BeginRequest(jsdthreadstate->context);
|
||||
while( NULL != (fp = JS_FrameIterator(cx, &iter)) )
|
||||
while( NULL != (fp = JS_BrokenFrameIterator(cx, &iter)) )
|
||||
{
|
||||
JSScript* script = JS_GetFrameScript(cx, fp);
|
||||
uintptr_t pc = (uintptr_t) JS_GetFramePC(cx, fp);
|
||||
|
|
|
@ -479,11 +479,8 @@ JS_GetScriptOriginPrincipals(JSScript *script)
|
|||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* Stack Frame Iterator
|
||||
*/
|
||||
JS_PUBLIC_API(JSStackFrame *)
|
||||
JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
|
||||
JS_BrokenFrameIterator(JSContext *cx, JSStackFrame **iteratorp)
|
||||
{
|
||||
StackFrame *fp = Valueify(*iteratorp);
|
||||
*iteratorp = Jsvalify((fp == NULL) ? js_GetTopStackFrame(cx, FRAME_EXPAND_ALL) : fp->prev());
|
||||
|
@ -1843,3 +1840,267 @@ js_CallContextDebugHandler(JSContext *cx)
|
|||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(StackDescription *)
|
||||
JS::DescribeStack(JSContext *cx, unsigned maxFrames)
|
||||
{
|
||||
Vector<FrameDescription> frames(cx);
|
||||
|
||||
for (ScriptFrameIter i(cx); !i.done(); ++i) {
|
||||
FrameDescription desc;
|
||||
desc.script = i.script();
|
||||
desc.lineno = PCToLineNumber(i.script(), i.pc());
|
||||
desc.fun = i.fp()->maybeFun();
|
||||
if (!frames.append(desc))
|
||||
return NULL;
|
||||
if (frames.length() == maxFrames)
|
||||
break;
|
||||
}
|
||||
|
||||
StackDescription *desc = cx->new_<StackDescription>();
|
||||
if (!desc)
|
||||
return NULL;
|
||||
|
||||
desc->nframes = frames.length();
|
||||
desc->frames = frames.extractRawBuffer();
|
||||
return desc;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::FreeStackDescription(JSContext *cx, StackDescription *desc)
|
||||
{
|
||||
cx->free_(desc->frames);
|
||||
cx->free_(desc);
|
||||
}
|
||||
|
||||
class AutoPropertyDescArray
|
||||
{
|
||||
JSContext *cx_;
|
||||
JSPropertyDescArray descArray_;
|
||||
|
||||
public:
|
||||
AutoPropertyDescArray(JSContext *cx)
|
||||
: cx_(cx)
|
||||
{
|
||||
PodZero(&descArray_);
|
||||
}
|
||||
~AutoPropertyDescArray()
|
||||
{
|
||||
if (descArray_.array)
|
||||
JS_PutPropertyDescArray(cx_, &descArray_);
|
||||
}
|
||||
|
||||
void fetch(JSObject *obj) {
|
||||
JS_ASSERT(!descArray_.array);
|
||||
if (!JS_GetPropertyDescArray(cx_, obj, &descArray_))
|
||||
descArray_.array = NULL;
|
||||
}
|
||||
|
||||
JSPropertyDescArray * operator ->() {
|
||||
return &descArray_;
|
||||
}
|
||||
};
|
||||
|
||||
static const char *
|
||||
FormatValue(JSContext *cx, const Value &v, JSAutoByteString &bytes)
|
||||
{
|
||||
JSString *str = ToString(cx, v);
|
||||
if (!str)
|
||||
return NULL;
|
||||
const char *buf = bytes.encode(cx, str);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
const char *found = strstr(buf, "function ");
|
||||
if (found && (found - buf <= 2))
|
||||
return "[function]";
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *
|
||||
FormatFrame(JSContext *cx, const ScriptFrameIter &iter, char *buf, int num,
|
||||
JSBool showArgs, JSBool showLocals, JSBool showThisProps)
|
||||
{
|
||||
JSScript* script = iter.script();
|
||||
jsbytecode* pc = iter.pc();
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, iter.fp()->scopeChain()))
|
||||
return buf;
|
||||
|
||||
const char *filename = script->filename;
|
||||
unsigned lineno = PCToLineNumber(script, pc);
|
||||
JSFunction *fun = iter.fp()->maybeFun();
|
||||
JSString *funname = NULL;
|
||||
if (fun)
|
||||
funname = fun->atom;
|
||||
|
||||
JSObject *callObj = NULL;
|
||||
AutoPropertyDescArray callProps(cx);
|
||||
|
||||
if (showArgs || showLocals) {
|
||||
callObj = JS_GetFrameCallObject(cx, Jsvalify(iter.fp()));
|
||||
if (callObj)
|
||||
callProps.fetch(callObj);
|
||||
}
|
||||
|
||||
Value thisVal = UndefinedValue();
|
||||
AutoPropertyDescArray thisProps(cx);
|
||||
if (ComputeThis(cx, iter.fp())) {
|
||||
thisVal = iter.fp()->thisValue();
|
||||
if (showThisProps && !thisVal.isPrimitive())
|
||||
thisProps.fetch(&thisVal.toObject());
|
||||
}
|
||||
|
||||
// print the frame number and function name
|
||||
if (funname) {
|
||||
JSAutoByteString funbytes;
|
||||
buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encode(cx, funname));
|
||||
} else if (fun) {
|
||||
buf = JS_sprintf_append(buf, "%d anonymous(", num);
|
||||
} else {
|
||||
buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num);
|
||||
}
|
||||
if (!buf)
|
||||
return buf;
|
||||
|
||||
// print the function arguments
|
||||
if (showArgs && callObj) {
|
||||
uint32_t namedArgCount = 0;
|
||||
for (uint32_t i = 0; i < callProps->length; i++) {
|
||||
JSPropertyDesc* desc = &callProps->array[i];
|
||||
JSAutoByteString nameBytes;
|
||||
const char *name = NULL;
|
||||
if (JSVAL_IS_STRING(desc->id))
|
||||
name = FormatValue(cx, desc->id, nameBytes);
|
||||
|
||||
JSAutoByteString valueBytes;
|
||||
const char *value = FormatValue(cx, desc->value, valueBytes);
|
||||
|
||||
buf = JS_sprintf_append(buf, "%s%s%s%s%s%s",
|
||||
namedArgCount ? ", " : "",
|
||||
name ? name :"",
|
||||
name ? " = " : "",
|
||||
desc->value.isString() ? "\"" : "",
|
||||
value ? value : "?unknown?",
|
||||
desc->value.isString() ? "\"" : "");
|
||||
if (!buf)
|
||||
return buf;
|
||||
namedArgCount++;
|
||||
}
|
||||
|
||||
// print any unnamed trailing args (found in 'arguments' object)
|
||||
Value val;
|
||||
if (JS_GetProperty(cx, callObj, "arguments", &val) && val.isObject()) {
|
||||
uint32_t argCount;
|
||||
JSObject* argsObj = &val.toObject();
|
||||
if (JS_GetProperty(cx, argsObj, "length", &val) &&
|
||||
ToUint32(cx, val, &argCount) &&
|
||||
argCount > namedArgCount)
|
||||
{
|
||||
for (uint32_t k = namedArgCount; k < argCount; k++) {
|
||||
char number[8];
|
||||
JS_snprintf(number, 8, "%d", (int) k);
|
||||
|
||||
if (JS_GetProperty(cx, argsObj, number, &val)) {
|
||||
JSAutoByteString valueBytes;
|
||||
const char *value = FormatValue(cx, val, valueBytes);
|
||||
buf = JS_sprintf_append(buf, "%s%s%s%s",
|
||||
k ? ", " : "",
|
||||
val.isString() ? "\"" : "",
|
||||
value ? value : "?unknown?",
|
||||
val.isString() ? "\"" : "");
|
||||
if (!buf)
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print filename and line number
|
||||
buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n",
|
||||
fun ? ")" : "",
|
||||
filename ? filename : "<unknown>",
|
||||
lineno);
|
||||
if (!buf)
|
||||
return buf;
|
||||
|
||||
// print local variables
|
||||
if (showLocals && callProps->array) {
|
||||
for (uint32_t i = 0; i < callProps->length; i++) {
|
||||
JSPropertyDesc* desc = &callProps->array[i];
|
||||
JSAutoByteString nameBytes;
|
||||
JSAutoByteString valueBytes;
|
||||
const char *name = FormatValue(cx, desc->id, nameBytes);
|
||||
const char *value = FormatValue(cx, desc->value, valueBytes);
|
||||
|
||||
if (name && value) {
|
||||
buf = JS_sprintf_append(buf, " %s = %s%s%s\n",
|
||||
name,
|
||||
desc->value.isString() ? "\"" : "",
|
||||
value,
|
||||
desc->value.isString() ? "\"" : "");
|
||||
if (!buf)
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print the value of 'this'
|
||||
if (showLocals) {
|
||||
if (!thisVal.isUndefined()) {
|
||||
JSAutoByteString thisValBytes;
|
||||
if (JSString* thisValStr = ToString(cx, thisVal)) {
|
||||
if (const char *str = thisValBytes.encode(cx, thisValStr)) {
|
||||
buf = JS_sprintf_append(buf, " this = %s\n", str);
|
||||
if (!buf)
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buf = JS_sprintf_append(buf, " <failed to get 'this' value>\n");
|
||||
}
|
||||
}
|
||||
|
||||
// print the properties of 'this', if it is an object
|
||||
if (showThisProps && thisProps->array) {
|
||||
for (uint32_t i = 0; i < thisProps->length; i++) {
|
||||
JSPropertyDesc* desc = &thisProps->array[i];
|
||||
if (desc->flags & JSPD_ENUMERATE) {
|
||||
JSAutoByteString nameBytes;
|
||||
JSAutoByteString valueBytes;
|
||||
const char *name = FormatValue(cx, desc->id, nameBytes);
|
||||
const char *value = FormatValue(cx, desc->value, valueBytes);
|
||||
if (name && value) {
|
||||
buf = JS_sprintf_append(buf, " this.%s = %s%s%s\n",
|
||||
name,
|
||||
desc->value.isString() ? "\"" : "",
|
||||
value,
|
||||
desc->value.isString() ? "\"" : "");
|
||||
if (!buf)
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(char *)
|
||||
JS::FormatStackDump(JSContext *cx, char *buf,
|
||||
JSBool showArgs, JSBool showLocals,
|
||||
JSBool showThisProps)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
for (ScriptFrameIter i(cx); !i.done(); ++i) {
|
||||
buf = FormatFrame(cx, i, buf, num, showArgs, showLocals, showThisProps);
|
||||
num++;
|
||||
}
|
||||
|
||||
if (!num)
|
||||
buf = JS_sprintf_append(buf, "JavaScript stack is empty\n");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,30 @@ class JS_PUBLIC_API(AutoEnterFrameCompartment) : public AutoEnterScriptCompartme
|
|||
bool enter(JSContext *cx, JSStackFrame *target);
|
||||
};
|
||||
|
||||
struct FrameDescription
|
||||
{
|
||||
JSScript *script;
|
||||
unsigned lineno;
|
||||
JSFunction *fun;
|
||||
};
|
||||
|
||||
struct StackDescription
|
||||
{
|
||||
unsigned nframes;
|
||||
FrameDescription *frames;
|
||||
};
|
||||
|
||||
extern JS_PUBLIC_API(StackDescription *)
|
||||
DescribeStack(JSContext *cx, unsigned maxFrames);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
FreeStackDescription(JSContext *cx, StackDescription *desc);
|
||||
|
||||
extern JS_PUBLIC_API(char *)
|
||||
FormatStackDump(JSContext *cx, char *buf,
|
||||
JSBool showArgs, JSBool showLocals,
|
||||
JSBool showThisProps);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -200,14 +224,16 @@ extern JS_PUBLIC_API(JSPrincipals *)
|
|||
JS_GetScriptOriginPrincipals(JSScript *script);
|
||||
|
||||
/*
|
||||
* Stack Frame Iterator
|
||||
* This function does not work when IonMonkey is active. It remains for legacy
|
||||
* code: caps/principal clamping, which will be removed shortly after
|
||||
* compartment-per-global, and jsd, which can only be used when IonMonkey is
|
||||
* disabled.
|
||||
*
|
||||
* Used to iterate through the JS stack frames to extract
|
||||
* information from the frames.
|
||||
* To find the calling script and line number, use JS_DescribeSciptedCaller.
|
||||
* To summarize the call stack, use JS::DescribeStack.
|
||||
*/
|
||||
|
||||
extern JS_PUBLIC_API(JSStackFrame *)
|
||||
JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp);
|
||||
JS_BrokenFrameIterator(JSContext *cx, JSStackFrame **iteratorp);
|
||||
|
||||
extern JS_PUBLIC_API(JSScript *)
|
||||
JS_GetFrameScript(JSContext *cx, JSStackFrame *fp);
|
||||
|
|
|
@ -10,11 +10,6 @@
|
|||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef TAB
|
||||
#undef TAB
|
||||
#endif
|
||||
#define TAB " "
|
||||
|
||||
static void DebugDump(const char* fmt, ...)
|
||||
{
|
||||
char buffer[2048];
|
||||
|
@ -35,232 +30,6 @@ static void DebugDump(const char* fmt, ...)
|
|||
printf("%s", buffer);
|
||||
}
|
||||
|
||||
static const char* JSVAL2String(JSContext* cx, jsval val, JSBool* isString,
|
||||
JSAutoByteString *bytes)
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
const char* value = nullptr;
|
||||
JSString* value_str = JS_ValueToString(cx, val);
|
||||
if (value_str)
|
||||
value = bytes->encode(cx, value_str);
|
||||
if (value) {
|
||||
const char* found = strstr(value, "function ");
|
||||
if (found && (value == found || value+1 == found || value+2 == found))
|
||||
value = "[function]";
|
||||
}
|
||||
|
||||
if (isString)
|
||||
*isString = JSVAL_IS_STRING(val);
|
||||
return value;
|
||||
}
|
||||
|
||||
static char* FormatJSFrame(JSContext* cx, JSStackFrame* fp,
|
||||
char* buf, int num,
|
||||
JSBool showArgs, JSBool showLocals, JSBool showThisProps)
|
||||
{
|
||||
JSPropertyDescArray callProps = {0, nullptr};
|
||||
JSPropertyDescArray thisProps = {0, nullptr};
|
||||
JSBool gotThisVal = false;
|
||||
jsval thisVal;
|
||||
JSObject* callObj = nullptr;
|
||||
JSString* funname = nullptr;
|
||||
JSAutoByteString funbytes;
|
||||
const char* filename = nullptr;
|
||||
PRInt32 lineno = 0;
|
||||
JSFunction* fun = nullptr;
|
||||
uint32_t namedArgCount = 0;
|
||||
JSBool isString;
|
||||
|
||||
// get the info for this stack frame
|
||||
|
||||
JSScript* script = JS_GetFrameScript(cx, fp);
|
||||
jsbytecode* pc = JS_GetFramePC(cx, fp);
|
||||
|
||||
JSAutoRequest ar(cx);
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, JS_GetGlobalForFrame(fp)))
|
||||
return buf;
|
||||
|
||||
if (script && pc) {
|
||||
filename = JS_GetScriptFilename(cx, script);
|
||||
lineno = (PRInt32) JS_PCToLineNumber(cx, script, pc);
|
||||
fun = JS_GetFrameFunction(cx, fp);
|
||||
if (fun)
|
||||
funname = JS_GetFunctionId(fun);
|
||||
|
||||
if (showArgs || showLocals) {
|
||||
callObj = JS_GetFrameCallObject(cx, fp);
|
||||
if (callObj)
|
||||
if (!JS_GetPropertyDescArray(cx, callObj, &callProps))
|
||||
callProps.array = nullptr; // just to be sure
|
||||
}
|
||||
|
||||
gotThisVal = JS_GetFrameThis(cx, fp, &thisVal);
|
||||
if (!gotThisVal ||
|
||||
!showThisProps ||
|
||||
JSVAL_IS_PRIMITIVE(thisVal) ||
|
||||
!JS_GetPropertyDescArray(cx, JSVAL_TO_OBJECT(thisVal),
|
||||
&thisProps)) {
|
||||
thisProps.array = nullptr; // just to be sure
|
||||
}
|
||||
}
|
||||
|
||||
// print the frame number and function name
|
||||
|
||||
if (funname)
|
||||
buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encode(cx, funname));
|
||||
else if (fun)
|
||||
buf = JS_sprintf_append(buf, "%d anonymous(", num);
|
||||
else
|
||||
buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num);
|
||||
if (!buf) goto out;
|
||||
|
||||
// print the function arguments
|
||||
|
||||
if (showArgs && callObj) {
|
||||
for (uint32_t i = 0; i < callProps.length; i++) {
|
||||
JSPropertyDesc* desc = &callProps.array[i];
|
||||
JSAutoByteString nameBytes;
|
||||
const char* name = JSVAL2String(cx, desc->id, &isString, &nameBytes);
|
||||
if (!isString)
|
||||
name = nullptr;
|
||||
JSAutoByteString valueBytes;
|
||||
const char* value = JSVAL2String(cx, desc->value, &isString, &valueBytes);
|
||||
|
||||
buf = JS_sprintf_append(buf, "%s%s%s%s%s%s",
|
||||
namedArgCount ? ", " : "",
|
||||
name ? name :"",
|
||||
name ? " = " : "",
|
||||
isString ? "\"" : "",
|
||||
value ? value : "?unknown?",
|
||||
isString ? "\"" : "");
|
||||
if (!buf) goto out;
|
||||
namedArgCount++;
|
||||
}
|
||||
|
||||
// print any unnamed trailing args (found in 'arguments' object)
|
||||
JS::Value val;
|
||||
if (JS_GetProperty(cx, callObj, "arguments", &val) &&
|
||||
val.isObject()) {
|
||||
uint32_t argCount;
|
||||
JSObject* argsObj = &val.toObject();
|
||||
if (JS_GetProperty(cx, argsObj, "length", &val) &&
|
||||
JS_ValueToECMAUint32(cx, val, &argCount) &&
|
||||
argCount > namedArgCount) {
|
||||
for (uint32_t k = namedArgCount; k < argCount; k++) {
|
||||
char number[8];
|
||||
JS_snprintf(number, 8, "%d", (int) k);
|
||||
|
||||
if (JS_GetProperty(cx, argsObj, number, &val)) {
|
||||
JSAutoByteString valueBytes;
|
||||
const char *value = JSVAL2String(cx, val, &isString, &valueBytes);
|
||||
buf = JS_sprintf_append(buf, "%s%s%s%s",
|
||||
k ? ", " : "",
|
||||
isString ? "\"" : "",
|
||||
value ? value : "?unknown?",
|
||||
isString ? "\"" : "");
|
||||
if (!buf) goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print filename and line number
|
||||
|
||||
buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n",
|
||||
fun ? ")" : "",
|
||||
filename ? filename : "<unknown>",
|
||||
lineno);
|
||||
if (!buf) goto out;
|
||||
|
||||
// print local variables
|
||||
|
||||
if (showLocals && callProps.array) {
|
||||
for (uint32_t i = 0; i < callProps.length; i++) {
|
||||
JSPropertyDesc* desc = &callProps.array[i];
|
||||
JSAutoByteString nameBytes;
|
||||
JSAutoByteString valueBytes;
|
||||
const char *name = JSVAL2String(cx, desc->id, nullptr, &nameBytes);
|
||||
const char *value = JSVAL2String(cx, desc->value, &isString, &valueBytes);
|
||||
|
||||
if (name && value) {
|
||||
buf = JS_sprintf_append(buf, TAB "%s = %s%s%s\n",
|
||||
name,
|
||||
isString ? "\"" : "",
|
||||
value,
|
||||
isString ? "\"" : "");
|
||||
if (!buf) goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print the value of 'this'
|
||||
|
||||
if (showLocals) {
|
||||
if (gotThisVal) {
|
||||
JSString* thisValStr;
|
||||
JSAutoByteString thisValBytes;
|
||||
|
||||
if (nullptr != (thisValStr = JS_ValueToString(cx, thisVal)) &&
|
||||
thisValBytes.encode(cx, thisValStr)) {
|
||||
buf = JS_sprintf_append(buf, TAB "this = %s\n", thisValBytes.ptr());
|
||||
if (!buf) goto out;
|
||||
}
|
||||
} else
|
||||
buf = JS_sprintf_append(buf, TAB "<failed to get 'this' value>\n");
|
||||
}
|
||||
|
||||
// print the properties of 'this', if it is an object
|
||||
|
||||
if (showThisProps && thisProps.array) {
|
||||
|
||||
for (uint32_t i = 0; i < thisProps.length; i++) {
|
||||
JSPropertyDesc* desc = &thisProps.array[i];
|
||||
if (desc->flags & JSPD_ENUMERATE) {
|
||||
JSAutoByteString nameBytes;
|
||||
JSAutoByteString valueBytes;
|
||||
const char *name = JSVAL2String(cx, desc->id, nullptr, &nameBytes);
|
||||
const char *value = JSVAL2String(cx, desc->value, &isString, &valueBytes);
|
||||
if (name && value) {
|
||||
buf = JS_sprintf_append(buf, TAB "this.%s = %s%s%s\n",
|
||||
name,
|
||||
isString ? "\"" : "",
|
||||
value,
|
||||
isString ? "\"" : "");
|
||||
if (!buf) goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (callProps.array)
|
||||
JS_PutPropertyDescArray(cx, &callProps);
|
||||
if (thisProps.array)
|
||||
JS_PutPropertyDescArray(cx, &thisProps);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char* FormatJSStackDump(JSContext* cx, char* buf,
|
||||
JSBool showArgs, JSBool showLocals,
|
||||
JSBool showThisProps)
|
||||
{
|
||||
JSStackFrame* fp;
|
||||
JSStackFrame* iter = nullptr;
|
||||
int num = 0;
|
||||
|
||||
while (nullptr != (fp = JS_FrameIterator(cx, &iter))) {
|
||||
buf = FormatJSFrame(cx, fp, buf, num, showArgs, showLocals, showThisProps);
|
||||
num++;
|
||||
}
|
||||
|
||||
if (!num)
|
||||
buf = JS_sprintf_append(buf, "JavaScript stack is empty\n");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
JSBool
|
||||
xpc_DumpJSStack(JSContext* cx, JSBool showArgs, JSBool showLocals, JSBool showThisProps)
|
||||
{
|
||||
|
@ -282,7 +51,7 @@ xpc_PrintJSStack(JSContext* cx, JSBool showArgs, JSBool showLocals,
|
|||
|
||||
JS_ClearPendingException(cx);
|
||||
|
||||
buf = FormatJSStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
|
||||
buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
|
||||
if (!buf)
|
||||
DebugDump("%s", "Failed to format JavaScript stack for dump\n");
|
||||
|
||||
|
@ -313,7 +82,7 @@ xpc_DumpEvalInJSStackFrame(JSContext* cx, uint32_t frameno, const char* text)
|
|||
|
||||
DebugDump("js[%d]> %s\n", frameno, text);
|
||||
|
||||
while (nullptr != (fp = JS_FrameIterator(cx, &iter))) {
|
||||
while (nullptr != (fp = JS_BrokenFrameIterator(cx, &iter))) {
|
||||
if (num == frameno)
|
||||
break;
|
||||
num++;
|
||||
|
|
|
@ -14,8 +14,7 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISTACKFRAME
|
||||
|
||||
static nsresult CreateStack(JSContext* cx, JSStackFrame* fp,
|
||||
XPCJSStackFrame** stack);
|
||||
static nsresult CreateStack(JSContext* cx, XPCJSStackFrame** stack);
|
||||
|
||||
static nsresult CreateStackFrameLocation(PRUint32 aLanguage,
|
||||
const char* aFilename,
|
||||
|
@ -49,10 +48,7 @@ XPCJSStack::CreateStack(JSContext* cx, nsIStackFrame** stack)
|
|||
if (!cx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
JSStackFrame *fp = NULL;
|
||||
if (!JS_FrameIterator(cx, &fp))
|
||||
return NS_ERROR_FAILURE;
|
||||
return XPCJSStackFrame::CreateStack(cx, fp, (XPCJSStackFrame**) stack);
|
||||
return XPCJSStackFrame::CreateStack(cx, (XPCJSStackFrame**) stack);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -94,62 +90,55 @@ XPCJSStackFrame::~XPCJSStackFrame()
|
|||
NS_IMPL_THREADSAFE_ISUPPORTS1(XPCJSStackFrame, nsIStackFrame)
|
||||
|
||||
nsresult
|
||||
XPCJSStackFrame::CreateStack(JSContext* cx, JSStackFrame* fp,
|
||||
XPCJSStackFrame** stack)
|
||||
XPCJSStackFrame::CreateStack(JSContext* cx, XPCJSStackFrame** stack)
|
||||
{
|
||||
static const unsigned MAX_FRAMES = 100;
|
||||
unsigned numFrames = 0;
|
||||
|
||||
nsRefPtr<XPCJSStackFrame> first = new XPCJSStackFrame();
|
||||
nsRefPtr<XPCJSStackFrame> self = first;
|
||||
while (fp && self) {
|
||||
if (!JS_IsScriptFrame(cx, fp)) {
|
||||
self->mLanguage = nsIProgrammingLanguage::CPLUSPLUS;
|
||||
} else {
|
||||
self->mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
|
||||
JSScript* script = JS_GetFrameScript(cx, fp);
|
||||
jsbytecode* pc = JS_GetFramePC(cx, fp);
|
||||
if (script && pc) {
|
||||
JS::AutoEnterFrameCompartment ac;
|
||||
if (ac.enter(cx, fp)) {
|
||||
const char* filename = JS_GetScriptFilename(cx, script);
|
||||
if (filename) {
|
||||
self->mFilename = (char*)
|
||||
nsMemory::Clone(filename,
|
||||
sizeof(char)*(strlen(filename)+1));
|
||||
}
|
||||
|
||||
self->mLineno = (PRInt32) JS_PCToLineNumber(cx, script, pc);
|
||||
JS::StackDescription* desc = JS::DescribeStack(cx, MAX_FRAMES);
|
||||
if (!desc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
JSFunction* fun = JS_GetFrameFunction(cx, fp);
|
||||
if (fun) {
|
||||
JSString *funid = JS_GetFunctionId(fun);
|
||||
if (funid) {
|
||||
size_t length = JS_GetStringEncodingLength(cx, funid);
|
||||
if (length != size_t(-1)) {
|
||||
self->mFunname = static_cast<char *>(nsMemory::Alloc(length + 1));
|
||||
if (self->mFunname) {
|
||||
JS_EncodeStringToBuffer(funid, self->mFunname, length);
|
||||
self->mFunname[length] = '\0';
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < desc->nframes && self; i++) {
|
||||
self->mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
|
||||
|
||||
JS::AutoEnterScriptCompartment ac;
|
||||
if (ac.enter(cx, desc->frames[i].script)) {
|
||||
const char* filename = JS_GetScriptFilename(cx, desc->frames[i].script);
|
||||
if (filename) {
|
||||
self->mFilename = (char*)
|
||||
nsMemory::Clone(filename,
|
||||
sizeof(char)*(strlen(filename)+1));
|
||||
}
|
||||
|
||||
self->mLineno = desc->frames[i].lineno;
|
||||
|
||||
JSFunction* fun = desc->frames[i].fun;
|
||||
if (fun) {
|
||||
JSString *funid = JS_GetFunctionId(fun);
|
||||
if (funid) {
|
||||
size_t length = JS_GetStringEncodingLength(cx, funid);
|
||||
if (length != size_t(-1)) {
|
||||
self->mFunname = static_cast<char *>(nsMemory::Alloc(length + 1));
|
||||
if (self->mFunname) {
|
||||
JS_EncodeStringToBuffer(funid, self->mFunname, length);
|
||||
self->mFunname[length] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self->mLanguage = nsIProgrammingLanguage::CPLUSPLUS;
|
||||
}
|
||||
}
|
||||
|
||||
if (++numFrames > MAX_FRAMES) {
|
||||
fp = NULL;
|
||||
} else if (JS_FrameIterator(cx, &fp)) {
|
||||
XPCJSStackFrame* frame = new XPCJSStackFrame();
|
||||
self->mCaller = frame;
|
||||
self = frame;
|
||||
}
|
||||
XPCJSStackFrame* frame = new XPCJSStackFrame();
|
||||
self->mCaller = frame;
|
||||
self = frame;
|
||||
}
|
||||
|
||||
JS::FreeStackDescription(cx, desc);
|
||||
|
||||
*stack = first.forget().get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче