js/src/jsapi-tests/testGCFinalizeCallback.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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 "jsapi-tests/tests.h"
     7 static const unsigned BufferSize = 20;
     8 static unsigned FinalizeCalls = 0;
     9 static JSFinalizeStatus StatusBuffer[BufferSize];
    10 static bool IsCompartmentGCBuffer[BufferSize];
    12 BEGIN_TEST(testGCFinalizeCallback)
    13 {
    14     JS_SetGCParameter(rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
    15     JS_SetFinalizeCallback(rt, FinalizeCallback);
    17     /* Full GC, non-incremental. */
    18     FinalizeCalls = 0;
    19     JS_GC(rt);
    20     CHECK(rt->gcIsFull);
    21     CHECK(checkSingleGroup());
    22     CHECK(checkFinalizeStatus());
    23     CHECK(checkFinalizeIsCompartmentGC(false));
    25     /* Full GC, incremental. */
    26     FinalizeCalls = 0;
    27     JS::PrepareForFullGC(rt);
    28     JS::IncrementalGC(rt, JS::gcreason::API, 1000000);
    29     CHECK(rt->gcIncrementalState == js::gc::NO_INCREMENTAL);
    30     CHECK(rt->gcIsFull);
    31     CHECK(checkMultipleGroups());
    32     CHECK(checkFinalizeStatus());
    33     CHECK(checkFinalizeIsCompartmentGC(false));
    35     JS::RootedObject global1(cx, createGlobal());
    36     JS::RootedObject global2(cx, createGlobal());
    37     JS::RootedObject global3(cx, createGlobal());
    38     CHECK(global1);
    39     CHECK(global2);
    40     CHECK(global3);
    42     /* Compartment GC, non-incremental, single compartment. */
    43     FinalizeCalls = 0;
    44     JS::PrepareZoneForGC(global1->zone());
    45     JS::GCForReason(rt, JS::gcreason::API);
    46     CHECK(!rt->gcIsFull);
    47     CHECK(checkSingleGroup());
    48     CHECK(checkFinalizeStatus());
    49     CHECK(checkFinalizeIsCompartmentGC(true));
    51     /* Compartment GC, non-incremental, multiple compartments. */
    52     FinalizeCalls = 0;
    53     JS::PrepareZoneForGC(global1->zone());
    54     JS::PrepareZoneForGC(global2->zone());
    55     JS::PrepareZoneForGC(global3->zone());
    56     JS::GCForReason(rt, JS::gcreason::API);
    57     CHECK(!rt->gcIsFull);
    58     CHECK(checkSingleGroup());
    59     CHECK(checkFinalizeStatus());
    60     CHECK(checkFinalizeIsCompartmentGC(true));
    62     /* Compartment GC, incremental, single compartment. */
    63     FinalizeCalls = 0;
    64     JS::PrepareZoneForGC(global1->zone());
    65     JS::IncrementalGC(rt, JS::gcreason::API, 1000000);
    66     CHECK(rt->gcIncrementalState == js::gc::NO_INCREMENTAL);
    67     CHECK(!rt->gcIsFull);
    68     CHECK(checkSingleGroup());
    69     CHECK(checkFinalizeStatus());
    70     CHECK(checkFinalizeIsCompartmentGC(true));
    72     /* Compartment GC, incremental, multiple compartments. */
    73     FinalizeCalls = 0;
    74     JS::PrepareZoneForGC(global1->zone());
    75     JS::PrepareZoneForGC(global2->zone());
    76     JS::PrepareZoneForGC(global3->zone());
    77     JS::IncrementalGC(rt, JS::gcreason::API, 1000000);
    78     CHECK(rt->gcIncrementalState == js::gc::NO_INCREMENTAL);
    79     CHECK(!rt->gcIsFull);
    80     CHECK(checkMultipleGroups());
    81     CHECK(checkFinalizeStatus());
    82     CHECK(checkFinalizeIsCompartmentGC(true));
    84 #ifdef JS_GC_ZEAL
    86     /* Full GC with reset due to new compartment, becoming compartment GC. */
    88     FinalizeCalls = 0;
    89     JS_SetGCZeal(cx, 9, 1000000);
    90     JS::PrepareForFullGC(rt);
    91     js::GCDebugSlice(rt, true, 1);
    92     CHECK(rt->gcIncrementalState == js::gc::MARK);
    93     CHECK(rt->gcIsFull);
    95     JS::RootedObject global4(cx, createGlobal());
    96     js::GCDebugSlice(rt, true, 1);
    97     CHECK(rt->gcIncrementalState == js::gc::NO_INCREMENTAL);
    98     CHECK(!rt->gcIsFull);
    99     CHECK(checkMultipleGroups());
   100     CHECK(checkFinalizeStatus());
   102     for (unsigned i = 0; i < FinalizeCalls - 1; ++i)
   103         CHECK(!IsCompartmentGCBuffer[i]);
   104     CHECK(IsCompartmentGCBuffer[FinalizeCalls - 1]);
   106     JS_SetGCZeal(cx, 0, 0);
   108 #endif
   110     /*
   111      * Make some use of the globals here to ensure the compiler doesn't optimize
   112      * them away in release builds, causing the compartments to be collected and
   113      * the test to fail.
   114      */
   115     CHECK(JS_IsGlobalObject(global1));
   116     CHECK(JS_IsGlobalObject(global2));
   117     CHECK(JS_IsGlobalObject(global3));
   119     JS_SetFinalizeCallback(rt, nullptr);
   120     return true;
   121 }
   123 bool checkSingleGroup()
   124 {
   125     CHECK(FinalizeCalls < BufferSize);
   126     CHECK(FinalizeCalls == 3);
   127     return true;
   128 }
   130 bool checkMultipleGroups()
   131 {
   132     CHECK(FinalizeCalls < BufferSize);
   133     CHECK(FinalizeCalls % 2 == 1);
   134     CHECK((FinalizeCalls - 1) / 2 > 1);
   135     return true;
   136 }
   138 bool checkFinalizeStatus()
   139 {
   140     /*
   141      * The finalize callback should be called twice for each compartment group
   142      * finalized, with status JSFINALIZE_GROUP_START and JSFINALIZE_GROUP_END,
   143      * and then once more with JSFINALIZE_COLLECTION_END.
   144      */
   146     for (unsigned i = 0; i < FinalizeCalls - 1; i += 2) {
   147         CHECK(StatusBuffer[i] == JSFINALIZE_GROUP_START);
   148         CHECK(StatusBuffer[i + 1] == JSFINALIZE_GROUP_END);
   149     }
   151     CHECK(StatusBuffer[FinalizeCalls - 1] == JSFINALIZE_COLLECTION_END);
   153     return true;
   154 }
   156 bool checkFinalizeIsCompartmentGC(bool isCompartmentGC)
   157 {
   158     for (unsigned i = 0; i < FinalizeCalls; ++i)
   159         CHECK(IsCompartmentGCBuffer[i] == isCompartmentGC);
   161     return true;
   162 }
   164 static void
   165 FinalizeCallback(JSFreeOp *fop, JSFinalizeStatus status, bool isCompartmentGC)
   166 {
   167     if (FinalizeCalls < BufferSize) {
   168         StatusBuffer[FinalizeCalls] = status;
   169         IsCompartmentGCBuffer[FinalizeCalls] = isCompartmentGC;
   170     }
   171     ++FinalizeCalls;
   172 }
   173 END_TEST(testGCFinalizeCallback)

mercurial