1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_Console_h
8 #define mozilla_dom_Console_h
11 #include "mozilla/dom/ConsoleBinding.h"
12 #include "mozilla/dom/ConsoleInstanceBinding.h"
13 #include "mozilla/TimeStamp.h"
14 #include "nsCycleCollectionParticipant.h"
15 #include "nsTHashMap.h"
16 #include "nsHashKeys.h"
17 #include "nsIObserver.h"
18 #include "nsWeakReference.h"
20 class nsIConsoleAPIStorage
;
21 class nsIGlobalObject
;
22 class nsPIDOMWindowInner
;
25 namespace mozilla::dom
{
28 class ConsoleCallData
;
29 class ConsoleInstance
;
30 class ConsoleRunnable
;
31 class ConsoleCallDataRunnable
;
32 class ConsoleProfileRunnable
;
33 class MainThreadConsoleData
;
35 class Console final
: public nsIObserver
, public nsSupportsWeakReference
{
37 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
38 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Console
, nsIObserver
)
41 static already_AddRefed
<Console
> Create(JSContext
* aCx
,
42 nsPIDOMWindowInner
* aWindow
,
45 static already_AddRefed
<Console
> CreateForWorklet(JSContext
* aCx
,
46 nsIGlobalObject
* aGlobal
,
47 uint64_t aOuterWindowID
,
48 uint64_t aInnerWindowID
,
52 static void Log(const GlobalObject
& aGlobal
,
53 const Sequence
<JS::Value
>& aData
);
56 static void Info(const GlobalObject
& aGlobal
,
57 const Sequence
<JS::Value
>& aData
);
60 static void Warn(const GlobalObject
& aGlobal
,
61 const Sequence
<JS::Value
>& aData
);
64 static void Error(const GlobalObject
& aGlobal
,
65 const Sequence
<JS::Value
>& aData
);
68 static void Exception(const GlobalObject
& aGlobal
,
69 const Sequence
<JS::Value
>& aData
);
72 static void Debug(const GlobalObject
& aGlobal
,
73 const Sequence
<JS::Value
>& aData
);
76 static void Table(const GlobalObject
& aGlobal
,
77 const Sequence
<JS::Value
>& aData
);
80 static void Trace(const GlobalObject
& aGlobal
,
81 const Sequence
<JS::Value
>& aData
);
84 static void Dir(const GlobalObject
& aGlobal
,
85 const Sequence
<JS::Value
>& aData
);
88 static void Dirxml(const GlobalObject
& aGlobal
,
89 const Sequence
<JS::Value
>& aData
);
92 static void Group(const GlobalObject
& aGlobal
,
93 const Sequence
<JS::Value
>& aData
);
96 static void GroupCollapsed(const GlobalObject
& aGlobal
,
97 const Sequence
<JS::Value
>& aData
);
100 static void GroupEnd(const GlobalObject
& aGlobal
);
103 static void Time(const GlobalObject
& aGlobal
, const nsAString
& aLabel
);
106 static void TimeLog(const GlobalObject
& aGlobal
, const nsAString
& aLabel
,
107 const Sequence
<JS::Value
>& aData
);
110 static void TimeEnd(const GlobalObject
& aGlobal
, const nsAString
& aLabel
);
113 static void TimeStamp(const GlobalObject
& aGlobal
,
114 const JS::Handle
<JS::Value
> aData
);
117 static void Profile(const GlobalObject
& aGlobal
,
118 const Sequence
<JS::Value
>& aData
);
121 static void ProfileEnd(const GlobalObject
& aGlobal
,
122 const Sequence
<JS::Value
>& aData
);
125 static void Assert(const GlobalObject
& aGlobal
, bool aCondition
,
126 const Sequence
<JS::Value
>& aData
);
129 static void Count(const GlobalObject
& aGlobal
, const nsAString
& aLabel
);
132 static void CountReset(const GlobalObject
& aGlobal
, const nsAString
& aLabel
);
135 static void Clear(const GlobalObject
& aGlobal
);
137 static already_AddRefed
<ConsoleInstance
> CreateInstance(
138 const GlobalObject
& aGlobal
, const ConsoleInstanceOptions
& aOptions
);
142 void RetrieveConsoleEvents(JSContext
* aCx
, nsTArray
<JS::Value
>& aEvents
,
145 void SetConsoleEventHandler(AnyCallback
* aHandler
);
148 Console(JSContext
* aCx
, nsIGlobalObject
* aGlobal
, uint64_t aOuterWindowID
,
149 uint64_t aInnerWIndowID
);
152 void Initialize(ErrorResult
& aRv
);
168 MethodGroupCollapsed
,
182 static already_AddRefed
<Console
> GetConsole(const GlobalObject
& aGlobal
);
184 static already_AddRefed
<Console
> GetConsoleInternal(
185 const GlobalObject
& aGlobal
, ErrorResult
& aRv
);
188 static void ProfileMethod(const GlobalObject
& aGlobal
, MethodName aName
,
189 const nsAString
& aAction
,
190 const Sequence
<JS::Value
>& aData
);
193 void ProfileMethodInternal(JSContext
* aCx
, MethodName aName
,
194 const nsAString
& aAction
,
195 const Sequence
<JS::Value
>& aData
);
197 // Implementation of the mainthread-only parts of ProfileMethod.
198 // This is indepedent of console instance state.
199 static void ProfileMethodMainthread(JSContext
* aCx
, const nsAString
& aAction
,
200 const Sequence
<JS::Value
>& aData
);
203 static void Method(const GlobalObject
& aGlobal
, MethodName aName
,
204 const nsAString
& aString
,
205 const Sequence
<JS::Value
>& aData
);
208 void MethodInternal(JSContext
* aCx
, MethodName aName
,
209 const nsAString
& aString
,
210 const Sequence
<JS::Value
>& aData
);
213 static void StringMethod(const GlobalObject
& aGlobal
, const nsAString
& aLabel
,
214 const Sequence
<JS::Value
>& aData
,
215 MethodName aMethodName
,
216 const nsAString
& aMethodString
);
219 void StringMethodInternal(JSContext
* aCx
, const nsAString
& aLabel
,
220 const Sequence
<JS::Value
>& aData
,
221 MethodName aMethodName
,
222 const nsAString
& aMethodString
);
224 MainThreadConsoleData
* GetOrCreateMainThreadData();
226 // Returns true on success; otherwise false.
227 bool StoreCallData(JSContext
* aCx
, ConsoleCallData
* aCallData
,
228 const Sequence
<JS::Value
>& aArguments
);
230 void UnstoreCallData(ConsoleCallData
* aData
);
232 // aCx and aArguments must be in the same JS compartment.
234 void NotifyHandler(JSContext
* aCx
, const Sequence
<JS::Value
>& aArguments
,
235 ConsoleCallData
* aData
);
237 // PopulateConsoleNotificationInTheTargetScope receives aCx and aArguments in
238 // the same JS compartment and populates the ConsoleEvent object
239 // (aEventValue) in the aTargetScope.
240 // aTargetScope can be:
241 // - the system-principal scope when we want to dispatch the ConsoleEvent to
242 // nsIConsoleAPIStorage (See the comment in Console.cpp about the use of
243 // xpc::PrivilegedJunkScope()
244 // - the mConsoleEventNotifier->CallableGlobal() when we want to notify this
245 // handler about a new ConsoleEvent.
246 // - It can be the global from the JSContext when RetrieveConsoleEvents is
248 static bool PopulateConsoleNotificationInTheTargetScope(
249 JSContext
* aCx
, const Sequence
<JS::Value
>& aArguments
,
250 JS::Handle
<JSObject
*> aTargetScope
,
251 JS::MutableHandle
<JS::Value
> aEventValue
, ConsoleCallData
* aData
,
252 nsTArray
<nsString
>* aGroupStack
);
263 static JS::Value
CreateTimerError(JSContext
* aCx
, const nsAString
& aLabel
,
264 TimerStatus aStatus
);
266 // StartTimer is called on the owning thread and populates aTimerLabel and
268 // * aCx - the JSContext rooting aName.
269 // * aName - this is (should be) the name of the timer as JS::Value.
270 // * aTimestamp - the monotonicTimer for this context taken from
271 // performance.now().
272 // * aTimerLabel - This label will be populated with the aName converted to a
274 // * aTimerValue - the StartTimer value stored into (or taken from)
276 TimerStatus
StartTimer(JSContext
* aCx
, const JS::Value
& aName
,
277 DOMHighResTimeStamp aTimestamp
, nsAString
& aTimerLabel
,
278 DOMHighResTimeStamp
* aTimerValue
);
280 // CreateStartTimerValue generates a ConsoleTimerStart dictionary exposed as
281 // JS::Value. If aTimerStatus is false, it generates a ConsoleTimerError
282 // instead. It's called only after the execution StartTimer on the owning
284 // * aCx - this is the context that will root the returned value.
285 // * aTimerLabel - this label must be what StartTimer received as aTimerLabel.
286 // * aTimerStatus - the return value of StartTimer.
287 static JS::Value
CreateStartTimerValue(JSContext
* aCx
,
288 const nsAString
& aTimerLabel
,
289 TimerStatus aTimerStatus
);
291 // LogTimer follows the same pattern as StartTimer: it runs on the
292 // owning thread and populates aTimerLabel and aTimerDuration, used by
293 // CreateLogOrEndTimerValue.
294 // * aCx - the JSContext rooting aName.
295 // * aName - this is (should be) the name of the timer as JS::Value.
296 // * aTimestamp - the monotonicTimer for this context taken from
297 // performance.now().
298 // * aTimerLabel - This label will be populated with the aName converted to a
300 // * aTimerDuration - the difference between aTimestamp and when the timer
301 // started (see StartTimer).
302 // * aCancelTimer - if true, the timer is removed from the table.
303 TimerStatus
LogTimer(JSContext
* aCx
, const JS::Value
& aName
,
304 DOMHighResTimeStamp aTimestamp
, nsAString
& aTimerLabel
,
305 double* aTimerDuration
, bool aCancelTimer
);
307 // This method generates a ConsoleTimerEnd dictionary exposed as JS::Value, or
308 // a ConsoleTimerError dictionary if aTimerStatus is false. See LogTimer.
309 // * aCx - this is the context that will root the returned value.
310 // * aTimerLabel - this label must be what LogTimer received as aTimerLabel.
311 // * aTimerDuration - this is what LogTimer received as aTimerDuration
312 // * aTimerStatus - the return value of LogTimer.
313 static JS::Value
CreateLogOrEndTimerValue(JSContext
* aCx
,
314 const nsAString
& aLabel
,
316 TimerStatus aStatus
);
318 // The method populates a Sequence from an array of JS::Value.
319 bool ArgumentsToValueList(const Sequence
<JS::Value
>& aData
,
320 Sequence
<JS::Value
>& aSequence
) const;
322 // This method follows the same pattern as StartTimer: its runs on the owning
323 // thread and populate aCountLabel, used by CreateCounterOrResetCounterValue.
324 // Returns 3 possible values:
325 // * MAX_PAGE_COUNTERS in case of error that has to be reported;
326 // * 0 in case of a CX exception. The operation cannot continue;
327 // * the incremented counter value.
329 // * aCx - the JSContext rooting aData.
330 // * aData - the arguments received by the console.count() method.
331 // * aCountLabel - the label that will be populated by this method.
332 uint32_t IncreaseCounter(JSContext
* aCx
, const Sequence
<JS::Value
>& aData
,
333 nsAString
& aCountLabel
);
335 // This method follows the same pattern as StartTimer: its runs on the owning
336 // thread and populate aCountLabel, used by CreateCounterResetValue. Returns
337 // 3 possible values:
338 // * MAX_PAGE_COUNTERS in case of error that has to be reported;
339 // * 0 elsewhere. In case of a CX exception, aCountLabel will be an empty
342 // * aCx - the JSContext rooting aData.
343 // * aData - the arguments received by the console.count() method.
344 // * aCountLabel - the label that will be populated by this method.
345 uint32_t ResetCounter(JSContext
* aCx
, const Sequence
<JS::Value
>& aData
,
346 nsAString
& aCountLabel
);
348 static bool ShouldIncludeStackTrace(MethodName aMethodName
);
350 void AssertIsOnOwningThread() const;
352 bool IsShuttingDown() const;
354 bool MonotonicTimer(JSContext
* aCx
, MethodName aMethodName
,
355 const Sequence
<JS::Value
>& aData
,
356 DOMHighResTimeStamp
* aTimeStamp
);
358 void StringifyElement(Element
* aElement
, nsAString
& aOut
);
361 void MaybeExecuteDumpFunction(JSContext
* aCx
, const nsAString
& aMethodName
,
362 const Sequence
<JS::Value
>& aData
,
363 nsIStackFrame
* aStack
);
366 void MaybeExecuteDumpFunctionForTime(JSContext
* aCx
, MethodName aMethodName
,
367 const nsAString
& aMethodString
,
368 uint64_t aMonotonicTimer
,
369 const JS::Value
& aData
);
372 void ExecuteDumpFunction(const nsAString
& aMessage
);
374 bool ShouldProceed(MethodName aName
) const;
376 uint32_t WebIDLLogLevelToInteger(ConsoleLogLevel aLevel
) const;
378 uint32_t InternalLogLevelToInteger(MethodName aName
) const;
382 bool Initialize(JSContext
* aCx
, const Sequence
<JS::Value
>& aArguments
);
383 void Trace(const TraceCallbacks
& aCallbacks
, void* aClosure
);
384 bool PopulateArgumentsSequence(Sequence
<JS::Value
>& aSequence
) const;
385 JSObject
* Global() const { return mGlobal
; }
388 void AssertIsOnOwningThread() const {
389 NS_ASSERT_OWNINGTHREAD(ArgumentData
);
392 NS_DECL_OWNINGTHREAD
;
393 JS::Heap
<JSObject
*> mGlobal
;
394 nsTArray
<JS::Heap
<JS::Value
>> mArguments
;
397 // Owning/CC thread only
398 nsCOMPtr
<nsIGlobalObject
> mGlobal
;
400 // Touched on the owner thread.
401 nsTHashMap
<nsStringHashKey
, DOMHighResTimeStamp
> mTimerRegistry
;
402 nsTHashMap
<nsStringHashKey
, uint32_t> mCounterRegistry
;
404 nsTArray
<RefPtr
<ConsoleCallData
>> mCallDataStorage
;
405 // These are references to the arguments we received in each call
406 // from the DOM bindings.
407 // Vector<T> supports non-memmovable types such as ArgumentData
408 // (without any need to jump through hoops like
409 // MOZ_DECLARE_RELOCATE_USING_MOVE_CONSTRUCTOR_FOR_TEMPLATE for nsTArray).
410 Vector
<ArgumentData
> mArgumentStorage
;
412 RefPtr
<AnyCallback
> mConsoleEventNotifier
;
414 RefPtr
<MainThreadConsoleData
> mMainThreadData
;
415 // This is the stack for grouping relating to Console-thread events, when
416 // the Console thread is not the main thread.
417 nsTArray
<nsString
> mGroupStack
;
422 // Set only by ConsoleInstance:
424 nsString mPassedInnerID
;
425 RefPtr
<ConsoleInstanceDumpCallback
> mDumpFunction
;
428 bool mChromeInstance
;
429 uint32_t mCurrentLogLevel
;
431 enum { eUnknown
, eInitialized
, eShuttingDown
} mStatus
;
433 // This is used when Console is created and it's used only for JSM custom
435 mozilla::TimeStamp mCreationTimeStamp
;
437 friend class ConsoleCallData
;
438 friend class ConsoleCallDataWorkletRunnable
;
439 friend class ConsoleInstance
;
440 friend class ConsoleProfileWorkerRunnable
;
441 friend class ConsoleProfileWorkletRunnable
;
442 friend class ConsoleRunnable
;
443 friend class ConsoleWorkerRunnable
;
444 friend class ConsoleWorkletRunnable
;
445 friend class MainThreadConsoleData
;
448 } // namespace mozilla::dom
450 #endif /* mozilla_dom_Console_h */