js/src/jsapi-tests/testPersistentRooted.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jsapi-tests/testPersistentRooted.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,184 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#if defined(JSGC_USE_EXACT_ROOTING)
     1.9 +
    1.10 +#include "js/Class.h"
    1.11 +#include "jsapi-tests/tests.h"
    1.12 +
    1.13 +using namespace JS;
    1.14 +
    1.15 +struct BarkWhenTracedClass {
    1.16 +    static int finalizeCount;
    1.17 +    static int traceCount;
    1.18 +
    1.19 +    static const JSClass class_;
    1.20 +    static void finalize(JSFreeOp *fop, JSObject *obj) { finalizeCount++; }
    1.21 +    static void trace(JSTracer *trc, JSObject *obj) { traceCount++; }
    1.22 +    static void reset() { finalizeCount = 0; traceCount = 0; }
    1.23 +};
    1.24 +
    1.25 +int BarkWhenTracedClass::finalizeCount;
    1.26 +int BarkWhenTracedClass::traceCount;
    1.27 +
    1.28 +const JSClass BarkWhenTracedClass::class_ = {
    1.29 +  "BarkWhenTracedClass", 0,
    1.30 +  JS_PropertyStub,
    1.31 +  JS_DeletePropertyStub,
    1.32 +  JS_PropertyStub,
    1.33 +  JS_StrictPropertyStub,
    1.34 +  JS_EnumerateStub,
    1.35 +  JS_ResolveStub,
    1.36 +  JS_ConvertStub,
    1.37 +  finalize,
    1.38 +  nullptr,
    1.39 +  nullptr,
    1.40 +  nullptr,
    1.41 +  trace
    1.42 +};
    1.43 +
    1.44 +struct Kennel {
    1.45 +    PersistentRootedObject obj;
    1.46 +    Kennel(JSContext *cx) : obj(cx) { }
    1.47 +    Kennel(JSContext *cx, const HandleObject &woof) : obj(cx, woof) { };
    1.48 +};
    1.49 +
    1.50 +// A function for allocating a Kennel and a barker. Only allocating
    1.51 +// PersistentRooteds on the heap, and in this function, helps ensure that the
    1.52 +// conservative GC doesn't find stray references to the barker. Ugh.
    1.53 +MOZ_NEVER_INLINE static Kennel *
    1.54 +Allocate(JSContext *cx)
    1.55 +{
    1.56 +    RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_, JS::NullPtr(), JS::NullPtr()));
    1.57 +    if (!barker)
    1.58 +        return nullptr;
    1.59 +
    1.60 +    return new Kennel(cx, barker);
    1.61 +}
    1.62 +
    1.63 +// Do a GC, expecting |n| barkers to be finalized.
    1.64 +static bool
    1.65 +GCFinalizesNBarkers(JSContext *cx, int n)
    1.66 +{
    1.67 +    int preGCTrace = BarkWhenTracedClass::traceCount;
    1.68 +    int preGCFinalize = BarkWhenTracedClass::finalizeCount;
    1.69 +
    1.70 +    JS_GC(JS_GetRuntime(cx));
    1.71 +
    1.72 +    return (BarkWhenTracedClass::finalizeCount == preGCFinalize + n &&
    1.73 +            BarkWhenTracedClass::traceCount > preGCTrace);
    1.74 +}
    1.75 +
    1.76 +// PersistentRooted instances protect their contents from being recycled.
    1.77 +BEGIN_TEST(test_PersistentRooted)
    1.78 +{
    1.79 +    BarkWhenTracedClass::reset();
    1.80 +
    1.81 +    Kennel *kennel = Allocate(cx);
    1.82 +    CHECK(kennel);
    1.83 +
    1.84 +    // GC should be able to find our barker.
    1.85 +    CHECK(GCFinalizesNBarkers(cx, 0));
    1.86 +
    1.87 +    delete(kennel);
    1.88 +
    1.89 +    // Now GC should not be able to find the barker.
    1.90 +    JS_GC(JS_GetRuntime(cx));
    1.91 +    CHECK(BarkWhenTracedClass::finalizeCount == 1);
    1.92 +
    1.93 +    return true;
    1.94 +}
    1.95 +END_TEST(test_PersistentRooted)
    1.96 +
    1.97 +// GC should not be upset by null PersistentRooteds.
    1.98 +BEGIN_TEST(test_PersistentRootedNull)
    1.99 +{
   1.100 +    BarkWhenTracedClass::reset();
   1.101 +
   1.102 +    Kennel kennel(cx);
   1.103 +    CHECK(!kennel.obj);
   1.104 +
   1.105 +    JS_GC(JS_GetRuntime(cx));
   1.106 +    CHECK(BarkWhenTracedClass::finalizeCount == 0);
   1.107 +
   1.108 +    return true;
   1.109 +}
   1.110 +END_TEST(test_PersistentRootedNull)
   1.111 +
   1.112 +// Copy construction works.
   1.113 +BEGIN_TEST(test_PersistentRootedCopy)
   1.114 +{
   1.115 +    BarkWhenTracedClass::reset();
   1.116 +
   1.117 +    Kennel *kennel = Allocate(cx);
   1.118 +    CHECK(kennel);
   1.119 +
   1.120 +    CHECK(GCFinalizesNBarkers(cx, 0));
   1.121 +
   1.122 +    // Copy construction! AMAZING!
   1.123 +    Kennel *newKennel = new Kennel(*kennel);
   1.124 +
   1.125 +    CHECK(GCFinalizesNBarkers(cx, 0));
   1.126 +
   1.127 +    delete(kennel);
   1.128 +
   1.129 +    CHECK(GCFinalizesNBarkers(cx, 0));
   1.130 +
   1.131 +    delete(newKennel);
   1.132 +
   1.133 +    // Now that kennel and nowKennel are both deallocated, GC should not be
   1.134 +    // able to find the barker.
   1.135 +    JS_GC(JS_GetRuntime(cx));
   1.136 +    CHECK(BarkWhenTracedClass::finalizeCount == 1);
   1.137 +
   1.138 +    return true;
   1.139 +}
   1.140 +END_TEST(test_PersistentRootedCopy)
   1.141 +
   1.142 +// Assignment works.
   1.143 +BEGIN_TEST(test_PersistentRootedAssign)
   1.144 +{
   1.145 +    BarkWhenTracedClass::reset();
   1.146 +
   1.147 +    Kennel *kennel = Allocate(cx);
   1.148 +    CHECK(kennel);
   1.149 +
   1.150 +    CHECK(GCFinalizesNBarkers(cx, 0));
   1.151 +
   1.152 +    // Allocate a new, empty kennel.
   1.153 +    Kennel *kennel2 = new Kennel(cx);
   1.154 +
   1.155 +    // Assignment! ASTONISHING!
   1.156 +    *kennel2 = *kennel;
   1.157 +
   1.158 +    // With both kennels referring to the same barker, it is held alive.
   1.159 +    CHECK(GCFinalizesNBarkers(cx, 0));
   1.160 +
   1.161 +    delete(kennel2);
   1.162 +
   1.163 +    // The destination of the assignment alone holds the barker alive.
   1.164 +    CHECK(GCFinalizesNBarkers(cx, 0));
   1.165 +
   1.166 +    // Allocate a second barker.
   1.167 +    kennel2 = Allocate(cx);
   1.168 +    CHECK(kennel);
   1.169 +
   1.170 +    *kennel = *kennel2;
   1.171 +
   1.172 +    // Nothing refers to the first kennel any more.
   1.173 +    CHECK(GCFinalizesNBarkers(cx, 1));
   1.174 +
   1.175 +    delete(kennel);
   1.176 +    delete(kennel2);
   1.177 +
   1.178 +    // Now that kennel and kennel2 are both deallocated, GC should not be
   1.179 +    // able to find the barker.
   1.180 +    JS_GC(JS_GetRuntime(cx));
   1.181 +    CHECK(BarkWhenTracedClass::finalizeCount == 2);
   1.182 +
   1.183 +    return true;
   1.184 +}
   1.185 +END_TEST(test_PersistentRootedAssign)
   1.186 +
   1.187 +#endif // defined(JSGC_USE_EXACT_ROOTING)

mercurial