Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / js / src / jsapi-tests / testPersistentRooted.cpp
blob4b3ab3050dbd5023637fbf7d4d08682106fb05c1
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "js/Class.h"
6 #include "jsapi-tests/tests.h"
8 using namespace JS;
10 struct BarkWhenTracedClass {
11 static int finalizeCount;
12 static int traceCount;
14 static const JSClass class_;
15 static void finalize(JS::GCContext* gcx, JSObject* obj) { finalizeCount++; }
16 static void trace(JSTracer* trc, JSObject* obj) { traceCount++; }
17 static void reset() {
18 finalizeCount = 0;
19 traceCount = 0;
23 int BarkWhenTracedClass::finalizeCount;
24 int BarkWhenTracedClass::traceCount;
26 static const JSClassOps BarkWhenTracedClassClassOps = {
27 nullptr, // addProperty
28 nullptr, // delProperty
29 nullptr, // enumerate
30 nullptr, // newEnumerate
31 nullptr, // resolve
32 nullptr, // mayResolve
33 BarkWhenTracedClass::finalize, // finalize
34 nullptr, // call
35 nullptr, // construct
36 BarkWhenTracedClass::trace, // trace
39 const JSClass BarkWhenTracedClass::class_ = {"BarkWhenTracedClass",
40 JSCLASS_FOREGROUND_FINALIZE,
41 &BarkWhenTracedClassClassOps};
43 struct Kennel {
44 PersistentRootedObject obj;
45 Kennel() {}
46 explicit Kennel(JSContext* cx) : obj(cx) {}
47 Kennel(JSContext* cx, const HandleObject& woof) : obj(cx, woof) {}
48 void init(JSContext* cx, const HandleObject& woof) { obj.init(cx, woof); }
49 void clear() { obj = nullptr; }
52 // A function for allocating a Kennel and a barker. Only allocating
53 // PersistentRooteds on the heap, and in this function, helps ensure that the
54 // conservative GC doesn't find stray references to the barker. Ugh.
55 MOZ_NEVER_INLINE static Kennel* Allocate(JSContext* cx) {
56 RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_));
57 if (!barker) {
58 return nullptr;
61 return new Kennel(cx, barker);
64 // Do a GC, expecting |n| barkers to be finalized.
65 static bool GCFinalizesNBarkers(JSContext* cx, int n) {
66 int preGCTrace = BarkWhenTracedClass::traceCount;
67 int preGCFinalize = BarkWhenTracedClass::finalizeCount;
69 JS_GC(cx);
71 return (BarkWhenTracedClass::finalizeCount == preGCFinalize + n &&
72 BarkWhenTracedClass::traceCount > preGCTrace);
75 // PersistentRooted instances protect their contents from being recycled.
76 BEGIN_TEST(test_PersistentRooted) {
77 BarkWhenTracedClass::reset();
79 mozilla::UniquePtr<Kennel> kennel(Allocate(cx));
80 CHECK(kennel.get());
82 // GC should be able to find our barker.
83 CHECK(GCFinalizesNBarkers(cx, 0));
85 kennel = nullptr;
87 // Now GC should not be able to find the barker.
88 JS_GC(cx);
89 CHECK(BarkWhenTracedClass::finalizeCount == 1);
91 return true;
93 END_TEST(test_PersistentRooted)
95 // GC should not be upset by null PersistentRooteds.
96 BEGIN_TEST(test_PersistentRootedNull) {
97 BarkWhenTracedClass::reset();
99 Kennel kennel(cx);
100 CHECK(!kennel.obj);
102 JS_GC(cx);
103 CHECK(BarkWhenTracedClass::finalizeCount == 0);
105 return true;
107 END_TEST(test_PersistentRootedNull)
109 // Copy construction works.
110 BEGIN_TEST(test_PersistentRootedCopy) {
111 BarkWhenTracedClass::reset();
113 mozilla::UniquePtr<Kennel> kennel(Allocate(cx));
114 CHECK(kennel.get());
116 CHECK(GCFinalizesNBarkers(cx, 0));
118 // Copy construction! AMAZING!
119 mozilla::UniquePtr<Kennel> newKennel(new Kennel(*kennel));
121 CHECK(GCFinalizesNBarkers(cx, 0));
123 kennel = nullptr;
125 CHECK(GCFinalizesNBarkers(cx, 0));
127 newKennel = nullptr;
129 // Now that kennel and nowKennel are both deallocated, GC should not be
130 // able to find the barker.
131 JS_GC(cx);
132 CHECK(BarkWhenTracedClass::finalizeCount == 1);
134 return true;
136 END_TEST(test_PersistentRootedCopy)
138 // Assignment works.
139 BEGIN_TEST(test_PersistentRootedAssign) {
140 BarkWhenTracedClass::reset();
142 mozilla::UniquePtr<Kennel> kennel(Allocate(cx));
143 CHECK(kennel.get());
145 CHECK(GCFinalizesNBarkers(cx, 0));
147 // Allocate a new, empty kennel.
148 mozilla::UniquePtr<Kennel> kennel2(new Kennel(cx));
150 // Assignment! ASTONISHING!
151 *kennel2 = *kennel;
153 // With both kennels referring to the same barker, it is held alive.
154 CHECK(GCFinalizesNBarkers(cx, 0));
156 kennel2 = nullptr;
158 // The destination of the assignment alone holds the barker alive.
159 CHECK(GCFinalizesNBarkers(cx, 0));
161 // Allocate a second barker.
162 kennel2 = mozilla::UniquePtr<Kennel>(Allocate(cx));
163 CHECK(kennel2.get());
165 *kennel = *kennel2;
167 // Nothing refers to the first kennel any more.
168 CHECK(GCFinalizesNBarkers(cx, 1));
170 kennel = nullptr;
171 kennel2 = nullptr;
173 // Now that kennel and kennel2 are both deallocated, GC should not be
174 // able to find the barker.
175 JS_GC(cx);
176 CHECK(BarkWhenTracedClass::finalizeCount == 2);
178 return true;
180 END_TEST(test_PersistentRootedAssign)
182 static PersistentRootedObject gGlobalRoot;
184 // PersistentRooted instances can initialized in a separate step to allow for
185 // global PersistentRooteds.
186 BEGIN_TEST(test_GlobalPersistentRooted) {
187 BarkWhenTracedClass::reset();
189 CHECK(!gGlobalRoot.initialized());
192 RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_));
193 CHECK(barker);
195 gGlobalRoot.init(cx, barker);
198 CHECK(gGlobalRoot.initialized());
200 // GC should be able to find our barker.
201 CHECK(GCFinalizesNBarkers(cx, 0));
203 gGlobalRoot.reset();
204 CHECK(!gGlobalRoot.initialized());
206 // Now GC should not be able to find the barker.
207 JS_GC(cx);
208 CHECK(BarkWhenTracedClass::finalizeCount == 1);
210 return true;
212 END_TEST(test_GlobalPersistentRooted)