diff options
Diffstat (limited to 'js/src/jsapi-tests/testGCUniqueId.cpp')
-rw-r--r-- | js/src/jsapi-tests/testGCUniqueId.cpp | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/testGCUniqueId.cpp b/js/src/jsapi-tests/testGCUniqueId.cpp new file mode 100644 index 0000000000..1c5652f280 --- /dev/null +++ b/js/src/jsapi-tests/testGCUniqueId.cpp @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "js/GCVector.h" + +#include "jsapi-tests/tests.h" + +#include "gc/StableCellHasher-inl.h" + +using namespace js; + +static void MinimizeHeap(JSContext* cx) { + // The second collection is to force us to wait for the background + // sweeping that the first GC started to finish. + JS_GC(cx); + JS_GC(cx); + js::gc::FinishGC(cx); +} + +BEGIN_TEST(testGCUID) { + AutoLeaveZeal nozeal(cx); + + uint64_t uid = 0; + uint64_t tmp = 0; + + // Ensure the heap is as minimal as it can get. + MinimizeHeap(cx); + + JS::RootedObject obj(cx, JS_NewPlainObject(cx)); + uintptr_t nurseryAddr = uintptr_t(obj.get()); + CHECK(obj); + CHECK(gc::IsInsideNursery(obj)); + + // Do not start with an ID. + CHECK(!gc::HasUniqueId(obj)); + + // Ensure we can get a new UID. + CHECK(gc::GetOrCreateUniqueId(obj, &uid)); + CHECK(uid > gc::LargestTaggedNullCellPointer); + + // We should now have an id. + CHECK(gc::HasUniqueId(obj)); + + // Calling again should get us the same thing. + CHECK(gc::GetOrCreateUniqueId(obj, &tmp)); + CHECK(uid == tmp); + + // Tenure the thing and check that the UID moved with it. + MinimizeHeap(cx); + uintptr_t tenuredAddr = uintptr_t(obj.get()); + CHECK(tenuredAddr != nurseryAddr); + CHECK(!gc::IsInsideNursery(obj)); + CHECK(gc::HasUniqueId(obj)); + CHECK(gc::GetOrCreateUniqueId(obj, &tmp)); + CHECK(uid == tmp); + + // Allocate a new nursery thing in the same location and check that we + // removed the prior uid that was attached to the location. + obj = JS_NewPlainObject(cx); + CHECK(obj); + CHECK(uintptr_t(obj.get()) == nurseryAddr); + CHECK(!gc::HasUniqueId(obj)); + + // Try to get another tenured object in the same location and check that + // the uid was removed correctly. + obj = nullptr; + MinimizeHeap(cx); + obj = JS_NewPlainObject(cx); + MinimizeHeap(cx); + CHECK(uintptr_t(obj.get()) == tenuredAddr); + CHECK(!gc::HasUniqueId(obj)); + CHECK(gc::GetOrCreateUniqueId(obj, &tmp)); + CHECK(uid != tmp); + uid = tmp; + + // Allocate a few arenas worth of objects to ensure we get some compaction. + const static size_t N = 2049; + using ObjectVector = JS::GCVector<JSObject*>; + JS::Rooted<ObjectVector> vec(cx, ObjectVector(cx)); + for (size_t i = 0; i < N; ++i) { + obj = JS_NewPlainObject(cx); + CHECK(obj); + CHECK(vec.append(obj)); + } + + // Transfer our vector to tenured if it isn't there already. + MinimizeHeap(cx); + + // Tear holes in the heap by unrooting the even objects and collecting. + JS::Rooted<ObjectVector> vec2(cx, ObjectVector(cx)); + for (size_t i = 0; i < N; ++i) { + if (i % 2 == 1) { + CHECK(vec2.append(vec[i])); + } + } + vec.clear(); + + // Grab the last object in the vector as our object of interest. + obj = vec2.back(); + CHECK(obj); + CHECK(!gc::IsInsideNursery(obj)); + tenuredAddr = uintptr_t(obj.get()); + CHECK(gc::GetOrCreateUniqueId(obj, &uid)); + + // Force a compaction to move the object and check that the uid moved to + // the new tenured heap location. + JS::PrepareForFullGC(cx); + JS::NonIncrementalGC(cx, JS::GCOptions::Shrink, JS::GCReason::API); + + // There's a very low probability that this check could fail, but it is + // possible. If it becomes an annoying intermittent then we should make + // this test more robust by recording IDs of many objects and then checking + // that some have moved. + CHECK(uintptr_t(obj.get()) != tenuredAddr); + CHECK(gc::HasUniqueId(obj)); + CHECK(gc::GetOrCreateUniqueId(obj, &tmp)); + CHECK(uid == tmp); + + return true; +} +END_TEST(testGCUID) |