diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index b7847ab5e9d5..8e429be38e03 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -4475,6 +4475,7 @@ Debugger::observesScript(JSScript *script) const Debugger::replaceFrameGuts(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to, ScriptFrameIter &iter) { + // Forward live Debugger.Frame objects. for (Debugger::FrameRange r(from); !r.empty(); r.popFront()) { RootedNativeObject frameobj(cx, r.frontFrame()); Debugger *dbg = r.frontDebugger(); @@ -4497,6 +4498,9 @@ Debugger::replaceFrameGuts(JSContext *cx, AbstractFramePtr from, AbstractFramePt } } + // Rekey missingScopes to maintain Debugger.Environment identity. + DebugScopes::rekeyMissingScopes(cx, from, to); + return true; } diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 421deccf3345..7505cf798908 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -2380,6 +2380,22 @@ DebugScopes::hasLiveScope(ScopeObject &scope) return nullptr; } +/* static */ void +DebugScopes::rekeyMissingScopes(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to) +{ + DebugScopes *scopes = cx->compartment()->debugScopes; + if (!scopes) + return; + + for (MissingScopeMap::Enum e(scopes->missingScopes); !e.empty(); e.popFront()) { + ScopeIterKey key = e.front().key(); + if (key.frame() == from) { + key.updateFrame(to); + e.rekeyFront(key); + } + } +} + /*****************************************************************************/ static JSObject * diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 8ba71c75e4f7..c73efb7a7af6 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -774,6 +774,7 @@ class ScopeIterKey void updateCur(JSObject *obj) { cur_ = obj; } void updateStaticScope(NestedScopeObject *obj) { staticScope_ = obj; } + void updateFrame(AbstractFramePtr frame) { frame_ = frame; } /* For use as hash policy */ typedef ScopeIterKey Lookup; @@ -941,6 +942,8 @@ class DebugScopes static bool updateLiveScopes(JSContext *cx); static ScopeIterVal *hasLiveScope(ScopeObject &scope); + static void rekeyMissingScopes(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to); + // In debug-mode, these must be called whenever exiting a scope that might // have stack-allocated locals. static void onPopCall(AbstractFramePtr frame, JSContext *cx);