Bug 1614261 - Add -g option to JS shell dis() to dump GC things. r=jorendorff

Differential Revision: https://phabricator.services.mozilla.com/D62188

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Tooru Fujisawa 2020-02-19 15:49:01 +00:00
parent 3464fec8e5
commit 611da7b1e3
3 changed files with 219 additions and 5 deletions

View File

@ -3182,10 +3182,112 @@ static MOZ_MUST_USE bool ScopeNotes(JSContext* cx, HandleScript script,
return true;
}
static MOZ_MUST_USE bool GCThings(JSContext* cx, HandleScript script,
Sprinter* sp) {
if (!sp->put("\nGC things:\n index type value\n")) {
return false;
}
size_t i = 0;
for (JS::GCCellPtr gcThing : script->gcthings()) {
if (!sp->jsprintf("%8zu ", i)) {
return false;
}
if (gcThing.is<BigInt>()) {
if (!sp->put("BigInt ")) {
return false;
}
gcThing.as<BigInt>().dump(*sp);
if (!sp->put("\n")) {
return false;
}
} else if (gcThing.is<Scope>()) {
if (!sp->put("Scope ")) {
return false;
}
Rooted<Scope*> scope(cx, &gcThing.as<Scope>());
if (!Scope::dumpForDisassemble(cx, scope, *sp,
" ")) {
return false;
}
if (!sp->put("\n")) {
return false;
}
} else if (gcThing.is<JSObject>()) {
JSObject* obj = &gcThing.as<JSObject>();
if (obj->is<JSFunction>()) {
if (!sp->put("Function ")) {
return false;
}
RootedFunction fun(cx, &obj->as<JSFunction>());
if (fun->displayAtom()) {
Rooted<JSAtom*> name(cx, fun->displayAtom());
UniqueChars utf8chars = JS_EncodeStringToUTF8(cx, name);
if (!utf8chars) {
return false;
}
if (!sp->put(utf8chars.get())) {
return false;
}
} else {
if (!sp->put("(anonymous)")) {
return false;
}
}
if (fun->hasBaseScript()) {
BaseScript* script = fun->baseScript();
if (!sp->jsprintf(" @ %u:%u\n", script->lineno(), script->column())) {
return false;
}
} else {
if (!sp->put(" (no script)\n")) {
return false;
}
}
} else {
if (obj->is<RegExpObject>()) {
if (!sp->put("RegExp ")) {
return false;
}
} else {
if (!sp->put("Object ")) {
return false;
}
}
RootedValue objValue(cx, ObjectValue(*obj));
RootedString str(cx, ValueToSource(cx, objValue));
if (!str) {
return false;
}
UniqueChars utf8chars = JS_EncodeStringToUTF8(cx, str);
if (!utf8chars) {
return false;
}
if (!sp->put(utf8chars.get())) {
return false;
}
if (!sp->put("\n")) {
return false;
}
}
} else {
if (!sp->put("Unknown\n")) {
return false;
}
}
i++;
}
return true;
}
static MOZ_MUST_USE bool DisassembleScript(JSContext* cx, HandleScript script,
HandleFunction fun, bool lines,
bool recursive, bool sourceNotes,
Sprinter* sp) {
bool gcThings, Sprinter* sp) {
if (fun) {
if (!sp->put("flags:")) {
return false;
@ -3244,6 +3346,11 @@ static MOZ_MUST_USE bool DisassembleScript(JSContext* cx, HandleScript script,
if (!ScopeNotes(cx, script, sp)) {
return false;
}
if (gcThings) {
if (!GCThings(cx, script, sp)) {
return false;
}
}
if (recursive) {
for (JS::GCCellPtr gcThing : script->gcthings()) {
@ -3262,7 +3369,7 @@ static MOZ_MUST_USE bool DisassembleScript(JSContext* cx, HandleScript script,
RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
if (script) {
if (!DisassembleScript(cx, script, fun, lines, recursive,
sourceNotes, sp)) {
sourceNotes, gcThings, sp)) {
return false;
}
}
@ -3286,13 +3393,15 @@ struct DisassembleOptionParser {
bool lines;
bool recursive;
bool sourceNotes;
bool gcThings;
DisassembleOptionParser(unsigned argc, Value* argv)
: argc(argc),
argv(argv),
lines(false),
recursive(false),
sourceNotes(true) {}
sourceNotes(true),
gcThings(false) {}
bool parse(JSContext* cx) {
/* Read options off early arguments */
@ -3308,6 +3417,8 @@ struct DisassembleOptionParser {
recursive = true;
} else if (JS_LinearStringEqualsLiteral(linearStr, "-S")) {
sourceNotes = false;
} else if (JS_LinearStringEqualsLiteral(linearStr, "-g")) {
gcThings = true;
} else {
break;
}
@ -3345,6 +3456,11 @@ static bool DisassembleToSprinter(JSContext* cx, unsigned argc, Value* vp,
if (!ScopeNotes(cx, script, sprinter)) {
return false;
}
if (p.gcThings) {
if (!GCThings(cx, script, sprinter)) {
return false;
}
}
}
} else {
for (unsigned i = 0; i < p.argc; i++) {
@ -3360,7 +3476,7 @@ static bool DisassembleToSprinter(JSContext* cx, unsigned argc, Value* vp,
return false;
}
if (!DisassembleScript(cx, script, fun, p.lines, p.recursive,
p.sourceNotes, sprinter)) {
p.sourceNotes, p.gcThings, sprinter)) {
return false;
}
}
@ -3457,7 +3573,7 @@ static bool DisassFile(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
if (!DisassembleScript(cx, script, nullptr, p.lines, p.recursive,
p.sourceNotes, &sprinter)) {
p.sourceNotes, p.gcThings, &sprinter)) {
return false;
}

View File

@ -488,6 +488,99 @@ void Scope::dump() {
fprintf(stderr, "\n");
}
#if defined(DEBUG) || defined(JS_JITSPEW)
/* static */
bool Scope::dumpForDisassemble(JSContext* cx, JS::Handle<Scope*> scope,
GenericPrinter& out, const char* indent) {
if (!out.put(ScopeKindString(scope->kind()))) {
return false;
}
if (!out.put(" {")) {
return false;
}
size_t i = 0;
for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++, i++) {
if (i == 0) {
if (!out.put("\n")) {
return false;
}
}
UniqueChars bytes = AtomToPrintableString(cx, bi.name());
if (!bytes) {
return false;
}
if (!out.put(indent)) {
return false;
}
if (!out.printf(" %2zu: %s %s ", i, BindingKindString(bi.kind()),
bytes.get())) {
return false;
}
switch (bi.location().kind()) {
case BindingLocation::Kind::Global:
if (bi.isTopLevelFunction()) {
if (!out.put("(global function)\n")) {
return false;
}
} else {
if (!out.put("(global)\n")) {
return false;
}
}
break;
case BindingLocation::Kind::Argument:
if (!out.printf("(arg slot %u)\n", bi.location().argumentSlot())) {
return false;
}
break;
case BindingLocation::Kind::Frame:
if (!out.printf("(frame slot %u)\n", bi.location().slot())) {
return false;
}
break;
case BindingLocation::Kind::Environment:
if (!out.printf("(env slot %u)\n", bi.location().slot())) {
return false;
}
break;
case BindingLocation::Kind::NamedLambdaCallee:
if (!out.put("(named lambda callee)\n")) {
return false;
}
break;
case BindingLocation::Kind::Import:
if (!out.put("(import)\n")) {
return false;
}
break;
}
}
if (i > 0) {
if (!out.put(indent)) {
return false;
}
}
if (!out.put("}")) {
return false;
}
ScopeIter si(scope);
si++;
for (; si; si++) {
if (!out.put(" -> ")) {
return false;
}
if (!out.put(ScopeKindString(si.kind()))) {
return false;
}
}
return true;
}
#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
uint32_t LexicalScope::firstFrameSlot() const {
switch (kind()) {
case ScopeKind::Lexical:

View File

@ -20,6 +20,7 @@
#include "util/Poison.h"
#include "vm/BytecodeUtil.h"
#include "vm/JSObject.h"
#include "vm/Printer.h" // GenericPrinter
#include "vm/ScopeKind.h"
#include "vm/Xdr.h"
@ -357,6 +358,10 @@ class Scope : public js::gc::TenuredCell {
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
void dump();
#if defined(DEBUG) || defined(JS_JITSPEW)
static bool dumpForDisassemble(JSContext* cx, JS::Handle<Scope*> scope,
GenericPrinter& out, const char* indent);
#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
};
/** Empty base class for scope Data classes to inherit from. */