xpcom/glue/tests/gtest/TestGCPostBarriers.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,150 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * vim: sw=2 ts=8 et :
     1.6 + */
     1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    1.10 +
    1.11 +/*
    1.12 + * Tests that generational garbage collection post-barriers are correctly
    1.13 + * implemented for nsTArrays that contain JavaScript Values.
    1.14 + */
    1.15 +
    1.16 +#include "jsapi.h"
    1.17 +#include "nsTArray.h"
    1.18 +
    1.19 +#include "gtest/gtest.h"
    1.20 +
    1.21 +#include "js/TracingAPI.h"
    1.22 +#include "js/HeapAPI.h"
    1.23 +
    1.24 +#include "mozilla/CycleCollectedJSRuntime.h"
    1.25 +
    1.26 +using namespace JS;
    1.27 +using namespace mozilla;
    1.28 +
    1.29 +template <class ArrayT>
    1.30 +static void
    1.31 +TraceArray(JSTracer* trc, void* data)
    1.32 +{
    1.33 +  ArrayT* array = static_cast<ArrayT *>(data);
    1.34 +  for (unsigned i = 0; i < array->Length(); ++i)
    1.35 +    JS_CallHeapObjectTracer(trc, &array->ElementAt(i), "array-element");
    1.36 +}
    1.37 +
    1.38 +/*
    1.39 + * Use arrays with initial size much smaller than the final number of elements
    1.40 + * to test that moving Heap<T> elements works correctly.
    1.41 + */
    1.42 +const size_t ElementCount = 100;
    1.43 +const size_t InitialElements = ElementCount / 10;
    1.44 +
    1.45 +template <class ArrayT>
    1.46 +static void
    1.47 +RunTest(JSRuntime* rt, JSContext* cx, ArrayT* array)
    1.48 +{
    1.49 +  JS_GC(rt);
    1.50 +
    1.51 +  ASSERT_TRUE(array != nullptr);
    1.52 +  JS_AddExtraGCRootsTracer(rt, TraceArray<ArrayT>, array);
    1.53 +
    1.54 +  /*
    1.55 +   * Create the array and fill it with new JS objects. With GGC these will be
    1.56 +   * allocated in the nursery.
    1.57 +   */
    1.58 +  RootedValue value(cx);
    1.59 +  const char* property = "foo";
    1.60 +  JS::shadow::Runtime* srt = reinterpret_cast<JS::shadow::Runtime*>(rt);
    1.61 +  for (size_t i = 0; i < ElementCount; ++i) {
    1.62 +    RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
    1.63 +#ifdef JSGC_GENERATIONAL
    1.64 +    ASSERT_TRUE(js::gc::IsInsideNursery(srt, obj));
    1.65 +#else
    1.66 +    ASSERT_FALSE(js::gc::IsInsideNursery(srt, obj));
    1.67 +#endif
    1.68 +    value = Int32Value(i);
    1.69 +    ASSERT_TRUE(JS_SetProperty(cx, obj, property, value));
    1.70 +    array->AppendElement(obj);
    1.71 +  }
    1.72 +
    1.73 +  /*
    1.74 +   * If postbarriers are not working, we will crash here when we try to mark
    1.75 +   * objects that have been moved to the tenured heap.
    1.76 +   */
    1.77 +  JS_GC(rt);
    1.78 +
    1.79 +  /*
    1.80 +   * Sanity check that our array contains what we expect.
    1.81 +   */
    1.82 +  for (size_t i = 0; i < ElementCount; ++i) {
    1.83 +    RootedObject obj(cx, array->ElementAt(i));
    1.84 +    ASSERT_FALSE(js::gc::IsInsideNursery(srt, obj));
    1.85 +    ASSERT_TRUE(JS_GetProperty(cx, obj, property, &value));
    1.86 +    ASSERT_TRUE(value.isInt32());
    1.87 +    ASSERT_EQ(static_cast<int32_t>(i), value.toInt32());
    1.88 +  }
    1.89 +
    1.90 +  JS_RemoveExtraGCRootsTracer(rt, TraceArray<ArrayT>, array);
    1.91 +}
    1.92 +
    1.93 +static void
    1.94 +CreateGlobalAndRunTest(JSRuntime* rt, JSContext* cx)
    1.95 +{
    1.96 +  static const JSClass GlobalClass = {
    1.97 +    "global", JSCLASS_GLOBAL_FLAGS,
    1.98 +    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
    1.99 +    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
   1.100 +    nullptr, nullptr, nullptr, nullptr,
   1.101 +    JS_GlobalObjectTraceHook
   1.102 +  };
   1.103 +
   1.104 +  JS::CompartmentOptions options;
   1.105 +  options.setVersion(JSVERSION_LATEST);
   1.106 +  JS::PersistentRootedObject global(cx);
   1.107 +  global = JS_NewGlobalObject(cx, &GlobalClass, nullptr, JS::FireOnNewGlobalHook, options);
   1.108 +  ASSERT_TRUE(global != nullptr);
   1.109 +
   1.110 +  JSCompartment *oldCompartment = JS_EnterCompartment(cx, global);
   1.111 +
   1.112 +  typedef Heap<JSObject*> ElementT;
   1.113 +
   1.114 +  {
   1.115 +    nsTArray<ElementT>* array = new nsTArray<ElementT>(InitialElements);
   1.116 +    RunTest(rt, cx, array);
   1.117 +    delete array;
   1.118 +  }
   1.119 +
   1.120 +  {
   1.121 +    FallibleTArray<ElementT>* array = new FallibleTArray<ElementT>(InitialElements);
   1.122 +    RunTest(rt, cx, array);
   1.123 +    delete array;
   1.124 +  }
   1.125 +
   1.126 +  {
   1.127 +    nsAutoTArray<ElementT, InitialElements> array;
   1.128 +    RunTest(rt, cx, &array);
   1.129 +  }
   1.130 +
   1.131 +  {
   1.132 +    AutoFallibleTArray<ElementT, InitialElements> array;
   1.133 +    RunTest(rt, cx, &array);
   1.134 +  }
   1.135 +
   1.136 +  JS_LeaveCompartment(cx, oldCompartment);
   1.137 +}
   1.138 +
   1.139 +TEST(GCPostBarriers, nsTArray) {
   1.140 +  CycleCollectedJSRuntime* ccrt = CycleCollectedJSRuntime::Get();
   1.141 +  ASSERT_TRUE(ccrt != nullptr);
   1.142 +  JSRuntime* rt = ccrt->Runtime();
   1.143 +  ASSERT_TRUE(rt != nullptr);
   1.144 +
   1.145 +  JSContext *cx = JS_NewContext(rt, 8192);
   1.146 +  ASSERT_TRUE(cx != nullptr);
   1.147 +  JS_BeginRequest(cx);
   1.148 +
   1.149 +  CreateGlobalAndRunTest(rt, cx);
   1.150 +
   1.151 +  JS_EndRequest(cx);
   1.152 +  JS_DestroyContext(cx);
   1.153 +}

mercurial