mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 982561 - Add tests for weak maps with key delegates r=terrence
This commit is contained in:
parent
f23c03f6a3
commit
6405c34d6e
@ -8,6 +8,7 @@
|
||||
#define gc_Zone_h
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
@ -147,6 +148,7 @@ struct Zone : public JS::shadow::Zone,
|
||||
bool gcScheduled;
|
||||
GCState gcState;
|
||||
bool gcPreserveCode;
|
||||
mozilla::DebugOnly<unsigned> gcLastZoneGroupIndex;
|
||||
|
||||
public:
|
||||
bool isCollecting() const {
|
||||
@ -228,6 +230,16 @@ struct Zone : public JS::shadow::Zone,
|
||||
return gcState == Finished;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* For testing purposes, return the index of the zone group which this zone
|
||||
* was swept in in the last GC.
|
||||
*/
|
||||
unsigned lastZoneGroupIndex() {
|
||||
return gcLastZoneGroupIndex;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This is updated by both the main and GC helper threads. */
|
||||
mozilla::Atomic<size_t, mozilla::ReleaseAcquire> gcBytes;
|
||||
|
||||
|
@ -72,6 +72,7 @@ UNIFIED_SOURCES += [
|
||||
'testTypedArrays.cpp',
|
||||
'testUncaughtError.cpp',
|
||||
'testUTF8.cpp',
|
||||
'testWeakMap.cpp',
|
||||
'testXDR.cpp',
|
||||
]
|
||||
|
||||
|
246
js/src/jsapi-tests/testWeakMap.cpp
Normal file
246
js/src/jsapi-tests/testWeakMap.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*/
|
||||
/* 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 "gc/Zone.h"
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
using namespace JS;
|
||||
|
||||
#ifdef JSGC_USE_EXACT_ROOTING
|
||||
|
||||
BEGIN_TEST(testWeakMap_basicOperations)
|
||||
{
|
||||
RootedObject map(cx, NewWeakMapObject(cx));
|
||||
CHECK(IsWeakMapObject(map));
|
||||
|
||||
RootedObject key(cx, newKey());
|
||||
CHECK(key);
|
||||
CHECK(!IsWeakMapObject(key));
|
||||
|
||||
RootedValue r(cx);
|
||||
CHECK(GetWeakMapEntry(cx, map, key, &r));
|
||||
CHECK(r.isUndefined());
|
||||
|
||||
CHECK(checkSize(map, 0));
|
||||
|
||||
RootedValue val(cx, Int32Value(1));
|
||||
CHECK(SetWeakMapEntry(cx, map, key, val));
|
||||
|
||||
CHECK(GetWeakMapEntry(cx, map, key, &r));
|
||||
CHECK(r == val);
|
||||
CHECK(checkSize(map, 1));
|
||||
|
||||
JS_GC(rt);
|
||||
|
||||
CHECK(GetWeakMapEntry(cx, map, key, &r));
|
||||
CHECK(r == val);
|
||||
CHECK(checkSize(map, 1));
|
||||
|
||||
key = nullptr;
|
||||
JS_GC(rt);
|
||||
|
||||
CHECK(checkSize(map, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *newKey()
|
||||
{
|
||||
return JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr());
|
||||
}
|
||||
|
||||
bool
|
||||
checkSize(HandleObject map, uint32_t expected)
|
||||
{
|
||||
RootedObject keys(cx);
|
||||
CHECK(JS_NondeterministicGetWeakMapKeys(cx, map, &keys));
|
||||
|
||||
uint32_t length;
|
||||
CHECK(JS_GetArrayLength(cx, keys, &length));
|
||||
CHECK(length == expected);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testWeakMap_basicOperations)
|
||||
|
||||
BEGIN_TEST(testWeakMap_keyDelegates)
|
||||
{
|
||||
JS_SetGCParameter(rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
|
||||
JS_GC(rt);
|
||||
|
||||
RootedObject map(cx, NewWeakMapObject(cx));
|
||||
CHECK(map);
|
||||
|
||||
RootedObject key(cx, newKey());
|
||||
CHECK(key);
|
||||
|
||||
RootedObject delegate(cx, newDelegate());
|
||||
CHECK(delegate);
|
||||
|
||||
SetKeyDelegate(key, delegate);
|
||||
|
||||
/*
|
||||
* Perform an incremental GC, introducing an unmarked CCW to force the map
|
||||
* zone to finish marking before the delegate zone.
|
||||
*/
|
||||
CHECK(newCCW(map, delegate));
|
||||
GCDebugSlice(rt, true, 1000000);
|
||||
#ifdef DEBUG
|
||||
CHECK(map->zone()->lastZoneGroupIndex() < delegate->zone()->lastZoneGroupIndex());
|
||||
#endif
|
||||
|
||||
/* Add our entry to the weakmap. */
|
||||
RootedValue val(cx, Int32Value(1));
|
||||
CHECK(SetWeakMapEntry(cx, map, key, val));
|
||||
CHECK(checkSize(map, 1));
|
||||
|
||||
/* Check the delegate keeps the entry alive even if the key is not reachable. */
|
||||
key = nullptr;
|
||||
CHECK(newCCW(map, delegate));
|
||||
GCDebugSlice(rt, true, 100000);
|
||||
CHECK(checkSize(map, 1));
|
||||
|
||||
/*
|
||||
* Check that the zones finished marking at the same time, which is
|
||||
* neccessary because of the presence of the delegate and the CCW.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
CHECK(map->zone()->lastZoneGroupIndex() == delegate->zone()->lastZoneGroupIndex());
|
||||
#endif
|
||||
|
||||
/* Check that when the delegate becomes unreacable the entry is removed. */
|
||||
delegate = nullptr;
|
||||
JS_GC(rt);
|
||||
CHECK(checkSize(map, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void SetKeyDelegate(JSObject *key, JSObject *delegate)
|
||||
{
|
||||
JS_SetPrivate(key, delegate);
|
||||
}
|
||||
|
||||
static JSObject *GetKeyDelegate(JSObject *obj)
|
||||
{
|
||||
return static_cast<JSObject*>(JS_GetPrivate(obj));
|
||||
}
|
||||
|
||||
JSObject *newKey()
|
||||
{
|
||||
static const js::Class keyClass = {
|
||||
"keyWithDelgate",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
JS_NULL_CLASS_SPEC,
|
||||
{
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
false,
|
||||
GetKeyDelegate
|
||||
},
|
||||
JS_NULL_OBJECT_OPS
|
||||
};
|
||||
|
||||
RootedObject key(cx);
|
||||
key = JS_NewObject(cx,
|
||||
reinterpret_cast<const JSClass *>(&keyClass),
|
||||
JS::NullPtr(),
|
||||
JS::NullPtr());
|
||||
if (!key)
|
||||
return nullptr;
|
||||
|
||||
SetKeyDelegate(key, nullptr);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
JSObject *newCCW(HandleObject sourceZone, HandleObject destZone)
|
||||
{
|
||||
/*
|
||||
* Now ensure that this zone will be swept first by adding a cross
|
||||
* compartment wrapper to a new objct in the same zone as the
|
||||
* delegate obejct.
|
||||
*/
|
||||
RootedObject object(cx);
|
||||
{
|
||||
JSAutoCompartment ac(cx, destZone);
|
||||
object = JS_NewObject(cx, nullptr, NullPtr(), NullPtr());
|
||||
if (!object)
|
||||
return nullptr;
|
||||
}
|
||||
{
|
||||
JSAutoCompartment ac(cx, sourceZone);
|
||||
if (!JS_WrapObject(cx, &object))
|
||||
return nullptr;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
JSObject *newDelegate()
|
||||
{
|
||||
static const JSClass delegateClass = {
|
||||
"delegate",
|
||||
JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_RESERVED_SLOTS(1),
|
||||
JS_PropertyStub,
|
||||
JS_DeletePropertyStub,
|
||||
JS_PropertyStub,
|
||||
JS_StrictPropertyStub,
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
JS_GlobalObjectTraceHook
|
||||
};
|
||||
|
||||
/* Create the global object. */
|
||||
JS::CompartmentOptions options;
|
||||
options.setVersion(JSVERSION_LATEST);
|
||||
JS::RootedObject global(cx);
|
||||
global = JS_NewGlobalObject(cx, &delegateClass, nullptr, JS::FireOnNewGlobalHook, options);
|
||||
JS_SetReservedSlot(global, 0, Int32Value(42));
|
||||
|
||||
/*
|
||||
* Ensure the delegate is not in the nursery because for the purpose of this
|
||||
* test we're going to put it in a private slot where it won't get updated.
|
||||
*/
|
||||
JS_GC(rt);
|
||||
|
||||
return global;
|
||||
}
|
||||
|
||||
bool
|
||||
checkSize(HandleObject map, uint32_t expected)
|
||||
{
|
||||
RootedObject keys(cx);
|
||||
CHECK(JS_NondeterministicGetWeakMapKeys(cx, map, &keys));
|
||||
|
||||
uint32_t length;
|
||||
CHECK(JS_GetArrayLength(cx, keys, &length));
|
||||
CHECK(length == expected);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testWeakMap_keyDelegates)
|
||||
|
||||
#endif // JSGC_USE_EXACT_ROOTING
|
@ -3815,6 +3815,8 @@ GCRuntime::beginSweepingZoneGroup()
|
||||
|
||||
if (rt->sweepZoneCallback)
|
||||
rt->sweepZoneCallback(zone);
|
||||
|
||||
zone->gcLastZoneGroupIndex = zoneGroupIndex;
|
||||
}
|
||||
|
||||
validateIncrementalMarking();
|
||||
|
Loading…
Reference in New Issue
Block a user