/src/mozilla-central/xpcom/tests/gtest/TestGCPostBarriers.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | /* |
8 | | * Tests that generational garbage collection post-barriers are correctly |
9 | | * implemented for nsTArrays that contain JavaScript Values. |
10 | | */ |
11 | | |
12 | | #include "jsapi.h" |
13 | | #include "nsTArray.h" |
14 | | |
15 | | #include "gtest/gtest.h" |
16 | | |
17 | | #include "js/TracingAPI.h" |
18 | | #include "js/HeapAPI.h" |
19 | | |
20 | | #include "mozilla/CycleCollectedJSContext.h" |
21 | | |
22 | | using namespace JS; |
23 | | using namespace mozilla; |
24 | | |
25 | | template<class ArrayT> |
26 | | static void |
27 | | TraceArray(JSTracer* trc, void* data) |
28 | 0 | { |
29 | 0 | ArrayT* array = static_cast<ArrayT *>(data); |
30 | 0 | for (unsigned i = 0; i < array->Length(); ++i) |
31 | 0 | JS::TraceEdge(trc, &array->ElementAt(i), "array-element"); |
32 | 0 | } Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void TraceArray<nsTArray<JS::Heap<JSObject*> > >(JSTracer*, void*) Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void TraceArray<FallibleTArray<JS::Heap<JSObject*> > >(JSTracer*, void*) Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void TraceArray<AutoTArray<JS::Heap<JSObject*>, 10ul> >(JSTracer*, void*) |
33 | | |
34 | | /* |
35 | | * Use arrays with initial size much smaller than the final number of elements |
36 | | * to test that moving Heap<T> elements works correctly. |
37 | | */ |
38 | | const size_t ElementCount = 100; |
39 | | const size_t InitialElements = ElementCount / 10; |
40 | | |
41 | | template<class ArrayT> |
42 | | static void |
43 | | RunTest(JSContext* cx, ArrayT* array) |
44 | 0 | { |
45 | 0 | JS_GC(cx); |
46 | 0 |
|
47 | 0 | ASSERT_TRUE(array != nullptr); |
48 | 0 | JS_AddExtraGCRootsTracer(cx, TraceArray<ArrayT>, array); |
49 | 0 |
|
50 | 0 | /* |
51 | 0 | * Create the array and fill it with new JS objects. With GGC these will be |
52 | 0 | * allocated in the nursery. |
53 | 0 | */ |
54 | 0 | RootedValue value(cx); |
55 | 0 | const char* property = "foo"; |
56 | 0 | for (size_t i = 0; i < ElementCount; ++i) { |
57 | 0 | RootedObject obj(cx, JS_NewPlainObject(cx)); |
58 | 0 | ASSERT_FALSE(JS::ObjectIsTenured(obj)); |
59 | 0 | value = Int32Value(i); |
60 | 0 | ASSERT_TRUE(JS_SetProperty(cx, obj, property, value)); |
61 | 0 | ASSERT_TRUE(array->AppendElement(obj, fallible)); |
62 | 0 | } |
63 | 0 |
|
64 | 0 | /* |
65 | 0 | * If postbarriers are not working, we will crash here when we try to mark |
66 | 0 | * objects that have been moved to the tenured heap. |
67 | 0 | */ |
68 | 0 | JS_GC(cx); |
69 | 0 |
|
70 | 0 | /* |
71 | 0 | * Sanity check that our array contains what we expect. |
72 | 0 | */ |
73 | 0 | for (size_t i = 0; i < ElementCount; ++i) { |
74 | 0 | RootedObject obj(cx, array->ElementAt(i)); |
75 | 0 | ASSERT_TRUE(JS::ObjectIsTenured(obj)); |
76 | 0 | ASSERT_TRUE(JS_GetProperty(cx, obj, property, &value)); |
77 | 0 | ASSERT_TRUE(value.isInt32()); |
78 | 0 | ASSERT_EQ(static_cast<int32_t>(i), value.toInt32()); |
79 | 0 | } |
80 | 0 |
|
81 | 0 | JS_RemoveExtraGCRootsTracer(cx, TraceArray<ArrayT>, array); |
82 | 0 | } Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunTest<nsTArray<JS::Heap<JSObject*> > >(JSContext*, nsTArray<JS::Heap<JSObject*> >*) Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunTest<FallibleTArray<JS::Heap<JSObject*> > >(JSContext*, FallibleTArray<JS::Heap<JSObject*> >*) Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunTest<AutoTArray<JS::Heap<JSObject*>, 10ul> >(JSContext*, AutoTArray<JS::Heap<JSObject*>, 10ul>*) |
83 | | |
84 | | static void |
85 | | CreateGlobalAndRunTest(JSContext* cx) |
86 | 0 | { |
87 | 0 | static const JSClassOps GlobalClassOps = { |
88 | 0 | nullptr, nullptr, nullptr, nullptr, |
89 | 0 | nullptr, nullptr, nullptr, nullptr, |
90 | 0 | nullptr, nullptr, JS_GlobalObjectTraceHook |
91 | 0 | }; |
92 | 0 |
|
93 | 0 | static const JSClass GlobalClass = { |
94 | 0 | "global", JSCLASS_GLOBAL_FLAGS, |
95 | 0 | &GlobalClassOps |
96 | 0 | }; |
97 | 0 |
|
98 | 0 | JS::RealmOptions options; |
99 | 0 | JS::PersistentRootedObject global(cx); |
100 | 0 | global = JS_NewGlobalObject(cx, &GlobalClass, nullptr, JS::FireOnNewGlobalHook, options); |
101 | 0 | ASSERT_TRUE(global != nullptr); |
102 | 0 |
|
103 | 0 | JS::Realm* oldRealm = JS::EnterRealm(cx, global); |
104 | 0 |
|
105 | 0 | typedef Heap<JSObject*> ElementT; |
106 | 0 |
|
107 | 0 | { |
108 | 0 | nsTArray<ElementT>* array = new nsTArray<ElementT>(InitialElements); |
109 | 0 | RunTest(cx, array); |
110 | 0 | delete array; |
111 | 0 | } |
112 | 0 |
|
113 | 0 | { |
114 | 0 | FallibleTArray<ElementT>* array = new FallibleTArray<ElementT>(InitialElements); |
115 | 0 | RunTest(cx, array); |
116 | 0 | delete array; |
117 | 0 | } |
118 | 0 |
|
119 | 0 | { |
120 | 0 | AutoTArray<ElementT, InitialElements> array; |
121 | 0 | RunTest(cx, &array); |
122 | 0 | } |
123 | 0 |
|
124 | 0 | JS::LeaveRealm(cx, oldRealm); |
125 | 0 | } |
126 | | |
127 | 0 | TEST(GCPostBarriers, nsTArray) { |
128 | 0 | CycleCollectedJSContext* ccjscx = CycleCollectedJSContext::Get(); |
129 | 0 | ASSERT_TRUE(ccjscx != nullptr); |
130 | 0 | JSContext* cx = ccjscx->Context(); |
131 | 0 | ASSERT_TRUE(cx != nullptr); |
132 | 0 |
|
133 | 0 | CreateGlobalAndRunTest(cx); |
134 | 0 | } |