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/. */
4 
5 #include "mozilla/ArrayUtils.h"
6 #include "mozilla/UniquePtr.h"
7 
8 #include "jsapi-tests/tests.h"
9 
10 static unsigned gSliceCallbackCount = 0;
11 
NonIncrementalGCSliceCallback(JSContext * cx,JS::GCProgress progress,const JS::GCDescription & desc)12 static void NonIncrementalGCSliceCallback(JSContext* cx,
13                                           JS::GCProgress progress,
14                                           const JS::GCDescription& desc) {
15   using namespace JS;
16   static GCProgress expect[] = {GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END,
17                                 GC_CYCLE_END};
18 
19   MOZ_RELEASE_ASSERT(gSliceCallbackCount < mozilla::ArrayLength(expect));
20   MOZ_RELEASE_ASSERT(progress == expect[gSliceCallbackCount++]);
21   MOZ_RELEASE_ASSERT(desc.isZone_ == false);
22   MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_NORMAL);
23   MOZ_RELEASE_ASSERT(desc.reason_ == JS::GCReason::API);
24   if (progress == GC_CYCLE_END) {
25     mozilla::UniquePtr<char16_t> summary(desc.formatSummaryMessage(cx));
26     mozilla::UniquePtr<char16_t> message(desc.formatSliceMessage(cx));
27     mozilla::UniquePtr<char16_t> json(desc.formatJSONTelemetry(cx, 0));
28   }
29 }
30 
BEGIN_TEST(testGCSliceCallback)31 BEGIN_TEST(testGCSliceCallback) {
32   gSliceCallbackCount = 0;
33   JS::SetGCSliceCallback(cx, NonIncrementalGCSliceCallback);
34   JS_GC(cx);
35   JS::SetGCSliceCallback(cx, nullptr);
36   CHECK(gSliceCallbackCount == 4);
37   return true;
38 }
END_TEST(testGCSliceCallback)39 END_TEST(testGCSliceCallback)
40 
41 static void RootsRemovedGCSliceCallback(JSContext* cx, JS::GCProgress progress,
42                                         const JS::GCDescription& desc) {
43   using namespace JS;
44 
45   static GCProgress expectProgress[] = {
46       GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END,   GC_SLICE_BEGIN,
47       GC_SLICE_END,   GC_CYCLE_END,   GC_CYCLE_BEGIN, GC_SLICE_BEGIN,
48       GC_SLICE_END,   GC_CYCLE_END};
49 
50   static GCReason expectReasons[] = {
51       GCReason::DEBUG_GC,      GCReason::DEBUG_GC,      GCReason::DEBUG_GC,
52       GCReason::DEBUG_GC,      GCReason::DEBUG_GC,      GCReason::DEBUG_GC,
53       GCReason::ROOTS_REMOVED, GCReason::ROOTS_REMOVED, GCReason::ROOTS_REMOVED,
54       GCReason::ROOTS_REMOVED};
55 
56   static_assert(
57       mozilla::ArrayLength(expectProgress) ==
58           mozilla::ArrayLength(expectReasons),
59       "expectProgress and expectReasons arrays should be the same length");
60 
61   MOZ_RELEASE_ASSERT(gSliceCallbackCount <
62                      mozilla::ArrayLength(expectProgress));
63   MOZ_RELEASE_ASSERT(progress == expectProgress[gSliceCallbackCount]);
64   MOZ_RELEASE_ASSERT(desc.isZone_ == false);
65   MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_SHRINK);
66   MOZ_RELEASE_ASSERT(desc.reason_ == expectReasons[gSliceCallbackCount]);
67   gSliceCallbackCount++;
68 }
69 
BEGIN_TEST(testGCRootsRemoved)70 BEGIN_TEST(testGCRootsRemoved) {
71 #ifdef JS_GC_ZEAL
72   AutoLeaveZeal nozeal(cx);
73 #endif /* JS_GC_ZEAL */
74 
75   JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_ZONE_INCREMENTAL);
76 
77   gSliceCallbackCount = 0;
78   JS::SetGCSliceCallback(cx, RootsRemovedGCSliceCallback);
79 
80   JS::RootedObject obj(cx, JS_NewPlainObject(cx));
81   CHECK(obj);
82 
83   JS::PrepareForFullGC(cx);
84   js::SliceBudget budget(js::WorkBudget(1));
85   cx->runtime()->gc.startDebugGC(GC_SHRINK, budget);
86   CHECK(JS::IsIncrementalGCInProgress(cx));
87 
88   // Trigger another GC after the current one in shrinking / shutdown GCs.
89   cx->runtime()->gc.notifyRootsRemoved();
90 
91   JS::FinishIncrementalGC(cx, JS::GCReason::DEBUG_GC);
92   CHECK(!JS::IsIncrementalGCInProgress(cx));
93 
94   JS::SetGCSliceCallback(cx, nullptr);
95 
96   JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_GLOBAL);
97 
98   return true;
99 }
100 END_TEST(testGCRootsRemoved)
101