/* -*- 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/. */
CHECK_EQUAL(cp1.constructor(), 1); // direct SafelyInitialized<T>
CHECK_EQUAL(cp2.constructor(), 2); // direct MyContainer(double)
CHECK_EQUAL(cp3.constructor(), 3); // direct MyContainer(cx)
CHECK_EQUAL(cp4.constructor(), 4); // direct MyContainer(cx, cx, cx)
// Construct uncopyable type in place.
JS::PersistentRooted<MyNonCopyableContainer> ncp1(cx);
JS::PersistentRooted<MyNonCopyableContainer> ncp2(cx, 7.8);
// We're not just using a 1-arg constructor, right?
JS::PersistentRooted<MyNonCopyableContainer> ncp3(cx, cx);
JS::PersistentRooted<MyNonCopyableContainer> ncp4(cx, cx, cx, cx);
CHECK_EQUAL(ncp1.constructor(), 1); // direct SafelyInitialized<T>
CHECK_EQUAL(ncp2.constructor(), 2); // direct Ctor(double)
CHECK_EQUAL(ncp3.constructor(), 3); // direct Ctor(cx)
CHECK_EQUAL(ncp4.constructor(), 4); // direct Ctor(cx, cx, cx)
// Unlike the above, the following test is an example of an invalid usage: for // performance and simplicity reasons, PersistentRooted<Traceable> is not // allowed to outlive the container it belongs to. The following commented out // test can be used to verify that the relevant assertion fires as expected.
MOZ_RUNINIT static JS::PersistentRooted<MyContainer> sContainer;
BEGIN_TEST(testGCPersistentRootedTraceableCannotOutliveRuntime) {
JS::Rooted<MyContainer> container(cx);
container.obj() = JS_NewObject(cx, nullptr);
container.str() = JS_NewStringCopyZ(cx, "Hello");
sContainer.init(cx, container);
// Commenting the following line will trigger an assertion that the // PersistentRooted outlives the runtime it is attached to.
sContainer.reset();
for (size_t i = 0; i < 10; ++i) {
RootedObject obj(cx, JS_NewObject(cx, nullptr));
RootedValue val(cx, UndefinedValue()); // Construct a unique property name to ensure that the object creates a // new shape. char buffer[2];
buffer[0] = 'a' + i;
buffer[1] = '\0';
CHECK(JS_SetProperty(cx, obj, buffer, val));
CHECK(map.putNew(obj->shape(), obj));
}
JS_GC(cx);
JS_GC(cx);
for (auto r = map.all(); !r.empty(); r.popFront()) {
RootedObject obj(cx, r.front().value());
CHECK(obj->shape() == r.front().key());
}
returntrue;
}
END_TEST(testGCRootedHashMap)
// Repeat of the test above, but without rooting. This is a rooting hazard. The // JS_EXPECT_HAZARDS annotation will cause the hazard taskcluster job to fail // if the hazard below is *not* detected.
BEGIN_TEST_WITH_ATTRIBUTES(testUnrootedGCHashMap, JS_EXPECT_HAZARDS) {
AutoLeaveZeal noZeal(cx);
MyHashMap map(cx, 15);
for (size_t i = 0; i < 10; ++i) {
RootedObject obj(cx, JS_NewObject(cx, nullptr));
RootedValue val(cx, UndefinedValue()); // Construct a unique property name to ensure that the object creates a // new shape. char buffer[2];
buffer[0] = 'a' + i;
buffer[1] = '\0';
CHECK(JS_SetProperty(cx, obj, buffer, val));
CHECK(map.putNew(obj->shape(), obj));
}
JS_GC(cx);
// Access map to keep it live across the GC.
CHECK(map.count() == 10);
returntrue;
}
END_TEST(testUnrootedGCHashMap)
BEGIN_TEST(testSafelyUnrootedGCHashMap) { // This is not rooted, but it doesn't use GC pointers as keys or values so // it's ok.
js::GCHashMap<uint64_t, uint64_t> map(cx, 15);
for (size_t i = 0; i < 10; ++i) {
RootedObject obj(cx, JS_NewObject(cx, nullptr));
RootedValue val(cx, UndefinedValue()); // Construct a unique property name to ensure that the object creates a // new shape. char buffer[2];
buffer[0] = 'a' + i;
buffer[1] = '\0';
CHECK(JS_SetProperty(cx, obj, buffer, val));
CHECK(shapes.append(obj->as<NativeObject>().shape()));
}
JS_GC(cx);
JS_GC(cx);
for (size_t i = 0; i < 10; ++i) { // Check the shape to ensure it did not get collected. char letter = 'a' + i; bool match;
ShapePropertyIter<NoGC> iter(shapes[i]);
CHECK(JS_StringEqualsAscii(cx, iter->key().toString(), &letter, 1, &match));
CHECK(match);
}
// Ensure iterator enumeration works through the rooted. for (auto shape : shapes) {
CHECK(shape);
}
CHECK(receiveConstRefToShapeVector(shapes));
// Ensure rooted converts to handles.
CHECK(receiveHandleToShapeVector(shapes));
CHECK(receiveMutableHandleToShapeVector(&shapes));
returntrue;
}
bool receiveConstRefToShapeVector( const JS::Rooted<GCVector<NativeShape*>>& rooted) { // Ensure range enumeration works through the reference. for (auto shape : rooted) {
CHECK(shape);
} returntrue;
}
bool receiveHandleToShapeVector(JS::Handle<GCVector<NativeShape*>> handle) { // Ensure range enumeration works through the handle. for (auto shape : handle) {
CHECK(shape);
} returntrue;
}
bool receiveMutableHandleToShapeVector(
JS::MutableHandle<GCVector<NativeShape*>> handle) { // Ensure range enumeration works through the handle. for (auto shape : handle) {
CHECK(shape);
} returntrue;
}
END_TEST(testGCRootedVector)
BEGIN_TEST(testTraceableFifo) { using ShapeFifo = TraceableFifo<NativeShape*>;
JS::Rooted<ShapeFifo> shapes(cx, ShapeFifo(cx));
CHECK(shapes.empty());
for (size_t i = 0; i < 10; ++i) {
RootedObject obj(cx, JS_NewObject(cx, nullptr));
RootedValue val(cx, UndefinedValue()); // Construct a unique property name to ensure that the object creates a // new shape. char buffer[2];
buffer[0] = 'a' + i;
buffer[1] = '\0';
CHECK(JS_SetProperty(cx, obj, buffer, val));
CHECK(shapes.pushBack(obj->as<NativeObject>().shape()));
}
CHECK(shapes.length() == 10);
JS_GC(cx);
JS_GC(cx);
for (size_t i = 0; i < 10; ++i) { // Check the shape to ensure it did not get collected. char letter = 'a' + i; bool match;
ShapePropertyIter<NoGC> iter(shapes.front());
CHECK(JS_StringEqualsAscii(cx, iter->key().toString(), &letter, 1, &match));
CHECK(match);
shapes.popFront();
}
staticbool FillVector(JSContext* cx, MutableHandle<ShapeVec> shapes) { for (size_t i = 0; i < 10; ++i) {
RootedObject obj(cx, JS_NewObject(cx, nullptr));
RootedValue val(cx, UndefinedValue()); // Construct a unique property name to ensure that the object creates a // new shape. char buffer[2];
buffer[0] = 'a' + i;
buffer[1] = '\0'; if (!JS_SetProperty(cx, obj, buffer, val)) { returnfalse;
} if (!shapes.append(obj->as<NativeObject>().shape())) { returnfalse;
}
}
// Ensure iterator enumeration works through the mutable handle. for (auto shape : shapes) { if (!shape) { returnfalse;
}
}
returntrue;
}
staticbool CheckVector(JSContext* cx, Handle<ShapeVec> shapes) { for (size_t i = 0; i < 10; ++i) { // Check the shape to ensure it did not get collected. char letter = 'a' + i; bool match;
ShapePropertyIter<NoGC> iter(shapes[i]); if (!JS_StringEqualsAscii(cx, iter->key().toString(), &letter, 1, &match)) { returnfalse;
} if (!match) { returnfalse;
}
}
// Ensure iterator enumeration works through the handle. for (auto shape : shapes) { if (!shape) { returnfalse;
}
}
struct SimpleTraceable { // I'm using plain objects rather than Heap<T> because Heap<T> would get // traced via the store buffer. Heap<T> would be a more realistic example, // but would require compaction to test for tracing.
JSObject* obj;
JS::Value val;
// This would fail to compile because Result<> deletes its copy constructor, // which prevents updating after tracing: // // Rooted<Result<Result<mozilla::Ok, JS::Value>, JSObject*>>
// But this should be fine when no tracing is required.
Result<Result<mozilla::Ok, int>, double> dummy(3.4);
// One thing I didn't realize initially about Result<>: unwrap() takes // ownership of a value. In the case of Result<Maybe>, that means the // contained Maybe is reset to Nothing.
Result<mozilla::Maybe<int>, int> confusing(mozilla::Some(7));
CHECK(confusing.unwrap().isSome());
CHECK(!confusing.unwrap().isSome());
// This depends on a pointer fitting in 48 bits, leaving space for an empty // struct and a bool in a packed struct. Windows doesn't seem to do this // packing, so we'll skip this test here. We're primarily checking whether // copy constructors get called, which should be cross-platform, and // secondarily making sure that the Rooted/tracing stuff is compiled and // executed properly. There are certainly more clever ways to do this that // would work cross-platform, but it doesn't seem worth the bother right now.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.