diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index c7b2f84f912..d515aa0ce08 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4318,6 +4318,36 @@ ReflectTrackedOptimizations(JSContext* cx, unsigned argc, Value* vp) return true; } +#ifdef DEBUG +static bool +DumpStaticScopeChain(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + RootedObject callee(cx, &args.callee()); + + if (args.length() != 1) { + ReportUsageError(cx, callee, "Wrong number of arguments"); + return false; + } + + if (!args[0].isObject() || !args[0].toObject().is()) { + ReportUsageError(cx, callee, "Argument must be an interpreted function"); + return false; + } + + RootedFunction fun(cx, &args[0].toObject().as()); + if (!fun->isInterpreted()) { + ReportUsageError(cx, callee, "Argument must be an interpreted function"); + return false; + } + + js::DumpStaticScopeChain(fun->getOrCreateScript(cx)); + + args.rval().setUndefined(); + return true; +} +#endif + namespace js { namespace shell { @@ -4966,6 +4996,12 @@ static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = { " any. If |fun| is not a scripted function or has not been compiled by\n" " Ion, null is returned."), +#ifdef DEBUG + JS_FN_HELP("dumpStaticScopeChain", DumpStaticScopeChain, 1, 0, +"dumpStaticScopeChain(fun)", +" Prints the static scope chain of an interpreted function fun."), +#endif + JS_FS_HELP_END }; diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index d53880d27f4..53016b172be 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -2561,6 +2561,36 @@ js::HasNonSyntacticStaticScopeChain(JSObject* staticScope) #ifdef DEBUG +void +js::DumpStaticScopeChain(JSScript* script) +{ + JSObject* enclosingScope = script->enclosingStaticScope(); + for (StaticScopeIter ssi(enclosingScope); !ssi.done(); ssi++) { + switch (ssi.type()) { + case StaticScopeIter::Function: + fprintf(stdout, "function"); + break; + case StaticScopeIter::Block: + fprintf(stdout, "block"); + break; + case StaticScopeIter::With: + fprintf(stdout, "with"); + break; + case StaticScopeIter::NamedLambda: + fprintf(stdout, "named lambda"); + break; + case StaticScopeIter::Eval: + fprintf(stdout, "eval"); + break; + case StaticScopeIter::NonSyntactic: + fprintf(stdout, "non-syntactic"); + break; + } + fprintf(stdout, " -> "); + } + fprintf(stdout, "global\n"); +} + typedef HashSet PropertyNameSet; static bool diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 4a63056bad1..8ad24228193 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -1176,6 +1176,7 @@ CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain, bool HasNonSyntacticStaticScopeChain(JSObject* staticScope); #ifdef DEBUG +void DumpStaticScopeChain(JSScript* script); bool AnalyzeEntrainedVariables(JSContext* cx, HandleScript script); #endif