AtomMarking-inl.h (5054B)
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 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef gc_AtomMarking_inl_h 8 #define gc_AtomMarking_inl_h 9 10 #include "gc/AtomMarking.h" 11 12 #include "mozilla/Assertions.h" 13 #include "mozilla/Maybe.h" 14 15 #include <type_traits> 16 17 #include "vm/JSContext.h" 18 #include "vm/StringType.h" 19 #include "vm/SymbolType.h" 20 21 #include "gc/Heap-inl.h" 22 23 namespace js { 24 namespace gc { 25 26 /* static */ 27 inline size_t AtomMarkingRuntime::getAtomBit(TenuredCell* thing) { 28 MOZ_ASSERT(thing->zoneFromAnyThread()->isAtomsZone()); 29 Arena* arena = thing->arena(); 30 size_t arenaBit = (reinterpret_cast<uintptr_t>(thing) - arena->address()) / 31 CellBytesPerMarkBit; 32 return arena->atomBitmapStart() * JS_BITS_PER_WORD + arenaBit; 33 } 34 35 template <typename T, bool Fallible> 36 MOZ_ALWAYS_INLINE bool AtomMarkingRuntime::inlinedMarkAtomInternal(Zone* zone, 37 T* thing) { 38 static_assert(std::is_same_v<T, JSAtom> || std::is_same_v<T, JS::Symbol>, 39 "Should only be called with JSAtom* or JS::Symbol* argument"); 40 41 MOZ_ASSERT(zone); 42 MOZ_ASSERT(!zone->isAtomsZone()); 43 44 MOZ_ASSERT(thing); 45 js::gc::TenuredCell* cell = &thing->asTenured(); 46 MOZ_ASSERT(cell->zoneFromAnyThread()->isAtomsZone()); 47 48 if (thing->isPermanentAndMayBeShared()) { 49 return true; 50 } 51 52 if constexpr (std::is_same_v<T, JSAtom>) { 53 if (thing->isPinned()) { 54 return true; 55 } 56 } 57 58 size_t bit = getAtomBit(cell); 59 size_t blackBit = bit + size_t(ColorBit::BlackBit); 60 size_t grayOrBlackBit = bit + size_t(ColorBit::GrayOrBlackBit); 61 MOZ_ASSERT(grayOrBlackBit / JS_BITS_PER_WORD < allocatedWords); 62 63 { 64 mozilla::Maybe<AutoEnterOOMUnsafeRegion> oomUnsafe; 65 if constexpr (!Fallible) { 66 oomUnsafe.emplace(); 67 } 68 69 bool ok = zone->markedAtoms().setBit(blackBit); 70 if constexpr (std::is_same_v<T, JS::Symbol>) { 71 ok = ok && zone->markedAtoms().setBit(grayOrBlackBit); 72 } 73 74 if (!ok) { 75 if constexpr (!Fallible) { 76 oomUnsafe->crash("AtomMarkingRuntime::inlinedMarkAtomInternal"); 77 } else { 78 return false; 79 } 80 } 81 } 82 83 // Children of the thing also need to be marked in the context's zone. 84 // We don't have a JSTracer for this so manually handle the cases in which 85 // an atom can reference other atoms. 86 markChildren(zone, thing); 87 88 return true; 89 } 90 91 inline void AtomMarkingRuntime::maybeUnmarkGrayAtomically(Zone* zone, 92 JS::Symbol* symbol) { 93 MOZ_ASSERT(zone); 94 MOZ_ASSERT(!zone->isAtomsZone()); 95 MOZ_ASSERT(symbol); 96 MOZ_ASSERT(symbol->zoneFromAnyThread()->isAtomsZone()); 97 98 if (symbol->isPermanentAndMayBeShared()) { 99 return; 100 } 101 102 // The atom is currently marked black or gray. 103 MOZ_ASSERT(atomIsMarked(zone, symbol)); 104 105 // Set the black bit. This has the effect of making the mark black if it was 106 // previously gray. 107 size_t blackBit = getAtomBit(symbol) + size_t(ColorBit::BlackBit); 108 MOZ_ASSERT(blackBit / JS_BITS_PER_WORD < allocatedWords); 109 zone->markedAtoms().atomicSetExistingBit(blackBit); 110 111 MOZ_ASSERT(getAtomMarkColor(zone, symbol) == CellColor::Black); 112 } 113 114 inline bool GCRuntime::isSymbolReferencedByUncollectedZone(JS::Symbol* sym, 115 MarkColor color) { 116 MOZ_ASSERT(sym->zone()->isAtomsZone()); 117 118 if (!atomsUsedByUncollectedZones.ref()) { 119 return false; 120 } 121 122 MOZ_ASSERT(atomsZone()->wasGCStarted()); 123 124 size_t bit = AtomMarkingRuntime::getAtomBit(sym); 125 size_t blackBit = bit + size_t(ColorBit::BlackBit); 126 size_t grayOrBlackBit = bit + size_t(ColorBit::GrayOrBlackBit); 127 MOZ_ASSERT(grayOrBlackBit / JS_BITS_PER_WORD < atomMarking.allocatedWords); 128 129 const DenseBitmap& bitmap = *atomsUsedByUncollectedZones.ref(); 130 if (grayOrBlackBit >= bitmap.count()) { 131 return false; // Atom created during collection. 132 } 133 134 if (bitmap.getBit(blackBit)) { 135 return true; 136 } 137 138 return color == MarkColor::Gray && bitmap.getBit(grayOrBlackBit); 139 } 140 141 void AtomMarkingRuntime::markChildren(Zone* zone, JSAtom*) {} 142 143 void AtomMarkingRuntime::markChildren(Zone* zone, JS::Symbol* symbol) { 144 if (JSAtom* description = symbol->description()) { 145 inlinedMarkAtom(zone, description); 146 } 147 } 148 149 template <typename T> 150 MOZ_ALWAYS_INLINE void AtomMarkingRuntime::inlinedMarkAtom(Zone* zone, 151 T* thing) { 152 MOZ_ALWAYS_TRUE((inlinedMarkAtomInternal<T, false>(zone, thing))); 153 } 154 155 template <typename T> 156 MOZ_ALWAYS_INLINE bool AtomMarkingRuntime::inlinedMarkAtomFallible(Zone* zone, 157 T* thing) { 158 return inlinedMarkAtomInternal<T, true>(zone, thing); 159 } 160 161 } // namespace gc 162 } // namespace js 163 164 #endif // gc_AtomMarking_inl_h