blob: 01497e9c425afde3bdb34af6bacda80e99d7ea30 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
extern crate libc;
extern crate mmtk;
#[macro_use]
extern crate log;
extern crate probe;
use std::collections::HashSet;
use std::panic::PanicHookInfo;
use std::sync::Mutex;
use std::thread::ThreadId;
use abi::RubyUpcalls;
use binding::{RubyBinding, RubyBindingFast, RubyConfiguration};
use mmtk::vm::slot::{SimpleSlot, UnimplementedMemorySlice};
use mmtk::vm::VMBinding;
use mmtk::MMTK;
use once_cell::sync::OnceCell;
pub mod abi;
pub mod active_plan;
pub mod api;
pub mod binding;
pub mod collection;
pub mod object_model;
pub mod reference_glue;
pub mod scanning;
pub mod utils;
pub mod weak_proc;
#[derive(Default)]
pub struct Ruby;
/// Ruby slot type, i.e. a slot that holds a VALUE.
/// Currently we use SimpleSlot.
/// It doesn't matter, becaues we have not started using slot-enqueuing, yet.
pub type RubySlot = SimpleSlot;
/// Ruby memory slice, i.e. an array of VALUEs.
/// It is used by array-copy barriers which is supposed to perform bettern than copying array
/// elements one by one. At this moment, we just leave it unimplemented.
pub type RubyMemorySlice = UnimplementedMemorySlice<RubySlot>;
impl VMBinding for Ruby {
type VMObjectModel = object_model::VMObjectModel;
type VMScanning = scanning::VMScanning;
type VMCollection = collection::VMCollection;
type VMActivePlan = active_plan::VMActivePlan;
type VMReferenceGlue = reference_glue::VMReferenceGlue;
type VMSlot = RubySlot;
type VMMemorySlice = RubyMemorySlice;
}
/// The singleton object for the Ruby binding itself.
pub static BINDING: OnceCell<RubyBinding> = OnceCell::new();
/// Some data needs to be accessed fast.
/// We sacrifice safety for speed using unsynchronized global variables.
pub static mut BINDING_FAST: RubyBindingFast = RubyBindingFast::new();
/// Some data needs to be accessed fast.
pub static CONFIGURATION: RubyConfiguration = RubyConfiguration::new();
pub fn binding<'b>() -> &'b RubyBinding {
BINDING
.get()
.expect("Attempt to use the binding before it is initialization")
}
pub fn mmtk() -> &'static MMTK<Ruby> {
binding().mmtk
}
pub fn upcalls() -> &'static RubyUpcalls {
binding().upcalls()
}
pub static GC_THREADS: OnceCell<Mutex<HashSet<ThreadId>>> = OnceCell::new();
pub(crate) fn register_gc_thread(thread_id: ThreadId) {
let mut gc_threads = GC_THREADS.get().unwrap().lock().unwrap();
gc_threads.insert(thread_id);
}
pub(crate) fn unregister_gc_thread(thread_id: ThreadId) {
let mut gc_threads = GC_THREADS.get().unwrap().lock().unwrap();
gc_threads.remove(&thread_id);
}
pub(crate) fn is_gc_thread(thread_id: ThreadId) -> bool {
let gc_threads = GC_THREADS.get().unwrap().lock().unwrap();
gc_threads.contains(&thread_id)
}
fn handle_gc_thread_panic(panic_info: &PanicHookInfo) {
eprintln!("ERROR: An MMTk GC thread panicked. This is a bug.");
eprintln!("{panic_info}");
let bt = std::backtrace::Backtrace::capture();
match bt.status() {
std::backtrace::BacktraceStatus::Unsupported => {
eprintln!("Backtrace is unsupported.")
}
std::backtrace::BacktraceStatus::Disabled => {
eprintln!("Backtrace is disabled.");
eprintln!("run with `RUST_BACKTRACE=1` environment variable to display a backtrace");
}
std::backtrace::BacktraceStatus::Captured => {
eprintln!("{bt}");
}
s => {
eprintln!("Unknown backtrace status: {s:?}");
}
}
std::process::abort();
}
pub(crate) fn set_panic_hook() {
if GC_THREADS.set(Default::default()).is_err() {
return;
}
let old_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
if is_gc_thread(std::thread::current().id()) {
handle_gc_thread_panic(panic_info);
} else {
old_hook(panic_info);
}
}));
}
|