Remove JS_FrameIterator (bug 732653, r=luke,mrbkap).

This commit is contained in:
David Anderson 2012-08-15 17:28:33 -07:00
Родитель 58e1815704
Коммит e83e82b9dd
7 изменённых файлов: 340 добавлений и 295 удалений

Просмотреть файл

@ -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;
}