diff options
Diffstat (limited to 'dom/base/TimeoutHandler.cpp')
-rw-r--r-- | dom/base/TimeoutHandler.cpp | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/dom/base/TimeoutHandler.cpp b/dom/base/TimeoutHandler.cpp new file mode 100644 index 0000000000..ddf2b6abd7 --- /dev/null +++ b/dom/base/TimeoutHandler.cpp @@ -0,0 +1,178 @@ +/* -*- 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/. */ + +#include "TimeoutHandler.h" + +#include "mozilla/Assertions.h" +#include "mozilla/HoldDropJSObjects.h" +#include "nsJSUtils.h" + +namespace mozilla::dom { + +//----------------------------------------------------------------------------- +// TimeoutHandler +//----------------------------------------------------------------------------- + +TimeoutHandler::TimeoutHandler(JSContext* aCx) : TimeoutHandler() { + nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn); +} + +bool TimeoutHandler::Call(const char* /* unused */) { return false; } + +void TimeoutHandler::GetLocation(const char** aFileName, uint32_t* aLineNo, + uint32_t* aColumn) { + *aFileName = mFileName.get(); + *aLineNo = mLineNo; + *aColumn = mColumn; +} + +void TimeoutHandler::GetDescription(nsACString& aOutString) { + aOutString.AppendPrintf("<generic handler> (%s:%d:%d)", mFileName.get(), + mLineNo, mColumn); +} + +//----------------------------------------------------------------------------- +// ScriptTimeoutHandler +//----------------------------------------------------------------------------- + +ScriptTimeoutHandler::ScriptTimeoutHandler(JSContext* aCx, + nsIGlobalObject* aGlobal, + const nsAString& aExpression) + : TimeoutHandler(aCx), mGlobal(aGlobal), mExpr(aExpression) {} + +NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptTimeoutHandler) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptTimeoutHandler) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(ScriptTimeoutHandler) + if (MOZ_UNLIKELY(cb.WantDebugInfo())) { + nsAutoCString name("ScriptTimeoutHandler"); + name.AppendLiteral(" ["); + name.Append(tmp->mFileName); + name.Append(':'); + name.AppendInt(tmp->mLineNo); + name.Append(':'); + name.AppendInt(tmp->mColumn); + name.Append(']'); + cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name.get()); + } else { + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(ScriptTimeoutHandler, tmp->mRefCnt.get()) + } + + // If we need to make TimeoutHandler CCed, don't call its Traverse method + // here, otherwise we ends up report same object twice if logging is on. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=1588208. + + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptTimeoutHandler) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptTimeoutHandler) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptTimeoutHandler) + +void ScriptTimeoutHandler::GetDescription(nsACString& aOutString) { + if (mExpr.Length() > 15) { + aOutString.AppendPrintf( + "<string handler (truncated): \"%s...\"> (%s:%d:%d)", + NS_ConvertUTF16toUTF8(Substring(mExpr, 0, 13)).get(), mFileName.get(), + mLineNo, mColumn); + } else { + aOutString.AppendPrintf("<string handler: \"%s\"> (%s:%d:%d)", + NS_ConvertUTF16toUTF8(mExpr).get(), mFileName.get(), + mLineNo, mColumn); + } +} + +//----------------------------------------------------------------------------- +// CallbackTimeoutHandler +//----------------------------------------------------------------------------- + +CallbackTimeoutHandler::CallbackTimeoutHandler( + JSContext* aCx, nsIGlobalObject* aGlobal, Function* aFunction, + nsTArray<JS::Heap<JS::Value>>&& aArguments) + : TimeoutHandler(aCx), mGlobal(aGlobal), mFunction(aFunction) { + mozilla::HoldJSObjects(this); + mArgs = std::move(aArguments); +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(CallbackTimeoutHandler) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CallbackTimeoutHandler) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mFunction) + tmp->ReleaseJSObjects(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(CallbackTimeoutHandler) + if (MOZ_UNLIKELY(cb.WantDebugInfo())) { + nsAutoCString name("CallbackTimeoutHandler"); + JSObject* obj = tmp->mFunction->CallablePreserveColor(); + JSFunction* fun = + JS_GetObjectFunction(js::UncheckedUnwrapWithoutExpose(obj)); + if (fun && JS_GetFunctionId(fun)) { + JSLinearString* funId = JS_ASSERT_STRING_IS_LINEAR(JS_GetFunctionId(fun)); + size_t size = 1 + JS_PutEscapedLinearString(nullptr, 0, funId, 0); + char* funIdName = new char[size]; + if (funIdName) { + JS_PutEscapedLinearString(funIdName, size, funId, 0); + name.AppendLiteral(" ["); + name.Append(funIdName); + delete[] funIdName; + name.Append(']'); + } + } + cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name.get()); + } else { + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(CallbackTimeoutHandler, + tmp->mRefCnt.get()) + } + + // If we need to make TimeoutHandler CCed, don't call its Traverse method + // here, otherwise we ends up report same object twice if logging is on. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=1588208. + + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFunction) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackTimeoutHandler) + for (size_t i = 0; i < tmp->mArgs.Length(); ++i) { + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArgs[i]) + } +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CallbackTimeoutHandler) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(CallbackTimeoutHandler) +NS_IMPL_CYCLE_COLLECTING_RELEASE(CallbackTimeoutHandler) + +void CallbackTimeoutHandler::ReleaseJSObjects() { + mArgs.Clear(); + mozilla::DropJSObjects(this); +} + +bool CallbackTimeoutHandler::Call(const char* aExecutionReason) { + IgnoredErrorResult rv; + JS::Rooted<JS::Value> ignoredVal(RootingCx()); + MOZ_KnownLive(mFunction)->Call(MOZ_KnownLive(mGlobal), mArgs, &ignoredVal, rv, + aExecutionReason); + return !rv.IsUncatchableException(); +} + +void CallbackTimeoutHandler::MarkForCC() { mFunction->MarkForCC(); } + +void CallbackTimeoutHandler::GetDescription(nsACString& aOutString) { + mFunction->GetDescription(aOutString); +} + +} // namespace mozilla::dom |