forked from mirrors/gecko-dev
		
	 c2126ea399
			
		
	
	
		c2126ea399
		
	
	
	
	
		
			
			Depends on D145741 Differential Revision: https://phabricator.services.mozilla.com/D145742
		
			
				
	
	
		
			448 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			448 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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);
 | |
| 
 | |
|   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 */
 |