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 497663 6b952be63f69e244ab688cdb7a84d121b009a162
parent 497662 8f74f5dbf5c0d12bebf84841b8553b179b7d04a0
child 497664 9e81f9458926dbb1796ac5c3c0b06fa1ee1d10e9
push id10002
push userarchaeopteryx@coole-files.de
push dateFri, 19 Oct 2018 23:09:29 +0000
treeherdermozilla-beta@01378c910610 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1498980
milestone64.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 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;
     }
 }