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); showThisProps = ToBoolean(v);
} }
JS::UniqueChars buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps); JS::UniqueChars buf = JS::FormatStackDump(cx, showArgs, showLocals, showThisProps);
if (!buf) if (!buf)
return false; return false;

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

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

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

@ -301,8 +301,7 @@ namespace JS {
/** Exposed for DumpJSStack */ /** Exposed for DumpJSStack */
extern JS_FRIEND_API(JS::UniqueChars) extern JS_FRIEND_API(JS::UniqueChars)
FormatStackDump(JSContext* cx, JS::UniqueChars&& buf, bool showArgs, bool showLocals, FormatStackDump(JSContext* cx, bool showArgs, bool showLocals, bool showThisProps);
bool showThisProps);
/** /**
* Set all of the uninitialized lexicals on an object to undefined. Return * 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 showLocals = ToBoolean(args.get(1));
bool showThisProps = ToBoolean(args.get(2)); 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) { if (!buf) {
fputs("Failed to format JavaScript stack for dump\n", gOutFile->fp); fputs("Failed to format JavaScript stack for dump\n", gOutFile->fp);
JS_ClearPendingException(cx); JS_ClearPendingException(cx);

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

@ -53,7 +53,7 @@ xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
{ {
JS::AutoSaveExceptionState state(cx); 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) if (!buf)
DebugDump("%s", "Failed to format JavaScript stack for dump\n"); 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. // so nothing such should happen.
nsContentUtils::ExtractErrorValues(cx, value, details.mFilename, &details.mLine, &details.mColumn, details.mMessage); 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); CopyUTF8toUTF16(mozilla::MakeStringSpan(buf.get()), details.mStack);
mThrownError.emplace(std::move(details)); mThrownError.emplace(std::move(details));