Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  testGCGrayMarking.cpp   Sprache: C

 
/* -*- 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 <algorithm>

#include "gc/WeakMap.h"
#include "gc/Zone.h"
#include "js/PropertyAndElement.h"  // JS_DefineProperty, JS_DefinePropertyById
#include "js/Proxy.h"
#include "js/WeakMap.h"
#include "jsapi-tests/tests.h"

using namespace js;
using namespace js::gc;

static constexpr CellColor AllCellColors[] = {CellColor::White, CellColor::Gray,
                                              CellColor::Black};

static constexpr CellColor MarkedCellColors[] = {CellColor::Gray,
                                                 CellColor::Black};

namespace js {

struct GCManagedObjectWeakMap : public ObjectWeakMap {
  using ObjectWeakMap::ObjectWeakMap;
};

}  // namespace js

namespace JS {

template <>
struct MapTypeToRootKind<js::GCManagedObjectWeakMap*> {
  static const JS::RootKind kind = JS::RootKind::Traceable;
};

template <>
struct GCPolicy<js::GCManagedObjectWeakMap*>
    : public NonGCPointerPolicy<js::GCManagedObjectWeakMap*> {};

}  // namespace JS

class AutoNoAnalysisForTest {
 public:
  AutoNoAnalysisForTest() {}
} JS_HAZ_GC_SUPPRESSED;

BEGIN_TEST(testGCGrayMarking) {
  AutoNoAnalysisForTest disableAnalysis;
  AutoDisableCompactingGC disableCompactingGC(cx);
  AutoLeaveZeal nozeal(cx);

  CHECK(InitGlobals());
  JSAutoRealm ar(cx, global1);

  InitGrayRootTracer();

  // Enable incremental GC.
  AutoGCParameter param1(cx, JSGC_INCREMENTAL_GC_ENABLED, true);
  AutoGCParameter param2(cx, JSGC_PER_ZONE_GC_ENABLED, true);

  bool ok = TestMarking() && TestJSWeakMaps() && TestInternalWeakMaps() &&
            TestCCWs() && TestGrayUnmarking();

  global1 = nullptr;
  global2 = nullptr;
  RemoveGrayRootTracer();

  return ok;
}

bool TestMarking() {
  JSObject* sameTarget = AllocPlainObject();
  CHECK(sameTarget);

  JSObject* sameSource = AllocSameCompartmentSourceObject(sameTarget);
  CHECK(sameSource);

  JSObject* crossTarget = AllocPlainObject();
  CHECK(crossTarget);

  JSObject* crossSource = GetCrossCompartmentWrapper(crossTarget);
  CHECK(crossSource);

  // Test GC with black roots marks objects black.

  JS::RootedObject blackRoot1(cx, sameSource);
  JS::RootedObject blackRoot2(cx, crossSource);

  JS_GC(cx);

  CHECK(IsMarkedBlack(sameSource));
  CHECK(IsMarkedBlack(crossSource));
  CHECK(IsMarkedBlack(sameTarget));
  CHECK(IsMarkedBlack(crossTarget));

  // Test GC with black and gray roots marks objects black.

  grayRoots.grayRoot1 = sameSource;
  grayRoots.grayRoot2 = crossSource;

  JS_GC(cx);

  CHECK(IsMarkedBlack(sameSource));
  CHECK(IsMarkedBlack(crossSource));
  CHECK(IsMarkedBlack(sameTarget));
  CHECK(IsMarkedBlack(crossTarget));

  CHECK(!JS::ObjectIsMarkedGray(sameSource));

  // Test GC with gray roots marks object gray.

  blackRoot1 = nullptr;
  blackRoot2 = nullptr;

  JS_GC(cx);

  CHECK(IsMarkedGray(sameSource));
  CHECK(IsMarkedGray(crossSource));
  CHECK(IsMarkedGray(sameTarget));
  CHECK(IsMarkedGray(crossTarget));

  CHECK(JS::ObjectIsMarkedGray(sameSource));

  // Test ExposeToActiveJS marks gray objects black.

  JS::ExposeObjectToActiveJS(sameSource);
  JS::ExposeObjectToActiveJS(crossSource);
  CHECK(IsMarkedBlack(sameSource));
  CHECK(IsMarkedBlack(crossSource));
  CHECK(IsMarkedBlack(sameTarget));
  CHECK(IsMarkedBlack(crossTarget));

  // Test a zone GC with black roots marks gray object in other zone black.

  JS_GC(cx);

  CHECK(IsMarkedGray(crossSource));
  CHECK(IsMarkedGray(crossTarget));

  blackRoot1 = crossSource;
  CHECK(ZoneGC(crossSource->zone()));

  CHECK(IsMarkedBlack(crossSource));
  CHECK(IsMarkedBlack(crossTarget));

  blackRoot1 = nullptr;
  blackRoot2 = nullptr;
  grayRoots.grayRoot1 = nullptr;
  grayRoots.grayRoot2 = nullptr;

  return true;
}

static constexpr CellColor DontMark = CellColor::White;

enum MarkKeyOrDelegate : bool { MarkKey = true, MarkDelegate = false };

bool TestJSWeakMaps() {
  for (auto keyOrDelegateColor : MarkedCellColors) {
    for (auto mapColor : MarkedCellColors) {
      for (auto markKeyOrDelegate : {MarkKey, MarkDelegate}) {
        CellColor expected = std::min(keyOrDelegateColor, mapColor);
        CHECK(TestJSWeakMap(markKeyOrDelegate, keyOrDelegateColor, mapColor,
                            expected));
#ifdef JS_GC_ZEAL
        CHECK(TestJSWeakMapWithGrayUnmarking(
            markKeyOrDelegate, keyOrDelegateColor, mapColor, expected));
#endif
      }
    }
  }

  return true;
}

bool TestInternalWeakMaps() {
  for (auto keyMarkColor : AllCellColors) {
    for (auto delegateMarkColor : AllCellColors) {
      if (keyMarkColor == CellColor::White &&
          delegateMarkColor == CellColor::White) {
        continue;
      }

      // The map is black. The delegate marks its key via wrapper preservation.
      // The key maps its delegate and the value. Thus, all three end up the
      // maximum of the key and delegate colors.
      CellColor expected = std::max(keyMarkColor, delegateMarkColor);
      CHECK(TestInternalWeakMap(keyMarkColor, delegateMarkColor, expected));

#ifdef JS_GC_ZEAL
      CHECK(TestInternalWeakMapWithGrayUnmarking(keyMarkColor,
                                                 delegateMarkColor, expected));
#endif
    }
  }

  return true;
}

bool TestJSWeakMap(MarkKeyOrDelegate markKey, CellColor weakMapMarkColor,
                   CellColor keyOrDelegateMarkColor,
                   CellColor expectedValueColor) {
  using std::swap;

  // Test marking a JS WeakMap object.
  //
  // This marks the map and one of the key or delegate. The key/delegate and the
  // value can end up different colors depending on the color of the map.

  JSObject* weakMap;
  JSObject* key;
  JSObject* value;

  // If both map and key are marked the same color, test both possible
  // orderings.
  unsigned markOrderings = weakMapMarkColor == keyOrDelegateMarkColor ? 2 : 1;

  for (unsigned markOrder = 0; markOrder < markOrderings; markOrder++) {
    CHECK(CreateJSWeakMapObjects(&weakMap, &key, &value));

    JSObject* delegate = UncheckedUnwrapWithoutExpose(key);
    JSObject* keyOrDelegate = markKey ? key : delegate;

    RootedObject blackRoot1(cx);
    RootedObject blackRoot2(cx);

    RootObject(weakMap, weakMapMarkColor, blackRoot1, grayRoots.grayRoot1);
    RootObject(keyOrDelegate, keyOrDelegateMarkColor, blackRoot2,
               grayRoots.grayRoot2);

    if (markOrder != 0) {
      swap(blackRoot1.get(), blackRoot2.get());
      swap(grayRoots.grayRoot1, grayRoots.grayRoot2);
    }

    JS_GC(cx);

    ClearGrayRoots();

    CHECK(weakMap->color() == weakMapMarkColor);
    CHECK(keyOrDelegate->color() == keyOrDelegateMarkColor);
    CHECK(value->color() == expectedValueColor);
  }

  return true;
}

#ifdef JS_GC_ZEAL

bool TestJSWeakMapWithGrayUnmarking(MarkKeyOrDelegate markKey,
                                    CellColor weakMapMarkColor,
                                    CellColor keyOrDelegateMarkColor,
                                    CellColor expectedValueColor) {
  // This is like the previous test, but things are marked black by gray
  // unmarking during incremental GC.

  JSObject* weakMap;
  JSObject* key;
  JSObject* value;

  // If both map and key are marked the same color, test both possible
  // orderings.
  unsigned markOrderings = weakMapMarkColor == keyOrDelegateMarkColor ? 2 : 1;

  JS::SetGCZeal(cx, uint8_t(ZealMode::YieldWhileGrayMarking), 0);

  for (unsigned markOrder = 0; markOrder < markOrderings; markOrder++) {
    CHECK(CreateJSWeakMapObjects(&weakMap, &key, &value));

    JSObject* delegate = UncheckedUnwrapWithoutExpose(key);
    JSObject* keyOrDelegate = markKey ? key : delegate;

    grayRoots.grayRoot1 = keyOrDelegate;
    grayRoots.grayRoot2 = weakMap;

    // Start an incremental GC and run until gray roots have been pushed onto
    // the mark stack.
    JS::PrepareForFullGC(cx);
    JS::SliceBudget budget(JS::TimeBudget(1000000));
    JS::StartIncrementalGC(cx, JS::GCOptions::Normal, JS::GCReason::DEBUG_GC,
                           budget);
    MOZ_ASSERT(cx->runtime()->gc.state() == gc::State::Sweep);
    MOZ_ASSERT(cx->zone()->gcState() == Zone::MarkBlackAndGray);

    // Unmark gray things as specified.
    if (markOrder != 0) {
      MaybeExposeObject(weakMap, weakMapMarkColor);
      MaybeExposeObject(keyOrDelegate, keyOrDelegateMarkColor);
    } else {
      MaybeExposeObject(keyOrDelegate, keyOrDelegateMarkColor);
      MaybeExposeObject(weakMap, weakMapMarkColor);
    }

    JS::FinishIncrementalGC(cx, JS::GCReason::API);

    ClearGrayRoots();

    CHECK(weakMap->color() == weakMapMarkColor);
    CHECK(keyOrDelegate->color() == keyOrDelegateMarkColor);
    CHECK(value->color() == expectedValueColor);
  }

  JS::UnsetGCZeal(cx, uint8_t(ZealMode::YieldWhileGrayMarking));

  return true;
}

static void MaybeExposeObject(JSObject* object, CellColor color) {
  if (color == CellColor::Black) {
    JS::ExposeObjectToActiveJS(object);
  }
}

#endif  // JS_GC_ZEAL

bool CreateJSWeakMapObjects(JSObject** weakMapOut, JSObject** keyOut,
                            JSObject** valueOut) {
  RootedObject key(cx, AllocWeakmapKeyObject());
  CHECK(key);

  RootedObject value(cx, AllocPlainObject());
  CHECK(value);

  RootedObject weakMap(cx, JS::NewWeakMapObject(cx));
  CHECK(weakMap);

  JS::RootedValue keyValue(cx, ObjectValue(*key));
  JS::RootedValue valueValue(cx, ObjectValue(*value));
  CHECK(SetWeakMapEntry(cx, weakMap, keyValue, valueValue));

  *weakMapOut = weakMap;
  *keyOut = key;
  *valueOut = value;
  return true;
}

bool TestInternalWeakMap(CellColor keyMarkColor, CellColor delegateMarkColor,
                         CellColor expectedColor) {
  using std::swap;

  // Test marking for internal weakmaps (without an owning JSObject).
  //
  // All of the key, delegate and value are expected to end up the same color.

  UniquePtr<GCManagedObjectWeakMap> weakMap;
  JSObject* key;
  JSObject* value;

  // If both key and delegate are marked the same color, test both possible
  // orderings.
  unsigned markOrderings = keyMarkColor == delegateMarkColor ? 2 : 1;

  for (unsigned markOrder = 0; markOrder < markOrderings; markOrder++) {
    CHECK(CreateInternalWeakMapObjects(&weakMap, &key, &value));

    JSObject* delegate = UncheckedUnwrapWithoutExpose(key);

    RootedObject blackRoot1(cx);
    RootedObject blackRoot2(cx);

    Rooted<GCManagedObjectWeakMap*> rootMap(cx, weakMap.get());
    RootObject(key, keyMarkColor, blackRoot1, grayRoots.grayRoot1);
    RootObject(delegate, delegateMarkColor, blackRoot2, grayRoots.grayRoot2);

    if (markOrder != 0) {
      swap(blackRoot1.get(), blackRoot2.get());
      swap(grayRoots.grayRoot1, grayRoots.grayRoot2);
    }

    JS_GC(cx);

    ClearGrayRoots();

    CHECK(key->color() == expectedColor);
    CHECK(delegate->color() == expectedColor);
    CHECK(value->color() == expectedColor);
  }

  return true;
}

#ifdef JS_GC_ZEAL

bool TestInternalWeakMapWithGrayUnmarking(CellColor keyMarkColor,
                                          CellColor delegateMarkColor,
                                          CellColor expectedColor) {
  UniquePtr<GCManagedObjectWeakMap> weakMap;
  JSObject* key;
  JSObject* value;

  // If both key and delegate are marked the same color, test both possible
  // orderings.
  unsigned markOrderings = keyMarkColor == delegateMarkColor ? 2 : 1;

  JS::SetGCZeal(cx, uint8_t(ZealMode::YieldWhileGrayMarking), 0);

  for (unsigned markOrder = 0; markOrder < markOrderings; markOrder++) {
    CHECK(CreateInternalWeakMapObjects(&weakMap, &key, &value));

    JSObject* delegate = UncheckedUnwrapWithoutExpose(key);

    Rooted<GCManagedObjectWeakMap*> rootMap(cx, weakMap.get());
    grayRoots.grayRoot1 = key;
    grayRoots.grayRoot2 = delegate;

    // Start an incremental GC and run until gray roots have been pushed onto
    // the mark stack.
    JS::PrepareForFullGC(cx);
    JS::SliceBudget budget(JS::TimeBudget(1000000));
    JS::StartIncrementalGC(cx, JS::GCOptions::Normal, JS::GCReason::DEBUG_GC,
                           budget);
    MOZ_ASSERT(cx->runtime()->gc.state() == gc::State::Sweep);
    MOZ_ASSERT(cx->zone()->gcState() == Zone::MarkBlackAndGray);

    // Unmark gray things as specified.
    if (markOrder != 0) {
      MaybeExposeObject(key, keyMarkColor);
      MaybeExposeObject(delegate, delegateMarkColor);
    } else {
      MaybeExposeObject(key, keyMarkColor);
      MaybeExposeObject(delegate, delegateMarkColor);
    }

    JS::FinishIncrementalGC(cx, JS::GCReason::API);

    ClearGrayRoots();

    CHECK(key->color() == expectedColor);
    CHECK(delegate->color() == expectedColor);
    CHECK(value->color() == expectedColor);
  }

  JS::UnsetGCZeal(cx, uint8_t(ZealMode::YieldWhileGrayMarking));

  return true;
}

#endif  // JS_GC_ZEAL

bool CreateInternalWeakMapObjects(UniquePtr<GCManagedObjectWeakMap>* weakMapOut,
                                  JSObject** keyOut, JSObject** valueOut) {
  RootedObject key(cx, AllocWeakmapKeyObject());
  CHECK(key);

  RootedObject value(cx, AllocPlainObject());
  CHECK(value);

  auto weakMap = cx->make_unique<GCManagedObjectWeakMap>(cx);
  CHECK(weakMap);

  CHECK(weakMap->add(cx, key, value));

  *weakMapOut = std::move(weakMap);
  *keyOut = key;
  *valueOut = value;
  return true;
}

void RootObject(JSObject* object, CellColor color, RootedObject& blackRoot,
                JS::Heap<JSObject*>& grayRoot) {
  if (color == CellColor::Black) {
    blackRoot = object;
  } else if (color == CellColor::Gray) {
    grayRoot = object;
  } else {
    MOZ_RELEASE_ASSERT(color == CellColor::White);
  }
}

bool TestCCWs() {
  JSObject* target = AllocPlainObject();
  CHECK(target);

  // Test getting a new wrapper doesn't return a gray wrapper.

  RootedObject blackRoot(cx, target);
  JSObject* wrapper = GetCrossCompartmentWrapper(target);
  CHECK(wrapper);
  CHECK(!IsMarkedGray(wrapper));

  // Test getting an existing wrapper doesn't return a gray wrapper.

  grayRoots.grayRoot1 = wrapper;
  grayRoots.grayRoot2 = nullptr;
  JS_GC(cx);
  CHECK(IsMarkedGray(wrapper));
  CHECK(IsMarkedBlack(target));

  CHECK(GetCrossCompartmentWrapper(target) == wrapper);
  CHECK(!IsMarkedGray(wrapper));

  // Test getting an existing wrapper doesn't return a gray wrapper
  // during incremental GC.

  JS_GC(cx);
  CHECK(IsMarkedGray(wrapper));
  CHECK(IsMarkedBlack(target));

  JSRuntime* rt = cx->runtime();
  JS::PrepareForFullGC(cx);
  JS::SliceBudget budget(JS::WorkBudget(1));
  rt->gc.startDebugGC(JS::GCOptions::Normal, budget);
  while (rt->gc.state() == gc::State::Prepare) {
    rt->gc.debugGCSlice(budget);
  }
  CHECK(JS::IsIncrementalGCInProgress(cx));

  CHECK(!IsMarkedBlack(wrapper));
  CHECK(wrapper->zone()->isGCMarkingBlackOnly());

  CHECK(GetCrossCompartmentWrapper(target) == wrapper);
  CHECK(IsMarkedBlack(wrapper));

  JS::FinishIncrementalGC(cx, JS::GCReason::API);

  // Test behaviour of gray CCWs marked black by a barrier during incremental
  // GC.

  // Initial state: source and target are gray.
  blackRoot = nullptr;
  grayRoots.grayRoot1 = wrapper;
  grayRoots.grayRoot2 = nullptr;
  JS_GC(cx);
  CHECK(IsMarkedGray(wrapper));
  CHECK(IsMarkedGray(target));

  // Incremental zone GC started: the source is now unmarked.
  JS::PrepareZoneForGC(cx, wrapper->zone());
  budget = JS::SliceBudget(JS::WorkBudget(1));
  rt->gc.startDebugGC(JS::GCOptions::Normal, budget);
  while (rt->gc.state() == gc::State::Prepare) {
    rt->gc.debugGCSlice(budget);
  }
  CHECK(JS::IsIncrementalGCInProgress(cx));
  CHECK(wrapper->zone()->isGCMarkingBlackOnly());
  CHECK(!target->zone()->wasGCStarted());
  CHECK(!IsMarkedBlack(wrapper));
  CHECK(!IsMarkedGray(wrapper));
  CHECK(IsMarkedGray(target));

  // Betweeen GC slices: source marked black by barrier, target is
  // still gray. Target will be marked gray
  // eventually. ObjectIsMarkedGray() is conservative and reports
  // that target is not marked gray; AssertObjectIsNotGray() will
  // assert.
  grayRoots.grayRoot1.get();
  CHECK(IsMarkedBlack(wrapper));
  CHECK(IsMarkedGray(target));
  CHECK(!JS::ObjectIsMarkedGray(target));

  // Final state: source and target are black.
  JS::FinishIncrementalGC(cx, JS::GCReason::API);
  CHECK(IsMarkedBlack(wrapper));
  CHECK(IsMarkedBlack(target));

  grayRoots.grayRoot1 = nullptr;
  grayRoots.grayRoot2 = nullptr;

  return true;
}

bool TestGrayUnmarking() {
  const size_t length = 2000;

  JSObject* chain = AllocObjectChain(length);
  CHECK(chain);

  RootedObject blackRoot(cx, chain);
  JS_GC(cx);
  size_t count;
  CHECK(IterateObjectChain(chain, ColorCheckFunctor(MarkColor::Black, &count)));
  CHECK(count == length);

  blackRoot = nullptr;
  grayRoots.grayRoot1 = chain;
  JS_GC(cx);
  CHECK(cx->runtime()->gc.areGrayBitsValid());
  CHECK(IterateObjectChain(chain, ColorCheckFunctor(MarkColor::Gray, &count)));
  CHECK(count == length);

  JS::ExposeObjectToActiveJS(chain);
  CHECK(cx->runtime()->gc.areGrayBitsValid());
  CHECK(IterateObjectChain(chain, ColorCheckFunctor(MarkColor::Black, &count)));
  CHECK(count == length);

  grayRoots.grayRoot1 = nullptr;

  return true;
}

struct ColorCheckFunctor {
  MarkColor color;
  size_t& count;

  ColorCheckFunctor(MarkColor colorArg, size_t* countArg)
      : color(colorArg), count(*countArg) {
    count = 0;
  }

  bool operator()(JSObject* obj) {
    if (!CheckCellColor(obj, color)) {
      return false;
    }

    NativeObject& nobj = obj->as<NativeObject>();
    if (!CheckCellColor(nobj.shape(), color)) {
      return false;
    }

    NativeShape* shape = nobj.shape();
    if (!CheckCellColor(shape, color)) {
      return false;
    }

    // Shapes and symbols are never marked gray.
    ShapePropertyIter<NoGC> iter(shape);
    jsid id = iter->key();
    if (id.isGCThing() &&
        !CheckCellColor(id.toGCCellPtr().asCell(), MarkColor::Black)) {
      return false;
    }

    count++;
    return true;
  }
};

JS::PersistentRootedObject global1;
JS::PersistentRootedObject global2;

struct GrayRoots {
  JS::Heap<JSObject*> grayRoot1;
  JS::Heap<JSObject*> grayRoot2;
};

GrayRoots grayRoots;

bool InitGlobals() {
  global1.init(cx, global);
  if (!createGlobal()) {
    return false;
  }
  global2.init(cx, global);
  return global2 != nullptr;
}

void ClearGrayRoots() {
  grayRoots.grayRoot1 = nullptr;
  grayRoots.grayRoot2 = nullptr;
}

void InitGrayRootTracer() {
  ClearGrayRoots();
  JS_SetGrayGCRootsTracer(cx, TraceGrayRoots, &grayRoots);
}

void RemoveGrayRootTracer() {
  ClearGrayRoots();
  JS_SetGrayGCRootsTracer(cx, nullptr, nullptr);
}

static bool TraceGrayRoots(JSTracer* trc, JS::SliceBudget& budget, void* data) {
  auto grayRoots = static_cast<GrayRoots*>(data);
  TraceEdge(trc, &grayRoots->grayRoot1, "gray root 1");
  TraceEdge(trc, &grayRoots->grayRoot2, "gray root 2");
  return true;
}

JSObject* AllocPlainObject() {
  JS::RootedObject obj(cx, JS_NewPlainObject(cx));
  EvictNursery();

  MOZ_ASSERT(obj->compartment() == global1->compartment());
  return obj;
}

JSObject* AllocSameCompartmentSourceObject(JSObject* target) {
  JS::RootedObject source(cx, JS_NewPlainObject(cx));
  if (!source) {
    return nullptr;
  }

  JS::RootedObject obj(cx, target);
  if (!JS_DefineProperty(cx, source, "ptr", obj, 0)) {
    return nullptr;
  }

  EvictNursery();

  MOZ_ASSERT(source->compartment() == global1->compartment());
  return source;
}

JSObject* GetCrossCompartmentWrapper(JSObject* target) {
  MOZ_ASSERT(target->compartment() == global1->compartment());
  JS::RootedObject obj(cx, target);
  JSAutoRealm ar(cx, global2);
  if (!JS_WrapObject(cx, &obj)) {
    return nullptr;
  }

  EvictNursery();

  MOZ_ASSERT(obj->compartment() == global2->compartment());
  return obj;
}

JSObject* AllocWeakmapKeyObject() {
  JS::RootedObject delegate(cx, JS_NewPlainObject(cx));
  if (!delegate) {
    return nullptr;
  }

  JS::RootedObject key(cx,
                       js::Wrapper::New(cx, delegate, &js::Wrapper::singleton));

  EvictNursery();
  return key;
}

JSObject* AllocObjectChain(size_t length) {
  // Allocate a chain of linked JSObjects.

  // Use a unique property name so the shape is not shared with any other
  // objects.
  RootedString nextPropName(cx, JS_NewStringCopyZ(cx, "unique14142135"));
  RootedId nextId(cx);
  if (!JS_StringToId(cx, nextPropName, &nextId)) {
    return nullptr;
  }

  RootedObject head(cx);
  for (size_t i = 0; i < length; i++) {
    RootedValue next(cx, ObjectOrNullValue(head));
    head = AllocPlainObject();
    if (!head) {
      return nullptr;
    }
    if (!JS_DefinePropertyById(cx, head, nextId, next, 0)) {
      return nullptr;
    }
  }

  return head;
}

template <typename F>
bool IterateObjectChain(JSObject* chain, F f) {
  RootedObject obj(cx, chain);
  while (obj) {
    if (!f(obj)) {
      return false;
    }

    // Access the 'next' property via the object's slots to avoid triggering
    // gray marking assertions when calling JS_GetPropertyById.
    NativeObject& nobj = obj->as<NativeObject>();
    MOZ_ASSERT(nobj.slotSpan() == 1);
    obj = nobj.getSlot(0).toObjectOrNull();
  }

  return true;
}

static bool IsMarkedBlack(Cell* cell) {
  TenuredCell* tc = &cell->asTenured();
  return tc->isMarkedBlack();
}

static bool IsMarkedGray(Cell* cell) {
  TenuredCell* tc = &cell->asTenured();
  bool isGray = tc->isMarkedGray();
  MOZ_ASSERT_IF(isGray, tc->isMarkedAny());
  return isGray;
}

static bool CheckCellColor(Cell* cell, MarkColor color) {
  MOZ_ASSERT(color == MarkColor::Black || color == MarkColor::Gray);
  if (color == MarkColor::Black && !IsMarkedBlack(cell)) {
    printf("Found non-black cell: %p\n", cell);
    return false;
  } else if (color == MarkColor::Gray && !IsMarkedGray(cell)) {
    printf("Found non-gray cell: %p\n", cell);
    return false;
  }

  return true;
}

void EvictNursery() { cx->runtime()->gc.evictNursery(); }

bool ZoneGC(JS::Zone* zone) {
  JS::PrepareZoneForGC(cx, zone);
  cx->runtime()->gc.gc(JS::GCOptions::Normal, JS::GCReason::API);
  CHECK(!cx->runtime()->gc.isFullGc());
  return true;
}

END_TEST(testGCGrayMarking)

87%


¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge