1use std::{
9 marker::PhantomData,
10 ptr::{NonNull, null_mut},
11 sync::atomic::{AtomicPtr, Ordering},
12};
13
14use jl_sys::{jl_sym_t, jl_symbol_n, jl_value_t};
15
16use super::{
17 cache::Cache,
18 managed::private::ManagedPriv,
19 types::{construct_type::ConstructType, typecheck::Typecheck},
20};
21use crate::{
22 data::managed::{Managed, module::Module, value::ValueUnbound},
23 gc_safe::GcSafeOnceLock,
24 memory::{PTls, target::Target},
25 prelude::{Symbol, Value},
26 private::Private,
27};
28
29type CacheImpl = Cache<()>;
30
31static CACHE: CacheImpl = CacheImpl::new(());
32
33pub(crate) unsafe fn mark_static_data_cache(ptls: PTls, full: bool) {
34 unsafe {
35 CACHE.mark(ptls, full);
36 }
37}
38
39struct StaticDataInner<T>(ValueUnbound, PhantomData<T>);
40unsafe impl<T> Send for StaticDataInner<T> {}
41unsafe impl<T> Sync for StaticDataInner<T> {}
42
43pub struct StaticGlobal<T> {
45 global: GcSafeOnceLock<StaticDataInner<T>>,
46 path: &'static str,
47}
48
49impl<T> StaticGlobal<T>
50where
51 T: Managed<'static, 'static> + Typecheck,
52{
53 #[inline]
58 pub const fn new(path: &'static str) -> StaticGlobal<T> {
59 StaticGlobal {
60 global: GcSafeOnceLock::new(),
61 path,
62 }
63 }
64
65 #[inline]
69 pub fn get_or_init<'target, Tgt>(&self, target: &Tgt) -> T
70 where
71 Tgt: Target<'target>,
72 {
73 unsafe {
74 if let Some(global) = self.global.get() {
75 return global.0.cast_unchecked::<T>();
76 } else {
77 self.init(target)
78 }
79 }
80 }
81
82 #[inline(never)]
83 #[cold]
84 unsafe fn init<'target, Tgt>(&self, target: &Tgt) -> T
85 where
86 Tgt: Target<'target>,
87 {
88 unsafe {
89 let global = self.global.get_or_init(|| {
93 let split_path = self.path.split('.').collect::<Vec<_>>();
94 let n_parts = split_path.len();
95
96 let mut module = match split_path[0] {
97 "Main" => Module::main(target),
98 "Base" => Module::base(target),
99 "Core" => Module::core(target),
100 pkg => Module::package_root_module(target, pkg).unwrap(),
101 };
102
103 if n_parts == 1 {
104 let global = module.leak().as_value().cast::<T>().unwrap();
105 return StaticDataInner(global.as_value(), PhantomData);
106 }
107
108 for i in 1..n_parts - 1 {
109 module = module
110 .submodule(target, split_path[i])
111 .unwrap()
112 .as_managed();
113 }
114
115 let global = module
116 .global(target, split_path[n_parts - 1])
117 .unwrap()
118 .leak()
119 .as_value()
120 .cast::<T>()
121 .unwrap();
122
123 CACHE.write(|cache| {
124 cache.roots_mut().insert(global.as_value());
125 });
126
127 return StaticDataInner(global.as_value(), PhantomData);
128 });
129
130 global.0.cast_unchecked()
131 }
132 }
133}
134
135impl StaticGlobal<ValueUnbound> {
136 pub const fn new_value(path: &'static str) -> StaticGlobal<ValueUnbound> {
141 StaticGlobal {
142 global: GcSafeOnceLock::new(),
143 path,
144 }
145 }
146}
147
148pub struct StaticSymbolRef {
152 sym: AtomicPtr<jl_sym_t>,
153 sym_s: &'static str,
154}
155
156impl StaticSymbolRef {
157 #[inline]
162 pub const fn new(sym_s: &'static str) -> StaticSymbolRef {
163 StaticSymbolRef {
164 sym: AtomicPtr::new(null_mut()),
165 sym_s,
166 }
167 }
168
169 #[inline]
171 pub fn get_or_init<'target, Tgt>(&self, target: &Tgt) -> Symbol<'target>
172 where
173 Tgt: Target<'target>,
174 {
175 let ptr = self.sym.load(Ordering::Relaxed);
176 if ptr.is_null() {
177 self.init(target)
179 } else {
180 unsafe { Symbol::wrap_non_null(NonNull::new_unchecked(ptr), Private) }
181 }
182 }
183
184 #[cold]
185 #[inline(never)]
186 fn init<'target, Tgt>(&self, _: &Tgt) -> Symbol<'target>
187 where
188 Tgt: Target<'target>,
189 {
190 unsafe {
191 let bytes = self.sym_s.as_bytes();
192 let n_bytes = bytes.len();
193 let bytes_ptr = bytes.as_ptr().cast();
194
195 let sym = jl_symbol_n(bytes_ptr, n_bytes);
196 self.sym.store(sym, Ordering::Relaxed);
197
198 Symbol::wrap_non_null(NonNull::new_unchecked(sym), Private)
199 }
200 }
201}
202
203pub struct StaticRef<T: Managed<'static, 'static>> {
207 global: AtomicPtr<T::Wraps>,
208 path: &'static str,
209}
210
211impl<T> StaticRef<T>
212where
213 T: Managed<'static, 'static> + Typecheck,
214{
215 #[inline]
220 pub const fn new(path: &'static str) -> StaticRef<T> {
221 StaticRef {
222 global: AtomicPtr::new(null_mut()),
223 path,
224 }
225 }
226
227 #[inline]
231 pub fn get_or_init<'target, Tgt>(&self, target: &Tgt) -> T
232 where
233 Tgt: Target<'target>,
234 {
235 let ptr = self.global.load(Ordering::Relaxed);
236 if ptr.is_null() {
237 self.init(target)
239 } else {
240 unsafe { T::wrap_non_null(NonNull::new_unchecked(ptr), Private) }
241 }
242 }
243
244 #[cold]
245 #[inline(never)]
246 fn init<'target, Tgt>(&self, target: &Tgt) -> T
247 where
248 Tgt: Target<'target>,
249 {
250 unsafe {
251 let split_path = self.path.split('.').collect::<Vec<_>>();
252 let n_parts = split_path.len();
253
254 let mut module = match split_path[0] {
255 "Main" => Module::main(target),
256 "Base" => Module::base(target),
257 "Core" => Module::core(target),
258 pkg => Module::package_root_module(target, pkg).unwrap(),
259 };
260
261 if n_parts == 1 {
262 let global = module.leak().as_value().cast::<T>().unwrap();
263 let ptr = global.unwrap(Private);
264 self.global.store(ptr, Ordering::Relaxed);
265 return T::wrap_non_null(NonNull::new_unchecked(ptr), Private);
266 }
267
268 for i in 1..n_parts - 1 {
269 module = module
270 .submodule(target, split_path[i])
271 .unwrap()
272 .as_managed();
273 }
274
275 let global = module
276 .global(target, split_path[n_parts - 1])
277 .unwrap()
278 .leak()
279 .as_value()
280 .cast::<T>()
281 .unwrap();
282
283 CACHE.write(|cache| {
284 cache.roots_mut().insert(global.as_value());
285 });
286
287 let ptr = global.unwrap(Private);
288 self.global.store(ptr, Ordering::Relaxed);
289 T::wrap_non_null(NonNull::new_unchecked(ptr), Private)
290 }
291 }
292
293 #[inline]
295 pub(crate) unsafe fn get_or_eval<'target, Tgt>(&self, target: &Tgt) -> T
296 where
297 Tgt: Target<'target>,
298 {
299 unsafe {
300 let ptr = self.global.load(Ordering::Relaxed);
301 if ptr.is_null() {
302 self.eval(target)
303 } else {
304 T::wrap_non_null(NonNull::new_unchecked(ptr), Private)
305 }
306 }
307 }
308
309 #[cold]
311 #[inline(never)]
312 unsafe fn eval<'target, Tgt>(&self, target: &Tgt) -> T
313 where
314 Tgt: Target<'target>,
315 {
316 unsafe {
317 let v = Value::eval_string(target, self.path)
318 .unwrap()
319 .leak()
320 .as_value()
321 .cast::<T>()
322 .unwrap();
323
324 CACHE.write(|cache| {
325 cache.roots_mut().insert(v.as_value());
326 });
327
328 let ptr = v.unwrap(Private);
329 self.global.store(ptr, Ordering::Relaxed);
330 T::wrap_non_null(NonNull::new_unchecked(ptr), Private)
331 }
332 }
333}
334
335pub struct StaticConstructibleType<T: ConstructType> {
337 global: AtomicPtr<jl_value_t>,
338 _marker: PhantomData<T>,
339}
340
341impl<T> StaticConstructibleType<T>
342where
343 T: ConstructType,
344{
345 #[inline]
347 pub const fn new() -> StaticConstructibleType<T> {
348 StaticConstructibleType {
349 global: AtomicPtr::new(null_mut()),
350 _marker: PhantomData,
351 }
352 }
353
354 #[inline]
356 pub fn get_or_init<'target, Tgt>(&self, target: &Tgt) -> Value<'target, 'static>
357 where
358 Tgt: Target<'target>,
359 {
360 let ptr = self.global.load(Ordering::Relaxed);
361 if ptr.is_null() {
362 self.init(target)
364 } else {
365 unsafe { Value::wrap_non_null(NonNull::new_unchecked(ptr), Private) }
366 }
367 }
368
369 #[cold]
370 #[inline(never)]
371 fn init<'target, Tgt>(&self, target: &Tgt) -> Value<'target, 'static>
372 where
373 Tgt: Target<'target>,
374 {
375 unsafe {
376 let v = T::construct_type(target).as_value();
377 CACHE.write(|cache| {
378 cache.roots_mut().insert(v);
379 });
380 self.global.store(v.unwrap(Private), Ordering::Relaxed);
381
382 v
383 }
384 }
385}
386
387#[macro_export]
389macro_rules! define_static_global {
390 ($(#[$meta:meta])* $vis:vis $ty:ident, $type:ty, $path:expr_2021) => {
391 $(#[$meta])*
392 $vis static $name: $crate::data::static_data::StaticGlobal<$type> =
393 $crate::data::static_data::StaticGlobal::new($path);
394 };
395 ($(#[$meta:meta])* $vis:vis $name:ident, $path:expr_2021) => {
396 $(#[$meta])*
397 $vis static $name: $crate::data::static_data::StaticGlobal<
398 $crate::data::managed::value::ValueUnbound,
399 > = $crate::data::static_data::StaticGlobal::new_value($path);
400 };
401}
402
403#[macro_export]
405macro_rules! define_static_ref {
406 ($(#[$meta:meta])* $vis:vis $name:ident, $type:ty, $path:expr_2021) => {
407 $(#[$meta])*
408 $vis static $name: $crate::data::static_data::StaticRef<$type> =
409 $crate::data::static_data::StaticRef::new($path);
410 };
411}
412
413#[macro_export]
415macro_rules! define_static_symbol_ref {
416 ($(#[$meta:meta])+ $vis:vis $name:ident, $sym:expr_2021) => {
417 $(#[$meta])+
418 $vis static $name: $crate::data::static_data::StaticSymbolRef =
419 $crate::data::static_data::StaticSymbolRef::new($sym);
420 };
421}
422
423#[macro_export]
425macro_rules! static_global {
426 ($name:ident, $target:expr_2021) => {{ $name.get_or_init(&$target) }};
427}
428#[macro_export]
430macro_rules! static_ref {
431 ($name:ident, $target:expr_2021) => {{ $name.get_or_init(&$target) }};
432}
433#[macro_export]
435macro_rules! static_symbol_ref {
436 ($name:ident, $target:expr_2021) => {{ $name.get_or_init(&$target) }};
437}
438
439pub use define_static_global;
440pub use define_static_ref;
441pub use define_static_symbol_ref;
442pub use static_global;
443pub use static_ref;
444pub use static_symbol_ref;
445
446#[macro_export]
451macro_rules! inline_static_global {
452 ($(#[$meta:meta])* $name:ident, $type:ty, $path:expr_2021, $target:expr_2021) => {{
453 $crate::data::static_data::define_static_global!($(#[$meta])* $name, $type, $path);
454 $crate::data::static_data::static_global!($name, $target)
455 }};
456 ($(#[$meta:meta])* $name:ident, $path:expr_2021, $target:expr_2021) => {{
457 $crate::data::static_data::define_static_global!($(#[$meta])* $name, $path);
458 $crate::data::static_data::static_global!($name, $target)
459 }};
460}
461
462#[macro_export]
467macro_rules! inline_static_ref {
468 ($(#[$meta:meta])* $name:ident, $type:ty, $path:expr_2021, $target:expr_2021) => {{
469 $crate::data::static_data::define_static_ref!($(#[$meta])* $name, $type, $path);
470 $crate::data::static_data::static_ref!($name, $target)
471 }};
472}
473
474#[macro_export]
479macro_rules! inline_static_symbol_ref {
480 ($(#[$meta:meta])* $name:ident, $sym:expr_2021, $target:expr_2021) => {{
481 $crate::data::static_data::define_static_symbol_ref!($(#[$meta])* $name, $sym);
482 $crate::data::static_data::static_symbol_ref!($name, $target)
483 }};
484}
485
486pub use inline_static_global;
487pub use inline_static_ref;
488pub use inline_static_symbol_ref;