Bug 847405: Ensure that evalInGlobal never creates frames with the 'FUNCTION' flag set. r=jorendorff
authorJim Blandy <jimb@mozilla.com>
Mon, 09 Sep 2013 10:08:16 -0700
changeset 159162 3ffdc887c562d791d1d509ca9aadbd0923cfdfa5
parent 159107 77841a0ee5309a54b64806fc5ed96bbada6dd66b
child 159163 1eaaa25929385ef20f03ffb145823c2ff91ebd25
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs847405
milestone26.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 847405: Ensure that evalInGlobal never creates frames with the 'FUNCTION' flag set. r=jorendorff
js/src/jit-test/tests/debug/Object-evalInGlobal-09.js
js/src/vm/Debugger.cpp
js/src/vm/Stack.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-evalInGlobal-09.js
@@ -0,0 +1,9 @@
+// The frame created for evalInGlobal is never marked as a 'FUNCTION' frame.
+
+(function () {
+  var g = newGlobal();
+  var dbg = new Debugger;
+  var gw = dbg.addDebuggee(g);
+  gw.evalInGlobalWithBindings("eval('Math')",{}).return
+})();
+
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4194,17 +4194,17 @@ js::EvaluateInEnv(JSContext *cx, Handle<
     RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), env, callerScript,
                                                     options, chars.get(), length,
                                                     /* source = */ NULL,
                                                     /* staticLevel = */ frame ? 1 : 0));
     if (!script)
         return false;
 
     script->isActiveEval = true;
-    ExecuteType type = !frame && env->is<GlobalObject>() ? EXECUTE_DEBUG_GLOBAL : EXECUTE_DEBUG;
+    ExecuteType type = !frame ? EXECUTE_DEBUG_GLOBAL : EXECUTE_DEBUG;
     return ExecuteKernel(cx, script, *env, thisv, type, frame, rval.address());
 }
 
 enum EvalBindings { EvalHasExtraBindings = true, EvalWithDefaultBindings = false };
 
 static bool
 DebuggerGenericEval(JSContext *cx, const char *fullMethodName, const Value &code,
                     EvalBindings evalWithBindings, HandleValue bindings, HandleValue options,
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -231,17 +231,32 @@ class StackFrame
   public:
     enum Flags {
         /* Primary frame type */
         GLOBAL             =        0x1,  /* frame pushed for a global script */
         FUNCTION           =        0x2,  /* frame pushed for a scripted call */
 
         /* Frame subtypes */
         EVAL               =        0x4,  /* frame pushed for eval() or debugger eval */
-        DEBUGGER           =        0x8,  /* frame pushed for debugger eval */
+
+
+        /*
+         * Frame pushed for debugger eval.
+         * - Don't bother to JIT it, because it's probably short-lived.
+         * - It is required to have a scope chain object outside the
+         *   js::ScopeObject hierarchy: either a global object, or a
+         *   DebugScopeObject (not a ScopeObject, despite the name)
+         * - If evalInFramePrev_ is set, then this frame was created for an
+         *   "eval in frame" call, which can push a successor to any live
+         *   frame; so its logical "prev" frame is not necessarily the
+         *   previous frame in memory. Iteration should treat
+         *   evalInFramePrev_ as this frame's previous frame.
+         */
+        DEBUGGER           =        0x8,
+
         GENERATOR          =       0x10,  /* frame is associated with a generator */
         CONSTRUCTING       =       0x20,  /* frame is for a constructor invocation */
 
         /*
          * Generator frame state
          *
          * YIELDING and SUSPENDED are similar, but there are differences. After
          * a generator yields, SendToGenerator immediately clears the YIELDING
@@ -297,17 +312,23 @@ class StackFrame
      * Previous frame and its pc and sp. Always NULL for InterpreterActivation's
      * entry frame, always non-NULL for inline frames.
      */
     StackFrame          *prev_;
     jsbytecode          *prevpc_;
     Value               *prevsp_;
 
     void                *hookData_;     /* if HAS_HOOK_DATA, closure returned by call hook */
-    AbstractFramePtr    evalInFramePrev_; /* for an eval/debugger frame, the prev frame */
+
+    /*
+     * For an eval-in-frame DEBUGGER frame, the frame in whose scope we're
+     * evaluating code. Iteration treats this as our previous frame.
+     */
+    AbstractFramePtr    evalInFramePrev_;
+
     Value               *argv_;         /* If hasArgs(), points to frame's arguments. */
     LifoAlloc::Mark     mark_;          /* Used to release memory for this frame. */
 
     static void staticAsserts() {
         JS_STATIC_ASSERT(offsetof(StackFrame, rval_) % sizeof(Value) == 0);
         JS_STATIC_ASSERT(sizeof(StackFrame) % sizeof(Value) == 0);
     }