Bug 1485066 - Part 11: Remove the unused |inBuf| argument from JS::FormatStackDump and change it to use Sprinter. r=Waldo

This commit is contained in:
André Bargull 2018-09-05 03:01:23 -07:00
Родитель 2f63260ab2
Коммит ceccb59fda
6 изменённых файлов: 102 добавлений и 133 удалений

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

@ -3305,7 +3305,7 @@ GetBacktrace(JSContext* cx, unsigned argc, Value* vp)
showThisProps = ToBoolean(v);
}
JS::UniqueChars buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
JS::UniqueChars buf = JS::FormatStackDump(cx, showArgs, showLocals, showThisProps);
if (!buf)
return false;

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

@ -7,6 +7,7 @@
#include "jsfriendapi.h"
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/TimeStamp.h"
@ -808,62 +809,34 @@ js::DumpScript(JSContext* cx, JSScript* scriptArg)
#endif
static const char*
FormatValue(JSContext* cx, const Value& vArg, UniqueChars& bytes)
FormatValue(JSContext* cx, HandleValue v, UniqueChars& bytes)
{
RootedValue v(cx, vArg);
if (v.isMagic(JS_OPTIMIZED_OUT))
return "[unavailable]";
/*
* We could use Maybe<AutoRealm> here, but G++ can't quite follow
* that, and warns about uninitialized members being used in the
* destructor.
*/
RootedString str(cx);
if (v.isObject()) {
if (IsCrossCompartmentWrapper(&v.toObject()))
return "[cross-compartment wrapper]";
AutoRealm ar(cx, &v.toObject());
str = ToString<CanGC>(cx, v);
} else {
str = ToString<CanGC>(cx, v);
}
if (!str)
return nullptr;
bytes = JS_EncodeStringToLatin1(cx, str);
if (!bytes)
return nullptr;
const char* buf = bytes.get();
const char* found = strstr(buf, "function ");
if (found && (found - buf <= 2))
if (IsCallable(v))
return "[function]";
return buf;
}
// Wrapper for JS_sprintf_append() that reports allocation failure to the
// context.
static JS::UniqueChars
MOZ_FORMAT_PRINTF(3, 4)
sprintf_append(JSContext* cx, JS::UniqueChars&& buf, const char* fmt, ...)
{
va_list ap;
if (v.isObject() && IsCrossCompartmentWrapper(&v.toObject()))
return "[cross-compartment wrapper]";
va_start(ap, fmt);
JS::UniqueChars result = JS_vsprintf_append(std::move(buf), fmt, ap);
va_end(ap);
JSString* str;
{
mozilla::Maybe<AutoRealm> ar;
if (v.isObject())
ar.emplace(cx, &v.toObject());
if (!result) {
ReportOutOfMemory(cx);
return nullptr;
str = ToString<CanGC>(cx, v);
if (!str)
return nullptr;
}
return result;
bytes = JS_EncodeStringToLatin1(cx, str);
return bytes.get();
}
static JS::UniqueChars
FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int num,
static bool
FormatFrame(JSContext* cx, const FrameIter& iter, Sprinter& sp, int num,
bool showArgs, bool showLocals, bool showThisProps)
{
MOZ_ASSERT(!cx->isExceptionPending());
@ -887,23 +860,23 @@ FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int n
!(fun->isBoundFunction() && iter.isConstructing()))
{
if (!GetFunctionThis(cx, iter.abstractFramePtr(), &thisVal))
return nullptr;
return false;
}
// print the frame number and function name
JS::UniqueChars buf(std::move(inBuf));
if (funname) {
UniqueChars funbytes = JS_EncodeStringToLatin1(cx, funname);
if (!funbytes)
return nullptr;
buf = sprintf_append(cx, std::move(buf), "%d %s(", num, funbytes.get());
return false;
if (!sp.printf("%d %s(", num, funbytes.get()))
return false;
} else if (fun) {
buf = sprintf_append(cx, std::move(buf), "%d anonymous(", num);
if (!sp.printf("%d anonymous(", num))
return false;
} else {
buf = sprintf_append(cx, std::move(buf), "%d <TOP LEVEL>", num);
if (!sp.printf("%d <TOP LEVEL>", num))
return false;
}
if (!buf)
return nullptr;
if (showArgs && iter.hasArgs()) {
PositionalFormalParameterIter fi(script);
@ -929,7 +902,7 @@ FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int n
const char* value = FormatValue(cx, arg, valueBytes);
if (!value) {
if (cx->isThrowingOutOfMemory())
return nullptr;
return false;
cx->clearPendingException();
}
@ -942,7 +915,7 @@ FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int n
nameBytes = JS_EncodeStringToLatin1(cx, fi.name());
name = nameBytes.get();
if (!name)
return nullptr;
return false;
} else {
name = "(destructured parameter)";
}
@ -950,35 +923,34 @@ FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int n
}
if (value) {
buf = sprintf_append(cx, std::move(buf), "%s%s%s%s%s%s",
!first ? ", " : "",
name ? name :"",
name ? " = " : "",
arg.isString() ? "\"" : "",
value,
arg.isString() ? "\"" : "");
if (!buf)
return nullptr;
if (!sp.printf("%s%s%s%s%s%s",
!first ? ", " : "",
name ? name :"",
name ? " = " : "",
arg.isString() ? "\"" : "",
value,
arg.isString() ? "\"" : ""))
{
return false;
}
first = false;
} else {
buf = sprintf_append(cx, std::move(buf),
" <Failed to get argument while inspecting stack frame>\n");
if (!buf)
return nullptr;
if (!sp.put(" <Failed to get argument while inspecting stack frame>\n"))
return false;
}
}
}
// print filename and line number
buf = sprintf_append(cx, std::move(buf), "%s [\"%s\":%d]\n",
fun ? ")" : "",
filename ? filename : "<unknown>",
lineno);
if (!buf)
return nullptr;
if (!sp.printf("%s [\"%s\":%d]\n",
fun ? ")" : "",
filename ? filename : "<unknown>",
lineno))
{
return false;
}
// Note: Right now we don't dump the local variables anymore, because
// that is hard to support across all the JITs etc.
@ -986,23 +958,22 @@ FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int n
// print the value of 'this'
if (showLocals) {
if (!thisVal.isUndefined()) {
UniqueChars thisValBytes;
RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal));
if (!thisValStr) {
if (cx->isThrowingOutOfMemory())
return nullptr;
return false;
cx->clearPendingException();
}
if (thisValStr) {
thisValBytes = JS_EncodeStringToLatin1(cx, thisValStr);
UniqueChars thisValBytes = JS_EncodeStringToLatin1(cx, thisValStr);
if (!thisValBytes)
return nullptr;
buf = sprintf_append(cx, std::move(buf), " this = %s\n", thisValBytes.get());
return false;
if (!sp.printf(" this = %s\n", thisValBytes.get()))
return false;
} else {
buf = sprintf_append(cx, std::move(buf), " <failed to get 'this' value>\n");
if (!sp.put(" <failed to get 'this' value>\n"))
return false;
}
if (!buf)
return nullptr;
}
}
@ -1012,11 +983,10 @@ FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int n
AutoIdVector keys(cx);
if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &keys)) {
if (cx->isThrowingOutOfMemory())
return nullptr;
return false;
cx->clearPendingException();
}
RootedId id(cx);
for (size_t i = 0; i < keys.length(); i++) {
RootedId id(cx, keys[i]);
RootedValue key(cx, IdToValue(id));
@ -1024,12 +994,10 @@ FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int n
if (!GetProperty(cx, obj, obj, id, &v)) {
if (cx->isThrowingOutOfMemory())
return nullptr;
return false;
cx->clearPendingException();
buf = sprintf_append(cx, std::move(buf),
" <Failed to fetch property while inspecting stack frame>\n");
if (!buf)
return nullptr;
if (!sp.put(" <Failed to fetch property while inspecting stack frame>\n"))
return false;
continue;
}
@ -1037,7 +1005,7 @@ FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int n
const char* name = FormatValue(cx, key, nameBytes);
if (!name) {
if (cx->isThrowingOutOfMemory())
return nullptr;
return false;
cx->clearPendingException();
}
@ -1045,77 +1013,79 @@ FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int n
const char* value = FormatValue(cx, v, valueBytes);
if (!value) {
if (cx->isThrowingOutOfMemory())
return nullptr;
return false;
cx->clearPendingException();
}
if (name && value) {
buf = sprintf_append(cx, std::move(buf), " this.%s = %s%s%s\n",
name,
v.isString() ? "\"" : "",
value,
v.isString() ? "\"" : "");
if (!sp.printf(" this.%s = %s%s%s\n",
name,
v.isString() ? "\"" : "",
value,
v.isString() ? "\"" : ""))
{
return false;
}
} else {
buf = sprintf_append(cx, std::move(buf),
" <Failed to format values while inspecting stack frame>\n");
if (!sp.put(" <Failed to format values while inspecting stack frame>\n"))
return false;
}
if (!buf)
return nullptr;
}
}
MOZ_ASSERT(!cx->isExceptionPending());
return buf;
return true;
}
static JS::UniqueChars
FormatWasmFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int num)
static bool
FormatWasmFrame(JSContext* cx, const FrameIter& iter, Sprinter& sp, int num)
{
UniqueChars nameStr;
if (JSAtom* functionDisplayAtom = iter.maybeFunctionDisplayAtom()) {
nameStr = StringToNewUTF8CharsZ(cx, *functionDisplayAtom);
if (!nameStr)
return nullptr;
return false;
}
JS::UniqueChars buf = sprintf_append(cx, std::move(inBuf), "%d %s()",
num,
nameStr ? nameStr.get() : "<wasm-function>");
if (!buf)
return nullptr;
if (!sp.printf("%d %s()", num, nameStr ? nameStr.get() : "<wasm-function>"))
return false;
buf = sprintf_append(cx, std::move(buf), " [\"%s\":wasm-function[%d]:0x%x]\n",
iter.filename() ? iter.filename() : "<unknown>",
iter.wasmFuncIndex(),
iter.wasmBytecodeOffset());
if (!buf)
return nullptr;
if (!sp.printf(" [\"%s\":wasm-function[%d]:0x%x]\n",
iter.filename() ? iter.filename() : "<unknown>",
iter.wasmFuncIndex(),
iter.wasmBytecodeOffset()))
{
return false;
}
MOZ_ASSERT(!cx->isExceptionPending());
return buf;
return true;
}
JS_FRIEND_API(JS::UniqueChars)
JS::FormatStackDump(JSContext* cx, JS::UniqueChars&& inBuf, bool showArgs, bool showLocals,
bool showThisProps)
JS::FormatStackDump(JSContext* cx, bool showArgs, bool showLocals, bool showThisProps)
{
int num = 0;
JS::UniqueChars buf(std::move(inBuf));
Sprinter sp(cx);
if (!sp.init())
return nullptr;
for (AllFramesIter i(cx); !i.done(); ++i) {
if (i.hasScript())
buf = FormatFrame(cx, i, std::move(buf), num, showArgs, showLocals, showThisProps);
else
buf = FormatWasmFrame(cx, i, std::move(buf), num);
if (!buf)
bool ok = i.hasScript()
? FormatFrame(cx, i, sp, num, showArgs, showLocals, showThisProps)
: FormatWasmFrame(cx, i, sp, num);
if (!ok)
return nullptr;
num++;
}
if (!num)
buf = JS_sprintf_append(std::move(buf), "JavaScript stack is empty\n");
if (num == 0) {
if (!sp.put("JavaScript stack is empty\n"))
return nullptr;
}
return buf;
return sp.release();
}
extern JS_FRIEND_API(bool)

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

@ -301,8 +301,7 @@ namespace JS {
/** Exposed for DumpJSStack */
extern JS_FRIEND_API(JS::UniqueChars)
FormatStackDump(JSContext* cx, JS::UniqueChars&& buf, bool showArgs, bool showLocals,
bool showThisProps);
FormatStackDump(JSContext* cx, bool showArgs, bool showLocals, bool showThisProps);
/**
* Set all of the uninitialized lexicals on an object to undefined. Return

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

@ -4187,7 +4187,7 @@ StackDump(JSContext* cx, unsigned argc, Value* vp)
bool showLocals = ToBoolean(args.get(1));
bool showThisProps = ToBoolean(args.get(2));
JS::UniqueChars buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
JS::UniqueChars buf = JS::FormatStackDump(cx, showArgs, showLocals, showThisProps);
if (!buf) {
fputs("Failed to format JavaScript stack for dump\n", gOutFile->fp);
JS_ClearPendingException(cx);

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

@ -53,7 +53,7 @@ xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
{
JS::AutoSaveExceptionState state(cx);
JS::UniqueChars buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
JS::UniqueChars buf = JS::FormatStackDump(cx, showArgs, showLocals, showThisProps);
if (!buf)
DebugDump("%s", "Failed to format JavaScript stack for dump\n");

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

@ -1642,7 +1642,7 @@ CycleCollectedJSRuntime::ErrorInterceptor::interceptError(JSContext* cx, const J
// so nothing such should happen.
nsContentUtils::ExtractErrorValues(cx, value, details.mFilename, &details.mLine, &details.mColumn, details.mMessage);
JS::UniqueChars buf = JS::FormatStackDump(cx, nullptr, /* showArgs = */ false, /* showLocals = */ false, /* showThisProps = */ false);
JS::UniqueChars buf = JS::FormatStackDump(cx, /* showArgs = */ false, /* showLocals = */ false, /* showThisProps = */ false);
CopyUTF8toUTF16(mozilla::MakeStringSpan(buf.get()), details.mStack);
mThrownError.emplace(std::move(details));