1#[cfg(test)]
38mod test;
39
40use std::{
41 cell::RefCell,
42 collections::HashMap,
43 panic::{AssertUnwindSafe, catch_unwind, resume_unwind},
44};
45
46use super::{Builder, trap};
47use crate::common::sized_index::SizedIndex;
48use crate::{
49 naive::Naive,
50 vm::{Any, Array, Function, IVm, ToAny, ToArray},
51};
52
53type A = Naive;
54type V = Any<A>;
55
56pub type Code = fn(self_: i64, args: i64) -> i64;
60
61pub const UNDEFINED: i64 = 0;
63pub const NULL: i64 = 1;
65pub const FALSE: i64 = 2;
67pub const TRUE: i64 = 3;
69
70const CONSTANTS: usize = 4;
71
72const MEMORY: usize = 0x1_0000;
74
75#[derive(Debug)]
78pub struct Thrown;
79
80struct Slab<T> {
85 slots: Vec<(u32, Option<T>)>,
86 born: Vec<u64>,
89 free: Vec<usize>,
90 bits: u32,
91 generations: u32,
92}
93
94impl<T> Slab<T> {
95 fn new(bits: u32, generation_bits: u32) -> Self {
96 Slab {
97 slots: Vec::new(),
98 born: Vec::new(),
99 free: Vec::new(),
100 bits,
101 generations: u32::MAX >> (32 - generation_bits),
102 }
103 }
104
105 fn find(&self, h: u64) -> Option<usize> {
107 let i = (h & ((1 << self.bits) - 1)) as usize;
108 let generation = u32::try_from(h >> self.bits).ok()?;
109 match self.slots.get(i) {
110 Some((g, Some(_))) if *g == generation => Some(i),
111 _ => None,
112 }
113 }
114
115 fn get(&self, h: u64) -> Option<&T> {
116 self.find(h).and_then(|i| self.slots[i].1.as_ref())
117 }
118
119 fn get_mut(&mut self, h: u64) -> Option<&mut T> {
120 self.find(h).and_then(|i| self.slots[i].1.as_mut())
121 }
122
123 fn take(&mut self, h: u64) -> Option<T> {
124 let i = self.find(h)?;
125 let (generation, v) = &mut self.slots[i];
126 if *generation < self.generations {
129 *generation += 1;
130 self.free.push(i);
131 }
132 v.take()
133 }
134
135 fn put(&mut self, name: &str, birth: u64, v: T) -> u64 {
136 let i = match self.free.pop() {
137 Some(i) => i,
138 None => {
139 if (self.slots.len() as u64) >> self.bits != 0 {
140 trap(name, "too many handles")
141 }
142 self.slots.push((0, None));
143 self.born.push(0);
144 self.slots.len() - 1
145 }
146 };
147 self.slots[i].1 = Some(v);
148 self.born[i] = birth;
149 (u64::from(self.slots[i].0) << self.bits) | i as u64
150 }
151
152 fn free_born(&mut self, births: core::ops::RangeInclusive<u64>) {
154 for i in 0..self.slots.len() {
155 if births.contains(&self.born[i]) {
156 let h = (u64::from(self.slots[i].0) << self.bits) | i as u64;
157 self.take(h);
158 }
159 }
160 }
161
162 fn count(&self) -> usize {
163 self.slots.iter().filter(|(_, v)| v.is_some()).count()
164 }
165}
166
167struct State {
168 values: Slab<V>,
169 builders: Slab<Builder<A>>,
170 memory: Vec<u8>,
171 table: Vec<Code>,
172 texts: HashMap<Vec<u16>, &'static str>,
173 births: u64,
176 marks: Vec<u64>,
179 thrown: Option<(V, u64)>,
181}
182
183impl State {
184 fn birth(&mut self) -> u64 {
185 self.births += 1;
186 self.births
187 }
188}
189
190impl State {
191 fn new() -> Self {
192 let mut values = Slab::new(32, 32);
195 for v in [
196 super::undefined(),
197 super::null(),
198 super::from_bool(false),
199 super::from_bool(true),
200 ] {
201 values.put("constant", 0, v);
202 }
203 State {
204 values,
205 builders: Slab::new(16, 15),
206 memory: core::iter::repeat_n(0, MEMORY).collect(),
207 table: Vec::new(),
208 texts: HashMap::new(),
209 births: 0,
210 marks: Vec::new(),
211 thrown: None,
212 }
213 }
214}
215
216thread_local! {
217 static STATE: RefCell<State> = RefCell::new(State::new());
218}
219
220fn with<R>(f: impl FnOnce(&mut State) -> R) -> R {
221 STATE.with_borrow_mut(f)
222}
223
224fn is_constant(h: i64) -> bool {
228 (0..CONSTANTS as i64).contains(&h)
229}
230
231fn get(name: &str, h: i64) -> V {
233 with(|s| s.values.get(h as u64).cloned()).unwrap_or_else(|| trap(name, "not a value"))
234}
235
236fn take(name: &str, h: i64) -> V {
238 if is_constant(h) {
239 return get(name, h);
240 }
241 with(|s| s.values.take(h as u64)).unwrap_or_else(|| trap(name, "not a value"))
242}
243
244fn put(v: V) -> i64 {
247 match super::kind(&v) {
248 super::Kind::Undefined => return UNDEFINED,
249 super::Kind::Null => return NULL,
250 super::Kind::Boolean => return from_bool(super::to_bool(&v) as i32),
251 _ => {}
252 }
253 with(|s| {
254 let birth = s.birth();
255 s.values.put("put", birth, v)
256 }) as i64
257}
258
259fn take_builder(name: &str, b: i32) -> Builder<A> {
260 with(|s| s.builders.take(b as u32 as u64)).unwrap_or_else(|| trap(name, "not a builder"))
261}
262
263fn put_builder(name: &str, b: Builder<A>) -> i32 {
264 with(|s| {
265 let birth = s.birth();
266 s.builders.put(name, birth, b)
267 }) as i32
268}
269
270fn on_builder(name: &str, b: i32, f: impl FnOnce(&mut Builder<A>)) {
272 with(|s| {
273 let builder = s
274 .builders
275 .get_mut(b as u32 as u64)
276 .unwrap_or_else(|| trap(name, "not a builder"));
277 f(builder)
278 })
279}
280
281fn count(name: &str, n: i32) -> u32 {
283 u32::try_from(n).unwrap_or_else(|_| trap(name, "not a count"))
284}
285
286pub fn with_memory<R>(f: impl FnOnce(&mut Vec<u8>) -> R) -> R {
290 with(|s| f(&mut s.memory))
291}
292
293fn bytes(name: &str, ptr: i32, len: i32, size: usize) -> core::ops::Range<usize> {
294 let start = ptr as u32 as usize;
295 let n = (len as u32 as usize).checked_mul(size);
296 match n.and_then(|n| start.checked_add(n)) {
297 Some(end) if end <= with(|s| s.memory.len()) => start..end,
298 _ => trap(name, "out of bounds"),
299 }
300}
301
302fn load_units(name: &str, ptr: i32, len: i32) -> Vec<u16> {
303 let r = bytes(name, ptr, len, 2);
304 with(|s| {
305 s.memory[r]
306 .as_chunks::<2>()
307 .0
308 .iter()
309 .map(|&c| u16::from_le_bytes(c))
310 .collect()
311 })
312}
313
314fn load_words(name: &str, ptr: i32, len: i32) -> Vec<u64> {
315 let r = bytes(name, ptr, len, 8);
316 with(|s| {
317 s.memory[r]
318 .as_chunks::<8>()
319 .0
320 .iter()
321 .map(|&c| u64::from_le_bytes(c))
322 .collect()
323 })
324}
325
326fn store(name: &str, ptr: i32, len: i32, size: usize, data: &[u8]) {
327 let r = bytes(name, ptr, len, size);
328 with(|s| s.memory[r].copy_from_slice(data))
329}
330
331pub fn kind(v: i64) -> i32 {
335 super::kind(&get("kind", v)) as i32
336}
337
338pub fn to_f64(v: i64) -> f64 {
340 super::to_f64(&get("to_f64", v))
341}
342
343pub fn from_f64(x: f64) -> i64 {
345 put(super::from_f64(x))
346}
347
348pub fn to_bool(v: i64) -> i32 {
350 super::to_bool(&get("to_bool", v)) as i32
351}
352
353pub fn from_bool(b: i32) -> i64 {
355 if b == 0 { FALSE } else { TRUE }
356}
357
358pub fn make_string(ptr: i32, len: i32) -> i64 {
362 put(super::make_string(&load_units("make_string", ptr, len)))
363}
364
365pub fn read_units(s: i64, start: i32, len: i32, ptr: i32) {
367 bytes("read_units", ptr, len, 2);
368 let mut out: Vec<u16> = core::iter::repeat_n(0, len as u32 as usize).collect();
369 super::read_units(&get("read_units", s), start as u32, &mut out);
370 let data: Vec<u8> = out.iter().flat_map(|u| u.to_le_bytes()).collect();
371 store("read_units", ptr, len, 2, &data);
372}
373
374pub fn make_bigint(sign: i32, ptr: i32, len: i32) -> i64 {
376 put(super::make_bigint(
377 sign,
378 &load_words("make_bigint", ptr, len),
379 ))
380}
381
382pub fn sign(b: i64) -> i32 {
384 super::sign(&get("sign", b))
385}
386
387pub fn read_words(b: i64, start: i32, len: i32, ptr: i32) {
390 bytes("read_words", ptr, len, 8);
391 let mut out: Vec<u64> = core::iter::repeat_n(0, len as u32 as usize).collect();
392 super::read_words(&get("read_words", b), start as u32, &mut out);
393 let data: Vec<u8> = out.iter().flat_map(|w| w.to_le_bytes()).collect();
394 store("read_words", ptr, len, 8, &data);
395}
396
397pub fn unit(s: i64, i: i32) -> i32 {
401 super::unit(&get("unit", s), i as u32).into()
402}
403
404pub fn from_unit(u: i32) -> i64 {
406 let u = u16::try_from(u).unwrap_or_else(|_| trap("from_unit", "not a unit"));
407 put(super::from_unit(u))
408}
409
410pub fn concat(a: i64, b: i64) -> i64 {
412 put(super::concat(&get("concat", a), &get("concat", b)))
413}
414
415pub fn substring(s: i64, start: i32, end: i32) -> i64 {
417 put(super::substring(
418 &get("substring", s),
419 start as u32,
420 end as u32,
421 ))
422}
423
424pub fn join(parts: i64, separator: i64) -> i64 {
426 put(super::join(&get("join", parts), &get("join", separator)))
427}
428
429pub fn begin_array(len: i32) -> i32 {
433 put_builder("begin_array", super::begin_array(count("begin_array", len)))
434}
435
436pub fn begin_object(len: i32) -> i32 {
438 put_builder(
439 "begin_object",
440 super::begin_object(count("begin_object", len)),
441 )
442}
443
444pub fn push(b: i32, v: i64) {
446 let v = take("push", v);
447 on_builder("push", b, |b| b.push(v))
448}
449
450pub fn push_property(b: i32, key: i64, v: i64) {
452 let key = take("push_property", key);
453 let v = take("push_property", v);
454 on_builder("push_property", b, |b| b.push_property(key, v))
455}
456
457pub fn seal(b: i32) -> i64 {
459 put(take_builder("seal", b).seal())
460}
461
462pub fn length(v: i64) -> i32 {
464 super::length(&get("length", v)) as i32
465}
466
467pub fn item(v: i64, i: i32) -> i64 {
469 put(super::item(&get("item", v), i as u32))
470}
471
472pub fn key(o: i64, i: i32) -> i64 {
474 put(super::key(&get("key", o), i as u32))
475}
476
477pub fn find(o: i64, key: i64) -> i32 {
479 super::find(&get("find", o), &get("find", key))
480}
481
482pub fn dup(v: i64) -> i64 {
486 let x = get("dup", v);
487 if is_constant(v) { v } else { put(x) }
488}
489
490pub fn drop(v: i64) {
492 take("drop", v);
493}
494
495pub fn add_code(code: Code) -> i32 {
499 with(|s| {
500 s.table.push(code);
501 (s.table.len() - 1) as i32
502 })
503}
504
505fn run(self_: &<A as IVm>::InternalFunction, args: Array<A>) -> Result<V, V> {
508 let index = super::to_f64(&A::frame(self_)[0]) as usize;
509 let code = with(|s| s.table[index]);
510 let handles = Handles([
511 put(Function::<A>::new(self_.clone()).to_any()),
512 put(args.to_any()),
513 ]);
514 Ok(take("call", code(handles.0[0], handles.0[1])))
515}
516
517struct Handles([i64; 2]);
519
520impl Drop for Handles {
521 fn drop(&mut self) {
522 for h in self.0 {
523 take("call", h);
524 }
525 }
526}
527
528fn intern(text: &V) -> &'static str {
531 let mut units: Vec<u16> = core::iter::repeat_n(0, super::length(text) as usize).collect();
532 super::read_units(text, 0, &mut units);
533 if let Some(t) = with(|s| s.texts.get(&units).copied()) {
534 return t;
535 }
536 let t: &'static str = std::string::String::from_utf16_lossy(&units).leak();
537 with(|s| s.texts.insert(units, t));
538 t
539}
540
541pub fn make_function(code: i32, frame: i64, length: i32, text: i64) -> i64 {
544 if !with(|s| usize::try_from(code).is_ok_and(|i| i < s.table.len())) {
545 trap("make_function", "not a code index")
546 }
547 let length = count("make_function", length);
548 let frame = take("make_function", frame);
549 let text = take("make_function", text);
550 let text = match super::kind(&text) {
551 super::Kind::Undefined => None,
552 super::Kind::String => Some(intern(&text)),
553 _ => trap("make_function", "not a string"),
554 };
555 let frame = super::as_array("make_function", &frame);
556 let items: Vec<V> = core::iter::once(super::from_f64(code as f64))
557 .chain(frame.index_iter())
558 .collect();
559 put(A::static_function(run, length, items.to_array(), text).to_any())
560}
561
562pub fn call(f: i64, args: i64) -> i64 {
565 let f = get("call", f);
566 let args = get("call", args);
567 match super::call(&f, &args) {
568 Ok(v) => put(v),
569 Err(e) => throw(put(e)),
570 }
571}
572
573pub fn frame(self_: i64, i: i32) -> i64 {
576 let f = super::as_function("frame", &get("frame", self_));
577 let frame = A::frame(f.internal());
578 let n = frame.length().saturating_sub(1);
579 put(frame[super::index("frame", i as u32, n) + 1].clone())
580}
581
582pub fn text(f: i64) -> i64 {
584 put(super::text(&get("text", f)))
585}
586
587pub fn throw(v: i64) -> ! {
589 let v = take("throw", v);
590 with(|s| s.thrown = Some((v, s.births)));
591 #[cfg(all(target_arch = "wasm32", panic = "abort"))]
592 core::arch::wasm32::unreachable();
593 #[cfg(not(all(target_arch = "wasm32", panic = "abort")))]
594 std::panic::panic_any(Thrown)
595}
596
597pub fn same(a: i64, b: i64) -> i32 {
601 super::same(&get("same", a), &get("same", b)) as i32
602}
603
604pub fn has_thrown() -> i32 {
609 with(|s| s.thrown.is_some()) as i32
610}
611
612pub fn thrown() -> i64 {
614 with(|s| s.thrown.as_ref().map(|(v, _)| v.clone())).map_or(UNDEFINED, put)
615}
616
617pub fn enter() {
620 with(|s| s.marks.push(s.births))
621}
622
623pub fn leave() {
625 with(|s| s.marks.pop());
626}
627
628pub fn recover() {
635 with(|s| {
636 let mark = s.marks.pop();
637 if let (Some(mark), Some((_, at))) = (mark, &s.thrown) {
638 let births = mark + 1..=*at;
639 s.values.free_born(births.clone());
640 s.builders.free_born(births);
641 }
642 s.thrown = None;
643 })
644}
645
646pub fn catch(f: impl FnOnce() -> i64) -> Result<i64, i64> {
651 enter();
652 match catch_unwind(AssertUnwindSafe(f)) {
653 Ok(v) => {
654 leave();
655 Ok(v)
656 }
657 Err(payload) => {
658 if has_thrown() == 0 {
659 resume_unwind(payload)
660 }
661 let e = thrown();
662 recover();
663 Err(e)
664 }
665 }
666}
667
668pub fn live() -> usize {
671 with(|s| s.values.count() - CONSTANTS)
672}