summaryrefslogtreecommitdiffstats
path: root/dom/console/Console.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/console/Console.h450
1 files changed, 450 insertions, 0 deletions
diff --git a/dom/console/Console.h b/dom/console/Console.h
new file mode 100644
index 0000000000..c7a5590467
--- /dev/null
+++ b/dom/console/Console.h
@@ -0,0 +1,450 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_Console_h
+#define mozilla_dom_Console_h
+
+#include "domstubs.h"
+#include "mozilla/dom/ConsoleBinding.h"
+#include "mozilla/TimeStamp.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsTHashMap.h"
+#include "nsHashKeys.h"
+#include "nsIObserver.h"
+#include "nsWeakReference.h"
+
+class nsIConsoleAPIStorage;
+class nsIGlobalObject;
+class nsPIDOMWindowInner;
+class nsIStackFrame;
+
+namespace mozilla::dom {
+
+class AnyCallback;
+class ConsoleCallData;
+class ConsoleInstance;
+class ConsoleRunnable;
+class ConsoleCallDataRunnable;
+class ConsoleProfileRunnable;
+class MainThreadConsoleData;
+
+class Console final : public nsIObserver, public nsSupportsWeakReference {
+ public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Console, nsIObserver)
+ NS_DECL_NSIOBSERVER
+
+ static already_AddRefed<Console> Create(JSContext* aCx,
+ nsPIDOMWindowInner* aWindow,
+ ErrorResult& aRv);
+
+ static already_AddRefed<Console> CreateForWorklet(JSContext* aCx,
+ nsIGlobalObject* aGlobal,
+ uint64_t aOuterWindowID,
+ uint64_t aInnerWindowID,
+ ErrorResult& aRv);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Log(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Info(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Warn(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Error(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Exception(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Debug(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Table(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Trace(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Dir(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Dirxml(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Group(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void GroupCollapsed(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void GroupEnd(const GlobalObject& aGlobal);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Time(const GlobalObject& aGlobal, const nsAString& aLabel);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void TimeLog(const GlobalObject& aGlobal, const nsAString& aLabel,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void TimeEnd(const GlobalObject& aGlobal, const nsAString& aLabel);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void TimeStamp(const GlobalObject& aGlobal,
+ const JS::Handle<JS::Value> aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Profile(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void ProfileEnd(const GlobalObject& aGlobal,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Assert(const GlobalObject& aGlobal, bool aCondition,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Count(const GlobalObject& aGlobal, const nsAString& aLabel);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void CountReset(const GlobalObject& aGlobal, const nsAString& aLabel);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Clear(const GlobalObject& aGlobal);
+
+ static already_AddRefed<ConsoleInstance> CreateInstance(
+ const GlobalObject& aGlobal, const ConsoleInstanceOptions& aOptions);
+
+ void ClearStorage();
+
+ void RetrieveConsoleEvents(JSContext* aCx, nsTArray<JS::Value>& aEvents,
+ ErrorResult& aRv);
+
+ void SetConsoleEventHandler(AnyCallback* aHandler);
+
+ private:
+ Console(JSContext* aCx, nsIGlobalObject* aGlobal, uint64_t aOuterWindowID,
+ uint64_t aInnerWIndowID);
+ ~Console();
+
+ void Initialize(ErrorResult& aRv);
+
+ void Shutdown();
+
+ enum MethodName {
+ MethodLog,
+ MethodInfo,
+ MethodWarn,
+ MethodError,
+ MethodException,
+ MethodDebug,
+ MethodTable,
+ MethodTrace,
+ MethodDir,
+ MethodDirxml,
+ MethodGroup,
+ MethodGroupCollapsed,
+ MethodGroupEnd,
+ MethodTime,
+ MethodTimeLog,
+ MethodTimeEnd,
+ MethodTimeStamp,
+ MethodAssert,
+ MethodCount,
+ MethodCountReset,
+ MethodClear,
+ MethodProfile,
+ MethodProfileEnd,
+ };
+
+ static already_AddRefed<Console> GetConsole(const GlobalObject& aGlobal);
+
+ static already_AddRefed<Console> GetConsoleInternal(
+ const GlobalObject& aGlobal, ErrorResult& aRv);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void ProfileMethod(const GlobalObject& aGlobal, MethodName aName,
+ const nsAString& aAction,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ void ProfileMethodInternal(JSContext* aCx, MethodName aName,
+ const nsAString& aAction,
+ const Sequence<JS::Value>& aData);
+
+ // Implementation of the mainthread-only parts of ProfileMethod.
+ // This is indepedent of console instance state.
+ static void ProfileMethodMainthread(JSContext* aCx, const nsAString& aAction,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void Method(const GlobalObject& aGlobal, MethodName aName,
+ const nsAString& aString,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ void MethodInternal(JSContext* aCx, MethodName aName,
+ const nsAString& aString,
+ const Sequence<JS::Value>& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ static void StringMethod(const GlobalObject& aGlobal, const nsAString& aLabel,
+ const Sequence<JS::Value>& aData,
+ MethodName aMethodName,
+ const nsAString& aMethodString);
+
+ MOZ_CAN_RUN_SCRIPT
+ void StringMethodInternal(JSContext* aCx, const nsAString& aLabel,
+ const Sequence<JS::Value>& aData,
+ MethodName aMethodName,
+ const nsAString& aMethodString);
+
+ MainThreadConsoleData* GetOrCreateMainThreadData();
+
+ // Returns true on success; otherwise false.
+ bool StoreCallData(JSContext* aCx, ConsoleCallData* aCallData,
+ const Sequence<JS::Value>& aArguments);
+
+ void UnstoreCallData(ConsoleCallData* aData);
+
+ // aCx and aArguments must be in the same JS compartment.
+ MOZ_CAN_RUN_SCRIPT
+ void NotifyHandler(JSContext* aCx, const Sequence<JS::Value>& aArguments,
+ ConsoleCallData* aData);
+
+ // PopulateConsoleNotificationInTheTargetScope receives aCx and aArguments in
+ // the same JS compartment and populates the ConsoleEvent object
+ // (aEventValue) in the aTargetScope.
+ // aTargetScope can be:
+ // - the system-principal scope when we want to dispatch the ConsoleEvent to
+ // nsIConsoleAPIStorage (See the comment in Console.cpp about the use of
+ // xpc::PrivilegedJunkScope()
+ // - the mConsoleEventNotifier->CallableGlobal() when we want to notify this
+ // handler about a new ConsoleEvent.
+ // - It can be the global from the JSContext when RetrieveConsoleEvents is
+ // called.
+ static bool PopulateConsoleNotificationInTheTargetScope(
+ JSContext* aCx, const Sequence<JS::Value>& aArguments,
+ JS::Handle<JSObject*> aTargetScope,
+ JS::MutableHandle<JS::Value> aEventValue, ConsoleCallData* aData,
+ nsTArray<nsString>* aGroupStack);
+
+ enum TimerStatus {
+ eTimerUnknown,
+ eTimerDone,
+ eTimerAlreadyExists,
+ eTimerDoesntExist,
+ eTimerJSException,
+ eTimerMaxReached,
+ };
+
+ static JS::Value CreateTimerError(JSContext* aCx, const nsAString& aLabel,
+ TimerStatus aStatus);
+
+ // StartTimer is called on the owning thread and populates aTimerLabel and
+ // aTimerValue.
+ // * aCx - the JSContext rooting aName.
+ // * aName - this is (should be) the name of the timer as JS::Value.
+ // * aTimestamp - the monotonicTimer for this context taken from
+ // performance.now().
+ // * aTimerLabel - This label will be populated with the aName converted to a
+ // string.
+ // * aTimerValue - the StartTimer value stored into (or taken from)
+ // mTimerRegistry.
+ TimerStatus StartTimer(JSContext* aCx, const JS::Value& aName,
+ DOMHighResTimeStamp aTimestamp, nsAString& aTimerLabel,
+ DOMHighResTimeStamp* aTimerValue);
+
+ // CreateStartTimerValue generates a ConsoleTimerStart dictionary exposed as
+ // JS::Value. If aTimerStatus is false, it generates a ConsoleTimerError
+ // instead. It's called only after the execution StartTimer on the owning
+ // thread.
+ // * aCx - this is the context that will root the returned value.
+ // * aTimerLabel - this label must be what StartTimer received as aTimerLabel.
+ // * aTimerStatus - the return value of StartTimer.
+ static JS::Value CreateStartTimerValue(JSContext* aCx,
+ const nsAString& aTimerLabel,
+ TimerStatus aTimerStatus);
+
+ // LogTimer follows the same pattern as StartTimer: it runs on the
+ // owning thread and populates aTimerLabel and aTimerDuration, used by
+ // CreateLogOrEndTimerValue.
+ // * aCx - the JSContext rooting aName.
+ // * aName - this is (should be) the name of the timer as JS::Value.
+ // * aTimestamp - the monotonicTimer for this context taken from
+ // performance.now().
+ // * aTimerLabel - This label will be populated with the aName converted to a
+ // string.
+ // * aTimerDuration - the difference between aTimestamp and when the timer
+ // started (see StartTimer).
+ // * aCancelTimer - if true, the timer is removed from the table.
+ TimerStatus LogTimer(JSContext* aCx, const JS::Value& aName,
+ DOMHighResTimeStamp aTimestamp, nsAString& aTimerLabel,
+ double* aTimerDuration, bool aCancelTimer);
+
+ // This method generates a ConsoleTimerEnd dictionary exposed as JS::Value, or
+ // a ConsoleTimerError dictionary if aTimerStatus is false. See LogTimer.
+ // * aCx - this is the context that will root the returned value.
+ // * aTimerLabel - this label must be what LogTimer received as aTimerLabel.
+ // * aTimerDuration - this is what LogTimer received as aTimerDuration
+ // * aTimerStatus - the return value of LogTimer.
+ static JS::Value CreateLogOrEndTimerValue(JSContext* aCx,
+ const nsAString& aLabel,
+ double aDuration,
+ TimerStatus aStatus);
+
+ // The method populates a Sequence from an array of JS::Value.
+ bool ArgumentsToValueList(const Sequence<JS::Value>& aData,
+ Sequence<JS::Value>& aSequence) const;
+
+ // This method follows the same pattern as StartTimer: its runs on the owning
+ // thread and populate aCountLabel, used by CreateCounterOrResetCounterValue.
+ // Returns 3 possible values:
+ // * MAX_PAGE_COUNTERS in case of error that has to be reported;
+ // * 0 in case of a CX exception. The operation cannot continue;
+ // * the incremented counter value.
+ // Params:
+ // * aCx - the JSContext rooting aData.
+ // * aData - the arguments received by the console.count() method.
+ // * aCountLabel - the label that will be populated by this method.
+ uint32_t IncreaseCounter(JSContext* aCx, const Sequence<JS::Value>& aData,
+ nsAString& aCountLabel);
+
+ // This method follows the same pattern as StartTimer: its runs on the owning
+ // thread and populate aCountLabel, used by CreateCounterResetValue. Returns
+ // 3 possible values:
+ // * MAX_PAGE_COUNTERS in case of error that has to be reported;
+ // * 0 elsewhere. In case of a CX exception, aCountLabel will be an empty
+ // string.
+ // Params:
+ // * aCx - the JSContext rooting aData.
+ // * aData - the arguments received by the console.count() method.
+ // * aCountLabel - the label that will be populated by this method.
+ uint32_t ResetCounter(JSContext* aCx, const Sequence<JS::Value>& aData,
+ nsAString& aCountLabel);
+
+ static bool ShouldIncludeStackTrace(MethodName aMethodName);
+
+ void AssertIsOnOwningThread() const;
+
+ bool IsShuttingDown() const;
+
+ bool MonotonicTimer(JSContext* aCx, MethodName aMethodName,
+ const Sequence<JS::Value>& aData,
+ DOMHighResTimeStamp* aTimeStamp);
+
+ void StringifyElement(Element* aElement, nsAString& aOut);
+
+ MOZ_CAN_RUN_SCRIPT
+ void MaybeExecuteDumpFunction(JSContext* aCx, const nsAString& aMethodName,
+ const Sequence<JS::Value>& aData,
+ nsIStackFrame* aStack);
+
+ MOZ_CAN_RUN_SCRIPT
+ void MaybeExecuteDumpFunctionForTime(JSContext* aCx, MethodName aMethodName,
+ const nsAString& aMethodString,
+ uint64_t aMonotonicTimer,
+ const JS::Value& aData);
+
+ MOZ_CAN_RUN_SCRIPT
+ void ExecuteDumpFunction(const nsAString& aMessage);
+
+ bool ShouldProceed(MethodName aName) const;
+
+ uint32_t WebIDLLogLevelToInteger(ConsoleLogLevel aLevel) const;
+
+ uint32_t InternalLogLevelToInteger(MethodName aName) const;
+
+ class ArgumentData {
+ public:
+ bool Initialize(JSContext* aCx, const Sequence<JS::Value>& aArguments);
+ void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
+ bool PopulateArgumentsSequence(Sequence<JS::Value>& aSequence) const;
+ JSObject* Global() const { return mGlobal; }
+
+ private:
+ void AssertIsOnOwningThread() const {
+ NS_ASSERT_OWNINGTHREAD(ArgumentData);
+ }
+
+ NS_DECL_OWNINGTHREAD;
+ JS::Heap<JSObject*> mGlobal;
+ nsTArray<JS::Heap<JS::Value>> mArguments;
+ };
+
+ // Owning/CC thread only
+ nsCOMPtr<nsIGlobalObject> mGlobal;
+
+ // Touched on the owner thread.
+ nsTHashMap<nsStringHashKey, DOMHighResTimeStamp> mTimerRegistry;
+ nsTHashMap<nsStringHashKey, uint32_t> mCounterRegistry;
+
+ nsTArray<RefPtr<ConsoleCallData>> mCallDataStorage;
+ // These are references to the arguments we received in each call
+ // from the DOM bindings.
+ // Vector<T> supports non-memmovable types such as ArgumentData
+ // (without any need to jump through hoops like
+ // MOZ_DECLARE_RELOCATE_USING_MOVE_CONSTRUCTOR_FOR_TEMPLATE for nsTArray).
+ Vector<ArgumentData> mArgumentStorage;
+
+ RefPtr<AnyCallback> mConsoleEventNotifier;
+
+ RefPtr<MainThreadConsoleData> mMainThreadData;
+ // This is the stack for grouping relating to Console-thread events, when
+ // the Console thread is not the main thread.
+ nsTArray<nsString> mGroupStack;
+
+ uint64_t mOuterID;
+ uint64_t mInnerID;
+
+ // Set only by ConsoleInstance:
+ nsString mConsoleID;
+ nsString mPassedInnerID;
+ RefPtr<ConsoleInstanceDumpCallback> mDumpFunction;
+ bool mDumpToStdout;
+ nsString mPrefix;
+ bool mChromeInstance;
+ ConsoleLogLevel mMaxLogLevel;
+ nsString mMaxLogLevelPref;
+
+ enum { eUnknown, eInitialized, eShuttingDown } mStatus;
+
+ // This is used when Console is created and it's used only for JSM custom
+ // console instance.
+ mozilla::TimeStamp mCreationTimeStamp;
+
+ friend class ConsoleCallData;
+ friend class ConsoleCallDataWorkletRunnable;
+ friend class ConsoleInstance;
+ friend class ConsoleProfileWorkerRunnable;
+ friend class ConsoleProfileWorkletRunnable;
+ friend class ConsoleRunnable;
+ friend class ConsoleWorkerRunnable;
+ friend class ConsoleWorkletRunnable;
+ friend class MainThreadConsoleData;
+};
+
+} // namespace mozilla::dom
+
+#endif /* mozilla_dom_Console_h */