tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Console.h (17243B)


      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/. */
      6 
      7 #ifndef mozilla_dom_Console_h
      8 #define mozilla_dom_Console_h
      9 
     10 #include "domstubs.h"
     11 #include "mozilla/TimeStamp.h"
     12 #include "mozilla/dom/ConsoleBinding.h"
     13 #include "mozilla/dom/ConsoleInstanceBinding.h"
     14 #include "nsCycleCollectionParticipant.h"
     15 #include "nsHashKeys.h"
     16 #include "nsIObserver.h"
     17 #include "nsTHashMap.h"
     18 #include "nsWeakReference.h"
     19 
     20 class nsIConsoleAPIStorage;
     21 class nsIGlobalObject;
     22 class nsPIDOMWindowInner;
     23 class nsIStackFrame;
     24 
     25 namespace mozilla::dom {
     26 
     27 class AnyCallback;
     28 class ConsoleCallData;
     29 class ConsoleInstance;
     30 class ConsoleRunnable;
     31 class ConsoleCallDataRunnable;
     32 class ConsoleProfileRunnable;
     33 class MainThreadConsoleData;
     34 
     35 class Console final : public nsIObserver, public nsSupportsWeakReference {
     36 public:
     37  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     38  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Console, nsIObserver)
     39  NS_DECL_NSIOBSERVER
     40 
     41  static already_AddRefed<Console> Create(JSContext* aCx,
     42                                          nsPIDOMWindowInner* aWindow,
     43                                          ErrorResult& aRv);
     44 
     45  static already_AddRefed<Console> CreateForWorklet(JSContext* aCx,
     46                                                    nsIGlobalObject* aGlobal,
     47                                                    uint64_t aOuterWindowID,
     48                                                    uint64_t aInnerWindowID,
     49                                                    ErrorResult& aRv);
     50 
     51  MOZ_CAN_RUN_SCRIPT
     52  static void Log(const GlobalObject& aGlobal,
     53                  const Sequence<JS::Value>& aData);
     54 
     55  MOZ_CAN_RUN_SCRIPT
     56  static void Info(const GlobalObject& aGlobal,
     57                   const Sequence<JS::Value>& aData);
     58 
     59  MOZ_CAN_RUN_SCRIPT
     60  static void Warn(const GlobalObject& aGlobal,
     61                   const Sequence<JS::Value>& aData);
     62 
     63  MOZ_CAN_RUN_SCRIPT
     64  static void Error(const GlobalObject& aGlobal,
     65                    const Sequence<JS::Value>& aData);
     66 
     67  MOZ_CAN_RUN_SCRIPT
     68  static void Exception(const GlobalObject& aGlobal,
     69                        const Sequence<JS::Value>& aData);
     70 
     71  MOZ_CAN_RUN_SCRIPT
     72  static void Debug(const GlobalObject& aGlobal,
     73                    const Sequence<JS::Value>& aData);
     74 
     75  MOZ_CAN_RUN_SCRIPT
     76  static void Table(const GlobalObject& aGlobal,
     77                    const Sequence<JS::Value>& aData);
     78 
     79  MOZ_CAN_RUN_SCRIPT
     80  static void Trace(const GlobalObject& aGlobal,
     81                    const Sequence<JS::Value>& aData);
     82 
     83  MOZ_CAN_RUN_SCRIPT
     84  static void Dir(const GlobalObject& aGlobal,
     85                  const Sequence<JS::Value>& aData);
     86 
     87  MOZ_CAN_RUN_SCRIPT
     88  static void Dirxml(const GlobalObject& aGlobal,
     89                     const Sequence<JS::Value>& aData);
     90 
     91  MOZ_CAN_RUN_SCRIPT
     92  static void Group(const GlobalObject& aGlobal,
     93                    const Sequence<JS::Value>& aData);
     94 
     95  MOZ_CAN_RUN_SCRIPT
     96  static void GroupCollapsed(const GlobalObject& aGlobal,
     97                             const Sequence<JS::Value>& aData);
     98 
     99  MOZ_CAN_RUN_SCRIPT
    100  static void GroupEnd(const GlobalObject& aGlobal);
    101 
    102  MOZ_CAN_RUN_SCRIPT
    103  static void Time(const GlobalObject& aGlobal, const nsAString& aLabel);
    104 
    105  MOZ_CAN_RUN_SCRIPT
    106  static void TimeLog(const GlobalObject& aGlobal, const nsAString& aLabel,
    107                      const Sequence<JS::Value>& aData);
    108 
    109  MOZ_CAN_RUN_SCRIPT
    110  static void TimeEnd(const GlobalObject& aGlobal, const nsAString& aLabel);
    111 
    112  MOZ_CAN_RUN_SCRIPT
    113  static void TimeStamp(const GlobalObject& aGlobal,
    114                        const JS::Handle<JS::Value> aData);
    115 
    116  MOZ_CAN_RUN_SCRIPT
    117  static void Profile(const GlobalObject& aGlobal,
    118                      const Sequence<JS::Value>& aData);
    119 
    120  MOZ_CAN_RUN_SCRIPT
    121  static void ProfileEnd(const GlobalObject& aGlobal,
    122                         const Sequence<JS::Value>& aData);
    123 
    124  MOZ_CAN_RUN_SCRIPT
    125  static void Assert(const GlobalObject& aGlobal, bool aCondition,
    126                     const Sequence<JS::Value>& aData);
    127 
    128  MOZ_CAN_RUN_SCRIPT
    129  static void Count(const GlobalObject& aGlobal, const nsAString& aLabel);
    130 
    131  MOZ_CAN_RUN_SCRIPT
    132  static void CountReset(const GlobalObject& aGlobal, const nsAString& aLabel);
    133 
    134  MOZ_CAN_RUN_SCRIPT
    135  static void Clear(const GlobalObject& aGlobal);
    136 
    137  MOZ_CAN_RUN_SCRIPT
    138  static already_AddRefed<ConsoleInstance> CreateInstance(
    139      const GlobalObject& aGlobal, const ConsoleInstanceOptions& aOptions);
    140 
    141  void ClearStorage();
    142 
    143  void RetrieveConsoleEvents(JSContext* aCx, nsTArray<JS::Value>& aEvents,
    144                             ErrorResult& aRv);
    145 
    146  void SetConsoleEventHandler(AnyCallback* aHandler);
    147 
    148 private:
    149  Console(JSContext* aCx, nsIGlobalObject* aGlobal, uint64_t aOuterWindowID,
    150          uint64_t aInnerWIndowID, const nsAString& aPrefix = u""_ns);
    151  ~Console();
    152 
    153  void Initialize(ErrorResult& aRv);
    154 
    155  void Shutdown();
    156 
    157  enum MethodName {
    158    MethodLog,
    159    MethodInfo,
    160    MethodWarn,
    161    MethodError,
    162    MethodException,
    163    MethodDebug,
    164    MethodTable,
    165    MethodTrace,
    166    MethodDir,
    167    MethodDirxml,
    168    MethodGroup,
    169    MethodGroupCollapsed,
    170    MethodGroupEnd,
    171    MethodTime,
    172    MethodTimeLog,
    173    MethodTimeEnd,
    174    MethodTimeStamp,
    175    MethodAssert,
    176    MethodCount,
    177    MethodCountReset,
    178    MethodClear,
    179    MethodProfile,
    180    MethodProfileEnd,
    181  };
    182 
    183  static already_AddRefed<Console> GetConsole(const GlobalObject& aGlobal);
    184 
    185  static already_AddRefed<Console> GetConsoleInternal(
    186      const GlobalObject& aGlobal, ErrorResult& aRv);
    187 
    188  MOZ_CAN_RUN_SCRIPT
    189  static void ProfileMethod(const GlobalObject& aGlobal, MethodName aName,
    190                            const nsAString& aAction,
    191                            const Sequence<JS::Value>& aData);
    192 
    193  MOZ_CAN_RUN_SCRIPT
    194  void ProfileMethodInternal(JSContext* aCx, MethodName aName,
    195                             const nsAString& aAction,
    196                             const Sequence<JS::Value>& aData);
    197 
    198  // Implementation of the mainthread-only parts of ProfileMethod.
    199  // This is indepedent of console instance state.
    200  static void ProfileMethodMainthread(JSContext* aCx, const nsAString& aAction,
    201                                      const Sequence<JS::Value>& aData);
    202 
    203  MOZ_CAN_RUN_SCRIPT
    204  static void Method(const GlobalObject& aGlobal, MethodName aName,
    205                     const nsAString& aString,
    206                     const Sequence<JS::Value>& aData);
    207 
    208  MOZ_CAN_RUN_SCRIPT
    209  void MethodInternal(JSContext* aCx, MethodName aName,
    210                      const nsAString& aString,
    211                      const Sequence<JS::Value>& aData);
    212 
    213  MOZ_CAN_RUN_SCRIPT
    214  static void StringMethod(const GlobalObject& aGlobal, const nsAString& aLabel,
    215                           const Sequence<JS::Value>& aData,
    216                           MethodName aMethodName,
    217                           const nsAString& aMethodString);
    218 
    219  MOZ_CAN_RUN_SCRIPT
    220  void StringMethodInternal(JSContext* aCx, const nsAString& aLabel,
    221                            const Sequence<JS::Value>& aData,
    222                            MethodName aMethodName,
    223                            const nsAString& aMethodString);
    224 
    225  MainThreadConsoleData* GetOrCreateMainThreadData();
    226 
    227  // Returns true on success; otherwise false.
    228  bool StoreCallData(JSContext* aCx, ConsoleCallData* aCallData,
    229                     const Sequence<JS::Value>& aArguments);
    230 
    231  void UnstoreCallData(ConsoleCallData* aData);
    232 
    233  // aCx and aArguments must be in the same JS compartment.
    234  MOZ_CAN_RUN_SCRIPT
    235  void NotifyHandler(JSContext* aCx, const Sequence<JS::Value>& aArguments,
    236                     ConsoleCallData* aData);
    237 
    238  // PopulateConsoleNotificationInTheTargetScope receives aCx and aArguments in
    239  // the same JS compartment and populates the ConsoleEvent object
    240  // (aEventValue) in the aTargetScope.
    241  // aTargetScope can be:
    242  // - the system-principal scope when we want to dispatch the ConsoleEvent to
    243  //   nsIConsoleAPIStorage (See the comment in Console.cpp about the use of
    244  //   xpc::PrivilegedJunkScope()
    245  // - the mConsoleEventNotifier->CallableGlobal() when we want to notify this
    246  //   handler about a new ConsoleEvent.
    247  // - It can be the global from the JSContext when RetrieveConsoleEvents is
    248  //   called.
    249  static bool PopulateConsoleNotificationInTheTargetScope(
    250      JSContext* aCx, const Sequence<JS::Value>& aArguments,
    251      JS::Handle<JSObject*> aTargetScope,
    252      JS::MutableHandle<JS::Value> aEventValue, ConsoleCallData* aData,
    253      nsTArray<nsString>* aGroupStack);
    254 
    255  enum TimerStatus {
    256    eTimerUnknown,
    257    eTimerDone,
    258    eTimerAlreadyExists,
    259    eTimerDoesntExist,
    260    eTimerJSException,
    261    eTimerMaxReached,
    262  };
    263 
    264  static JS::Value CreateTimerError(JSContext* aCx, const nsAString& aLabel,
    265                                    TimerStatus aStatus);
    266 
    267  // StartTimer is called on the owning thread and populates aTimerLabel and
    268  // aTimerValue.
    269  // * aCx - the JSContext rooting aName.
    270  // * aName - this is (should be) the name of the timer as JS::Value.
    271  // * aTimestamp - the monotonicTimer for this context taken from
    272  //                performance.now().
    273  // * aTimerLabel - This label will be populated with the aName converted to a
    274  //                 string.
    275  // * aTimerValue - the StartTimer value stored into (or taken from)
    276  //                 mTimerRegistry.
    277  TimerStatus StartTimer(JSContext* aCx, const JS::Value& aName,
    278                         DOMHighResTimeStamp aTimestamp, nsAString& aTimerLabel,
    279                         DOMHighResTimeStamp* aTimerValue);
    280 
    281  // CreateStartTimerValue generates a ConsoleTimerStart dictionary exposed as
    282  // JS::Value. If aTimerStatus is false, it generates a ConsoleTimerError
    283  // instead. It's called only after the execution StartTimer on the owning
    284  // thread.
    285  // * aCx - this is the context that will root the returned value.
    286  // * aTimerLabel - this label must be what StartTimer received as aTimerLabel.
    287  // * aTimerStatus - the return value of StartTimer.
    288  static JS::Value CreateStartTimerValue(JSContext* aCx,
    289                                         const nsAString& aTimerLabel,
    290                                         TimerStatus aTimerStatus);
    291 
    292  // LogTimer follows the same pattern as StartTimer: it runs on the
    293  // owning thread and populates aTimerLabel and aTimerDuration, used by
    294  // CreateLogOrEndTimerValue.
    295  // * aCx - the JSContext rooting aName.
    296  // * aName - this is (should be) the name of the timer as JS::Value.
    297  // * aTimestamp - the monotonicTimer for this context taken from
    298  //                performance.now().
    299  // * aTimerLabel - This label will be populated with the aName converted to a
    300  //                 string.
    301  // * aTimerDuration - the difference between aTimestamp and when the timer
    302  //                    started (see StartTimer).
    303  // * aCancelTimer - if true, the timer is removed from the table.
    304  TimerStatus LogTimer(JSContext* aCx, const JS::Value& aName,
    305                       DOMHighResTimeStamp aTimestamp, nsAString& aTimerLabel,
    306                       double* aTimerDuration, bool aCancelTimer);
    307 
    308  // This method generates a ConsoleTimerEnd dictionary exposed as JS::Value, or
    309  // a ConsoleTimerError dictionary if aTimerStatus is false. See LogTimer.
    310  // * aCx - this is the context that will root the returned value.
    311  // * aTimerLabel - this label must be what LogTimer received as aTimerLabel.
    312  // * aTimerDuration - this is what LogTimer received as aTimerDuration
    313  // * aTimerStatus - the return value of LogTimer.
    314  static JS::Value CreateLogOrEndTimerValue(JSContext* aCx,
    315                                            const nsAString& aLabel,
    316                                            double aDuration,
    317                                            TimerStatus aStatus);
    318 
    319  // The method populates a Sequence from an array of JS::Value.
    320  bool ArgumentsToValueList(const Sequence<JS::Value>& aData,
    321                            Sequence<JS::Value>& aSequence) const;
    322 
    323  // This method follows the same pattern as StartTimer: its runs on the owning
    324  // thread and populate aCountLabel, used by CreateCounterOrResetCounterValue.
    325  // Returns 3 possible values:
    326  // * MAX_PAGE_COUNTERS in case of error that has to be reported;
    327  // * 0 in case of a CX exception. The operation cannot continue;
    328  // * the incremented counter value.
    329  // Params:
    330  // * aCx - the JSContext rooting aData.
    331  // * aData - the arguments received by the console.count() method.
    332  // * aCountLabel - the label that will be populated by this method.
    333  uint32_t IncreaseCounter(JSContext* aCx, const Sequence<JS::Value>& aData,
    334                           nsAString& aCountLabel);
    335 
    336  // This method follows the same pattern as StartTimer: its runs on the owning
    337  // thread and populate aCountLabel, used by CreateCounterResetValue. Returns
    338  // 3 possible values:
    339  // * MAX_PAGE_COUNTERS in case of error that has to be reported;
    340  // * 0 elsewhere. In case of a CX exception, aCountLabel will be an empty
    341  // string.
    342  // Params:
    343  // * aCx - the JSContext rooting aData.
    344  // * aData - the arguments received by the console.count() method.
    345  // * aCountLabel - the label that will be populated by this method.
    346  uint32_t ResetCounter(JSContext* aCx, const Sequence<JS::Value>& aData,
    347                        nsAString& aCountLabel);
    348 
    349  static bool ShouldIncludeStackTrace(MethodName aMethodName);
    350 
    351  void AssertIsOnOwningThread() const;
    352 
    353  bool IsShuttingDown() const;
    354 
    355  bool MonotonicTimer(JSContext* aCx, MethodName aMethodName,
    356                      const Sequence<JS::Value>& aData,
    357                      DOMHighResTimeStamp* aTimeStamp);
    358 
    359  void StringifyElement(Element* aElement, nsAString& aOut);
    360 
    361  MOZ_CAN_RUN_SCRIPT
    362  void MaybeExecuteDumpFunction(JSContext* aCx, MethodName aMethodName,
    363                                const nsAString& aMethodString,
    364                                const Sequence<JS::Value>& aData,
    365                                nsIStackFrame* aStack,
    366                                DOMHighResTimeStamp aMonotonicTimer);
    367 
    368  MOZ_CAN_RUN_SCRIPT
    369  nsString GetDumpMessage(JSContext* aCx, MethodName aMethodName,
    370                          const nsAString& aMethodString,
    371                          const Sequence<JS::Value>& aData,
    372                          nsIStackFrame* aStack,
    373                          DOMHighResTimeStamp aMonotonicTimer,
    374                          bool aIsForMozLog);
    375 
    376  MOZ_CAN_RUN_SCRIPT
    377  void ExecuteDumpFunction(const nsAString& aMessage);
    378 
    379  bool ShouldProceed(MethodName aName) const;
    380 
    381  uint32_t WebIDLLogLevelToInteger(ConsoleLogLevel aLevel) const;
    382 
    383  uint32_t InternalLogLevelToInteger(MethodName aName) const;
    384  LogLevel InternalLogLevelToMozLog(MethodName aName) const;
    385 
    386  class ArgumentData {
    387   public:
    388    bool Initialize(JSContext* aCx, const Sequence<JS::Value>& aArguments);
    389    void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
    390    bool PopulateArgumentsSequence(Sequence<JS::Value>& aSequence) const;
    391    JSObject* Global() const { return mGlobal; }
    392 
    393   private:
    394    void AssertIsOnOwningThread() const {
    395      NS_ASSERT_OWNINGTHREAD(ArgumentData);
    396    }
    397 
    398    NS_DECL_OWNINGTHREAD;
    399    JS::Heap<JSObject*> mGlobal;
    400    nsTArray<JS::Heap<JS::Value>> mArguments;
    401  };
    402 
    403  // Owning/CC thread only
    404  nsCOMPtr<nsIGlobalObject> mGlobal;
    405 
    406  // Touched on the owner thread.
    407  nsTHashMap<nsStringHashKey, DOMHighResTimeStamp> mTimerRegistry;
    408  nsTHashMap<nsStringHashKey, uint32_t> mCounterRegistry;
    409 
    410  nsTArray<RefPtr<ConsoleCallData>> mCallDataStorage;
    411  // These are references to the arguments we received in each call
    412  // from the DOM bindings.
    413  // Vector<T> supports non-memmovable types such as ArgumentData
    414  // (without any need to jump through hoops like
    415  // MOZ_DECLARE_RELOCATE_USING_MOVE_CONSTRUCTOR_FOR_TEMPLATE for nsTArray).
    416  Vector<ArgumentData> mArgumentStorage;
    417 
    418  RefPtr<AnyCallback> mConsoleEventNotifier;
    419 
    420  RefPtr<MainThreadConsoleData> mMainThreadData;
    421  // This is the stack for grouping relating to Console-thread events, when
    422  // the Console thread is not the main thread.
    423  nsTArray<nsString> mGroupStack;
    424 
    425  uint64_t mOuterID;
    426  uint64_t mInnerID;
    427 
    428  // Set only by ConsoleInstance:
    429  nsString mConsoleID;
    430  nsString mPassedInnerID;
    431  RefPtr<ConsoleInstanceDumpCallback> mDumpFunction;
    432  bool mDumpToStdout;
    433  LogModule* mLogModule;
    434  nsString mPrefix;
    435  bool mChromeInstance;
    436  uint32_t mCurrentLogLevel;
    437 
    438  enum { eUnknown, eInitialized, eShuttingDown } mStatus;
    439 
    440  // This is used when Console is created and it's used only for JSM custom
    441  // console instance.
    442  mozilla::TimeStamp mCreationTimeStamp;
    443 
    444  friend class ConsoleCallData;
    445  friend class ConsoleCallDataWorkletRunnable;
    446  friend class ConsoleInstance;
    447  friend class ConsoleProfileWorkerRunnable;
    448  friend class ConsoleProfileWorkletRunnable;
    449  friend class ConsoleRunnable;
    450  friend class ConsoleWorkerRunnable;
    451  friend class ConsoleWorkletRunnable;
    452  friend class MainThreadConsoleData;
    453 };
    454 
    455 }  // namespace mozilla::dom
    456 
    457 #endif /* mozilla_dom_Console_h */