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/. */
7 #ifndef gc_Marking_inl_h
8 #define gc_Marking_inl_h
10 #include "gc/Marking.h"
12 #include <type_traits>
14 #include "gc/RelocationOverlay.h"
17 #include "vm/StringType.h"
18 #include "vm/TaggedProto.h"
19 #include "wasm/WasmAnyRef.h"
21 #include "gc/Nursery-inl.h"
26 // An abstraction to re-wrap any kind of typed pointer back to the tagged
27 // pointer it came from with |TaggedPtr<TargetType>::wrap(sourcePtr)|.
32 struct TaggedPtr
<JS::Value
> {
33 static JS::Value
wrap(JSObject
* obj
) {
35 return JS::NullValue();
37 #ifdef ENABLE_RECORD_TUPLE
38 if (MaybeForwardedIsExtendedPrimitive(*obj
)) {
39 return JS::ExtendedPrimitiveValue(*obj
);
42 return JS::ObjectValue(*obj
);
44 static JS::Value
wrap(JSString
* str
) { return JS::StringValue(str
); }
45 static JS::Value
wrap(JS::Symbol
* sym
) { return JS::SymbolValue(sym
); }
46 static JS::Value
wrap(JS::BigInt
* bi
) { return JS::BigIntValue(bi
); }
48 static JS::Value
wrap(T
* priv
) {
49 static_assert(std::is_base_of_v
<Cell
, T
>,
50 "Type must be a GC thing derived from js::gc::Cell");
51 return JS::PrivateGCThingValue(priv
);
53 static JS::Value
empty() { return JS::UndefinedValue(); }
57 struct TaggedPtr
<jsid
> {
58 static jsid
wrap(JSString
* str
) { return JS::PropertyKey::NonIntAtom(str
); }
59 static jsid
wrap(JS::Symbol
* sym
) { return PropertyKey::Symbol(sym
); }
60 static jsid
empty() { return JS::PropertyKey::Void(); }
64 struct TaggedPtr
<TaggedProto
> {
65 static TaggedProto
wrap(JSObject
* obj
) { return TaggedProto(obj
); }
66 static TaggedProto
empty() { return TaggedProto(); }
70 struct TaggedPtr
<wasm::AnyRef
> {
71 static wasm::AnyRef
wrap(JSObject
* obj
) {
72 return wasm::AnyRef::fromJSObjectOrNull(obj
);
74 static wasm::AnyRef
wrap(JSString
* str
) {
75 return wasm::AnyRef::fromJSString(str
);
77 static wasm::AnyRef
empty() { return wasm::AnyRef(); }
81 struct MightBeForwarded
{
82 static_assert(std::is_base_of_v
<Cell
, T
>);
83 static_assert(!std::is_same_v
<Cell
, T
> && !std::is_same_v
<TenuredCell
, T
>);
85 #define CAN_FORWARD_KIND_OR(_1, _2, Type, _3, _4, _5, canCompact) \
86 std::is_base_of_v<Type, T> ? canCompact:
88 // FOR_EACH_ALLOCKIND doesn't cover every possible type: make sure
89 // to default to `true` for unknown types.
90 static constexpr bool value
= FOR_EACH_ALLOCKIND(CAN_FORWARD_KIND_OR
) true;
91 #undef CAN_FORWARD_KIND_OR
95 inline bool IsForwarded(const T
* t
) {
96 if constexpr (!MightBeForwarded
<T
>::value
) {
97 MOZ_ASSERT(!t
->isForwarded());
101 return t
->isForwarded();
105 inline bool IsForwarded
<Cell
>(const Cell
* t
) {
106 return t
->isForwarded();
109 template <typename T
>
110 inline T
* Forwarded(const T
* t
) {
111 const RelocationOverlay
* overlay
= RelocationOverlay::fromCell(t
);
112 MOZ_ASSERT(overlay
->isForwarded());
113 return reinterpret_cast<T
*>(overlay
->forwardingAddress());
116 template <typename T
>
117 inline T
MaybeForwarded(T t
) {
118 if (IsForwarded(t
)) {
121 MOZ_ASSERT(!IsForwarded(t
));
125 inline const JSClass
* MaybeForwardedObjectClass(const JSObject
* obj
) {
126 Shape
* shape
= MaybeForwarded(obj
->shapeMaybeForwarded());
127 BaseShape
* baseShape
= MaybeForwarded(shape
->base());
128 return baseShape
->clasp();
131 template <typename T
>
132 inline bool MaybeForwardedObjectIs(const JSObject
* obj
) {
133 MOZ_ASSERT(!obj
->isForwarded());
134 return MaybeForwardedObjectClass(obj
) == &T::class_
;
137 template <typename T
>
138 inline T
& MaybeForwardedObjectAs(JSObject
* obj
) {
139 MOZ_ASSERT(MaybeForwardedObjectIs
<T
>(obj
));
140 return *static_cast<T
*>(obj
);
143 inline RelocationOverlay::RelocationOverlay(Cell
* dst
) {
144 MOZ_ASSERT(dst
->flags() == 0);
145 uintptr_t ptr
= uintptr_t(dst
);
146 header_
.setForwardingAddress(ptr
);
150 inline RelocationOverlay
* RelocationOverlay::forwardCell(Cell
* src
, Cell
* dst
) {
151 MOZ_ASSERT(!src
->isForwarded());
152 MOZ_ASSERT(!dst
->isForwarded());
153 return new (src
) RelocationOverlay(dst
);
156 inline bool IsAboutToBeFinalizedDuringMinorSweep(Cell
** cellp
) {
157 MOZ_ASSERT(JS::RuntimeHeapIsMinorCollecting());
159 if ((*cellp
)->isTenured()) {
163 return !Nursery::getForwardedPointer(cellp
);
166 // Special case pre-write barrier for strings used during rope flattening. This
167 // avoids eager marking of ropes which does not immediately mark the cells if we
168 // hit OOM. This does not traverse ropes and is instead called on every node in
169 // a rope during flattening.
170 inline void PreWriteBarrierDuringFlattening(JSString
* str
) {
172 MOZ_ASSERT(!JS::RuntimeHeapIsMajorCollecting());
174 if (IsInsideNursery(str
)) {
178 auto* cell
= reinterpret_cast<TenuredCell
*>(str
);
179 JS::shadow::Zone
* zone
= cell
->shadowZoneFromAnyThread();
180 if (!zone
->needsIncrementalBarrier()) {
184 MOZ_ASSERT(!str
->isPermanentAndMayBeShared());
185 MOZ_ASSERT(CurrentThreadCanAccessRuntime(zone
->runtimeFromAnyThread()));
186 PerformIncrementalBarrierDuringFlattening(str
);
189 #ifdef JSGC_HASH_TABLE_CHECKS
191 template <typename T
>
192 inline bool IsGCThingValidAfterMovingGC(T
* t
) {
193 return !IsInsideNursery(t
) && !t
->isForwarded();
196 template <typename T
>
197 inline void CheckGCThingAfterMovingGC(T
* t
) {
199 MOZ_RELEASE_ASSERT(IsGCThingValidAfterMovingGC(t
));
203 template <typename T
>
204 inline void CheckGCThingAfterMovingGC(const WeakHeapPtr
<T
*>& t
) {
205 CheckGCThingAfterMovingGC(t
.unbarrieredGet());
208 #endif // JSGC_HASH_TABLE_CHECKS
213 #endif // gc_Marking_inl_h