tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

testGCUniqueId.cpp (3849B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 */
      4 /* This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #include "js/GCVector.h"
      9 
     10 #include "jsapi-tests/tests.h"
     11 
     12 #include "gc/StableCellHasher-inl.h"
     13 
     14 using namespace js;
     15 
     16 static void MinimizeHeap(JSContext* cx) {
     17  // The second collection is to force us to wait for the background
     18  // sweeping that the first GC started to finish.
     19  JS_GC(cx);
     20  JS_GC(cx);
     21  js::gc::FinishGC(cx);
     22 }
     23 
     24 BEGIN_TEST(testGCUID) {
     25  AutoLeaveZeal nozeal(cx);
     26  AutoGCParameter gcparam(cx, JSGC_SEMISPACE_NURSERY_ENABLED, 0);
     27 
     28  uint64_t uid = 0;
     29  uint64_t tmp = 0;
     30 
     31  // Ensure the heap is as minimal as it can get.
     32  MinimizeHeap(cx);
     33 
     34  JS::RootedObject obj(cx, JS_NewPlainObject(cx));
     35  uintptr_t nurseryAddr = uintptr_t(obj.get());
     36  CHECK(obj);
     37  CHECK(gc::IsInsideNursery(obj));
     38 
     39  // Do not start with an ID.
     40  CHECK(!gc::HasUniqueId(obj));
     41 
     42  // Ensure we can get a new UID.
     43  CHECK(gc::GetOrCreateUniqueId(obj, &uid));
     44  CHECK(uid > gc::LargestTaggedNullCellPointer);
     45 
     46  // We should now have an id.
     47  CHECK(gc::HasUniqueId(obj));
     48 
     49  // Calling again should get us the same thing.
     50  CHECK(gc::GetOrCreateUniqueId(obj, &tmp));
     51  CHECK(uid == tmp);
     52 
     53  // Tenure the thing and check that the UID moved with it.
     54  MinimizeHeap(cx);
     55  uintptr_t tenuredAddr = uintptr_t(obj.get());
     56  CHECK(tenuredAddr != nurseryAddr);
     57  CHECK(!gc::IsInsideNursery(obj));
     58  CHECK(gc::HasUniqueId(obj));
     59  CHECK(gc::GetOrCreateUniqueId(obj, &tmp));
     60  CHECK(uid == tmp);
     61 
     62  // Allocate a new nursery thing in the same location and check that we
     63  // removed the prior uid that was attached to the location.
     64  obj = JS_NewPlainObject(cx);
     65  CHECK(obj);
     66  CHECK(uintptr_t(obj.get()) == nurseryAddr);
     67  CHECK(!gc::HasUniqueId(obj));
     68 
     69  // Try to get another tenured object in the same location and check that
     70  // the uid was removed correctly.
     71  obj = nullptr;
     72  MinimizeHeap(cx);
     73  obj = JS_NewPlainObject(cx);
     74  MinimizeHeap(cx);
     75  CHECK(uintptr_t(obj.get()) == tenuredAddr);
     76  CHECK(!gc::HasUniqueId(obj));
     77  CHECK(gc::GetOrCreateUniqueId(obj, &tmp));
     78  CHECK(uid != tmp);
     79  uid = tmp;
     80 
     81  // Allocate a few arenas worth of objects to ensure we get some compaction.
     82  const static size_t N = 2049;
     83  using ObjectVector = JS::GCVector<JSObject*>;
     84  JS::Rooted<ObjectVector> vec(cx, ObjectVector(cx));
     85  for (size_t i = 0; i < N; ++i) {
     86    obj = JS_NewPlainObject(cx);
     87    CHECK(obj);
     88    CHECK(vec.append(obj));
     89  }
     90 
     91  // Transfer our vector to tenured if it isn't there already.
     92  MinimizeHeap(cx);
     93 
     94  // Tear holes in the heap by unrooting the even objects and collecting.
     95  JS::Rooted<ObjectVector> vec2(cx, ObjectVector(cx));
     96  for (size_t i = 0; i < N; ++i) {
     97    if (i % 2 == 1) {
     98      CHECK(vec2.append(vec[i]));
     99    }
    100  }
    101  vec.clear();
    102 
    103  // Grab the last object in the vector as our object of interest.
    104  obj = vec2.back();
    105  CHECK(obj);
    106  CHECK(!gc::IsInsideNursery(obj));
    107  tenuredAddr = uintptr_t(obj.get());
    108  CHECK(gc::GetOrCreateUniqueId(obj, &uid));
    109 
    110  // Force a compaction to move the object and check that the uid moved to
    111  // the new tenured heap location.
    112  JS::PrepareForFullGC(cx);
    113  JS::NonIncrementalGC(cx, JS::GCOptions::Shrink, JS::GCReason::API);
    114 
    115  // There's a very low probability that this check could fail, but it is
    116  // possible.  If it becomes an annoying intermittent then we should make
    117  // this test more robust by recording IDs of many objects and then checking
    118  // that some have moved.
    119  CHECK(uintptr_t(obj.get()) != tenuredAddr);
    120  CHECK(gc::HasUniqueId(obj));
    121  CHECK(gc::GetOrCreateUniqueId(obj, &tmp));
    122  CHECK(uid == tmp);
    123 
    124  return true;
    125 }
    126 END_TEST(testGCUID)