Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit a1de03c

Browse files
committed
Bug 1529345 - Part 2: Add Gecko infrastructure for receiving notifications about debugger-related events. r=jimb,smaug
Differential Revision: https://phabricator.services.mozilla.com/D30565 --HG-- extra : moz-landing-system : lando
1 parent 6edbe83 commit a1de03c

31 files changed

Lines changed: 1056 additions & 10 deletions

config/windows-h-constant.decls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ auto MAXBYTE;
4444
auto MAXWORD;
4545
auto MAXDWORD;
4646

47+
auto ERROR;
48+
4749
auto DELETE;
4850
auto READ_CONTROL;
4951
auto WRITE_DAC;

dom/base/nsGlobalWindowInner.cpp

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
#include "nsHistory.h"
1818
#include "nsDOMNavigationTiming.h"
1919
#include "nsIDOMStorageManager.h"
20+
#include "mozilla/dom/CallbackDebuggerNotification.h"
2021
#include "mozilla/dom/ContentFrameMessageManager.h"
2122
#include "mozilla/dom/CSPEvalChecker.h"
23+
#include "mozilla/dom/DebuggerNotification.h"
2224
#include "mozilla/dom/DocumentInlines.h"
2325
#include "mozilla/dom/DOMJSProxyHandler.h"
2426
#include "mozilla/dom/EventTarget.h"
@@ -1370,6 +1372,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
13701372
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
13711373
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays)
13721374

1375+
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager)
1376+
13731377
// Traverse stuff from nsPIDOMWindow
13741378
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
13751379
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
@@ -1468,6 +1472,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
14681472
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
14691473
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays)
14701474

1475+
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager)
1476+
14711477
// Unlink stuff from nsPIDOMWindow
14721478
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
14731479
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
@@ -3289,6 +3295,9 @@ int32_t nsGlobalWindowInner::RequestAnimationFrame(
32893295
js::NotifyAnimationActivity(GetWrapperPreserveColor());
32903296
}
32913297

3298+
DebuggerNotificationDispatch(this,
3299+
DebuggerNotificationType::RequestAnimationFrame);
3300+
32923301
int32_t handle;
32933302
aError = mDoc->ScheduleFrameRequestCallback(aCallback, &handle);
32943303
return handle;
@@ -3300,6 +3309,9 @@ void nsGlobalWindowInner::CancelAnimationFrame(int32_t aHandle,
33003309
return;
33013310
}
33023311

3312+
DebuggerNotificationDispatch(this,
3313+
DebuggerNotificationType::CancelAnimationFrame);
3314+
33033315
mDoc->CancelFrameRequestCallback(aHandle);
33043316
}
33053317

@@ -3730,12 +3742,16 @@ void nsGlobalWindowInner::MozScrollSnap() {
37303742
}
37313743

37323744
void nsGlobalWindowInner::ClearTimeout(int32_t aHandle) {
3745+
DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearTimeout);
3746+
37333747
if (aHandle > 0) {
37343748
mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
37353749
}
37363750
}
37373751

37383752
void nsGlobalWindowInner::ClearInterval(int32_t aHandle) {
3753+
DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearInterval);
3754+
37393755
if (aHandle > 0) {
37403756
mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
37413757
}
@@ -4003,6 +4019,20 @@ EventListenerManager* nsGlobalWindowInner::GetExistingListenerManager() const {
40034019
return mListenerManager;
40044020
}
40054021

4022+
mozilla::dom::DebuggerNotificationManager*
4023+
nsGlobalWindowInner::GetOrCreateDebuggerNotificationManager() {
4024+
if (!mDebuggerNotificationManager) {
4025+
mDebuggerNotificationManager = new DebuggerNotificationManager(this);
4026+
}
4027+
4028+
return mDebuggerNotificationManager;
4029+
}
4030+
4031+
mozilla::dom::DebuggerNotificationManager*
4032+
nsGlobalWindowInner::GetExistingDebuggerNotificationManager() {
4033+
return mDebuggerNotificationManager;
4034+
}
4035+
40064036
//*****************************************************************************
40074037
// nsGlobalWindowInner::nsPIDOMWindow
40084038
//*****************************************************************************
@@ -5758,10 +5788,15 @@ int32_t nsGlobalWindowInner::SetTimeoutOrInterval(
57585788
}
57595789

57605790
if (inner != this) {
5761-
return inner->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments,
5762-
aIsInterval, aError);
5791+
RefPtr<nsGlobalWindowInner> innerRef(inner);
5792+
return innerRef->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments,
5793+
aIsInterval, aError);
57635794
}
57645795

5796+
DebuggerNotificationDispatch(
5797+
this, aIsInterval ? DebuggerNotificationType::SetInterval
5798+
: DebuggerNotificationType::SetTimeout);
5799+
57655800
if (!GetContextInternal() || !HasJSGlobal()) {
57665801
// This window was already closed, or never properly initialized,
57675802
// don't let a timer be scheduled on such a window.
@@ -5796,10 +5831,15 @@ int32_t nsGlobalWindowInner::SetTimeoutOrInterval(JSContext* aCx,
57965831
}
57975832

57985833
if (inner != this) {
5799-
return inner->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
5800-
aError);
5834+
RefPtr<nsGlobalWindowInner> innerRef(inner);
5835+
return innerRef->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
5836+
aError);
58015837
}
58025838

5839+
DebuggerNotificationDispatch(
5840+
this, aIsInterval ? DebuggerNotificationType::SetInterval
5841+
: DebuggerNotificationType::SetTimeout);
5842+
58035843
if (!GetContextInternal() || !HasJSGlobal()) {
58045844
// This window was already closed, or never properly initialized,
58055845
// don't let a timer be scheduled on such a window.
@@ -5857,8 +5897,17 @@ bool nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout,
58575897
reason = "setTimeout handler";
58585898
}
58595899

5860-
RefPtr<TimeoutHandler> handler(timeout->mScriptHandler);
5861-
bool abortIntervalHandler = !handler->Call(reason);
5900+
bool abortIntervalHandler;
5901+
{
5902+
RefPtr<TimeoutHandler> handler(timeout->mScriptHandler);
5903+
5904+
CallbackDebuggerNotificationGuard guard(
5905+
this, timeout->mIsInterval
5906+
? DebuggerNotificationType::SetIntervalCallback
5907+
: DebuggerNotificationType::SetTimeoutCallback);
5908+
abortIntervalHandler = !handler->Call(reason);
5909+
}
5910+
58625911
// If we received an uncatchable exception, do not schedule the timeout again.
58635912
// This allows the slow script dialog to break easy DoS attacks like
58645913
// setInterval(function() { while(1); }, 100);

dom/base/nsGlobalWindowInner.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "prclist.h"
3737
#include "mozilla/dom/BindingDeclarations.h"
3838
#include "mozilla/dom/ChromeMessageBroadcaster.h"
39+
#include "mozilla/dom/DebuggerNotificationManager.h"
3940
#include "mozilla/dom/NavigatorBinding.h"
4041
#include "mozilla/dom/StorageEvent.h"
4142
#include "mozilla/dom/StorageEventBinding.h"
@@ -284,6 +285,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
284285

285286
virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override;
286287

288+
mozilla::Maybe<mozilla::dom::EventCallbackDebuggerNotificationType>
289+
GetDebuggerNotificationType() const override {
290+
return mozilla::Some(
291+
mozilla::dom::EventCallbackDebuggerNotificationType::Global);
292+
}
293+
287294
bool ComputeDefaultWantsUntrusted(mozilla::ErrorResult& aRv) final;
288295

289296
virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() override;
@@ -317,6 +324,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
317324
virtual bool IsFrozen() const override;
318325
void SyncStateFromParentWindow();
319326

327+
mozilla::dom::DebuggerNotificationManager*
328+
GetOrCreateDebuggerNotificationManager() override;
329+
330+
mozilla::dom::DebuggerNotificationManager*
331+
GetExistingDebuggerNotificationManager() override;
332+
320333
mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const override;
321334
mozilla::Maybe<mozilla::dom::ClientState> GetClientState() const;
322335
mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController()
@@ -681,23 +694,35 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
681694
const mozilla::dom::WindowPostMessageOptions& aOptions,
682695
nsIPrincipal& aSubjectPrincipal,
683696
mozilla::ErrorResult& aError);
697+
698+
MOZ_CAN_RUN_SCRIPT
684699
int32_t SetTimeout(JSContext* aCx, mozilla::dom::Function& aFunction,
685700
int32_t aTimeout,
686701
const mozilla::dom::Sequence<JS::Value>& aArguments,
687702
mozilla::ErrorResult& aError);
703+
704+
MOZ_CAN_RUN_SCRIPT
688705
int32_t SetTimeout(JSContext* aCx, const nsAString& aHandler,
689706
int32_t aTimeout,
690707
const mozilla::dom::Sequence<JS::Value>& /* unused */,
691708
mozilla::ErrorResult& aError);
709+
710+
MOZ_CAN_RUN_SCRIPT
692711
void ClearTimeout(int32_t aHandle);
712+
713+
MOZ_CAN_RUN_SCRIPT
693714
int32_t SetInterval(JSContext* aCx, mozilla::dom::Function& aFunction,
694715
const int32_t aTimeout,
695716
const mozilla::dom::Sequence<JS::Value>& aArguments,
696717
mozilla::ErrorResult& aError);
718+
719+
MOZ_CAN_RUN_SCRIPT
697720
int32_t SetInterval(JSContext* aCx, const nsAString& aHandler,
698721
const int32_t aTimeout,
699722
const mozilla::dom::Sequence<JS::Value>& /* unused */,
700723
mozilla::ErrorResult& aError);
724+
725+
MOZ_CAN_RUN_SCRIPT
701726
void ClearInterval(int32_t aHandle);
702727
void GetOrigin(nsAString& aOrigin);
703728
void Atob(const nsAString& aAsciiBase64String, nsAString& aBinaryData,
@@ -794,8 +819,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
794819
void SetOuterHeight(JSContext* aCx, JS::Handle<JS::Value> aValue,
795820
mozilla::dom::CallerType aCallerType,
796821
mozilla::ErrorResult& aError);
822+
823+
MOZ_CAN_RUN_SCRIPT
797824
int32_t RequestAnimationFrame(mozilla::dom::FrameRequestCallback& aCallback,
798825
mozilla::ErrorResult& aError);
826+
827+
MOZ_CAN_RUN_SCRIPT
799828
void CancelAnimationFrame(int32_t aHandle, mozilla::ErrorResult& aError);
800829

801830
uint32_t RequestIdleCallback(JSContext* aCx,
@@ -1059,10 +1088,13 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
10591088
public:
10601089
// Timeout Functions
10611090
// |interval| is in milliseconds.
1091+
MOZ_CAN_RUN_SCRIPT
10621092
int32_t SetTimeoutOrInterval(
10631093
JSContext* aCx, mozilla::dom::Function& aFunction, int32_t aTimeout,
10641094
const mozilla::dom::Sequence<JS::Value>& aArguments, bool aIsInterval,
10651095
mozilla::ErrorResult& aError);
1096+
1097+
MOZ_CAN_RUN_SCRIPT
10661098
int32_t SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
10671099
int32_t aTimeout, bool aIsInterval,
10681100
mozilla::ErrorResult& aError);
@@ -1317,6 +1349,9 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
13171349
nsCOMPtr<nsIPrincipal> mDocumentStoragePrincipal;
13181350
nsCOMPtr<nsIContentSecurityPolicy> mDocumentCsp;
13191351

1352+
RefPtr<mozilla::dom::DebuggerNotificationManager>
1353+
mDebuggerNotificationManager;
1354+
13201355
// mBrowserChild is only ever populated in the content process.
13211356
nsCOMPtr<nsIBrowserChild> mBrowserChild;
13221357

dom/base/nsIGlobalObject.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ namespace mozilla {
3535
class DOMEventTargetHelper;
3636
namespace dom {
3737
class VoidFunction;
38+
class DebuggerNotificationManager;
3839
class ServiceWorker;
3940
class ServiceWorkerRegistration;
4041
class ServiceWorkerRegistrationDescriptor;
@@ -131,6 +132,16 @@ class nsIGlobalObject : public nsISupports,
131132

132133
virtual bool IsInSyncOperation() { return false; }
133134

135+
virtual mozilla::dom::DebuggerNotificationManager*
136+
GetOrCreateDebuggerNotificationManager() {
137+
return nullptr;
138+
}
139+
140+
virtual mozilla::dom::DebuggerNotificationManager*
141+
GetExistingDebuggerNotificationManager() {
142+
return nullptr;
143+
}
144+
134145
virtual mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const;
135146

136147
virtual mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController()

dom/base/nsINode.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,12 @@ class nsINode : public mozilla::dom::EventTarget {
940940
const override;
941941
virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override;
942942

943+
mozilla::Maybe<mozilla::dom::EventCallbackDebuggerNotificationType>
944+
GetDebuggerNotificationType() const override {
945+
return mozilla::Some(
946+
mozilla::dom::EventCallbackDebuggerNotificationType::Node);
947+
}
948+
943949
bool ComputeDefaultWantsUntrusted(mozilla::ErrorResult& aRv) final;
944950

945951
virtual bool IsApzAware() const override;

dom/bindings/Bindings.conf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,13 @@ DOMInterfaces = {
201201
'implicitJSContext': ['define'],
202202
},
203203

204+
'DebuggerNotification': {
205+
'concrete': True,
206+
},
207+
'CallbackDebuggerNotification': {
208+
'concrete': True,
209+
},
210+
204211
'DedicatedWorkerGlobalScope': {
205212
'headerFile': 'mozilla/dom/WorkerScope.h',
206213
},
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
enum DebuggerNotificationType {
6+
// DebuggerNotification
7+
"setTimeout",
8+
"clearTimeout",
9+
"setInterval",
10+
"clearInterval",
11+
"requestAnimationFrame",
12+
"cancelAnimationFrame",
13+
14+
// CallbackDebuggerNotification
15+
"setTimeoutCallback",
16+
"setIntervalCallback",
17+
"requestAnimationFrameCallback",
18+
19+
// EventCallbackDebuggerNotification
20+
"domEvent",
21+
};
22+
23+
[ChromeOnly]
24+
interface DebuggerNotification {
25+
readonly attribute DebuggerNotificationType type;
26+
27+
// The global object that has triggered the notification.
28+
readonly attribute object global;
29+
};
30+
31+
// For DOM events, we send notifications just before, and just after the
32+
// event handler has been dispatched so that listeners
33+
enum CallbackDebuggerNotificationPhase {
34+
"pre",
35+
"post",
36+
};
37+
38+
// A base notification type for notifications that are dispatched as pairs with
39+
// a before and after notification.
40+
[ChromeOnly]
41+
interface CallbackDebuggerNotification : DebuggerNotification {
42+
readonly attribute CallbackDebuggerNotificationPhase phase;
43+
};
44+
45+
enum EventCallbackDebuggerNotificationType {
46+
"global",
47+
"node",
48+
"xhr",
49+
"worker",
50+
};
51+
52+
// A notification that about the engine calling a DOM event handler.
53+
[ChromeOnly]
54+
interface EventCallbackDebuggerNotification : CallbackDebuggerNotification {
55+
readonly attribute Event event;
56+
readonly attribute EventCallbackDebuggerNotificationType targetType;
57+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
* You can obtain one at http://mozilla.org/MPL/2.0/.
5+
*/
6+
7+
callback DebuggerNotificationCallback = void (DebuggerNotification n);
8+
9+
[ChromeOnly, Constructor, Exposed=(Window, Worker)]
10+
interface DebuggerNotificationObserver {
11+
// Throws if the object is not a browser global or does not support
12+
// debugger notifications.
13+
// Returns false if already connected to this global.
14+
[Throws]
15+
boolean connect(object global);
16+
17+
// Throws if the object is not a browser global or does not support
18+
// debugger notifications.
19+
// Returns false if not connected to this global.
20+
[Throws]
21+
boolean disconnect(object global);
22+
23+
// Returns false if listener already added.
24+
boolean addListener(DebuggerNotificationCallback handler);
25+
26+
// Returns false if listener was not found.
27+
boolean removeListener(DebuggerNotificationCallback handler);
28+
};

0 commit comments

Comments
 (0)