Bug 1165486 - Debug function to dump static scope chain of scripts. (r=efaust)
authorShu-yu Guo <shu@rfrn.org>
Sun, 21 Jun 2015 11:49:58 -0700
changeset 249947 43b82c9c8a9f746e088d13159fb7a97bb05d0766
parent 249946 63b4dd8b552eeb71b5111e646f750fe549455f17
child 249948 177cfe17e0d402f04d85d538bc8c464b76fba702
push id28940
push usercbook@mozilla.com
push dateMon, 22 Jun 2015 12:03:34 +0000
treeherdermozilla-central@be81b8d6fae9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1165486
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1165486 - Debug function to dump static scope chain of scripts. (r=efaust)
js/src/shell/js.cpp
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4313,16 +4313,46 @@ ReflectTrackedOptimizations(JSContext* c
     RootedValue jsonVal(cx);
     if (!JS_ParseJSON(cx, str, &jsonVal))
         return false;
 
     args.rval().set(jsonVal);
     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<JSFunction>()) {
+        ReportUsageError(cx, callee, "Argument must be an interpreted function");
+        return false;
+    }
+
+    RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
+    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 {
 
 class ShellAutoEntryMonitor : JS::dbg::AutoEntryMonitor {
     Vector<UniqueChars, 1, js::SystemAllocPolicy> log;
     bool oom;
     bool enteredWithoutExit;
 
@@ -4961,16 +4991,22 @@ static const JSFunctionSpecWithHelp fuzz
 "        deeply nested wrapper chains that cannot exist in the wild."),
 
     JS_FN_HELP("trackedOpts", ReflectTrackedOptimizations, 1, 0,
 "trackedOpts(fun)",
 "  Returns an object describing the tracked optimizations of |fun|, if\n"
 "  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
 };
 
 static const JSFunctionSpecWithHelp console_functions[] = {
     JS_FN_HELP("log", Print, 0, 0,
 "log([exp ...])",
 "  Evaluate and print expressions to stdout.\n"
 "  This function is an alias of the print() function."),
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -2556,16 +2556,46 @@ js::HasNonSyntacticStaticScopeChain(JSOb
         if (ssi.type() == StaticScopeIter<NoGC>::NonSyntactic)
             return true;
     }
     return false;
 }
 
 #ifdef DEBUG
 
+void
+js::DumpStaticScopeChain(JSScript* script)
+{
+    JSObject* enclosingScope = script->enclosingStaticScope();
+    for (StaticScopeIter<NoGC> ssi(enclosingScope); !ssi.done(); ssi++) {
+        switch (ssi.type()) {
+          case StaticScopeIter<NoGC>::Function:
+            fprintf(stdout, "function");
+            break;
+          case StaticScopeIter<NoGC>::Block:
+            fprintf(stdout, "block");
+            break;
+          case StaticScopeIter<NoGC>::With:
+            fprintf(stdout, "with");
+            break;
+          case StaticScopeIter<NoGC>::NamedLambda:
+            fprintf(stdout, "named lambda");
+            break;
+          case StaticScopeIter<NoGC>::Eval:
+            fprintf(stdout, "eval");
+            break;
+          case StaticScopeIter<NoGC>::NonSyntactic:
+            fprintf(stdout, "non-syntactic");
+            break;
+        }
+        fprintf(stdout, " -> ");
+    }
+    fprintf(stdout, "global\n");
+}
+
 typedef HashSet<PropertyName*> PropertyNameSet;
 
 static bool
 RemoveReferencedNames(JSContext* cx, HandleScript script, PropertyNameSet& remainingNames)
 {
     // Remove from remainingNames --- the closure variables in some outer
     // script --- any free variables in this script. This analysis isn't perfect:
     //
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -1171,15 +1171,16 @@ ScopeIter::enclosingScope() const
 extern bool
 CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
                                 HandleObject dynamicTerminatingScope,
                                 MutableHandleObject dynamicScopeObj);
 
 bool HasNonSyntacticStaticScopeChain(JSObject* staticScope);
 
 #ifdef DEBUG
+void DumpStaticScopeChain(JSScript* script);
 bool
 AnalyzeEntrainedVariables(JSContext* cx, HandleScript script);
 #endif
 
 } // namespace js
 
 #endif /* vm_ScopeObject_h */