Bug 1165486 - Debug function to dump static scope chain of scripts. (r=efaust)
☠☠ backed out by f1930da6025e ☠ ☠
authorShu-yu Guo <shu@rfrn.org>
Mon, 15 Jun 2015 21:32:30 -0700
changeset 279815 42fcb204b544f82f072c1da4a6da7db990b7c5cb
parent 279814 9ec0a501209a1f0d32b5ef61d1cf2d1f15f6b2e1
child 279816 c3a547a77df99aa253df5e8da15ec8e7cead65cf
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [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 */