diff options
Diffstat (limited to '')
-rw-r--r-- | dom/base/nsJSEnvironment.h | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h new file mode 100644 index 0000000000..41e7123a62 --- /dev/null +++ b/dom/base/nsJSEnvironment.h @@ -0,0 +1,219 @@ +/* -*- 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 nsJSEnvironment_h +#define nsJSEnvironment_h + +#include "nsIScriptContext.h" +#include "nsIScriptGlobalObject.h" +#include "nsCOMPtr.h" +#include "prtime.h" +#include "nsCycleCollectionParticipant.h" +#include "nsIArray.h" +#include "mozilla/Attributes.h" +#include "mozilla/TimeStamp.h" +#include "nsThreadUtils.h" +#include "xpcpublic.h" + +class nsICycleCollectorListener; +class nsIDocShell; + +namespace mozilla { + +template <class> +class Maybe; +struct CycleCollectorResults; + +static const uint32_t kMajorForgetSkippableCalls = 5; + +} // namespace mozilla + +class nsJSContext : public nsIScriptContext { + public: + nsJSContext(bool aGCOnDestruction, nsIScriptGlobalObject* aGlobalObject); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext, + nsIScriptContext) + + virtual nsIScriptGlobalObject* GetGlobalObject() override; + inline nsIScriptGlobalObject* GetGlobalObjectRef() { + return mGlobalObjectRef; + } + + virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget, + const char* aPropName, + nsISupports* aVal) override; + + virtual bool GetProcessingScriptTag() override; + virtual void SetProcessingScriptTag(bool aResult) override; + + virtual nsresult InitClasses(JS::Handle<JSObject*> aGlobalObj) override; + + virtual void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) override; + virtual JSObject* GetWindowProxy() override; + + enum IsShrinking { ShrinkingGC, NonShrinkingGC }; + + // Setup all the statics etc - safe to call multiple times after Startup(). + static void EnsureStatics(); + + static void SetLowMemoryState(bool aState); + + static void GarbageCollectNow(JS::GCReason reason, + IsShrinking aShrinking = NonShrinkingGC); + + static void RunIncrementalGCSlice(JS::GCReason aReason, + IsShrinking aShrinking, + js::SliceBudget& aBudget); + + static void CycleCollectNow(mozilla::CCReason aReason, + nsICycleCollectorListener* aListener = nullptr); + + // Finish up any in-progress incremental GC. + static void PrepareForCycleCollectionSlice(mozilla::CCReason aReason, + mozilla::TimeStamp aDeadline); + + // Run a cycle collector slice, using a heuristic to decide how long to run + // it. + static void RunCycleCollectorSlice(mozilla::CCReason aReason, + mozilla::TimeStamp aDeadline); + + // Run a cycle collector slice, using the given work budget. + static void RunCycleCollectorWorkSlice(int64_t aWorkBudget); + + static void BeginCycleCollectionCallback(mozilla::CCReason aReason); + static void EndCycleCollectionCallback( + const mozilla::CycleCollectorResults& aResults); + + // Return the longest CC slice time since ClearMaxCCSliceTime() was last + // called. + static uint32_t GetMaxCCSliceTimeSinceClear(); + static void ClearMaxCCSliceTime(); + + // If there is some pending CC or GC timer/runner, this will run it. + static void RunNextCollectorTimer( + JS::GCReason aReason, + mozilla::TimeStamp aDeadline = mozilla::TimeStamp()); + // If user has been idle and aDocShell is for an iframe being loaded in an + // already loaded top level docshell, this will run a CC or GC + // timer/runner if there is such pending. + static void MaybeRunNextCollectorSlice(nsIDocShell* aDocShell, + JS::GCReason aReason); + + // The GC should run soon, in the zone of aObj if given. If aObj is + // nullptr, collect all Zones. + static void PokeGC(JS::GCReason aReason, JSObject* aObj, + mozilla::TimeDuration aDelay = 0); + + // If usage is nearing a threshold, request idle-only GC work. (This is called + // when a collection would be relatively convenient.) + static void MaybePokeGC(); + + // Immediately perform a non-incremental shrinking GC and CC. + static void DoLowMemoryGC(); + + // Perform a non-incremental shrinking GC and CC according to + // IdleScheduler. + static void LowMemoryGC(); + + static void MaybePokeCC(); + + // Calling LikelyShortLivingObjectCreated() makes a GC more likely. + static void LikelyShortLivingObjectCreated(); + + static bool HasHadCleanupSinceLastGC(); + + nsIScriptGlobalObject* GetCachedGlobalObject() { + // Verify that we have a global so that this + // does always return a null when GetGlobalObject() is null. + JSObject* global = GetWindowProxy(); + return global ? mGlobalObjectRef.get() : nullptr; + } + + protected: + virtual ~nsJSContext(); + + // Helper to convert xpcom datatypes to jsvals. + nsresult ConvertSupportsTojsvals(JSContext* aCx, nsISupports* aArgs, + JS::Handle<JSObject*> aScope, + JS::MutableHandleVector<JS::Value> aArgsOut); + + nsresult AddSupportsPrimitiveTojsvals(JSContext* aCx, nsISupports* aArg, + JS::Value* aArgv); + + private: + void Destroy(); + + JS::Heap<JSObject*> mWindowProxy; + + bool mGCOnDestruction; + bool mProcessingScriptTag; + + // mGlobalObjectRef ensures that the outer window stays alive as long as the + // context does. It is eventually collected by the cycle collector. + nsCOMPtr<nsIScriptGlobalObject> mGlobalObjectRef; + + static bool DOMOperationCallback(JSContext* cx); +}; + +namespace mozilla::dom { + +class SerializedStackHolder; + +void StartupJSEnvironment(); +void ShutdownJSEnvironment(); + +// Runnable that's used to do async error reporting +class AsyncErrorReporter final : public mozilla::Runnable { + public: + explicit AsyncErrorReporter(xpc::ErrorReport* aReport); + // SerializeStack is suitable for main or worklet thread use. + // Stacks from worker threads are not supported. + // See https://bugzilla.mozilla.org/show_bug.cgi?id=1578968 + void SerializeStack(JSContext* aCx, JS::Handle<JSObject*> aStack); + + // Set the exception value associated with this error report. + // Should only be called from the main thread. + void SetException(JSContext* aCx, JS::Handle<JS::Value> aException); + + protected: + NS_IMETHOD Run() override; + + // This is only used on main thread! + JS::PersistentRooted<JS::Value> mException; + bool mHasException = false; + + RefPtr<xpc::ErrorReport> mReport; + // This may be used to marshal a stack from an arbitrary thread/runtime into + // the main thread/runtime where the console service runs. + UniquePtr<SerializedStackHolder> mStackHolder; +}; + +} // namespace mozilla::dom + +// An interface for fast and native conversion to/from nsIArray. If an object +// supports this interface, JS can reach directly in for the argv, and avoid +// nsISupports conversion. If this interface is not supported, the object will +// be queried for nsIArray, and everything converted via xpcom objects. +#define NS_IJSARGARRAY_IID \ + { \ + 0xb6acdac8, 0xf5c6, 0x432c, { \ + 0xa8, 0x6e, 0x33, 0xee, 0xb1, 0xb0, 0xcd, 0xdc \ + } \ + } + +class nsIJSArgArray : public nsIArray { + public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSARGARRAY_IID) + // Bug 312003 describes why this must be "void **", but after calling argv + // may be cast to JS::Value* and the args found at: + // ((JS::Value*)argv)[0], ..., ((JS::Value*)argv)[argc - 1] + virtual nsresult GetArgs(uint32_t* argc, void** argv) = 0; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSArgArray, NS_IJSARGARRAY_IID) + +#endif /* nsJSEnvironment_h */ |