Bug 1498980 - Remove module environment from live debugger envionments after execution r=jorendorff
authorJon Coppeard <jcoppeard@mozilla.com>
Thu, 18 Oct 2018 10:33:33 +0100
changeset 490141 6b952be63f69e244ab688cdb7a84d121b009a162
parent 490140 8f74f5dbf5c0d12bebf84841b8553b179b7d04a0
child 490221 9e81f9458926dbb1796ac5c3c0b06fa1ee1d10e9
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjorendorff
bugs1498980
milestone64.0a1
Bug 1498980 - Remove module environment from live debugger envionments after execution r=jorendorff
js/src/jit-test/tests/modules/bug-1498980.js
js/src/vm/EnvironmentObject.cpp
js/src/vm/EnvironmentObject.h
js/src/vm/Interpreter.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug-1498980.js
@@ -0,0 +1,24 @@
+dbgGlobal = newGlobal();
+dbg = new dbgGlobal.Debugger;
+dbg.addDebuggee(this);
+
+function f() {
+    dbg.getNewestFrame().older.eval("");
+}
+
+function execModule(source) {
+    m = parseModule(source);
+    m.declarationInstantiation();
+    m.evaluation();
+}
+
+execModule("f();");
+gc();
+
+let caught;
+try {
+    execModule("throw 'foo'");
+} catch (e) {
+    caught = e;
+}
+assertEq(caught, 'foo');
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -2802,20 +2802,21 @@ DebugEnvironments::takeFrameSnapshot(JSC
      * copy of the unaliased variables' values in an array for later debugger
      * access via DebugEnvironmentProxy::handleUnaliasedAccess.
      *
      * Note: since it is simplest for this function to be infallible, failure
      * in this code will be silently ignored. This does not break any
      * invariants since DebugEnvironmentProxy::maybeSnapshot can already be nullptr.
      */
 
+    JSScript* script = frame.script();
+
     // Act like no snapshot was taken if we run OOM while taking the snapshot.
     Rooted<GCVector<Value>> vec(cx, GCVector<Value>(cx));
     if (debugEnv->environment().is<CallObject>()) {
-        JSScript* script = frame.script();
 
         FunctionScope* scope = &script->bodyScope()->as<FunctionScope>();
         uint32_t frameSlotCount = scope->nextFrameSlot();
         MOZ_ASSERT(frameSlotCount <= script->nfixed());
 
         // For simplicity, copy all frame slots from 0 to the frameSlotCount,
         // even if we don't need all of them (like in the case of a defaults
         // parameter scope having frame slots).
@@ -2843,32 +2844,38 @@ DebugEnvironments::takeFrameSnapshot(JSC
     } else {
         uint32_t frameSlotStart;
         uint32_t frameSlotEnd;
 
         if (debugEnv->environment().is<LexicalEnvironmentObject>()) {
             LexicalScope* scope = &debugEnv->environment().as<LexicalEnvironmentObject>().scope();
             frameSlotStart = scope->firstFrameSlot();
             frameSlotEnd = scope->nextFrameSlot();
-        } else {
+        } else if (debugEnv->environment().is<VarEnvironmentObject>()) {
             VarEnvironmentObject* env = &debugEnv->environment().as<VarEnvironmentObject>();
             if (frame.isFunctionFrame()) {
                 VarScope* scope = &env->scope().as<VarScope>();
                 frameSlotStart = scope->firstFrameSlot();
                 frameSlotEnd = scope->nextFrameSlot();
             } else {
                 EvalScope* scope = &env->scope().as<EvalScope>();
-                MOZ_ASSERT(scope == frame.script()->bodyScope());
+                MOZ_ASSERT(scope == script->bodyScope());
                 frameSlotStart = 0;
                 frameSlotEnd = scope->nextFrameSlot();
             }
+        } else {
+            MOZ_ASSERT(&debugEnv->environment().as<ModuleEnvironmentObject>() ==
+                       script->module()->environment());
+            ModuleScope* scope = &script->bodyScope()->as<ModuleScope>();
+            frameSlotStart = 0;
+            frameSlotEnd = scope->nextFrameSlot();
         }
 
         uint32_t frameSlotCount = frameSlotEnd - frameSlotStart;
-        MOZ_ASSERT(frameSlotCount <= frame.script()->nfixed());
+        MOZ_ASSERT(frameSlotCount <= script->nfixed());
 
         if (!vec.resize(frameSlotCount)) {
             cx->recoverFromOutOfMemory();
             return;
         }
         for (uint32_t slot = frameSlotStart; slot < frameSlotCount; slot++) {
             vec[slot - frameSlotStart].set(frame.unaliasedLocal(slot));
         }
@@ -3018,16 +3025,22 @@ DebugEnvironments::onPopWith(AbstractFra
 {
     Realm* realm = frame.realm();
     if (DebugEnvironments* envs = realm->debugEnvs()) {
         envs->liveEnvs.remove(&frame.environmentChain()->as<WithEnvironmentObject>());
     }
 }
 
 void
+DebugEnvironments::onPopModule(JSContext* cx, const EnvironmentIter& ei)
+{
+    onPopGeneric<ModuleEnvironmentObject, ModuleScope>(cx, ei);
+}
+
+void
 DebugEnvironments::onRealmUnsetIsDebuggee(Realm* realm)
 {
     if (DebugEnvironments* envs = realm->debugEnvs()) {
         envs->proxiedEnvs.clear();
         envs->missingEnvs.clear();
         envs->liveEnvs.clear();
     }
 }
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -1049,16 +1049,17 @@ class DebugEnvironments
     // In debug-mode, these must be called whenever exiting a scope that might
     // have stack-allocated locals.
     static void onPopCall(JSContext* cx, AbstractFramePtr frame);
     static void onPopVar(JSContext* cx, const EnvironmentIter& ei);
     static void onPopVar(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
     static void onPopLexical(JSContext* cx, const EnvironmentIter& ei);
     static void onPopLexical(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
     static void onPopWith(AbstractFramePtr frame);
+    static void onPopModule(JSContext* cx, const EnvironmentIter& ei);
     static void onRealmUnsetIsDebuggee(Realm* realm);
 };
 
 }  /* namespace js */
 
 template <>
 inline bool
 JSObject::is<js::EnvironmentObject>() const
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1238,20 +1238,24 @@ PopEnvironment(JSContext* cx, Environmen
       case ScopeKind::StrictEval:
         if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
             DebugEnvironments::onPopVar(cx, ei);
         }
         if (ei.scope().hasEnvironment()) {
             ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>();
         }
         break;
+      case ScopeKind::Module:
+        if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
+            DebugEnvironments::onPopModule(cx, ei);
+        }
+        break;
       case ScopeKind::Eval:
       case ScopeKind::Global:
       case ScopeKind::NonSyntactic:
-      case ScopeKind::Module:
         break;
       case ScopeKind::WasmInstance:
       case ScopeKind::WasmFunction:
         MOZ_CRASH("wasm is not interpreted");
         break;
     }
 }