Bug 1599659 - Predicate to test context for live SABs. r=jonco

SABs become foreground-finalizable so that we can access the runtime
during finalization.  Then a simple counter on the runtime will track
live SABs for the runtime, and the predicate on the context can get
its information from the runtime.

Fallout: SABs are now enabled on the globals used for jsapi-tests.

Differential Revision: https://phabricator.services.mozilla.com/D55783

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Lars T Hansen 2019-12-05 18:36:21 +00:00
Родитель e218334a65
Коммит ea7268ed2f
8 изменённых файлов: 72 добавлений и 3 удалений

Просмотреть файл

@ -92,6 +92,7 @@ UNIFIED_SOURCES += [
'testRegExp.cpp',
'testResolveRecursion.cpp',
'tests.cpp',
'testSABAccounting.cpp',
'testSameValue.cpp',
'testSavedStacks.cpp',
'testScriptInfo.cpp',

Просмотреть файл

@ -0,0 +1,34 @@
#include "jsapi.h"
#include "jsfriendapi.h"
#include "builtin/TestingFunctions.h"
#include "js/SharedArrayBuffer.h"
#include "jsapi-tests/tests.h"
BEGIN_TEST(testSABAccounting) {
// Purge what we can
JS::PrepareForFullGC(cx);
NonIncrementalGC(cx, GC_SHRINK, JS::GCReason::API);
// Self-hosting and chrome code should not use SABs, or the point of this
// predicate is completely lost.
CHECK(!JS_ContainsSharedArrayBuffer(cx));
JS::RootedObject obj(cx), obj2(cx);
CHECK(obj = JS::NewSharedArrayBuffer(cx, 4096));
CHECK(JS_ContainsSharedArrayBuffer(cx));
CHECK(obj2 = JS::NewSharedArrayBuffer(cx, 4096));
CHECK(JS_ContainsSharedArrayBuffer(cx));
// Discard those objects again.
obj = nullptr;
obj2 = nullptr;
JS::PrepareForFullGC(cx);
NonIncrementalGC(cx, GC_SHRINK, JS::GCReason::API);
// Should be back to base state.
CHECK(!JS_ContainsSharedArrayBuffer(cx));
return true;
}
END_TEST(testSABAccounting)

Просмотреть файл

@ -92,7 +92,8 @@ JSObject* JSAPITest::createGlobal(JSPrincipals* principals) {
.setStreamsEnabled(true)
.setFieldsEnabled(true)
.setAwaitFixEnabled(true)
.setWeakRefsEnabled(true);
.setWeakRefsEnabled(true)
.setSharedMemoryAndAtomicsEnabled(true);
newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), principals,
JS::FireOnNewGlobalHook, options);
if (!newGlobal) {

Просмотреть файл

@ -390,6 +390,10 @@ JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx) {
cx->fx.setCanWait(true);
}
JS_PUBLIC_API bool JS_ContainsSharedArrayBuffer(JSContext* cx) {
return cx->runtime()->hasLiveSABs();
}
JS_PUBLIC_API JSRuntime* JS_GetParentRuntime(JSContext* cx) {
return cx->runtime()->parentRuntime ? cx->runtime()->parentRuntime
: cx->runtime();

Просмотреть файл

@ -344,6 +344,12 @@ extern JS_PUBLIC_API JSRuntime* JS_GetRuntime(JSContext* cx);
extern JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx);
// Returns true if there are any live SharedArrayBuffer objects, including those
// for wasm memories, associated with the context. This is conservative,
// because it does not run GC. Some dead objects may not have been collected
// yet and thus will be thought live.
extern JS_PUBLIC_API bool JS_ContainsSharedArrayBuffer(JSContext* cx);
namespace js {
void AssertHeapIsIdle();

Просмотреть файл

@ -149,6 +149,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
staticStrings(nullptr),
commonNames(nullptr),
wellKnownSymbols(nullptr),
liveSABs(0),
offthreadIonCompilationEnabled_(true),
parallelParsingEnabled_(true),
#ifdef DEBUG

Просмотреть файл

@ -840,6 +840,24 @@ struct JSRuntime {
JSRuntime* thisFromCtor() { return this; }
private:
// Number of live SharedArrayBuffer objects, including those in Wasm shared
// memories. uint64_t to avoid any risk of overflow.
js::MainThreadData<uint64_t> liveSABs;
public:
void incSABCount() {
MOZ_RELEASE_ASSERT(liveSABs != UINT64_MAX);
liveSABs++;
}
void decSABCount() {
MOZ_RELEASE_ASSERT(liveSABs > 0);
liveSABs--;
}
bool hasLiveSABs() const { return liveSABs > 0; }
public:
void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); }

Просмотреть файл

@ -251,6 +251,7 @@ SharedArrayBufferObject* SharedArrayBufferObject::New(
MOZ_ASSERT(obj->getClass() == &class_);
cx->runtime()->incSABCount();
obj->acceptRawBuffer(buffer, length);
return obj;
@ -273,7 +274,9 @@ SharedArrayRawBuffer* SharedArrayBufferObject::rawBufferObject() const {
}
void SharedArrayBufferObject::Finalize(JSFreeOp* fop, JSObject* obj) {
MOZ_ASSERT(fop->maybeOnHelperThread());
// Must be foreground finalizable so that we can account for the object.
MOZ_ASSERT(fop->onMainThread());
fop->runtime()->decSABCount();
SharedArrayBufferObject& buf = obj->as<SharedArrayBufferObject>();
@ -327,6 +330,7 @@ SharedArrayBufferObject* SharedArrayBufferObject::createFromNewRawBuffer(
return nullptr;
}
cx->runtime()->incSABCount();
obj->acceptRawBuffer(buffer, initialSize);
return obj;
@ -373,7 +377,7 @@ const JSClass SharedArrayBufferObject::class_ = {
JSCLASS_DELAY_METADATA_BUILDER |
JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer) |
JSCLASS_BACKGROUND_FINALIZE,
JSCLASS_FOREGROUND_FINALIZE,
&SharedArrayBufferObjectClassOps, &SharedArrayBufferObjectClassSpec,
JS_NULL_CLASS_EXT};