mozjs_sys 0.67.1

System crate for the Mozilla SpiderMonkey JavaScript engine.
/* -*- 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/. */

/*
 * GC-internal iterators for various data structures.
 */

#ifndef gc_PrivateIterators_inl_h
#define gc_PrivateIterators_inl_h

#include "gc/PublicIterators.h"

#include "gc/GC-inl.h"

namespace js {
namespace gc {

class ArenaCellIterUnderGC : public ArenaCellIterImpl {
 public:
  explicit ArenaCellIterUnderGC(Arena* arena)
      : ArenaCellIterImpl(arena, CellIterDoesntNeedBarrier) {
    MOZ_ASSERT(CurrentThreadIsPerformingGC());
  }
};

class ArenaCellIterUnderFinalize : public ArenaCellIterImpl {
 public:
  explicit ArenaCellIterUnderFinalize(Arena* arena)
      : ArenaCellIterImpl(arena, CellIterDoesntNeedBarrier) {
    MOZ_ASSERT(CurrentThreadIsGCSweeping());
  }
};

class ArenaCellIterUnbarriered : public ArenaCellIterImpl {
 public:
  explicit ArenaCellIterUnbarriered(Arena* arena)
      : ArenaCellIterImpl(arena, CellIterDoesntNeedBarrier) {}
};

class GrayObjectIter : public ZoneAllCellIter<js::gc::TenuredCell> {
 public:
  explicit GrayObjectIter(JS::Zone* zone, AllocKind kind)
      : ZoneAllCellIter<js::gc::TenuredCell>() {
    initForTenuredIteration(zone, kind);
  }

  JSObject* get() const {
    return ZoneAllCellIter<js::gc::TenuredCell>::get<JSObject>();
  }
  operator JSObject*() const { return get(); }
  JSObject* operator->() const { return get(); }
};

class GCZonesIter {
  ZonesIter zone;

 public:
  explicit GCZonesIter(JSRuntime* rt, ZoneSelector selector = WithAtoms)
      : zone(rt, selector) {
    MOZ_ASSERT(JS::RuntimeHeapIsBusy());
    MOZ_ASSERT_IF(rt->gc.atomsZone->isCollectingFromAnyThread(),
                  !rt->hasHelperThreadZones());

    if (!done() && !zone->isCollectingFromAnyThread()) {
      next();
    }
  }

  bool done() const { return zone.done(); }

  void next() {
    MOZ_ASSERT(!done());
    do {
      zone.next();
    } while (!zone.done() && !zone->isCollectingFromAnyThread());
  }

  JS::Zone* get() const {
    MOZ_ASSERT(!done());
    return zone;
  }

  operator JS::Zone*() const { return get(); }
  JS::Zone* operator->() const { return get(); }
};

using GCCompartmentsIter =
    CompartmentsOrRealmsIterT<GCZonesIter, CompartmentsInZoneIter>;
using GCRealmsIter = CompartmentsOrRealmsIterT<GCZonesIter, RealmsInZoneIter>;

/* Iterates over all zones in the current sweep group. */
class SweepGroupZonesIter {
  JS::Zone* current;
  ZoneSelector selector;

 public:
  explicit SweepGroupZonesIter(JSRuntime* rt, ZoneSelector selector = WithAtoms)
      : selector(selector) {
    MOZ_ASSERT(CurrentThreadIsPerformingGC());
    current = rt->gc.getCurrentSweepGroup();
    maybeSkipAtomsZone();
  }

  void maybeSkipAtomsZone() {
    if (selector == SkipAtoms && current && current->isAtomsZone()) {
      current = current->nextNodeInGroup();
      MOZ_ASSERT_IF(current, !current->isAtomsZone());
    }
  }

  bool done() const { return !current; }

  void next() {
    MOZ_ASSERT(!done());
    current = current->nextNodeInGroup();
    maybeSkipAtomsZone();
  }

  JS::Zone* get() const {
    MOZ_ASSERT(!done());
    return current;
  }

  operator JS::Zone*() const { return get(); }
  JS::Zone* operator->() const { return get(); }
};

using SweepGroupCompartmentsIter =
    CompartmentsOrRealmsIterT<SweepGroupZonesIter, CompartmentsInZoneIter>;
using SweepGroupRealmsIter =
    CompartmentsOrRealmsIterT<SweepGroupZonesIter, RealmsInZoneIter>;

// Iterate the free cells in an arena. See also ArenaCellIterImpl which iterates
// the allocated cells.
class ArenaFreeCellIter {
  Arena* arena;
  size_t thingSize;
  FreeSpan span;
  uint_fast16_t thing;

 public:
  explicit ArenaFreeCellIter(Arena* arena)
      : arena(arena),
        thingSize(arena->getThingSize()),
        span(*arena->getFirstFreeSpan()),
        thing(span.first) {
    MOZ_ASSERT(arena);
    MOZ_ASSERT(thing < ArenaSize);
  }

  bool done() const {
    MOZ_ASSERT(thing < ArenaSize);
    return !thing;
  }

  TenuredCell* getCell() const {
    MOZ_ASSERT(!done());
    return reinterpret_cast<TenuredCell*>(uintptr_t(arena) + thing);
  }

  void next() {
    MOZ_ASSERT(!done());
    MOZ_ASSERT(thing >= span.first && thing <= span.last);

    if (thing == span.last) {
      span = *span.nextSpan(arena);
      thing = span.first;
    } else {
      thing += thingSize;
    }

    MOZ_ASSERT(thing < ArenaSize);
  }
};

}  // namespace gc
}  // namespace js

#endif  // gc_PrivateIterators_inl_h