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/. */
10 #include "mozilla/OperatorNewExtensions.h"
14 #include "gc/AllocKind.h"
16 #include "gc/GCEnum.h"
19 #include "js/RootingAPI.h"
20 #include "js/TypeDecls.h"
30 // Allocator implementation functions. SpiderMonkey code outside this file
33 // cx->newCell<T>(...)
37 // cx->newCell<T, AllowGC::NoGC>(...)
39 // `friend` js::gc::CellAllocator in a subtype T of Cell in order to allow it to
40 // be allocated with cx->newCell<T>(...). The friend declaration will allow
41 // calling T's constructor.
43 // The parameters will be passed to a type-specific function or constructor. For
44 // nursery-allocatable types, see e.g. the NewString, NewObject, and NewBigInt
45 // methods. For all other types, the parameters will be forwarded to the
49 template <typename T
, js::AllowGC allowGC
= CanGC
, typename
... Args
>
50 static T
* NewCell(JS::RootingContext
* rcx
, Args
&&... args
);
53 template <AllowGC allowGC
>
54 static void* RetryNurseryAlloc(JS::RootingContext
* rcx
,
55 JS::TraceKind traceKind
, AllocKind allocKind
,
56 size_t thingSize
, AllocSite
* site
);
57 template <AllowGC allowGC
>
58 static void* TryNewTenuredCell(JS::RootingContext
* rcx
, AllocKind kind
,
61 #if defined(DEBUG) || defined(JS_GC_ZEAL) || defined(JS_OOM_BREAKPOINT)
62 template <AllowGC allowGC
>
63 static bool PreAllocChecks(JS::RootingContext
* rcx
, AllocKind kind
);
65 template <AllowGC allowGC
>
66 static bool PreAllocChecks(JS::RootingContext
* rcx
, AllocKind kind
) {
72 static void CheckIncrementalZoneState(JSContext
* cx
, void* ptr
);
75 static MOZ_ALWAYS_INLINE
gc::Heap
CheckedHeap(gc::Heap heap
) {
76 if (heap
> Heap::Tenured
) {
77 // This helps the compiler to see that nursery allocation is never
78 // possible if Heap::Tenured is specified.
79 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad gc::Heap value");
84 // Allocate a cell in the nursery, unless |heap| is Heap::Tenured or nursery
85 // allocation is disabled for |traceKind| in the current zone.
86 template <JS::TraceKind traceKind
, AllowGC allowGC
= CanGC
>
87 static void* AllocNurseryOrTenuredCell(JS::RootingContext
* rcx
,
88 gc::AllocKind allocKind
,
89 size_t thingSize
, gc::Heap heap
,
91 MOZ_ASSERT(IsNurseryAllocable(allocKind
));
92 MOZ_ASSERT(MapAllocToTraceKind(allocKind
) == traceKind
);
93 MOZ_ASSERT(thingSize
== Arena::thingSize(allocKind
));
94 MOZ_ASSERT_IF(site
&& site
->initialHeap() == Heap::Tenured
,
95 heap
== Heap::Tenured
);
97 if (!PreAllocChecks
<allowGC
>(rcx
, allocKind
)) {
101 JS::Zone
* zone
= rcx
->zoneUnchecked();
102 gc::Heap minHeapToTenure
= CheckedHeap(zone
->minHeapToTenure(traceKind
));
103 if (CheckedHeap(heap
) < minHeapToTenure
) {
105 site
= zone
->unknownAllocSite(traceKind
);
108 void* ptr
= rcx
->nursery().tryAllocateCell(site
, thingSize
, traceKind
);
109 if (MOZ_LIKELY(ptr
)) {
113 return RetryNurseryAlloc
<allowGC
>(rcx
, traceKind
, allocKind
, thingSize
,
117 return TryNewTenuredCell
<allowGC
>(rcx
, allocKind
, thingSize
);
120 // Allocate a cell in the tenured heap.
121 template <AllowGC allowGC
= CanGC
>
122 static void* AllocTenuredCell(JS::RootingContext
* rcx
, gc::AllocKind kind
,
125 // Allocate a string. Use cx->newCell<T>([heap]).
127 // Use for nursery-allocatable strings. Returns a value cast to the correct
128 // type. Non-nursery-allocatable strings will go through the fallback
129 // tenured-only allocation path.
130 template <typename T
, AllowGC allowGC
= CanGC
, typename
... Args
>
131 static T
* NewString(JS::RootingContext
* rcx
, gc::Heap heap
, Args
&&... args
) {
132 static_assert(std::is_base_of_v
<JSString
, T
>);
133 gc::AllocKind kind
= gc::MapTypeToAllocKind
<T
>::kind
;
134 void* ptr
= AllocNurseryOrTenuredCell
<JS::TraceKind::String
, allowGC
>(
135 rcx
, kind
, sizeof(T
), heap
, nullptr);
136 if (MOZ_UNLIKELY(!ptr
)) {
139 return new (mozilla::KnownNotNull
, ptr
) T(std::forward
<Args
>(args
)...);
142 template <typename T
, AllowGC allowGC
/* = CanGC */>
143 static T
* NewBigInt(JS::RootingContext
* rcx
, Heap heap
) {
144 void* ptr
= AllocNurseryOrTenuredCell
<JS::TraceKind::BigInt
, allowGC
>(
145 rcx
, gc::AllocKind::BIGINT
, sizeof(T
), heap
, nullptr);
146 if (MOZ_UNLIKELY(!ptr
)) {
149 return new (mozilla::KnownNotNull
, ptr
) T();
152 template <typename T
, AllowGC allowGC
= CanGC
>
153 static T
* NewObject(JS::RootingContext
* rcx
, gc::AllocKind kind
,
154 gc::Heap heap
, const JSClass
* clasp
,
155 gc::AllocSite
* site
= nullptr) {
156 MOZ_ASSERT(IsObjectAllocKind(kind
));
157 MOZ_ASSERT_IF(heap
!= gc::Heap::Tenured
&& clasp
->hasFinalize() &&
158 !clasp
->isProxyObject(),
159 CanNurseryAllocateFinalizedClass(clasp
));
160 size_t thingSize
= JSObject::thingSize(kind
);
161 void* cell
= AllocNurseryOrTenuredCell
<JS::TraceKind::Object
, allowGC
>(
162 rcx
, kind
, thingSize
, heap
, site
);
163 if (MOZ_UNLIKELY(!cell
)) {
166 return new (mozilla::KnownNotNull
, cell
) T();
169 // Allocate all other kinds of GC thing.
170 template <typename T
, AllowGC allowGC
= CanGC
, typename
... Args
>
171 static T
* NewTenuredCell(JS::RootingContext
* rcx
, Args
&&... args
) {
172 gc::AllocKind kind
= gc::MapTypeToAllocKind
<T
>::kind
;
173 void* cell
= AllocTenuredCell
<allowGC
>(rcx
, kind
, sizeof(T
));
174 if (MOZ_UNLIKELY(!cell
)) {
177 return new (mozilla::KnownNotNull
, cell
) T(std::forward
<Args
>(args
)...);
183 // This is the entry point for all allocation, though callers should still not
184 // use this directly. Use cx->newCell<T>(...) instead.
186 // After a successful allocation the caller must fully initialize the thing
187 // before calling any function that can potentially trigger GC. This will
188 // ensure that GC tracing never sees junk values stored in the partially
189 // initialized thing.
190 template <typename T
, AllowGC allowGC
, typename
... Args
>
191 T
* gc::CellAllocator::NewCell(JS::RootingContext
* rcx
, Args
&&... args
) {
192 static_assert(std::is_base_of_v
<gc::Cell
, T
>);
194 // Objects. See the valid parameter list in NewObject, above.
195 if constexpr (std::is_base_of_v
<JSObject
, T
>) {
196 return NewObject
<T
, allowGC
>(rcx
, std::forward
<Args
>(args
)...);
200 else if constexpr (std::is_base_of_v
<JS::BigInt
, T
>) {
201 return NewBigInt
<T
, allowGC
>(rcx
, std::forward
<Args
>(args
)...);
204 // "Normal" strings (all of which can be nursery allocated). Atoms and
205 // external strings will fall through to the generic code below. All other
206 // strings go through NewString, which will forward the arguments to the
207 // appropriate string class's constructor.
208 else if constexpr (std::is_base_of_v
<JSString
, T
> &&
209 !std::is_base_of_v
<JSAtom
, T
> &&
210 !std::is_base_of_v
<JSExternalString
, T
>) {
211 return NewString
<T
, allowGC
>(rcx
, std::forward
<Args
>(args
)...);
215 // Allocate a new tenured GC thing that's not nursery-allocatable. Use
216 // cx->newCell<T>(...), where the parameters are forwarded to the type's
218 return NewTenuredCell
<T
, allowGC
>(rcx
, std::forward
<Args
>(args
)...);
224 #endif // gc_Allocator_h