1use crate::{
8 ast::DefinitionBody,
9 cps::{Compile, Cps, codegen::RuntimeFunctionsBuilder},
10 env::{Environment, Global, TopLevelEnvironment},
11 exceptions::{Exception, raise},
12 gc::{Gc, GcInner, Trace, init_gc},
13 hashtables::EqualHashSet,
14 lists::{Pair, list_to_vec},
15 num,
16 ports::{BufferMode, Port, Transcoder},
17 proc::{
18 Application, ContinuationPtr, DynamicState, FuncPtr, ProcDebugInfo, Procedure, UserPtr,
19 },
20 registry::Registry,
21 symbols::Symbol,
22 syntax::{Identifier, Span, Syntax},
23 value::{Cell, UnpackedValue, Value},
24};
25use parking_lot::RwLock;
26use scheme_rs_macros::{maybe_async, maybe_await, runtime_fn};
27use std::{
28 collections::{BTreeSet, HashSet},
29 mem::ManuallyDrop,
30 path::Path,
31 sync::Arc,
32};
33
34#[derive(Trace, Clone)]
65pub struct Runtime(pub(crate) Gc<RwLock<RuntimeInner>>);
66
67impl Default for Runtime {
68 fn default() -> Self {
69 Self::new()
70 }
71}
72
73impl Runtime {
74 pub fn new() -> Self {
77 let this = Self(Gc::new(RwLock::new(RuntimeInner::new())));
78 let new_registry = Registry::new(&this);
79 this.0.write().registry = new_registry;
80 this
81 }
82
83 #[maybe_async]
85 pub fn run_program(&self, path: &Path) -> Result<Vec<Value>, Exception> {
86 #[cfg(not(feature = "async"))]
87 use std::fs::File;
88
89 #[cfg(feature = "tokio")]
90 use tokio::fs::File;
91
92 let progm = TopLevelEnvironment::new_program(self, path);
93 let env = Environment::Top(progm.clone());
94 let mut form = {
95 let port = Port::new(
96 path.display(),
97 maybe_await!(File::open(path)).unwrap(),
98 BufferMode::Block,
99 Some(Transcoder::native()),
100 );
101 let file_name = path.file_name().unwrap().to_str().unwrap_or("<unknown>");
102 let span = Span::new(file_name);
103 maybe_await!(port.all_sexprs(span)).map_err(Exception::from)?
104 };
105
106 form.add_scope(progm.scope());
107 let body = maybe_await!(DefinitionBody::parse_lib_body(self, &form, &env))?;
108 let compiled = body.compile_top_level();
109 let closure = maybe_await!(self.compile_expr(compiled));
110
111 maybe_await!(Application::new(closure, Vec::new()).eval(&mut DynamicState::default()))
112 }
113
114 #[cfg(not(feature = "async"))]
116 #[track_caller]
117 pub fn def_lib(&self, lib: &str) -> Result<(), Exception> {
118 use std::panic::Location;
119
120 self.get_registry()
121 .def_lib(self, lib, Location::caller().file())
122 }
123
124 #[cfg(feature = "async")]
126 pub async fn def_lib(&self, lib: &str) -> Result<(), Exception> {
127 use std::panic::Location;
128
129 self.get_registry()
130 .def_lib(self, lib, Location::caller().file())
131 .await
132 }
133
134 pub(crate) fn get_registry(&self) -> Registry {
135 self.0.read().registry.clone()
136 }
137
138 #[maybe_async]
139 pub(crate) fn compile_expr(&self, expr: Cps) -> Procedure {
140 let (completion_tx, completion_rx) = completion();
141 let task = CompilationTask {
142 completion_tx,
143 compilation_unit: expr,
144 runtime: self.clone(),
145 };
146 let sender = { self.0.read().compilation_buffer_tx.clone() };
147 let _ = maybe_await!(sender.send(task));
148 maybe_await!(recv_procedure(completion_rx))
150 }
151
152 pub(crate) unsafe fn from_raw_inc_rc(rt: *mut GcInner<RwLock<RuntimeInner>>) -> Self {
153 unsafe { Self(Gc::from_raw_inc_rc(rt)) }
154 }
155}
156
157#[cfg(not(feature = "async"))]
158type CompilationBufferTx = std::sync::mpsc::SyncSender<CompilationTask>;
159#[cfg(not(feature = "async"))]
160type CompilationBufferRx = std::sync::mpsc::Receiver<CompilationTask>;
161
162#[cfg(feature = "async")]
163type CompilationBufferTx = tokio::sync::mpsc::Sender<CompilationTask>;
164#[cfg(feature = "async")]
165type CompilationBufferRx = tokio::sync::mpsc::Receiver<CompilationTask>;
166
167#[derive(Trace)]
168pub(crate) struct RuntimeInner {
169 pub(crate) registry: Registry,
171 compilation_buffer_tx: CompilationBufferTx,
173 pub(crate) constants_pool: EqualHashSet,
174 pub(crate) globals_pool: HashSet<Global>,
175 pub(crate) debug_info: DebugInfo,
176}
177
178impl Default for RuntimeInner {
179 fn default() -> Self {
180 Self::new()
181 }
182}
183
184const MAX_COMPILATION_TASKS: usize = 5; #[cfg(not(feature = "async"))]
187fn compilation_buffer() -> (CompilationBufferTx, CompilationBufferRx) {
188 std::sync::mpsc::sync_channel(MAX_COMPILATION_TASKS)
189}
190
191#[cfg(feature = "async")]
192fn compilation_buffer() -> (CompilationBufferTx, CompilationBufferRx) {
193 tokio::sync::mpsc::channel(MAX_COMPILATION_TASKS)
194}
195
196impl RuntimeInner {
197 fn new() -> Self {
198 init_gc();
200 let (compilation_buffer_tx, compilation_buffer_rx) = compilation_buffer();
201 std::thread::spawn(move || compilation_task(compilation_buffer_rx));
205 RuntimeInner {
206 registry: Registry::empty(),
207 compilation_buffer_tx,
208 constants_pool: EqualHashSet::new(),
209 globals_pool: HashSet::new(),
210 debug_info: DebugInfo::default(),
211 }
212 }
213}
214
215#[derive(Trace, Clone, Debug, Default)]
216pub(crate) struct DebugInfo {
217 stored_func_info: Vec<Arc<ProcDebugInfo>>,
219}
220
221impl DebugInfo {
222 pub fn store_func_info(&mut self, debug_info: Arc<ProcDebugInfo>) {
223 self.stored_func_info.push(debug_info);
224 }
225}
226
227#[cfg(not(feature = "async"))]
228type CompletionTx = std::sync::mpsc::SyncSender<Procedure>;
229#[cfg(not(feature = "async"))]
230type CompletionRx = std::sync::mpsc::Receiver<Procedure>;
231
232#[cfg(feature = "async")]
233type CompletionTx = tokio::sync::oneshot::Sender<Procedure>;
234#[cfg(feature = "async")]
235type CompletionRx = tokio::sync::oneshot::Receiver<Procedure>;
236
237#[cfg(not(feature = "async"))]
238fn completion() -> (CompletionTx, CompletionRx) {
239 std::sync::mpsc::sync_channel(1)
240}
241
242#[cfg(feature = "async")]
243fn completion() -> (CompletionTx, CompletionRx) {
244 tokio::sync::oneshot::channel()
245}
246
247#[cfg(not(feature = "async"))]
248fn recv_procedure(rx: CompletionRx) -> Procedure {
249 rx.recv().unwrap()
250}
251
252#[cfg(feature = "async")]
253async fn recv_procedure(rx: CompletionRx) -> Procedure {
254 rx.await.unwrap()
255}
256
257struct CompilationTask {
258 compilation_unit: Cps,
259 completion_tx: CompletionTx,
260 runtime: Runtime,
265}
266
267#[cfg(not(feature = "async"))]
268fn recv_compilation_task(rx: &mut CompilationBufferRx) -> Option<CompilationTask> {
269 rx.recv().ok()
270}
271
272#[cfg(feature = "async")]
273fn recv_compilation_task(rx: &mut CompilationBufferRx) -> Option<CompilationTask> {
274 rx.blocking_recv()
275}
276
277fn compilation_task(mut compilation_queue_rx: CompilationBufferRx) {
278 use cranelift::prelude::*;
279 use cranelift_jit::{JITBuilder, JITModule};
280
281 let mut flag_builder = settings::builder();
282 flag_builder.set("use_colocated_libcalls", "false").unwrap();
283 flag_builder.set("is_pic", "false").unwrap();
285 let isa_builder = cranelift_native::builder().unwrap_or_else(|msg| {
286 panic!("host machine is not supported: {msg}");
287 });
288 let isa = isa_builder
289 .finish(settings::Flags::new(flag_builder))
290 .unwrap();
291
292 let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
293
294 for runtime_fn in inventory::iter::<RuntimeFn> {
295 (runtime_fn.install_symbol)(&mut jit_builder);
296 }
297
298 let mut module = JITModule::new(jit_builder);
299 let mut runtime_funcs_builder = RuntimeFunctionsBuilder::default();
300
301 for runtime_fn in inventory::iter::<RuntimeFn> {
302 (runtime_fn.install_decl)(&mut runtime_funcs_builder, &mut module);
303 }
304
305 let runtime_funcs = runtime_funcs_builder.build().unwrap();
306
307 let mut debug_info = DebugInfo::default();
311
312 while let Some(task) = recv_compilation_task(&mut compilation_queue_rx) {
313 let CompilationTask {
314 completion_tx,
315 compilation_unit,
316 runtime,
317 } = task;
318
319 let proc =
320 compilation_unit.into_procedure(runtime, &runtime_funcs, &mut module, &mut debug_info);
321
322 let _ = completion_tx.send(proc);
323 }
324
325 unsafe {
327 module.free_memory();
328 }
329}
330
331pub(crate) struct RuntimeFn {
332 install_decl:
333 for<'a> fn(&'a mut RuntimeFunctionsBuilder, module: &'a mut cranelift_jit::JITModule),
334 install_symbol: for<'a> fn(&'a mut cranelift_jit::JITBuilder),
335}
336
337impl RuntimeFn {
338 pub(crate) const fn new(
339 install_decl: for<'a> fn(
340 &'a mut RuntimeFunctionsBuilder,
341 module: &'a mut cranelift_jit::JITModule,
342 ),
343 install_symbol: for<'a> fn(&'a mut cranelift_jit::JITBuilder),
344 ) -> Self {
345 Self {
346 install_decl,
347 install_symbol,
348 }
349 }
350}
351
352inventory::collect!(RuntimeFn);
353
354unsafe fn arc_from_ptr<T>(ptr: *const T) -> Option<Arc<T>> {
355 unsafe {
356 if ptr.is_null() {
357 return None;
358 }
359 Arc::increment_strong_count(ptr);
360 Some(Arc::from_raw(ptr))
361 }
362}
363
364#[runtime_fn]
366unsafe extern "C" fn alloc_cell() -> *const () {
367 Value::into_raw(Value::from(Cell(Gc::new(RwLock::new(Value::undefined())))))
368}
369
370#[runtime_fn]
372unsafe extern "C" fn read_cell(cell: *const ()) -> *const () {
373 unsafe {
374 let cell = Value::from_raw(cell);
375 let cell: Cell = cell.try_into().unwrap();
376 let cell = ManuallyDrop::new(cell);
379 let cell_read = cell.0.read();
380 Value::as_raw(&cell_read)
381 }
382}
383
384#[runtime_fn]
386unsafe extern "C" fn dropv(val: *const *const (), num_drops: u32) {
387 unsafe {
388 for i in 0..num_drops {
389 drop(Value::from_raw(val.add(i as usize).read()));
390 }
391 }
392}
393
394#[runtime_fn]
396unsafe extern "C" fn apply(
397 runtime: *mut GcInner<RwLock<RuntimeInner>>,
398 op: *const (),
399 args: *const *const (),
400 num_args: u32,
401 dyn_state: *mut DynamicState,
402) -> *mut Application {
403 unsafe {
404 let args: Vec<_> = (0..num_args)
405 .map(|i| Value::from_raw_inc_rc(args.add(i as usize).read()))
406 .collect();
407
408 let op = match Value::from_raw_inc_rc(op).unpack() {
409 UnpackedValue::Procedure(op) => op,
410 x => {
411 let raised = raise(
412 Runtime::from_raw_inc_rc(runtime),
413 Exception::invalid_operator(x.type_name()).into(),
414 dyn_state.as_mut().unwrap_unchecked(),
415 );
416 return Box::into_raw(Box::new(raised));
417 }
418 };
419
420 let app = Application::new(op, args);
421
422 Box::into_raw(Box::new(app))
423 }
424}
425
426#[runtime_fn]
428unsafe extern "C" fn get_frame(op: *const (), span: *const ()) -> *const () {
429 unsafe {
430 let op = Value::from_raw_inc_rc(op);
431 let Some(op) = op.cast_to_scheme_type::<Procedure>() else {
432 return Value::into_raw(Value::null());
433 };
434 let span = Value::from_raw_inc_rc(span);
435 let span = span.cast_to_rust_type::<Span>().unwrap();
436 let frame = Syntax::Identifier {
437 ident: Identifier {
438 sym: op
439 .get_debug_info()
440 .map_or_else(|| Symbol::intern("<lambda>"), |dbg| dbg.name),
441 scopes: BTreeSet::new(),
442 },
443 span: span.as_ref().clone(),
444 };
445 Value::into_raw(Value::from(frame))
446 }
447}
448
449#[runtime_fn]
451unsafe extern "C" fn set_continuation_mark(
452 tag: *const (),
453 val: *const (),
454 dyn_state: *mut DynamicState,
455) {
456 unsafe {
457 let tag = Value::from_raw_inc_rc(tag);
458 let val = Value::from_raw_inc_rc(val);
459 dyn_state
460 .as_mut()
461 .unwrap()
462 .set_continuation_mark(tag.cast_to_scheme_type().unwrap(), val);
463 }
464}
465
466#[runtime_fn]
468pub(crate) unsafe extern "C" fn halt(args: *const ()) -> *mut Application {
469 unsafe {
470 let args = ManuallyDrop::new(Value::from_raw(args));
472 let mut flattened = Vec::new();
473 list_to_vec(&args, &mut flattened);
474 let app = Application::halt_ok(flattened);
475 Box::into_raw(Box::new(app))
476 }
477}
478
479#[runtime_fn]
482unsafe extern "C" fn truthy(val: *const ()) -> bool {
483 unsafe {
484 ManuallyDrop::new(Value::from_raw(val)).is_true()
486 }
487}
488
489#[runtime_fn]
491unsafe extern "C" fn store(from: *const (), to: *const ()) {
492 unsafe {
493 let from = Value::from_raw_inc_rc(from);
496 let to: ManuallyDrop<Cell> = ManuallyDrop::new(Value::from_raw(to).try_into().unwrap());
497 *to.0.write() = from;
498 }
499}
500
501#[runtime_fn]
503unsafe extern "C" fn cons(vals: *const *const (), num_vals: u32, error: *mut Value) -> *const () {
504 unsafe {
505 if num_vals != 2 {
506 error.write(Exception::wrong_num_of_args(2, num_vals as usize).into());
507 return Value::into_raw(Value::undefined());
508 }
509 let car = Value::from_raw_inc_rc(vals.read());
510 let cdr = Value::from_raw_inc_rc(vals.add(1).read());
511 Value::into_raw(Value::from(Pair::new(car, cdr, true)))
512 }
513}
514
515#[runtime_fn]
517unsafe extern "C" fn list(vals: *const *const (), num_vals: u32, _error: *mut Value) -> *const () {
518 let mut list = Value::null();
519 unsafe {
520 for i in (0..num_vals).rev() {
521 list = Value::from(Pair::new(
522 Value::from_raw_inc_rc(vals.add(i as usize).read()),
523 list,
524 true,
525 ));
526 }
527 }
528 Value::into_raw(list)
529}
530
531#[runtime_fn]
533unsafe extern "C" fn make_continuation(
534 runtime: *mut GcInner<RwLock<RuntimeInner>>,
535 fn_ptr: ContinuationPtr,
536 env: *const *const (),
537 num_envs: u32,
538 num_required_args: u32,
539 variadic: bool,
540 dyn_state: *mut DynamicState,
541) -> *const () {
542 unsafe {
543 let env: Vec<_> = (0..num_envs)
545 .map(|i| Value::from_raw_inc_rc(env.add(i as usize).read()))
546 .collect();
547
548 let proc = dyn_state.as_mut().unwrap().new_k(
549 Runtime::from_raw_inc_rc(runtime),
550 env,
551 fn_ptr,
552 num_required_args as usize,
553 variadic,
554 );
555
556 Value::into_raw(Value::from(proc))
557 }
558}
559
560#[runtime_fn]
562unsafe extern "C" fn make_user(
563 runtime: *mut GcInner<RwLock<RuntimeInner>>,
564 fn_ptr: UserPtr,
565 env: *const *const (),
566 num_envs: u32,
567 num_required_args: u32,
568 variadic: bool,
569 debug_info: *const ProcDebugInfo,
570) -> *const () {
571 unsafe {
572 let env: Vec<_> = (0..num_envs)
574 .map(|i| Value::from_raw_inc_rc(env.add(i as usize).read()))
575 .collect();
576
577 let proc = Procedure::with_debug_info(
578 Runtime::from_raw_inc_rc(runtime),
579 env,
580 FuncPtr::User(fn_ptr),
581 num_required_args as usize,
582 variadic,
583 arc_from_ptr(debug_info),
584 );
585
586 Value::into_raw(Value::from(proc))
587 }
588}
589
590#[runtime_fn]
592unsafe extern "C" fn error_unbound_variable(symbol: u32) -> *const () {
593 let sym = Symbol(symbol);
594 let condition = Exception::error(format!("{sym} is unbound"));
595 Value::into_raw(Value::from(condition))
596}
597
598#[runtime_fn]
599unsafe extern "C" fn add(vals: *const *const (), num_vals: u32, error: *mut Value) -> *const () {
600 unsafe {
601 let vals: Vec<_> = (0..num_vals)
602 .map(|i| Value::from_raw_inc_rc(vals.add(i as usize).read()))
604 .collect();
605 match num::add_prim(&vals) {
606 Ok(num) => Value::into_raw(Value::from(num)),
607 Err(condition) => {
608 error.write(condition.into());
609 Value::into_raw(Value::undefined())
610 }
611 }
612 }
613}
614
615#[runtime_fn]
616unsafe extern "C" fn sub(vals: *const *const (), num_vals: u32, error: *mut Value) -> *const () {
617 unsafe {
618 let vals: Vec<_> = (0..num_vals)
619 .map(|i| Value::from_raw_inc_rc(vals.add(i as usize).read()))
620 .collect();
621 match num::sub_prim(&vals[0], &vals[1..]) {
622 Ok(num) => Value::into_raw(Value::from(num)),
623 Err(condition) => {
624 error.write(condition.into());
625 Value::into_raw(Value::undefined())
626 }
627 }
628 }
629}
630
631#[runtime_fn]
632unsafe extern "C" fn mul(vals: *const *const (), num_vals: u32, error: *mut Value) -> *const () {
633 unsafe {
634 let vals: Vec<_> = (0..num_vals)
635 .map(|i| Value::from_raw_inc_rc(vals.add(i as usize).read()))
636 .collect();
637 match num::mul_prim(&vals) {
638 Ok(num) => Value::into_raw(Value::from(num)),
639 Err(condition) => {
640 error.write(condition.into());
641 Value::into_raw(Value::undefined())
642 }
643 }
644 }
645}
646
647#[runtime_fn]
648unsafe extern "C" fn div(vals: *const *const (), num_vals: u32, error: *mut Value) -> *const () {
649 unsafe {
650 let vals: Vec<_> = (0..num_vals)
651 .map(|i| Value::from_raw_inc_rc(vals.add(i as usize).read()))
652 .collect();
653 match num::div_prim(&vals[0], &vals[1..]) {
654 Ok(num) => Value::into_raw(Value::from(num)),
655 Err(condition) => {
656 error.write(condition.into());
657 Value::into_raw(Value::undefined())
658 }
659 }
660 }
661}
662
663macro_rules! define_comparison_fn {
664 ( $name:ident, $prim:ident ) => {
665 #[runtime_fn]
666 unsafe extern "C" fn $name(
667 vals: *const *const (),
668 num_vals: u32,
669 error: *mut Value,
670 ) -> *const () {
671 unsafe {
672 let vals: Vec<_> = (0..num_vals)
673 .map(|i| Value::from_raw_inc_rc(vals.add(i as usize).read()))
674 .collect();
675 match num::$prim(&vals) {
676 Ok(res) => Value::into_raw(Value::from(res)),
677 Err(condition) => {
678 error.write(condition.into());
679 Value::into_raw(Value::undefined())
680 }
681 }
682 }
683 }
684 };
685}
686
687define_comparison_fn!(equal, equal_prim);
688define_comparison_fn!(greater, greater_prim);
689define_comparison_fn!(greater_equal, greater_equal_prim);
690define_comparison_fn!(lesser, lesser_prim);
691define_comparison_fn!(lesser_equal, lesser_equal_prim);