tor-browser

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

TimeoutHandler.cpp (8035B)


      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 #include "TimeoutHandler.h"
      8 
      9 #include "mozilla/Assertions.h"
     10 #include "mozilla/HoldDropJSObjects.h"
     11 
     12 namespace mozilla::dom {
     13 
     14 //-----------------------------------------------------------------------------
     15 // TimeoutHandler
     16 //-----------------------------------------------------------------------------
     17 
     18 bool TimeoutHandler::Call(const char* /* unused */) { return false; }
     19 
     20 void TimeoutHandler::GetDescription(nsACString& aOutString) {
     21  aOutString.AppendPrintf("<generic handler> (%s:%d:%d)",
     22                          mCaller.FileName().get(), mCaller.mLine,
     23                          mCaller.mColumn);
     24 }
     25 
     26 //-----------------------------------------------------------------------------
     27 // ScriptTimeoutHandler
     28 //-----------------------------------------------------------------------------
     29 
     30 ScriptTimeoutHandler::ScriptTimeoutHandler(JSContext* aCx,
     31                                           nsIGlobalObject* aGlobal,
     32                                           const nsAString& aExpression)
     33    : TimeoutHandler(aCx), mGlobal(aGlobal), mExpr(aExpression) {}
     34 
     35 NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptTimeoutHandler)
     36 
     37 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptTimeoutHandler)
     38  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
     39 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     40 
     41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(ScriptTimeoutHandler)
     42  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     43    nsAutoCString name("ScriptTimeoutHandler");
     44    name.AppendLiteral(" [");
     45    name.Append(tmp->mCaller.FileName());
     46    name.Append(':');
     47    name.AppendInt(tmp->mCaller.mLine);
     48    name.Append(':');
     49    name.AppendInt(tmp->mCaller.mColumn);
     50    name.Append(']');
     51    cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name.get());
     52  } else {
     53    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(ScriptTimeoutHandler, tmp->mRefCnt.get())
     54  }
     55 
     56  // If we need to make TimeoutHandler CCed, don't call its Traverse method
     57  // here, otherwise we ends up report same object twice if logging is on. See
     58  // https://bugzilla.mozilla.org/show_bug.cgi?id=1588208.
     59 
     60  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
     61 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     62 
     63 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptTimeoutHandler)
     64  NS_INTERFACE_MAP_ENTRY(nsISupports)
     65 NS_INTERFACE_MAP_END
     66 
     67 NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptTimeoutHandler)
     68 NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptTimeoutHandler)
     69 
     70 void ScriptTimeoutHandler::GetDescription(nsACString& aOutString) {
     71  if (mExpr.Length() > 15) {
     72    aOutString.AppendPrintf(
     73        "<string handler (truncated): \"%s...\"> (%s:%d:%d)",
     74        NS_ConvertUTF16toUTF8(Substring(mExpr, 0, 13)).get(),
     75        mCaller.FileName().get(), mCaller.mLine, mCaller.mColumn);
     76  } else {
     77    aOutString.AppendPrintf("<string handler: \"%s\"> (%s:%d:%d)",
     78                            NS_ConvertUTF16toUTF8(mExpr).get(),
     79                            mCaller.FileName().get(), mCaller.mLine,
     80                            mCaller.mColumn);
     81  }
     82 }
     83 
     84 //-----------------------------------------------------------------------------
     85 // CallbackTimeoutHandler
     86 //-----------------------------------------------------------------------------
     87 
     88 CallbackTimeoutHandler::CallbackTimeoutHandler(
     89    JSContext* aCx, nsIGlobalObject* aGlobal, Function* aFunction,
     90    nsTArray<JS::Heap<JS::Value>>&& aArguments)
     91    : TimeoutHandler(aCx), mGlobal(aGlobal), mFunction(aFunction) {
     92  mozilla::HoldJSObjectsWithKey(this);
     93  mArgs = std::move(aArguments);
     94 }
     95 
     96 NS_IMPL_CYCLE_COLLECTION_CLASS(CallbackTimeoutHandler)
     97 
     98 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CallbackTimeoutHandler)
     99  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
    100  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFunction)
    101  tmp->ReleaseJSObjects();
    102 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    103 
    104 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(CallbackTimeoutHandler)
    105  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
    106    nsAutoCString name("CallbackTimeoutHandler");
    107    JSObject* obj = tmp->mFunction->CallablePreserveColor();
    108    JSFunction* fun =
    109        JS_GetObjectFunction(js::UncheckedUnwrapWithoutExpose(obj));
    110    if (fun && JS_GetMaybePartialFunctionId(fun)) {
    111      JSLinearString* funId =
    112          JS_ASSERT_STRING_IS_LINEAR(JS_GetMaybePartialFunctionId(fun));
    113      size_t size = 1 + JS_PutEscapedLinearString(nullptr, 0, funId, 0);
    114      char* funIdName = new char[size];
    115      if (funIdName) {
    116        JS_PutEscapedLinearString(funIdName, size, funId, 0);
    117        name.AppendLiteral(" [");
    118        name.Append(funIdName);
    119        delete[] funIdName;
    120        name.Append(']');
    121      }
    122    }
    123    cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name.get());
    124  } else {
    125    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(CallbackTimeoutHandler,
    126                                      tmp->mRefCnt.get())
    127  }
    128 
    129  // If we need to make TimeoutHandler CCed, don't call its Traverse method
    130  // here, otherwise we ends up report same object twice if logging is on. See
    131  // https://bugzilla.mozilla.org/show_bug.cgi?id=1588208.
    132 
    133  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
    134  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFunction)
    135 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    136 
    137 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackTimeoutHandler)
    138  for (size_t i = 0; i < tmp->mArgs.Length(); ++i) {
    139    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArgs[i])
    140  }
    141 NS_IMPL_CYCLE_COLLECTION_TRACE_END
    142 
    143 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CallbackTimeoutHandler)
    144  NS_INTERFACE_MAP_ENTRY(nsISupports)
    145 NS_INTERFACE_MAP_END
    146 
    147 NS_IMPL_CYCLE_COLLECTING_ADDREF(CallbackTimeoutHandler)
    148 NS_IMPL_CYCLE_COLLECTING_RELEASE(CallbackTimeoutHandler)
    149 
    150 void CallbackTimeoutHandler::ReleaseJSObjects() {
    151  mArgs.Clear();
    152  mozilla::DropJSObjectsWithKey(this);
    153 }
    154 
    155 // This conversion is safe because JS::Heap<T> and T share the same
    156 // representation, and the codegen for Call() takes care of the Heap<>'s read
    157 // barrier.
    158 // TODO(emilio, bug 1986753): Remove this.
    159 static const nsTArray<JS::Value>& CastArgs(
    160    const nsTArray<JS::Heap<JS::Value>>& aArgs) {
    161  static_assert(sizeof(JS::Value) == sizeof(JS::Heap<JS::Value>),
    162                "JS::Heap<Value> must be binary compatible with Value.");
    163  return *reinterpret_cast<const nsTArray<JS::Value>*>(&aArgs);
    164 }
    165 
    166 bool CallbackTimeoutHandler::Call(const char* aExecutionReason) {
    167  IgnoredErrorResult rv;
    168  JS::Rooted<JS::Value> ignoredVal(RootingCx());
    169  MOZ_KnownLive(mFunction)->Call(MOZ_KnownLive(mGlobal), CastArgs(mArgs),
    170                                 &ignoredVal, rv, aExecutionReason);
    171  return !rv.IsUncatchableException();
    172 }
    173 
    174 void CallbackTimeoutHandler::MarkForCC() { mFunction->MarkForCC(); }
    175 
    176 void CallbackTimeoutHandler::GetDescription(nsACString& aOutString) {
    177  mFunction->GetDescription(aOutString);
    178 }
    179 
    180 //-----------------------------------------------------------------------------
    181 // DelayedJSDispatchableHandler
    182 //-----------------------------------------------------------------------------
    183 
    184 MOZ_CAN_RUN_SCRIPT bool DelayedJSDispatchableHandler::Call(
    185    const char* /* unused */) {
    186  MOZ_ASSERT(mDispatchable);
    187 
    188  // We get the cx in whatever state, as if we have already shutdown
    189  // then the notify task will already be cleared.
    190  JSContext* cx = danger::GetJSContext();
    191 
    192  JS::Dispatchable::Run(cx, std::move(mDispatchable),
    193                        JS::Dispatchable::NotShuttingDown);
    194  return true;
    195 }
    196 
    197 DelayedJSDispatchableHandler::~DelayedJSDispatchableHandler() {
    198  if (mDispatchable) {
    199    // If we shutdown with the DelayedJSDispatchableHandler still holding
    200    // the reference to mDispatchable, release it to the engine for cleanup.
    201    // In the case of WaitAsyncTimeoutTask, this will clear the task, and
    202    // delete itself.
    203    JS::Dispatchable::ReleaseFailedTask(std::move(mDispatchable));
    204  }
    205 }
    206 
    207 NS_IMPL_ISUPPORTS(DelayedJSDispatchableHandler, nsISupports)
    208 
    209 }  // namespace mozilla::dom