xpcom/glue/tests/gtest/TestGCPostBarriers.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:8a340bc48b57
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=8 et :
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 /*
9 * Tests that generational garbage collection post-barriers are correctly
10 * implemented for nsTArrays that contain JavaScript Values.
11 */
12
13 #include "jsapi.h"
14 #include "nsTArray.h"
15
16 #include "gtest/gtest.h"
17
18 #include "js/TracingAPI.h"
19 #include "js/HeapAPI.h"
20
21 #include "mozilla/CycleCollectedJSRuntime.h"
22
23 using namespace JS;
24 using namespace mozilla;
25
26 template <class ArrayT>
27 static void
28 TraceArray(JSTracer* trc, void* data)
29 {
30 ArrayT* array = static_cast<ArrayT *>(data);
31 for (unsigned i = 0; i < array->Length(); ++i)
32 JS_CallHeapObjectTracer(trc, &array->ElementAt(i), "array-element");
33 }
34
35 /*
36 * Use arrays with initial size much smaller than the final number of elements
37 * to test that moving Heap<T> elements works correctly.
38 */
39 const size_t ElementCount = 100;
40 const size_t InitialElements = ElementCount / 10;
41
42 template <class ArrayT>
43 static void
44 RunTest(JSRuntime* rt, JSContext* cx, ArrayT* array)
45 {
46 JS_GC(rt);
47
48 ASSERT_TRUE(array != nullptr);
49 JS_AddExtraGCRootsTracer(rt, TraceArray<ArrayT>, array);
50
51 /*
52 * Create the array and fill it with new JS objects. With GGC these will be
53 * allocated in the nursery.
54 */
55 RootedValue value(cx);
56 const char* property = "foo";
57 JS::shadow::Runtime* srt = reinterpret_cast<JS::shadow::Runtime*>(rt);
58 for (size_t i = 0; i < ElementCount; ++i) {
59 RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
60 #ifdef JSGC_GENERATIONAL
61 ASSERT_TRUE(js::gc::IsInsideNursery(srt, obj));
62 #else
63 ASSERT_FALSE(js::gc::IsInsideNursery(srt, obj));
64 #endif
65 value = Int32Value(i);
66 ASSERT_TRUE(JS_SetProperty(cx, obj, property, value));
67 array->AppendElement(obj);
68 }
69
70 /*
71 * If postbarriers are not working, we will crash here when we try to mark
72 * objects that have been moved to the tenured heap.
73 */
74 JS_GC(rt);
75
76 /*
77 * Sanity check that our array contains what we expect.
78 */
79 for (size_t i = 0; i < ElementCount; ++i) {
80 RootedObject obj(cx, array->ElementAt(i));
81 ASSERT_FALSE(js::gc::IsInsideNursery(srt, obj));
82 ASSERT_TRUE(JS_GetProperty(cx, obj, property, &value));
83 ASSERT_TRUE(value.isInt32());
84 ASSERT_EQ(static_cast<int32_t>(i), value.toInt32());
85 }
86
87 JS_RemoveExtraGCRootsTracer(rt, TraceArray<ArrayT>, array);
88 }
89
90 static void
91 CreateGlobalAndRunTest(JSRuntime* rt, JSContext* cx)
92 {
93 static const JSClass GlobalClass = {
94 "global", JSCLASS_GLOBAL_FLAGS,
95 JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
96 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
97 nullptr, nullptr, nullptr, nullptr,
98 JS_GlobalObjectTraceHook
99 };
100
101 JS::CompartmentOptions options;
102 options.setVersion(JSVERSION_LATEST);
103 JS::PersistentRootedObject global(cx);
104 global = JS_NewGlobalObject(cx, &GlobalClass, nullptr, JS::FireOnNewGlobalHook, options);
105 ASSERT_TRUE(global != nullptr);
106
107 JSCompartment *oldCompartment = JS_EnterCompartment(cx, global);
108
109 typedef Heap<JSObject*> ElementT;
110
111 {
112 nsTArray<ElementT>* array = new nsTArray<ElementT>(InitialElements);
113 RunTest(rt, cx, array);
114 delete array;
115 }
116
117 {
118 FallibleTArray<ElementT>* array = new FallibleTArray<ElementT>(InitialElements);
119 RunTest(rt, cx, array);
120 delete array;
121 }
122
123 {
124 nsAutoTArray<ElementT, InitialElements> array;
125 RunTest(rt, cx, &array);
126 }
127
128 {
129 AutoFallibleTArray<ElementT, InitialElements> array;
130 RunTest(rt, cx, &array);
131 }
132
133 JS_LeaveCompartment(cx, oldCompartment);
134 }
135
136 TEST(GCPostBarriers, nsTArray) {
137 CycleCollectedJSRuntime* ccrt = CycleCollectedJSRuntime::Get();
138 ASSERT_TRUE(ccrt != nullptr);
139 JSRuntime* rt = ccrt->Runtime();
140 ASSERT_TRUE(rt != nullptr);
141
142 JSContext *cx = JS_NewContext(rt, 8192);
143 ASSERT_TRUE(cx != nullptr);
144 JS_BeginRequest(cx);
145
146 CreateGlobalAndRunTest(rt, cx);
147
148 JS_EndRequest(cx);
149 JS_DestroyContext(cx);
150 }

mercurial