mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 05:15:45 +00:00
Bug 1191758 - Rework JS::FormatStackDump() to fix OOM handling r=terrence
This commit is contained in:
parent
4444ba08a7
commit
94ee08d336
@ -483,31 +483,26 @@ SIMDObject::initClass(JSContext* cx, Handle<GlobalObject*> global)
|
||||
i8x16 = CreateAndBindSimdClass<Int8x16Defn>(cx, global, SIMD, cx->names().int8x16);
|
||||
if (!i8x16)
|
||||
return nullptr;
|
||||
global->setInt8x16TypeDescr(*i8x16);
|
||||
|
||||
RootedObject i16x8(cx);
|
||||
i16x8 = CreateAndBindSimdClass<Int16x8Defn>(cx, global, SIMD, cx->names().int16x8);
|
||||
if (!i16x8)
|
||||
return nullptr;
|
||||
global->setInt16x8TypeDescr(*i16x8);
|
||||
|
||||
RootedObject f32x4(cx);
|
||||
f32x4 = CreateAndBindSimdClass<Float32x4Defn>(cx, global, SIMD, cx->names().float32x4);
|
||||
if (!f32x4)
|
||||
return nullptr;
|
||||
global->setFloat32x4TypeDescr(*f32x4);
|
||||
|
||||
RootedObject i32x4(cx);
|
||||
i32x4 = CreateAndBindSimdClass<Int32x4Defn>(cx, global, SIMD, cx->names().int32x4);
|
||||
if (!i32x4)
|
||||
return nullptr;
|
||||
global->setInt32x4TypeDescr(*i32x4);
|
||||
|
||||
RootedObject f64x2(cx);
|
||||
f64x2 = CreateAndBindSimdClass<Float64x2Defn>(cx, global, SIMD, cx->names().float64x2);
|
||||
if (!f64x2)
|
||||
return nullptr;
|
||||
global->setFloat64x2TypeDescr(*f64x2);
|
||||
|
||||
// Everything is set up, install SIMD on the global object.
|
||||
RootedValue SIMDValue(cx, ObjectValue(*SIMD));
|
||||
@ -517,6 +512,11 @@ SIMDObject::initClass(JSContext* cx, Handle<GlobalObject*> global)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
global->setInt8x16TypeDescr(*i8x16);
|
||||
global->setInt16x8TypeDescr(*i16x8);
|
||||
global->setFloat32x4TypeDescr(*f32x4);
|
||||
global->setInt32x4TypeDescr(*i32x4);
|
||||
global->setFloat64x2TypeDescr(*f64x2);
|
||||
global->setConstructor(JSProto_SIMD, SIMDValue);
|
||||
return SIMD;
|
||||
}
|
||||
|
@ -2005,6 +2005,9 @@ GetBacktrace(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
char* buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
|
||||
if (!buf)
|
||||
return false;
|
||||
|
||||
RootedString str(cx);
|
||||
if (!(str = JS_NewStringCopyZ(cx, buf)))
|
||||
return false;
|
||||
|
4
js/src/jit-test/tests/gc/oomInFormatStackDump.js
Normal file
4
js/src/jit-test/tests/gc/oomInFormatStackDump.js
Normal file
@ -0,0 +1,4 @@
|
||||
// |jit-test| --no-ggc; allow-unhandlable-oom; --no-threads
|
||||
|
||||
load(libdir + 'oomTest.js');
|
||||
oomTest(() => getBacktrace({args: true, locals: true, thisprops: true}));
|
@ -800,8 +800,10 @@ InvalidateScriptsInZone(JSContext* cx, Zone* zone, const Vector<DebugModeOSREntr
|
||||
continue;
|
||||
|
||||
if (script->hasIonScript()) {
|
||||
if (!invalid.append(script->ionScript()->recompileInfo()))
|
||||
if (!invalid.append(script->ionScript()->recompileInfo())) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel off-thread Ion compile for anything that has a
|
||||
|
@ -2906,8 +2906,10 @@ jit::IonScript::invalidate(JSContext* cx, bool resetUses, const char* reason)
|
||||
{
|
||||
JitSpew(JitSpew_IonInvalidate, " Invalidate IonScript %p: %s", this, reason);
|
||||
RecompileInfoVector list;
|
||||
if (!list.append(recompileInfo()))
|
||||
if (!list.append(recompileInfo())) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
Invalidate(cx, list, resetUses, true);
|
||||
return true;
|
||||
}
|
||||
@ -2940,8 +2942,10 @@ jit::Invalidate(JSContext* cx, JSScript* script, bool resetUses, bool cancelOffT
|
||||
|
||||
RecompileInfoVector scripts;
|
||||
MOZ_ASSERT(script->hasIonScript());
|
||||
if (!scripts.append(script->ionScript()->recompileInfo()))
|
||||
if (!scripts.append(script->ionScript()->recompileInfo())) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
Invalidate(cx, scripts, resetUses, cancelOffThread);
|
||||
return true;
|
||||
|
@ -656,6 +656,21 @@ FormatValue(JSContext* cx, const Value& vArg, JSAutoByteString& bytes)
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Wrapper for JS_sprintf_append() that reports allocation failure to the
|
||||
// context.
|
||||
template <typename... Args>
|
||||
static char*
|
||||
sprintf_append(JSContext* cx, char* buf, Args&&... args)
|
||||
{
|
||||
char* result = JS_sprintf_append(buf, mozilla::Forward<Args>(args)...);
|
||||
if (!result) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char*
|
||||
FormatFrame(JSContext* cx, const ScriptFrameIter& iter, char* buf, int num,
|
||||
bool showArgs, bool showLocals, bool showThisProps)
|
||||
@ -682,14 +697,17 @@ FormatFrame(JSContext* cx, const ScriptFrameIter& iter, char* buf, int num,
|
||||
// print the frame number and function name
|
||||
if (funname) {
|
||||
JSAutoByteString funbytes;
|
||||
buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encodeLatin1(cx, funname));
|
||||
char* str = funbytes.encodeLatin1(cx, funname);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
buf = sprintf_append(cx, buf, "%d %s(", num, str);
|
||||
} else if (fun) {
|
||||
buf = JS_sprintf_append(buf, "%d anonymous(", num);
|
||||
buf = sprintf_append(cx, buf, "%d anonymous(", num);
|
||||
} else {
|
||||
buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num);
|
||||
buf = sprintf_append(cx, buf, "%d <TOP LEVEL>", num);
|
||||
}
|
||||
if (!buf)
|
||||
return buf;
|
||||
return nullptr;
|
||||
|
||||
if (showArgs && iter.hasArgs()) {
|
||||
BindingIter bi(script);
|
||||
@ -714,6 +732,11 @@ FormatFrame(JSContext* cx, const ScriptFrameIter& iter, char* buf, int num,
|
||||
|
||||
JSAutoByteString valueBytes;
|
||||
const char* value = FormatValue(cx, arg, valueBytes);
|
||||
if (!value) {
|
||||
if (cx->isThrowingOutOfMemory())
|
||||
return nullptr;
|
||||
cx->clearPendingException();
|
||||
}
|
||||
|
||||
JSAutoByteString nameBytes;
|
||||
const char* name = nullptr;
|
||||
@ -721,40 +744,40 @@ FormatFrame(JSContext* cx, const ScriptFrameIter& iter, char* buf, int num,
|
||||
if (i < iter.numFormalArgs()) {
|
||||
MOZ_ASSERT(i == bi.argIndex());
|
||||
name = nameBytes.encodeLatin1(cx, bi->name());
|
||||
if (!buf)
|
||||
if (!name)
|
||||
return nullptr;
|
||||
bi++;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
buf = JS_sprintf_append(buf, "%s%s%s%s%s%s",
|
||||
!first ? ", " : "",
|
||||
name ? name :"",
|
||||
name ? " = " : "",
|
||||
arg.isString() ? "\"" : "",
|
||||
value,
|
||||
arg.isString() ? "\"" : "");
|
||||
buf = sprintf_append(cx, buf, "%s%s%s%s%s%s",
|
||||
!first ? ", " : "",
|
||||
name ? name :"",
|
||||
name ? " = " : "",
|
||||
arg.isString() ? "\"" : "",
|
||||
value,
|
||||
arg.isString() ? "\"" : "");
|
||||
if (!buf)
|
||||
return buf;
|
||||
return nullptr;
|
||||
|
||||
first = false;
|
||||
} else {
|
||||
buf = JS_sprintf_append(buf, " <Failed to get argument while inspecting stack frame>\n");
|
||||
buf = sprintf_append(cx, buf,
|
||||
" <Failed to get argument while inspecting stack frame>\n");
|
||||
if (!buf)
|
||||
return buf;
|
||||
cx->clearPendingException();
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print filename and line number
|
||||
buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n",
|
||||
fun ? ")" : "",
|
||||
filename ? filename : "<unknown>",
|
||||
lineno);
|
||||
buf = sprintf_append(cx, buf, "%s [\"%s\":%d]\n",
|
||||
fun ? ")" : "",
|
||||
filename ? filename : "<unknown>",
|
||||
lineno);
|
||||
if (!buf)
|
||||
return buf;
|
||||
return nullptr;
|
||||
|
||||
|
||||
// Note: Right now we don't dump the local variables anymore, because
|
||||
@ -765,17 +788,21 @@ FormatFrame(JSContext* cx, const ScriptFrameIter& iter, char* buf, int num,
|
||||
if (!thisVal.isUndefined()) {
|
||||
JSAutoByteString thisValBytes;
|
||||
RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal));
|
||||
const char* str = nullptr;
|
||||
if (thisValStr &&
|
||||
(str = thisValBytes.encodeLatin1(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");
|
||||
if (!thisValStr) {
|
||||
if (cx->isThrowingOutOfMemory())
|
||||
return nullptr;
|
||||
cx->clearPendingException();
|
||||
}
|
||||
if (thisValStr) {
|
||||
const char* str = thisValBytes.encodeLatin1(cx, thisValStr);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
buf = sprintf_append(cx, buf, " this = %s\n", str);
|
||||
} else {
|
||||
buf = sprintf_append(cx, buf, " <failed to get 'this' value>\n");
|
||||
}
|
||||
if (!buf)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -784,8 +811,9 @@ FormatFrame(JSContext* cx, const ScriptFrameIter& iter, char* buf, int num,
|
||||
|
||||
AutoIdVector keys(cx);
|
||||
if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &keys)) {
|
||||
if (cx->isThrowingOutOfMemory())
|
||||
return nullptr;
|
||||
cx->clearPendingException();
|
||||
return buf;
|
||||
}
|
||||
|
||||
RootedId id(cx);
|
||||
@ -795,27 +823,44 @@ FormatFrame(JSContext* cx, const ScriptFrameIter& iter, char* buf, int num,
|
||||
RootedValue v(cx);
|
||||
|
||||
if (!GetProperty(cx, obj, obj, id, &v)) {
|
||||
buf = JS_sprintf_append(buf, " <Failed to fetch property while inspecting stack frame>\n");
|
||||
if (cx->isThrowingOutOfMemory())
|
||||
return nullptr;
|
||||
cx->clearPendingException();
|
||||
buf = sprintf_append(cx, buf,
|
||||
" <Failed to fetch property while inspecting stack frame>\n");
|
||||
if (!buf)
|
||||
return nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
JSAutoByteString nameBytes;
|
||||
JSAutoByteString valueBytes;
|
||||
const char* name = FormatValue(cx, key, nameBytes);
|
||||
const char* value = FormatValue(cx, v, valueBytes);
|
||||
if (name && value) {
|
||||
buf = JS_sprintf_append(buf, " this.%s = %s%s%s\n",
|
||||
name,
|
||||
v.isString() ? "\"" : "",
|
||||
value,
|
||||
v.isString() ? "\"" : "");
|
||||
if (!buf)
|
||||
return buf;
|
||||
} else {
|
||||
buf = JS_sprintf_append(buf, " <Failed to format values while inspecting stack frame>\n");
|
||||
if (!name) {
|
||||
if (cx->isThrowingOutOfMemory())
|
||||
return nullptr;
|
||||
cx->clearPendingException();
|
||||
}
|
||||
|
||||
JSAutoByteString valueBytes;
|
||||
const char* value = FormatValue(cx, v, valueBytes);
|
||||
if (!value) {
|
||||
if (cx->isThrowingOutOfMemory())
|
||||
return nullptr;
|
||||
cx->clearPendingException();
|
||||
}
|
||||
|
||||
if (name && value) {
|
||||
buf = sprintf_append(cx, buf, " this.%s = %s%s%s\n",
|
||||
name,
|
||||
v.isString() ? "\"" : "",
|
||||
value,
|
||||
v.isString() ? "\"" : "");
|
||||
} else {
|
||||
buf = sprintf_append(cx, buf,
|
||||
" <Failed to format values while inspecting stack frame>\n");
|
||||
}
|
||||
if (!buf)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -830,6 +875,8 @@ JS::FormatStackDump(JSContext* cx, char* buf, bool showArgs, bool showLocals, bo
|
||||
|
||||
for (AllFramesIter i(cx); !i.done(); ++i) {
|
||||
buf = FormatFrame(cx, i, buf, num, showArgs, showLocals, showThisProps);
|
||||
if (!buf)
|
||||
return nullptr;
|
||||
num++;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ ExtractWellSized(ExclusiveContext* cx, Buffer& cb)
|
||||
CharT* tmp = cx->zone()->pod_realloc<CharT>(buf, capacity, length + 1);
|
||||
if (!tmp) {
|
||||
js_free(buf);
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
buf = tmp;
|
||||
|
Loading…
Reference in New Issue
Block a user