2013-06-18 23:02:07 +04:00
|
|
|
/* -*- 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/. */
|
|
|
|
|
2016-09-14 16:47:32 +03:00
|
|
|
#ifndef mozilla_CycleCollectedJSContext_h__
|
|
|
|
#define mozilla_CycleCollectedJSContext_h__
|
2013-06-18 23:02:07 +04:00
|
|
|
|
2015-05-02 05:33:01 +03:00
|
|
|
#include <queue>
|
|
|
|
|
2015-03-18 21:36:03 +03:00
|
|
|
#include "mozilla/DeferredFinalize.h"
|
2015-12-31 16:21:49 +03:00
|
|
|
#include "mozilla/mozalloc.h"
|
2013-06-23 16:03:39 +04:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
2015-12-31 16:21:49 +03:00
|
|
|
#include "mozilla/SegmentedVector.h"
|
2013-06-18 23:02:07 +04:00
|
|
|
#include "jsapi.h"
|
2016-03-02 20:38:24 +03:00
|
|
|
#include "jsfriendapi.h"
|
2013-06-18 23:02:07 +04:00
|
|
|
|
2013-06-18 23:02:15 +04:00
|
|
|
#include "nsCycleCollectionParticipant.h"
|
2013-06-18 23:02:14 +04:00
|
|
|
#include "nsDataHashtable.h"
|
|
|
|
#include "nsHashKeys.h"
|
2013-07-09 18:28:15 +04:00
|
|
|
#include "nsTArray.h"
|
2016-02-19 02:21:48 +03:00
|
|
|
#include "nsTHashtable.h"
|
2013-06-18 23:02:14 +04:00
|
|
|
|
2013-06-18 23:02:15 +04:00
|
|
|
class nsCycleCollectionNoteRootCallback;
|
2013-09-09 07:28:50 +04:00
|
|
|
class nsIException;
|
2014-10-28 15:08:19 +03:00
|
|
|
class nsIRunnable;
|
Bug 1179909: Refactor stable state handling. r=smaug
This is motivated by three separate but related problems:
1. Our concept of recursion depth is broken for things that run from AfterProcessNextEvent observers (e.g. Promises). We decrement the recursionDepth counter before firing observers, so a Promise callback running at the lowest event loop depth has a recursion depth of 0 (whereas a regular nsIRunnable would be 1). This is a problem because it's impossible to distinguish a Promise running after a sync XHR's onreadystatechange handler from a top-level event (since the former runs with depth 2 - 1 = 1, and the latter runs with just 1).
2. The nsIThreadObserver mechanism that is used by a lot of code to run "after" the current event is a poor fit for anything that runs script. First, the order the observers fire in is the order they were added, not anything fixed by spec. Additionally, running script can cause the event loop to spin, which is a big source of pain here (bholley has some nasty bug caused by this).
3. We run Promises from different points in the code for workers and main thread. The latter runs from XPConnect's nsIThreadObserver callbacks, while the former runs from a hardcoded call to run Promises in the worker event loop. What workers do is particularly problematic because it means we can't get the right recursion depth no matter what we do to nsThread.
The solve this, this patch does the following:
1. Consolidate some handling of microtasks and all handling of stable state from appshell and WorkerPrivate into CycleCollectedJSRuntime.
2. Make the recursionDepth counter only available to CycleCollectedJSRuntime (and its consumers) and remove it from the nsIThreadInternal and nsIThreadObserver APIs.
3. Adjust the recursionDepth counter so that microtasks run with the recursionDepth of the task they are associated with.
4. Introduce the concept of metastable state to replace appshell's RunBeforeNextEvent. Metastable state is reached after every microtask or task is completed. This provides the semantics that bent and I want for IndexedDB, where transactions autocommit at the end of a microtask and do not "spill" from one microtask into a subsequent microtask. This differs from appshell's RunBeforeNextEvent in two ways:
a) It fires between microtasks, which was the motivation for starting this.
b) It no longer ensures that we're at the same event loop depth in the native event queue. bent decided we don't care about this.
5. Reorder stable state to happen after microtasks such as Promises, per HTML. Right now we call the regular thread observers, including appshell, before the main thread observer (XPConnect), so stable state tasks happen before microtasks.
2015-08-11 16:10:46 +03:00
|
|
|
class nsThread;
|
2015-12-31 16:21:49 +03:00
|
|
|
class nsWrapperCache;
|
2013-06-18 23:02:14 +04:00
|
|
|
|
2013-09-19 22:29:31 +04:00
|
|
|
namespace js {
|
2014-06-19 04:57:51 +04:00
|
|
|
struct Class;
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace js
|
2013-09-19 22:29:31 +04:00
|
|
|
|
2013-06-18 23:02:07 +04:00
|
|
|
namespace mozilla {
|
|
|
|
|
2013-06-18 23:02:15 +04:00
|
|
|
class JSGCThingParticipant: public nsCycleCollectionParticipant
|
|
|
|
{
|
|
|
|
public:
|
2017-01-25 00:11:56 +03:00
|
|
|
constexpr JSGCThingParticipant()
|
|
|
|
: nsCycleCollectionParticipant(false) {}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
NS_IMETHOD_(void) Root(void*) override
|
2013-06-18 23:02:15 +04:00
|
|
|
{
|
2014-10-25 02:06:56 +04:00
|
|
|
MOZ_ASSERT(false, "Don't call Root on GC things");
|
2013-06-18 23:02:15 +04:00
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
NS_IMETHOD_(void) Unlink(void*) override
|
2013-06-18 23:02:15 +04:00
|
|
|
{
|
2014-10-25 02:06:56 +04:00
|
|
|
MOZ_ASSERT(false, "Don't call Unlink on GC things, as they may be dead");
|
2013-06-18 23:02:15 +04:00
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
NS_IMETHOD_(void) Unroot(void*) override
|
2013-06-18 23:02:15 +04:00
|
|
|
{
|
2014-10-25 02:06:56 +04:00
|
|
|
MOZ_ASSERT(false, "Don't call Unroot on GC things, as they may be dead");
|
2013-06-18 23:02:15 +04:00
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
NS_IMETHOD_(void) DeleteCycleCollectable(void* aPtr) override
|
2013-06-18 23:02:15 +04:00
|
|
|
{
|
2014-10-25 02:06:56 +04:00
|
|
|
MOZ_ASSERT(false, "Can't directly delete a cycle collectable GC thing");
|
2013-06-18 23:02:15 +04:00
|
|
|
}
|
|
|
|
|
2017-01-03 22:50:10 +03:00
|
|
|
NS_IMETHOD TraverseNative(void* aPtr, nsCycleCollectionTraversalCallback& aCb)
|
2015-03-21 19:28:04 +03:00
|
|
|
override;
|
2016-05-12 20:54:33 +03:00
|
|
|
|
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS_NAME_METHOD(JSGCThingParticipant)
|
2013-06-18 23:02:15 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
class JSZoneParticipant : public nsCycleCollectionParticipant
|
|
|
|
{
|
|
|
|
public:
|
2017-01-25 00:11:56 +03:00
|
|
|
constexpr JSZoneParticipant(): nsCycleCollectionParticipant(false)
|
2014-05-13 21:41:38 +04:00
|
|
|
{
|
|
|
|
}
|
2013-06-18 23:02:15 +04:00
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
NS_IMETHOD_(void) Root(void*) override
|
2013-06-18 23:02:15 +04:00
|
|
|
{
|
2014-10-25 02:06:56 +04:00
|
|
|
MOZ_ASSERT(false, "Don't call Root on GC things");
|
2013-06-18 23:02:15 +04:00
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
NS_IMETHOD_(void) Unlink(void*) override
|
2013-06-18 23:02:15 +04:00
|
|
|
{
|
2014-10-25 02:06:56 +04:00
|
|
|
MOZ_ASSERT(false, "Don't call Unlink on GC things, as they may be dead");
|
2013-06-18 23:02:15 +04:00
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
NS_IMETHOD_(void) Unroot(void*) override
|
2013-06-18 23:02:15 +04:00
|
|
|
{
|
2014-10-25 02:06:56 +04:00
|
|
|
MOZ_ASSERT(false, "Don't call Unroot on GC things, as they may be dead");
|
2013-06-18 23:02:15 +04:00
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
NS_IMETHOD_(void) DeleteCycleCollectable(void*) override
|
2013-06-18 23:02:15 +04:00
|
|
|
{
|
2014-10-25 02:06:56 +04:00
|
|
|
MOZ_ASSERT(false, "Can't directly delete a cycle collectable GC thing");
|
2013-06-18 23:02:15 +04:00
|
|
|
}
|
|
|
|
|
2017-01-03 22:50:10 +03:00
|
|
|
NS_IMETHOD TraverseNative(void* aPtr, nsCycleCollectionTraversalCallback& aCb)
|
2015-03-21 19:28:04 +03:00
|
|
|
override;
|
2016-05-12 20:54:33 +03:00
|
|
|
|
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS_NAME_METHOD(JSZoneParticipant)
|
2013-06-18 23:02:15 +04:00
|
|
|
};
|
|
|
|
|
2013-07-09 18:28:15 +04:00
|
|
|
class IncrementalFinalizeRunnable;
|
|
|
|
|
2013-11-21 02:35:16 +04:00
|
|
|
// Contains various stats about the cycle collection.
|
|
|
|
struct CycleCollectorResults
|
|
|
|
{
|
2014-05-07 04:25:26 +04:00
|
|
|
CycleCollectorResults()
|
|
|
|
{
|
|
|
|
// Initialize here so when we increment mNumSlices the first time we're
|
|
|
|
// not using uninitialized memory.
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
|
2013-11-21 02:35:16 +04:00
|
|
|
void Init()
|
|
|
|
{
|
|
|
|
mForcedGC = false;
|
|
|
|
mMergedZones = false;
|
2015-05-13 22:48:52 +03:00
|
|
|
mAnyManual = false;
|
2013-11-21 02:35:16 +04:00
|
|
|
mVisitedRefCounted = 0;
|
|
|
|
mVisitedGCed = 0;
|
|
|
|
mFreedRefCounted = 0;
|
|
|
|
mFreedGCed = 0;
|
2014-10-20 21:07:52 +04:00
|
|
|
mFreedJSZones = 0;
|
2014-05-07 04:25:26 +04:00
|
|
|
mNumSlices = 1;
|
|
|
|
// mNumSlices is initialized to one, because we call Init() after the
|
|
|
|
// per-slice increment of mNumSlices has already occurred.
|
2013-11-21 02:35:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool mForcedGC;
|
|
|
|
bool mMergedZones;
|
2015-05-13 22:48:52 +03:00
|
|
|
bool mAnyManual; // true if any slice of the CC was manually triggered, or at shutdown.
|
2013-11-21 02:35:16 +04:00
|
|
|
uint32_t mVisitedRefCounted;
|
|
|
|
uint32_t mVisitedGCed;
|
|
|
|
uint32_t mFreedRefCounted;
|
|
|
|
uint32_t mFreedGCed;
|
2014-10-20 21:07:52 +04:00
|
|
|
uint32_t mFreedJSZones;
|
2014-05-07 04:25:26 +04:00
|
|
|
uint32_t mNumSlices;
|
2013-11-21 02:35:16 +04:00
|
|
|
};
|
|
|
|
|
2016-09-14 16:47:32 +03:00
|
|
|
class CycleCollectedJSContext
|
2013-06-18 23:02:07 +04:00
|
|
|
{
|
2013-06-18 23:02:15 +04:00
|
|
|
friend class JSGCThingParticipant;
|
|
|
|
friend class JSZoneParticipant;
|
2013-07-09 18:28:15 +04:00
|
|
|
friend class IncrementalFinalizeRunnable;
|
2013-06-18 23:02:07 +04:00
|
|
|
protected:
|
2016-09-14 16:47:32 +03:00
|
|
|
CycleCollectedJSContext();
|
|
|
|
virtual ~CycleCollectedJSContext();
|
2013-06-18 23:02:07 +04:00
|
|
|
|
2016-09-16 13:31:37 +03:00
|
|
|
MOZ_IS_CLASS_INIT
|
2017-02-11 02:47:50 +03:00
|
|
|
nsresult Initialize(JSRuntime* aParentRuntime,
|
2016-02-14 16:30:25 +03:00
|
|
|
uint32_t aMaxBytes,
|
|
|
|
uint32_t aMaxNurseryBytes);
|
|
|
|
|
2013-06-23 16:03:39 +04:00
|
|
|
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
2013-06-18 23:02:16 +04:00
|
|
|
void UnmarkSkippableJSHolders();
|
|
|
|
|
2014-08-25 23:17:24 +04:00
|
|
|
virtual void
|
|
|
|
TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& aCb) {}
|
|
|
|
virtual void TraceAdditionalNativeGrayRoots(JSTracer* aTracer) {}
|
2013-06-18 23:02:15 +04:00
|
|
|
|
2014-08-25 23:17:24 +04:00
|
|
|
virtual void CustomGCCallback(JSGCStatus aStatus) {}
|
|
|
|
virtual void CustomOutOfMemoryCallback() {}
|
|
|
|
virtual void CustomLargeAllocationFailureCallback() {}
|
2013-07-09 18:28:15 +04:00
|
|
|
|
2016-03-24 18:12:00 +03:00
|
|
|
std::queue<nsCOMPtr<nsIRunnable>> mPromiseMicroTaskQueue;
|
|
|
|
std::queue<nsCOMPtr<nsIRunnable>> mDebuggerPromiseMicroTaskQueue;
|
|
|
|
|
2013-06-18 23:02:15 +04:00
|
|
|
private:
|
2013-06-18 23:02:15 +04:00
|
|
|
void
|
2015-01-09 02:30:54 +03:00
|
|
|
DescribeGCThing(bool aIsMarked, JS::GCCellPtr aThing,
|
2013-06-18 23:02:15 +04:00
|
|
|
nsCycleCollectionTraversalCallback& aCb) const;
|
|
|
|
|
|
|
|
virtual bool
|
2013-09-11 16:49:05 +04:00
|
|
|
DescribeCustomObjects(JSObject* aObject, const js::Class* aClasp,
|
2013-08-04 03:55:40 +04:00
|
|
|
char (&aName)[72]) const
|
|
|
|
{
|
|
|
|
return false; // We did nothing.
|
|
|
|
}
|
2013-06-18 23:02:15 +04:00
|
|
|
|
|
|
|
void
|
2015-01-09 02:30:54 +03:00
|
|
|
NoteGCThingJSChildren(JS::GCCellPtr aThing,
|
2013-06-18 23:02:15 +04:00
|
|
|
nsCycleCollectionTraversalCallback& aCb) const;
|
|
|
|
|
|
|
|
void
|
2013-09-11 16:49:05 +04:00
|
|
|
NoteGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj,
|
2013-06-18 23:02:15 +04:00
|
|
|
nsCycleCollectionTraversalCallback& aCb) const;
|
|
|
|
|
|
|
|
virtual bool
|
2013-09-11 16:49:05 +04:00
|
|
|
NoteCustomGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj,
|
2013-08-04 03:55:40 +04:00
|
|
|
nsCycleCollectionTraversalCallback& aCb) const
|
|
|
|
{
|
|
|
|
return false; // We did nothing.
|
|
|
|
}
|
2013-06-18 23:02:15 +04:00
|
|
|
|
|
|
|
enum TraverseSelect {
|
2014-05-05 21:30:39 +04:00
|
|
|
TRAVERSE_CPP,
|
|
|
|
TRAVERSE_FULL
|
2013-06-18 23:02:15 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2015-01-09 02:30:54 +03:00
|
|
|
TraverseGCThing(TraverseSelect aTs, JS::GCCellPtr aThing,
|
2013-06-18 23:02:15 +04:00
|
|
|
nsCycleCollectionTraversalCallback& aCb);
|
|
|
|
|
|
|
|
void
|
|
|
|
TraverseZone(JS::Zone* aZone, nsCycleCollectionTraversalCallback& aCb);
|
|
|
|
|
|
|
|
static void
|
2014-12-05 20:38:33 +03:00
|
|
|
TraverseObjectShim(void* aData, JS::GCCellPtr aThing);
|
2013-06-18 23:02:15 +04:00
|
|
|
|
2013-06-18 23:02:15 +04:00
|
|
|
void TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb);
|
2013-06-18 23:02:15 +04:00
|
|
|
|
2013-06-18 23:02:16 +04:00
|
|
|
static void TraceBlackJS(JSTracer* aTracer, void* aData);
|
2013-06-18 23:02:15 +04:00
|
|
|
static void TraceGrayJS(JSTracer* aTracer, void* aData);
|
2016-07-23 20:52:47 +03:00
|
|
|
static void GCCallback(JSContext* aContext, JSGCStatus aStatus, void* aData);
|
|
|
|
static void GCSliceCallback(JSContext* aContext, JS::GCProgress aProgress,
|
2015-04-22 19:43:02 +03:00
|
|
|
const JS::GCDescription& aDesc);
|
2016-07-23 20:52:47 +03:00
|
|
|
static void GCNurseryCollectionCallback(JSContext* aContext,
|
2016-01-19 23:48:22 +03:00
|
|
|
JS::GCNurseryProgress aProgress,
|
|
|
|
JS::gcreason::Reason aReason);
|
2014-08-25 23:17:24 +04:00
|
|
|
static void OutOfMemoryCallback(JSContext* aContext, void* aData);
|
|
|
|
static void LargeAllocationFailureCallback(void* aData);
|
2016-12-30 00:19:27 +03:00
|
|
|
/**
|
|
|
|
* Callback for reporting external string memory.
|
|
|
|
*/
|
|
|
|
static size_t SizeofExternalStringCallback(JSString* aStr,
|
|
|
|
mozilla::MallocSizeOf aMallocSizeOf);
|
|
|
|
|
2013-08-09 02:53:04 +04:00
|
|
|
static bool ContextCallback(JSContext* aCx, unsigned aOperation,
|
|
|
|
void* aData);
|
2016-07-02 03:00:47 +03:00
|
|
|
static JSObject* GetIncumbentGlobalCallback(JSContext* aCx);
|
2016-02-10 01:40:31 +03:00
|
|
|
static bool EnqueuePromiseJobCallback(JSContext* aCx,
|
|
|
|
JS::HandleObject aJob,
|
2016-03-22 18:22:23 +03:00
|
|
|
JS::HandleObject aAllocationSite,
|
2016-07-02 03:00:47 +03:00
|
|
|
JS::HandleObject aIncumbentGlobal,
|
2016-02-10 01:40:31 +03:00
|
|
|
void* aData);
|
2016-03-22 18:22:24 +03:00
|
|
|
static void PromiseRejectionTrackerCallback(JSContext* aCx,
|
|
|
|
JS::HandleObject aPromise,
|
|
|
|
PromiseRejectionHandlingState state,
|
|
|
|
void* aData);
|
2013-06-18 23:02:15 +04:00
|
|
|
|
2013-06-18 23:02:16 +04:00
|
|
|
virtual void TraceNativeBlackRoots(JSTracer* aTracer) { };
|
|
|
|
void TraceNativeGrayRoots(JSTracer* aTracer);
|
2013-06-18 23:02:15 +04:00
|
|
|
|
Bug 1179909: Refactor stable state handling. r=smaug
This is motivated by three separate but related problems:
1. Our concept of recursion depth is broken for things that run from AfterProcessNextEvent observers (e.g. Promises). We decrement the recursionDepth counter before firing observers, so a Promise callback running at the lowest event loop depth has a recursion depth of 0 (whereas a regular nsIRunnable would be 1). This is a problem because it's impossible to distinguish a Promise running after a sync XHR's onreadystatechange handler from a top-level event (since the former runs with depth 2 - 1 = 1, and the latter runs with just 1).
2. The nsIThreadObserver mechanism that is used by a lot of code to run "after" the current event is a poor fit for anything that runs script. First, the order the observers fire in is the order they were added, not anything fixed by spec. Additionally, running script can cause the event loop to spin, which is a big source of pain here (bholley has some nasty bug caused by this).
3. We run Promises from different points in the code for workers and main thread. The latter runs from XPConnect's nsIThreadObserver callbacks, while the former runs from a hardcoded call to run Promises in the worker event loop. What workers do is particularly problematic because it means we can't get the right recursion depth no matter what we do to nsThread.
The solve this, this patch does the following:
1. Consolidate some handling of microtasks and all handling of stable state from appshell and WorkerPrivate into CycleCollectedJSRuntime.
2. Make the recursionDepth counter only available to CycleCollectedJSRuntime (and its consumers) and remove it from the nsIThreadInternal and nsIThreadObserver APIs.
3. Adjust the recursionDepth counter so that microtasks run with the recursionDepth of the task they are associated with.
4. Introduce the concept of metastable state to replace appshell's RunBeforeNextEvent. Metastable state is reached after every microtask or task is completed. This provides the semantics that bent and I want for IndexedDB, where transactions autocommit at the end of a microtask and do not "spill" from one microtask into a subsequent microtask. This differs from appshell's RunBeforeNextEvent in two ways:
a) It fires between microtasks, which was the motivation for starting this.
b) It no longer ensures that we're at the same event loop depth in the native event queue. bent decided we don't care about this.
5. Reorder stable state to happen after microtasks such as Promises, per HTML. Right now we call the regular thread observers, including appshell, before the main thread observer (XPConnect), so stable state tasks happen before microtasks.
2015-08-11 16:10:46 +03:00
|
|
|
void AfterProcessMicrotask(uint32_t aRecursionDepth);
|
2016-01-13 01:37:57 +03:00
|
|
|
public:
|
Bug 1179909: Refactor stable state handling. r=smaug
This is motivated by three separate but related problems:
1. Our concept of recursion depth is broken for things that run from AfterProcessNextEvent observers (e.g. Promises). We decrement the recursionDepth counter before firing observers, so a Promise callback running at the lowest event loop depth has a recursion depth of 0 (whereas a regular nsIRunnable would be 1). This is a problem because it's impossible to distinguish a Promise running after a sync XHR's onreadystatechange handler from a top-level event (since the former runs with depth 2 - 1 = 1, and the latter runs with just 1).
2. The nsIThreadObserver mechanism that is used by a lot of code to run "after" the current event is a poor fit for anything that runs script. First, the order the observers fire in is the order they were added, not anything fixed by spec. Additionally, running script can cause the event loop to spin, which is a big source of pain here (bholley has some nasty bug caused by this).
3. We run Promises from different points in the code for workers and main thread. The latter runs from XPConnect's nsIThreadObserver callbacks, while the former runs from a hardcoded call to run Promises in the worker event loop. What workers do is particularly problematic because it means we can't get the right recursion depth no matter what we do to nsThread.
The solve this, this patch does the following:
1. Consolidate some handling of microtasks and all handling of stable state from appshell and WorkerPrivate into CycleCollectedJSRuntime.
2. Make the recursionDepth counter only available to CycleCollectedJSRuntime (and its consumers) and remove it from the nsIThreadInternal and nsIThreadObserver APIs.
3. Adjust the recursionDepth counter so that microtasks run with the recursionDepth of the task they are associated with.
4. Introduce the concept of metastable state to replace appshell's RunBeforeNextEvent. Metastable state is reached after every microtask or task is completed. This provides the semantics that bent and I want for IndexedDB, where transactions autocommit at the end of a microtask and do not "spill" from one microtask into a subsequent microtask. This differs from appshell's RunBeforeNextEvent in two ways:
a) It fires between microtasks, which was the motivation for starting this.
b) It no longer ensures that we're at the same event loop depth in the native event queue. bent decided we don't care about this.
5. Reorder stable state to happen after microtasks such as Promises, per HTML. Right now we call the regular thread observers, including appshell, before the main thread observer (XPConnect), so stable state tasks happen before microtasks.
2015-08-11 16:10:46 +03:00
|
|
|
void ProcessStableStateQueue();
|
2016-01-13 01:37:57 +03:00
|
|
|
private:
|
Bug 1179909: Refactor stable state handling. r=smaug
This is motivated by three separate but related problems:
1. Our concept of recursion depth is broken for things that run from AfterProcessNextEvent observers (e.g. Promises). We decrement the recursionDepth counter before firing observers, so a Promise callback running at the lowest event loop depth has a recursion depth of 0 (whereas a regular nsIRunnable would be 1). This is a problem because it's impossible to distinguish a Promise running after a sync XHR's onreadystatechange handler from a top-level event (since the former runs with depth 2 - 1 = 1, and the latter runs with just 1).
2. The nsIThreadObserver mechanism that is used by a lot of code to run "after" the current event is a poor fit for anything that runs script. First, the order the observers fire in is the order they were added, not anything fixed by spec. Additionally, running script can cause the event loop to spin, which is a big source of pain here (bholley has some nasty bug caused by this).
3. We run Promises from different points in the code for workers and main thread. The latter runs from XPConnect's nsIThreadObserver callbacks, while the former runs from a hardcoded call to run Promises in the worker event loop. What workers do is particularly problematic because it means we can't get the right recursion depth no matter what we do to nsThread.
The solve this, this patch does the following:
1. Consolidate some handling of microtasks and all handling of stable state from appshell and WorkerPrivate into CycleCollectedJSRuntime.
2. Make the recursionDepth counter only available to CycleCollectedJSRuntime (and its consumers) and remove it from the nsIThreadInternal and nsIThreadObserver APIs.
3. Adjust the recursionDepth counter so that microtasks run with the recursionDepth of the task they are associated with.
4. Introduce the concept of metastable state to replace appshell's RunBeforeNextEvent. Metastable state is reached after every microtask or task is completed. This provides the semantics that bent and I want for IndexedDB, where transactions autocommit at the end of a microtask and do not "spill" from one microtask into a subsequent microtask. This differs from appshell's RunBeforeNextEvent in two ways:
a) It fires between microtasks, which was the motivation for starting this.
b) It no longer ensures that we're at the same event loop depth in the native event queue. bent decided we don't care about this.
5. Reorder stable state to happen after microtasks such as Promises, per HTML. Right now we call the regular thread observers, including appshell, before the main thread observer (XPConnect), so stable state tasks happen before microtasks.
2015-08-11 16:10:46 +03:00
|
|
|
void ProcessMetastableStateQueue(uint32_t aRecursionDepth);
|
|
|
|
|
2015-05-13 22:48:52 +03:00
|
|
|
public:
|
2013-07-09 18:28:15 +04:00
|
|
|
enum DeferredFinalizeType {
|
|
|
|
FinalizeIncrementally,
|
|
|
|
FinalizeNow,
|
|
|
|
};
|
|
|
|
|
|
|
|
void FinalizeDeferredThings(DeferredFinalizeType aType);
|
|
|
|
|
2014-05-22 17:18:02 +04:00
|
|
|
// Two conditions, JSOutOfMemory and JSLargeAllocationFailure, are noted in
|
|
|
|
// crash reports. Here are the values that can appear in the reports:
|
2015-01-26 01:22:08 +03:00
|
|
|
enum class OOMState : uint32_t {
|
2014-05-22 17:18:02 +04:00
|
|
|
// The condition has never happened. No entry appears in the crash report.
|
|
|
|
OK,
|
|
|
|
|
|
|
|
// We are currently reporting the given condition.
|
2015-05-13 22:48:52 +03:00
|
|
|
//
|
2014-05-22 17:18:02 +04:00
|
|
|
// Suppose a crash report contains "JSLargeAllocationFailure:
|
|
|
|
// Reporting". This means we crashed while executing memory-pressure
|
|
|
|
// observers, trying to shake loose some memory. The large allocation in
|
|
|
|
// question did not return null: it is still on the stack. Had we not
|
|
|
|
// crashed, it would have been retried.
|
|
|
|
Reporting,
|
|
|
|
|
|
|
|
// The condition has been reported since the last GC.
|
|
|
|
//
|
|
|
|
// If a crash report contains "JSOutOfMemory: Reported", that means a small
|
|
|
|
// allocation failed, and then we crashed, probably due to buggy
|
|
|
|
// error-handling code that ran after allocation returned null.
|
|
|
|
//
|
|
|
|
// This contrasts with "Reporting" which means that no error-handling code
|
|
|
|
// had executed yet.
|
|
|
|
Reported,
|
|
|
|
|
|
|
|
// The condition has happened, but a GC cycle ended since then.
|
|
|
|
//
|
|
|
|
// GC is taken as a proxy for "we've been banging on the heap a good bit
|
|
|
|
// now and haven't crashed; the OOM was probably handled correctly".
|
|
|
|
Recovered
|
2015-01-26 01:22:08 +03:00
|
|
|
};
|
2014-05-22 17:18:02 +04:00
|
|
|
|
|
|
|
private:
|
2014-08-25 23:17:24 +04:00
|
|
|
void AnnotateAndSetOutOfMemory(OOMState* aStatePtr, OOMState aNewState);
|
2013-07-09 18:28:15 +04:00
|
|
|
void OnGC(JSGCStatus aStatus);
|
2014-05-22 17:18:02 +04:00
|
|
|
void OnOutOfMemory();
|
|
|
|
void OnLargeAllocationFailure();
|
2013-07-09 18:28:15 +04:00
|
|
|
|
2013-06-18 23:02:14 +04:00
|
|
|
public:
|
|
|
|
void AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer);
|
|
|
|
void RemoveJSHolder(void* aHolder);
|
|
|
|
#ifdef DEBUG
|
2013-08-15 21:29:02 +04:00
|
|
|
bool IsJSHolder(void* aHolder);
|
2013-06-18 23:02:14 +04:00
|
|
|
void AssertNoObjectsToTrace(void* aPossibleJSHolder);
|
|
|
|
#endif
|
|
|
|
|
2013-09-09 07:28:50 +04:00
|
|
|
already_AddRefed<nsIException> GetPendingException() const;
|
|
|
|
void SetPendingException(nsIException* aException);
|
|
|
|
|
2015-05-02 05:33:01 +03:00
|
|
|
std::queue<nsCOMPtr<nsIRunnable>>& GetPromiseMicroTaskQueue();
|
2016-03-24 18:12:00 +03:00
|
|
|
std::queue<nsCOMPtr<nsIRunnable>>& GetDebuggerPromiseMicroTaskQueue();
|
2014-10-28 15:08:19 +03:00
|
|
|
|
2013-08-02 05:29:05 +04:00
|
|
|
nsCycleCollectionParticipant* GCThingParticipant();
|
|
|
|
nsCycleCollectionParticipant* ZoneParticipant();
|
2013-06-18 23:02:15 +04:00
|
|
|
|
2014-05-13 21:41:38 +04:00
|
|
|
nsresult TraverseRoots(nsCycleCollectionNoteRootCallback& aCb);
|
2016-05-27 20:28:26 +03:00
|
|
|
virtual bool UsefulToMergeZones() const;
|
2013-06-18 23:02:15 +04:00
|
|
|
void FixWeakMappingGrayBits() const;
|
2017-03-05 12:23:33 +03:00
|
|
|
void CheckGrayBits() const;
|
2014-05-07 04:25:26 +04:00
|
|
|
bool AreGCGrayBitsValid() const;
|
2014-05-13 21:41:38 +04:00
|
|
|
void GarbageCollect(uint32_t aReason) const;
|
2013-06-18 23:02:15 +04:00
|
|
|
|
2015-12-31 16:21:49 +03:00
|
|
|
void NurseryWrapperAdded(nsWrapperCache* aCache);
|
|
|
|
void NurseryWrapperPreserved(JSObject* aWrapper);
|
2016-01-06 06:32:28 +03:00
|
|
|
void JSObjectsTenured();
|
2015-12-31 16:21:49 +03:00
|
|
|
|
2013-07-09 18:28:15 +04:00
|
|
|
void DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc,
|
|
|
|
DeferredFinalizeFunction aFunc,
|
|
|
|
void* aThing);
|
|
|
|
void DeferredFinalize(nsISupports* aSupports);
|
|
|
|
|
2013-08-04 03:55:39 +04:00
|
|
|
void DumpJSHeap(FILE* aFile);
|
2013-11-21 02:35:16 +04:00
|
|
|
|
|
|
|
virtual void PrepareForForgetSkippable() = 0;
|
|
|
|
virtual void BeginCycleCollectionCallback() = 0;
|
2014-05-13 21:41:38 +04:00
|
|
|
virtual void EndCycleCollectionCallback(CycleCollectorResults& aResults) = 0;
|
Bug 1203840 - Trigger dirty pages purge after CC. r=njn,r=smaug,r=mccr8
Jemalloc 4 purges dirty pages regularly during free() when the ratio of dirty
pages compared to active pages is higher than 1 << lg_dirty_mult. We set
lg_dirty_mult in jemalloc_config to limit RSS usage, but it also has an impact
on performance.
So instead of enforcing a high ratio to force more pages being purged, we keep
jemalloc's default ratio of 8, and force a regular purge of all dirty pages,
after cycle collection.
Keeping jemalloc's default ratio avoids cycle-collection-triggered purge to
have to go through really all dirty pages when there are a lot, in which case
the normal jemalloc purge during free() will already have kicked in. It also
takes care of everything that doesn't run the cycle collector still having
a level of purge, like plugins in the plugin-container.
At the same time, since jemalloc_purge_freed_pages does nothing with jemalloc 4,
repurpose the MEMORY_FREE_PURGED_PAGES_MS telemetry probe to track the time
spent in this cycle-collector-triggered purge.
2015-09-11 08:12:21 +03:00
|
|
|
virtual void DispatchDeferredDeletion(bool aContinuation, bool aPurge = false) = 0;
|
2013-08-04 03:55:39 +04:00
|
|
|
|
2016-08-11 15:39:22 +03:00
|
|
|
JSContext* Context() const
|
2013-08-30 13:47:19 +04:00
|
|
|
{
|
2016-08-11 15:39:22 +03:00
|
|
|
MOZ_ASSERT(mJSContext);
|
|
|
|
return mJSContext;
|
2013-08-30 13:47:19 +04:00
|
|
|
}
|
2013-09-09 07:28:50 +04:00
|
|
|
|
2016-08-11 15:39:22 +03:00
|
|
|
JS::RootingContext* RootingCx() const
|
2016-06-24 21:19:51 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(mJSContext);
|
2016-08-11 15:39:22 +03:00
|
|
|
return JS::RootingContext::get(mJSContext);
|
2016-06-24 21:19:51 +03:00
|
|
|
}
|
|
|
|
|
2016-09-05 18:54:04 +03:00
|
|
|
bool MicroTaskCheckpointDisabled() const
|
|
|
|
{
|
|
|
|
return mDisableMicroTaskCheckpoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisableMicroTaskCheckpoint(bool aDisable)
|
|
|
|
{
|
|
|
|
mDisableMicroTaskCheckpoint = aDisable;
|
|
|
|
}
|
|
|
|
|
|
|
|
class MOZ_RAII AutoDisableMicroTaskCheckpoint
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AutoDisableMicroTaskCheckpoint()
|
2016-09-14 16:47:32 +03:00
|
|
|
: mCCJSCX(CycleCollectedJSContext::Get())
|
2016-09-05 18:54:04 +03:00
|
|
|
{
|
2016-09-14 16:47:32 +03:00
|
|
|
mOldValue = mCCJSCX->MicroTaskCheckpointDisabled();
|
|
|
|
mCCJSCX->DisableMicroTaskCheckpoint(true);
|
2016-09-05 18:54:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
~AutoDisableMicroTaskCheckpoint()
|
|
|
|
{
|
2016-09-14 16:47:32 +03:00
|
|
|
mCCJSCX->DisableMicroTaskCheckpoint(mOldValue);
|
2016-09-05 18:54:04 +03:00
|
|
|
}
|
|
|
|
|
2016-09-14 16:47:32 +03:00
|
|
|
CycleCollectedJSContext* mCCJSCX;
|
2016-09-05 18:54:04 +03:00
|
|
|
bool mOldValue;
|
|
|
|
};
|
|
|
|
|
2016-04-19 07:04:32 +03:00
|
|
|
protected:
|
2016-08-11 15:39:22 +03:00
|
|
|
JSContext* MaybeContext() const { return mJSContext; }
|
2016-04-19 07:04:32 +03:00
|
|
|
|
|
|
|
public:
|
Bug 1179909: Refactor stable state handling. r=smaug
This is motivated by three separate but related problems:
1. Our concept of recursion depth is broken for things that run from AfterProcessNextEvent observers (e.g. Promises). We decrement the recursionDepth counter before firing observers, so a Promise callback running at the lowest event loop depth has a recursion depth of 0 (whereas a regular nsIRunnable would be 1). This is a problem because it's impossible to distinguish a Promise running after a sync XHR's onreadystatechange handler from a top-level event (since the former runs with depth 2 - 1 = 1, and the latter runs with just 1).
2. The nsIThreadObserver mechanism that is used by a lot of code to run "after" the current event is a poor fit for anything that runs script. First, the order the observers fire in is the order they were added, not anything fixed by spec. Additionally, running script can cause the event loop to spin, which is a big source of pain here (bholley has some nasty bug caused by this).
3. We run Promises from different points in the code for workers and main thread. The latter runs from XPConnect's nsIThreadObserver callbacks, while the former runs from a hardcoded call to run Promises in the worker event loop. What workers do is particularly problematic because it means we can't get the right recursion depth no matter what we do to nsThread.
The solve this, this patch does the following:
1. Consolidate some handling of microtasks and all handling of stable state from appshell and WorkerPrivate into CycleCollectedJSRuntime.
2. Make the recursionDepth counter only available to CycleCollectedJSRuntime (and its consumers) and remove it from the nsIThreadInternal and nsIThreadObserver APIs.
3. Adjust the recursionDepth counter so that microtasks run with the recursionDepth of the task they are associated with.
4. Introduce the concept of metastable state to replace appshell's RunBeforeNextEvent. Metastable state is reached after every microtask or task is completed. This provides the semantics that bent and I want for IndexedDB, where transactions autocommit at the end of a microtask and do not "spill" from one microtask into a subsequent microtask. This differs from appshell's RunBeforeNextEvent in two ways:
a) It fires between microtasks, which was the motivation for starting this.
b) It no longer ensures that we're at the same event loop depth in the native event queue. bent decided we don't care about this.
5. Reorder stable state to happen after microtasks such as Promises, per HTML. Right now we call the regular thread observers, including appshell, before the main thread observer (XPConnect), so stable state tasks happen before microtasks.
2015-08-11 16:10:46 +03:00
|
|
|
// nsThread entrypoints
|
|
|
|
virtual void BeforeProcessTask(bool aMightBlock) { };
|
|
|
|
virtual void AfterProcessTask(uint32_t aRecursionDepth);
|
|
|
|
|
|
|
|
// microtask processor entry point
|
|
|
|
void AfterProcessMicrotask();
|
|
|
|
|
|
|
|
uint32_t RecursionDepth();
|
|
|
|
|
|
|
|
// Run in stable state (call through nsContentUtils)
|
|
|
|
void RunInStableState(already_AddRefed<nsIRunnable>&& aRunnable);
|
|
|
|
// This isn't in the spec at all yet, but this gets the behavior we want for IDB.
|
|
|
|
// Runs after the current microtask completes.
|
|
|
|
void RunInMetastableState(already_AddRefed<nsIRunnable>&& aRunnable);
|
|
|
|
|
2016-09-14 16:47:32 +03:00
|
|
|
// Get the current thread's CycleCollectedJSContext. Returns null if there
|
2013-09-09 07:28:50 +04:00
|
|
|
// isn't one.
|
2016-09-14 16:47:32 +03:00
|
|
|
static CycleCollectedJSContext* Get();
|
2013-09-09 07:28:50 +04:00
|
|
|
|
2016-02-19 02:21:48 +03:00
|
|
|
// Add aZone to the set of zones waiting for a GC.
|
|
|
|
void AddZoneWaitingForGC(JS::Zone* aZone)
|
|
|
|
{
|
|
|
|
mZonesWaitingForGC.PutEntry(aZone);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare any zones for GC that have been passed to AddZoneWaitingForGC()
|
|
|
|
// since the last GC or since the last call to PrepareWaitingZonesForGC(),
|
|
|
|
// whichever was most recent. If there were no such zones, prepare for a
|
|
|
|
// full GC.
|
|
|
|
void PrepareWaitingZonesForGC();
|
|
|
|
|
2016-03-24 18:12:00 +03:00
|
|
|
// Queue an async microtask to the current main or worker thread.
|
2016-07-06 01:49:06 +03:00
|
|
|
virtual void DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable);
|
2016-03-24 18:12:00 +03:00
|
|
|
|
2015-04-10 18:27:57 +03:00
|
|
|
// Storage for watching rejected promises waiting for some client to
|
|
|
|
// consume their rejection.
|
2016-03-22 18:22:24 +03:00
|
|
|
// Promises in this list have been rejected in the last turn of the
|
|
|
|
// event loop without the rejection being handled.
|
|
|
|
// Note that this can contain nullptrs in place of promises removed because
|
|
|
|
// they're consumed before it'd be reported.
|
|
|
|
JS::PersistentRooted<JS::GCVector<JSObject*, 0, js::SystemAllocPolicy>> mUncaughtRejections;
|
|
|
|
|
|
|
|
// Promises in this list have previously been reported as rejected
|
|
|
|
// (because they were in the above list), but the rejection was handled
|
|
|
|
// in the last turn of the event loop.
|
|
|
|
JS::PersistentRooted<JS::GCVector<JSObject*, 0, js::SystemAllocPolicy>> mConsumedRejections;
|
2015-04-10 18:27:57 +03:00
|
|
|
nsTArray<nsCOMPtr<nsISupports /* UncaughtRejectionObserver */ >> mUncaughtRejectionObservers;
|
|
|
|
|
2013-06-18 23:02:07 +04:00
|
|
|
private:
|
2013-08-02 05:29:05 +04:00
|
|
|
JSGCThingParticipant mGCThingCycleCollectorGlobal;
|
2013-06-18 23:02:15 +04:00
|
|
|
|
2013-08-02 05:29:05 +04:00
|
|
|
JSZoneParticipant mJSZoneCycleCollectorGlobal;
|
2013-06-18 23:02:15 +04:00
|
|
|
|
2016-06-24 21:19:51 +03:00
|
|
|
JSContext* mJSContext;
|
2013-06-18 23:02:14 +04:00
|
|
|
|
2015-04-22 19:43:02 +03:00
|
|
|
JS::GCSliceCallback mPrevGCSliceCallback;
|
2016-01-19 23:48:22 +03:00
|
|
|
JS::GCNurseryCollectionCallback mPrevGCNurseryCollectionCallback;
|
2015-04-22 19:43:02 +03:00
|
|
|
|
2013-06-18 23:02:16 +04:00
|
|
|
nsDataHashtable<nsPtrHashKey<void>, nsScriptObjectTracer*> mJSHolders;
|
|
|
|
|
2013-07-09 18:28:15 +04:00
|
|
|
typedef nsDataHashtable<nsFuncPtrHashKey<DeferredFinalizeFunction>, void*>
|
|
|
|
DeferredFinalizerTable;
|
|
|
|
DeferredFinalizerTable mDeferredFinalizerTable;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IncrementalFinalizeRunnable> mFinalizeRunnable;
|
2013-07-09 18:28:15 +04:00
|
|
|
|
2013-09-09 07:28:50 +04:00
|
|
|
nsCOMPtr<nsIException> mPendingException;
|
Bug 1179909: Refactor stable state handling. r=smaug
This is motivated by three separate but related problems:
1. Our concept of recursion depth is broken for things that run from AfterProcessNextEvent observers (e.g. Promises). We decrement the recursionDepth counter before firing observers, so a Promise callback running at the lowest event loop depth has a recursion depth of 0 (whereas a regular nsIRunnable would be 1). This is a problem because it's impossible to distinguish a Promise running after a sync XHR's onreadystatechange handler from a top-level event (since the former runs with depth 2 - 1 = 1, and the latter runs with just 1).
2. The nsIThreadObserver mechanism that is used by a lot of code to run "after" the current event is a poor fit for anything that runs script. First, the order the observers fire in is the order they were added, not anything fixed by spec. Additionally, running script can cause the event loop to spin, which is a big source of pain here (bholley has some nasty bug caused by this).
3. We run Promises from different points in the code for workers and main thread. The latter runs from XPConnect's nsIThreadObserver callbacks, while the former runs from a hardcoded call to run Promises in the worker event loop. What workers do is particularly problematic because it means we can't get the right recursion depth no matter what we do to nsThread.
The solve this, this patch does the following:
1. Consolidate some handling of microtasks and all handling of stable state from appshell and WorkerPrivate into CycleCollectedJSRuntime.
2. Make the recursionDepth counter only available to CycleCollectedJSRuntime (and its consumers) and remove it from the nsIThreadInternal and nsIThreadObserver APIs.
3. Adjust the recursionDepth counter so that microtasks run with the recursionDepth of the task they are associated with.
4. Introduce the concept of metastable state to replace appshell's RunBeforeNextEvent. Metastable state is reached after every microtask or task is completed. This provides the semantics that bent and I want for IndexedDB, where transactions autocommit at the end of a microtask and do not "spill" from one microtask into a subsequent microtask. This differs from appshell's RunBeforeNextEvent in two ways:
a) It fires between microtasks, which was the motivation for starting this.
b) It no longer ensures that we're at the same event loop depth in the native event queue. bent decided we don't care about this.
5. Reorder stable state to happen after microtasks such as Promises, per HTML. Right now we call the regular thread observers, including appshell, before the main thread observer (XPConnect), so stable state tasks happen before microtasks.
2015-08-11 16:10:46 +03:00
|
|
|
nsThread* mOwningThread; // Manual refcounting to avoid include hell.
|
2014-05-22 17:18:02 +04:00
|
|
|
|
Bug 1179909: Refactor stable state handling. r=smaug
This is motivated by three separate but related problems:
1. Our concept of recursion depth is broken for things that run from AfterProcessNextEvent observers (e.g. Promises). We decrement the recursionDepth counter before firing observers, so a Promise callback running at the lowest event loop depth has a recursion depth of 0 (whereas a regular nsIRunnable would be 1). This is a problem because it's impossible to distinguish a Promise running after a sync XHR's onreadystatechange handler from a top-level event (since the former runs with depth 2 - 1 = 1, and the latter runs with just 1).
2. The nsIThreadObserver mechanism that is used by a lot of code to run "after" the current event is a poor fit for anything that runs script. First, the order the observers fire in is the order they were added, not anything fixed by spec. Additionally, running script can cause the event loop to spin, which is a big source of pain here (bholley has some nasty bug caused by this).
3. We run Promises from different points in the code for workers and main thread. The latter runs from XPConnect's nsIThreadObserver callbacks, while the former runs from a hardcoded call to run Promises in the worker event loop. What workers do is particularly problematic because it means we can't get the right recursion depth no matter what we do to nsThread.
The solve this, this patch does the following:
1. Consolidate some handling of microtasks and all handling of stable state from appshell and WorkerPrivate into CycleCollectedJSRuntime.
2. Make the recursionDepth counter only available to CycleCollectedJSRuntime (and its consumers) and remove it from the nsIThreadInternal and nsIThreadObserver APIs.
3. Adjust the recursionDepth counter so that microtasks run with the recursionDepth of the task they are associated with.
4. Introduce the concept of metastable state to replace appshell's RunBeforeNextEvent. Metastable state is reached after every microtask or task is completed. This provides the semantics that bent and I want for IndexedDB, where transactions autocommit at the end of a microtask and do not "spill" from one microtask into a subsequent microtask. This differs from appshell's RunBeforeNextEvent in two ways:
a) It fires between microtasks, which was the motivation for starting this.
b) It no longer ensures that we're at the same event loop depth in the native event queue. bent decided we don't care about this.
5. Reorder stable state to happen after microtasks such as Promises, per HTML. Right now we call the regular thread observers, including appshell, before the main thread observer (XPConnect), so stable state tasks happen before microtasks.
2015-08-11 16:10:46 +03:00
|
|
|
struct RunInMetastableStateData
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRunnable> mRunnable;
|
|
|
|
uint32_t mRecursionDepth;
|
|
|
|
};
|
|
|
|
|
|
|
|
nsTArray<nsCOMPtr<nsIRunnable>> mStableStateEvents;
|
|
|
|
nsTArray<RunInMetastableStateData> mMetastableStateEvents;
|
|
|
|
uint32_t mBaseRecursionDepth;
|
|
|
|
bool mDoingStableStates;
|
|
|
|
|
2016-09-05 18:54:04 +03:00
|
|
|
bool mDisableMicroTaskCheckpoint;
|
|
|
|
|
2014-05-22 17:18:02 +04:00
|
|
|
OOMState mOutOfMemoryState;
|
|
|
|
OOMState mLargeAllocationFailureState;
|
2015-12-31 16:21:49 +03:00
|
|
|
|
|
|
|
static const size_t kSegmentSize = 512;
|
|
|
|
SegmentedVector<nsWrapperCache*, kSegmentSize, InfallibleAllocPolicy>
|
|
|
|
mNurseryObjects;
|
|
|
|
SegmentedVector<JS::PersistentRooted<JSObject*>, kSegmentSize,
|
|
|
|
InfallibleAllocPolicy>
|
|
|
|
mPreservedNurseryObjects;
|
2016-02-19 02:21:48 +03:00
|
|
|
|
|
|
|
nsTHashtable<nsPtrHashKey<JS::Zone>> mZonesWaitingForGC;
|
2016-03-02 20:38:24 +03:00
|
|
|
|
|
|
|
struct EnvironmentPreparer : public js::ScriptEnvironmentPreparer {
|
|
|
|
void invoke(JS::HandleObject scope, Closure& closure) override;
|
|
|
|
};
|
|
|
|
EnvironmentPreparer mEnvironmentPreparer;
|
2013-06-18 23:02:07 +04:00
|
|
|
};
|
|
|
|
|
2014-06-05 03:48:50 +04:00
|
|
|
void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer);
|
|
|
|
|
2015-05-22 20:40:24 +03:00
|
|
|
// Returns true if the JS::TraceKind is one the cycle collector cares about.
|
|
|
|
inline bool AddToCCKind(JS::TraceKind aKind)
|
2014-12-05 20:38:34 +03:00
|
|
|
{
|
2016-09-24 01:42:13 +03:00
|
|
|
return aKind == JS::TraceKind::Object || aKind == JS::TraceKind::Script || aKind == JS::TraceKind::Scope;
|
2014-12-05 20:38:34 +03:00
|
|
|
}
|
|
|
|
|
2016-01-01 08:19:20 +03:00
|
|
|
bool
|
|
|
|
GetBuildId(JS::BuildIdCharVector* aBuildID);
|
|
|
|
|
2013-06-18 23:02:07 +04:00
|
|
|
} // namespace mozilla
|
|
|
|
|
2016-09-14 16:47:32 +03:00
|
|
|
#endif // mozilla_CycleCollectedJSContext_h__
|