js/src/jsapi-tests/testPersistentRooted.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 #if defined(JSGC_USE_EXACT_ROOTING)
     7 #include "js/Class.h"
     8 #include "jsapi-tests/tests.h"
    10 using namespace JS;
    12 struct BarkWhenTracedClass {
    13     static int finalizeCount;
    14     static int traceCount;
    16     static const JSClass class_;
    17     static void finalize(JSFreeOp *fop, JSObject *obj) { finalizeCount++; }
    18     static void trace(JSTracer *trc, JSObject *obj) { traceCount++; }
    19     static void reset() { finalizeCount = 0; traceCount = 0; }
    20 };
    22 int BarkWhenTracedClass::finalizeCount;
    23 int BarkWhenTracedClass::traceCount;
    25 const JSClass BarkWhenTracedClass::class_ = {
    26   "BarkWhenTracedClass", 0,
    27   JS_PropertyStub,
    28   JS_DeletePropertyStub,
    29   JS_PropertyStub,
    30   JS_StrictPropertyStub,
    31   JS_EnumerateStub,
    32   JS_ResolveStub,
    33   JS_ConvertStub,
    34   finalize,
    35   nullptr,
    36   nullptr,
    37   nullptr,
    38   trace
    39 };
    41 struct Kennel {
    42     PersistentRootedObject obj;
    43     Kennel(JSContext *cx) : obj(cx) { }
    44     Kennel(JSContext *cx, const HandleObject &woof) : obj(cx, woof) { };
    45 };
    47 // A function for allocating a Kennel and a barker. Only allocating
    48 // PersistentRooteds on the heap, and in this function, helps ensure that the
    49 // conservative GC doesn't find stray references to the barker. Ugh.
    50 MOZ_NEVER_INLINE static Kennel *
    51 Allocate(JSContext *cx)
    52 {
    53     RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_, JS::NullPtr(), JS::NullPtr()));
    54     if (!barker)
    55         return nullptr;
    57     return new Kennel(cx, barker);
    58 }
    60 // Do a GC, expecting |n| barkers to be finalized.
    61 static bool
    62 GCFinalizesNBarkers(JSContext *cx, int n)
    63 {
    64     int preGCTrace = BarkWhenTracedClass::traceCount;
    65     int preGCFinalize = BarkWhenTracedClass::finalizeCount;
    67     JS_GC(JS_GetRuntime(cx));
    69     return (BarkWhenTracedClass::finalizeCount == preGCFinalize + n &&
    70             BarkWhenTracedClass::traceCount > preGCTrace);
    71 }
    73 // PersistentRooted instances protect their contents from being recycled.
    74 BEGIN_TEST(test_PersistentRooted)
    75 {
    76     BarkWhenTracedClass::reset();
    78     Kennel *kennel = Allocate(cx);
    79     CHECK(kennel);
    81     // GC should be able to find our barker.
    82     CHECK(GCFinalizesNBarkers(cx, 0));
    84     delete(kennel);
    86     // Now GC should not be able to find the barker.
    87     JS_GC(JS_GetRuntime(cx));
    88     CHECK(BarkWhenTracedClass::finalizeCount == 1);
    90     return true;
    91 }
    92 END_TEST(test_PersistentRooted)
    94 // GC should not be upset by null PersistentRooteds.
    95 BEGIN_TEST(test_PersistentRootedNull)
    96 {
    97     BarkWhenTracedClass::reset();
    99     Kennel kennel(cx);
   100     CHECK(!kennel.obj);
   102     JS_GC(JS_GetRuntime(cx));
   103     CHECK(BarkWhenTracedClass::finalizeCount == 0);
   105     return true;
   106 }
   107 END_TEST(test_PersistentRootedNull)
   109 // Copy construction works.
   110 BEGIN_TEST(test_PersistentRootedCopy)
   111 {
   112     BarkWhenTracedClass::reset();
   114     Kennel *kennel = Allocate(cx);
   115     CHECK(kennel);
   117     CHECK(GCFinalizesNBarkers(cx, 0));
   119     // Copy construction! AMAZING!
   120     Kennel *newKennel = new Kennel(*kennel);
   122     CHECK(GCFinalizesNBarkers(cx, 0));
   124     delete(kennel);
   126     CHECK(GCFinalizesNBarkers(cx, 0));
   128     delete(newKennel);
   130     // Now that kennel and nowKennel are both deallocated, GC should not be
   131     // able to find the barker.
   132     JS_GC(JS_GetRuntime(cx));
   133     CHECK(BarkWhenTracedClass::finalizeCount == 1);
   135     return true;
   136 }
   137 END_TEST(test_PersistentRootedCopy)
   139 // Assignment works.
   140 BEGIN_TEST(test_PersistentRootedAssign)
   141 {
   142     BarkWhenTracedClass::reset();
   144     Kennel *kennel = Allocate(cx);
   145     CHECK(kennel);
   147     CHECK(GCFinalizesNBarkers(cx, 0));
   149     // Allocate a new, empty kennel.
   150     Kennel *kennel2 = new Kennel(cx);
   152     // Assignment! ASTONISHING!
   153     *kennel2 = *kennel;
   155     // With both kennels referring to the same barker, it is held alive.
   156     CHECK(GCFinalizesNBarkers(cx, 0));
   158     delete(kennel2);
   160     // The destination of the assignment alone holds the barker alive.
   161     CHECK(GCFinalizesNBarkers(cx, 0));
   163     // Allocate a second barker.
   164     kennel2 = Allocate(cx);
   165     CHECK(kennel);
   167     *kennel = *kennel2;
   169     // Nothing refers to the first kennel any more.
   170     CHECK(GCFinalizesNBarkers(cx, 1));
   172     delete(kennel);
   173     delete(kennel2);
   175     // Now that kennel and kennel2 are both deallocated, GC should not be
   176     // able to find the barker.
   177     JS_GC(JS_GetRuntime(cx));
   178     CHECK(BarkWhenTracedClass::finalizeCount == 2);
   180     return true;
   181 }
   182 END_TEST(test_PersistentRootedAssign)
   184 #endif // defined(JSGC_USE_EXACT_ROOTING)

mercurial