1use std::mem::ManuallyDrop;
2use std::rc::Rc;
3
4#[cfg(feature = "tracing")]
5use tracing::instrument;
6use tycho_types::error::Error;
7use tycho_types::prelude::*;
8
9use crate::error::VmResult;
10use crate::saferc::{SafeDelete, SafeRc, SafeRcMakeMut};
11use crate::stack::{
12 RcStackValue, Stack, StackValue, StackValueType, Tuple, TupleExt, load_slice_as_stack_value,
13 store_slice_as_stack_value,
14};
15use crate::state::VmState;
16use crate::util::{OwnedCellSlice, Uint4, ensure_empty_slice};
17
18#[derive(Debug, Default, Clone)]
20pub struct ControlData {
21 pub nargs: Option<u16>,
22 pub stack: Option<SafeRc<Stack>>,
23 pub save: ControlRegs,
24 pub cp: Option<u16>,
25}
26
27impl ControlData {
28 pub fn require_nargs(&self, copy: usize) -> VmResult<()> {
29 if matches!(self.nargs, Some(nargs) if (nargs as usize) < copy) {
30 vm_bail!(StackUnderflow(copy as _))
31 }
32 Ok(())
33 }
34}
35
36impl Store for ControlData {
37 fn store_into(
38 &self,
39 builder: &mut CellBuilder,
40 context: &dyn CellContext,
41 ) -> Result<(), Error> {
42 match self.nargs {
43 None => ok!(builder.store_bit_zero()),
44 Some(nargs) if nargs <= 0x1fff => {
45 ok!(builder.store_bit_one());
46 ok!(builder.store_uint(nargs as _, 13));
47 }
48 Some(_) => return Err(Error::IntOverflow),
49 }
50
51 ok!(self.stack.as_deref().store_into(builder, context));
52 ok!(self.save.store_into(builder, context));
53 ok!(self.cp.store_into(builder, context));
54 Ok(())
55 }
56}
57
58impl Load<'_> for ControlData {
59 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
60 Ok(ControlData {
61 nargs: match ok!(slice.load_bit()) {
62 false => None,
63 true => Some(ok!(slice.load_uint(13)) as u16),
64 },
65 stack: match ok!(slice.load_bit()) {
66 false => None,
67 true => Some(ok!(SafeRc::<Stack>::load_from(slice))),
68 },
69 save: ok!(ControlRegs::load_from(slice)),
70 cp: ok!(Load::load_from(slice)),
71 })
72 }
73}
74
75#[derive(Default, Debug, Clone)]
77pub struct ControlRegs {
78 pub c: [Option<RcCont>; 4],
79 pub d: [Option<Cell>; 2],
80 pub c7: Option<SafeRc<Tuple>>,
81}
82
83impl ControlRegs {
84 const CONT_REG_COUNT: usize = 4;
85 const DATA_REG_OFFSET: usize = Self::CONT_REG_COUNT;
86 const DATA_REG_COUNT: usize = 2;
87 const DATA_REG_RANGE: std::ops::Range<usize> =
88 Self::DATA_REG_OFFSET..Self::DATA_REG_OFFSET + Self::DATA_REG_COUNT;
89
90 pub fn is_valid_idx(i: usize) -> bool {
91 i < Self::CONT_REG_COUNT || Self::DATA_REG_RANGE.contains(&i) || i == 7
92 }
93
94 pub fn merge(&mut self, other: &ControlRegs) {
95 for (c, other_c) in std::iter::zip(&mut self.c, &other.c) {
96 Self::merge_stack_value(c, other_c);
97 }
98 for (d, other_d) in std::iter::zip(&mut self.d, &other.d) {
99 Self::merge_cell_value(d, other_d)
100 }
101 Self::merge_stack_value(&mut self.c7, &other.c7)
102 }
103
104 pub fn preclear(&mut self, other: &ControlRegs) {
105 for (c, other_c) in std::iter::zip(&mut self.c, &other.c) {
106 if other_c.is_some() {
107 *c = None;
108 }
109 }
110 for (d, other_d) in std::iter::zip(&mut self.d, &other.d) {
111 if other_d.is_some() {
112 *d = None;
113 }
114 }
115 if other.c7.is_some() {
116 self.c7 = None;
117 }
118 }
119
120 pub fn set(&mut self, i: usize, value: RcStackValue) -> VmResult<()> {
122 if i < Self::CONT_REG_COUNT {
123 self.c[i] = Some(ok!(value.into_cont()));
124 } else if Self::DATA_REG_RANGE.contains(&i) {
125 let cell = ok!(value.into_cell());
126 self.d[i - Self::DATA_REG_OFFSET] = Some(SafeRc::unwrap_or_clone(cell));
127 } else if i == 7 {
128 self.c7 = Some(ok!(value.into_tuple()));
129 } else {
130 vm_bail!(ControlRegisterOutOfRange(i))
131 }
132 Ok(())
133 }
134
135 pub fn set_c(&mut self, i: usize, cont: RcCont) -> bool {
136 if i < Self::CONT_REG_COUNT {
137 self.c[i] = Some(cont);
138 true
139 } else {
140 false
141 }
142 }
143
144 pub fn set_d(&mut self, mut i: usize, cell: Cell) -> bool {
145 i = i.wrapping_sub(Self::DATA_REG_OFFSET);
146 if i < Self::DATA_REG_COUNT {
147 self.d[i] = Some(cell);
148 true
149 } else {
150 false
151 }
152 }
153
154 pub fn get_d(&self, mut i: usize) -> Option<Cell> {
155 i = i.wrapping_sub(Self::DATA_REG_OFFSET);
156 if i < Self::DATA_REG_COUNT {
157 self.d[i].clone()
158 } else {
159 None
160 }
161 }
162
163 pub fn set_c7(&mut self, tuple: SafeRc<Tuple>) {
164 self.c7 = Some(tuple);
165 }
166
167 pub fn get_as_stack_value(&self, i: usize) -> Option<RcStackValue> {
168 if i < Self::CONT_REG_COUNT {
169 self.c.get(i)?.clone().map(SafeRc::into_dyn_value)
170 } else if Self::DATA_REG_RANGE.contains(&i) {
171 self.d[i - Self::DATA_REG_OFFSET]
172 .clone()
173 .map(SafeRc::new_dyn_value)
174 } else if i == 7 {
175 self.c7.clone().map(SafeRc::into_dyn_value)
176 } else {
177 None
178 }
179 }
180
181 pub fn define_c0(&mut self, cont: &Option<RcCont>) {
182 if self.c[0].is_none() {
183 self.c[0].clone_from(cont)
184 }
185 }
186
187 pub fn define_c1(&mut self, cont: &Option<RcCont>) {
188 if self.c[1].is_none() {
189 self.c[1].clone_from(cont)
190 }
191 }
192
193 pub fn define_c2(&mut self, cont: &Option<RcCont>) {
194 if self.c[2].is_none() {
195 self.c[2].clone_from(cont)
196 }
197 }
198
199 pub fn define(&mut self, i: usize, value: RcStackValue) -> VmResult<()> {
200 if i < Self::CONT_REG_COUNT {
201 let cont = ok!(value.into_cont());
202 vm_ensure!(self.c[i].is_none(), ControlRegisterRedefined);
203 self.c[i] = Some(cont);
204 } else if Self::DATA_REG_RANGE.contains(&i) {
205 let cell = ok!(value.into_cell());
206 let d = &mut self.d[i - Self::DATA_REG_OFFSET];
207 vm_ensure!(d.is_none(), ControlRegisterRedefined);
208 *d = Some(SafeRc::unwrap_or_clone(cell));
209 } else if i == 7 {
210 let tuple = ok!(value.into_tuple());
211
212 if self.c7.is_none() {
214 self.c7 = Some(tuple);
215 }
216 } else {
217 vm_bail!(ControlRegisterOutOfRange(i))
218 }
219 Ok(())
220 }
221
222 pub fn get_c7_params(&self) -> VmResult<&[RcStackValue]> {
223 let Some(c7) = self.c7.as_ref() else {
224 vm_bail!(ControlRegisterOutOfRange(7))
225 };
226
227 c7.try_get_tuple_range(0, 0..=255)
228 }
229
230 fn merge_cell_value(lhs: &mut Option<Cell>, rhs: &Option<Cell>) {
231 if let Some(rhs) = rhs {
232 if let Some(lhs) = lhs {
233 let lhs = lhs.as_ref() as *const _ as *const ();
234 let rhs = rhs.as_ref() as *const _ as *const ();
235 if std::ptr::eq(lhs, rhs) {
236 return;
237 }
238 }
239 *lhs = Some(rhs.clone())
240 }
241 }
242
243 fn merge_stack_value<T: SafeDelete + ?Sized>(
244 lhs: &mut Option<SafeRc<T>>,
245 rhs: &Option<SafeRc<T>>,
246 ) {
247 if let Some(rhs) = rhs {
248 if let Some(lhs) = lhs
249 && SafeRc::ptr_eq(lhs, rhs)
250 {
251 return;
252 }
253 *lhs = Some(rhs.clone())
254 }
255 }
256}
257
258impl Store for ControlRegs {
259 fn store_into(
260 &self,
261 builder: &mut CellBuilder,
262 context: &dyn CellContext,
263 ) -> Result<(), Error> {
264 #[repr(transparent)]
265 struct AsDictValue<'a>(&'a dyn StackValue);
266
267 impl Store for AsDictValue<'_> {
268 #[inline]
269 fn store_into(
270 &self,
271 builder: &mut CellBuilder,
272 context: &dyn CellContext,
273 ) -> Result<(), Error> {
274 self.0.store_as_stack_value(builder, context)
275 }
276 }
277
278 let mut dict = Dict::<Uint4, AsDictValue>::new();
281
282 for (i, c) in self.c.iter().enumerate() {
283 if let Some(c) = c {
284 ok!(dict.set_ext(Uint4(i), AsDictValue(c.as_stack_value()), context));
285 }
286 }
287 for (i, d) in self.d.iter().enumerate() {
288 if let Some(d) = d {
289 ok!(dict.set_ext(Uint4(i + Self::DATA_REG_OFFSET), AsDictValue(d), context));
290 }
291 }
292 if let Some(c7) = &self.c7 {
293 ok!(dict.set_ext(Uint4(7), AsDictValue(c7.as_ref()), context));
294 }
295
296 dict.store_into(builder, context)
297 }
298}
299
300impl Load<'_> for ControlRegs {
301 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
302 let dict = ok!(Dict::<Uint4, CellSlice<'_>>::load_from(slice));
303
304 let mut result = ControlRegs::default();
305 for entry in dict.iter() {
306 let (key, ref mut slice) = ok!(entry);
307 let value = ok!(Stack::load_stack_value(slice));
308 ok!(ensure_empty_slice(slice));
309 if result.set(key.0, value).is_err() {
310 return Err(Error::InvalidData);
311 }
312 }
313
314 Ok(result)
315 }
316}
317
318pub trait Cont: Store + SafeDelete + dyn_clone::DynClone + std::fmt::Debug {
320 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue>;
321
322 fn as_stack_value(&self) -> &dyn StackValue;
323
324 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
325
326 fn jump(self: Rc<Self>, state: &mut VmState, exit_code: &mut i32) -> VmResult<Option<RcCont>>;
327
328 fn get_control_data(&self) -> Option<&ControlData> {
329 None
330 }
331
332 fn get_control_data_mut(&mut self) -> Option<&mut ControlData> {
333 None
334 }
335}
336
337impl<T: Cont + 'static> StackValue for T {
338 #[inline]
339 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
340 self
341 }
342
343 fn raw_ty(&self) -> u8 {
344 StackValueType::Cont as _
345 }
346
347 fn store_as_stack_value(
348 &self,
349 builder: &mut CellBuilder,
350 context: &dyn CellContext,
351 ) -> Result<(), Error> {
352 ok!(builder.store_u8(0x06));
353 self.store_into(builder, context)
354 }
355
356 fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357 ok!(f.write_str("Cont{{"));
358 ok!(<T as Cont>::fmt(self, f));
359 f.write_str("}}")
360 }
361
362 fn as_cont(&self) -> Option<&dyn Cont> {
363 Some(self)
364 }
365
366 fn rc_into_cont(self: Rc<Self>) -> VmResult<Rc<dyn Cont>> {
367 Ok(self)
368 }
369}
370
371pub type RcCont = SafeRc<dyn Cont>;
373
374impl<'a> Load<'a> for RcCont {
375 #[inline]
376 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
377 load_cont(slice)
378 }
379}
380
381impl dyn Cont {
382 pub fn has_c0(&self) -> bool {
383 if let Some(control) = self.get_control_data() {
384 control.save.c[0].is_some()
385 } else {
386 false
387 }
388 }
389}
390
391impl SafeRcMakeMut for dyn Cont {
392 #[inline]
393 fn rc_make_mut(rc: &mut Rc<Self>) -> &mut Self {
394 dyn_clone::rc_make_mut(rc)
395 }
396}
397
398impl<T: Cont + 'static> SafeRc<T> {
399 #[inline]
400 pub fn into_dyn_cont(self) -> RcCont {
401 let value = SafeRc::into_inner(self);
402 SafeRc(ManuallyDrop::new(value))
403 }
404}
405
406impl<T: Cont + 'static> From<T> for RcCont {
407 #[inline]
408 fn from(value: T) -> Self {
409 Self(ManuallyDrop::new(Rc::new(value)))
410 }
411}
412
413impl<T: Cont + 'static> From<Rc<T>> for RcCont {
414 #[inline]
415 fn from(value: Rc<T>) -> Self {
416 Self(ManuallyDrop::new(value))
417 }
418}
419
420pub(crate) fn load_cont(slice: &mut CellSlice) -> Result<RcCont, Error> {
421 #[allow(clippy::unusual_byte_groupings)]
422 const MASK: u64 = 0x1_007_01_1_1_0001_0001;
423
424 let slice_bits = slice.size_bits();
426 let n = if slice_bits < 6 {
427 ok!(slice.get_small_uint(0, slice_bits)) << (6 - slice_bits)
428 } else {
429 ok!(slice.get_small_uint(0, 6))
430 };
431
432 let n = (MASK & (2u64 << n).wrapping_sub(1)).count_ones() - 1;
434
435 Ok(match n {
437 0 => SafeRc::from(ok!(OrdCont::load_from(slice))),
439 1 => SafeRc::from(ok!(ArgContExt::load_from(slice))),
441 2 => SafeRc::from(ok!(QuitCont::load_from(slice))),
443 3 => SafeRc::from(ok!(ExcQuitCont::load_from(slice))),
445 4 => SafeRc::from(ok!(RepeatCont::load_from(slice))),
447 5 => SafeRc::from(ok!(UntilCont::load_from(slice))),
449 6 => SafeRc::from(ok!(AgainCont::load_from(slice))),
451 7 => SafeRc::from(ok!(WhileCont::load_from(slice))),
453 8 => SafeRc::from(ok!(PushIntCont::load_from(slice))),
455 _ => return Err(Error::InvalidTag),
457 })
458}
459
460#[derive(Debug, Copy, Clone)]
462pub struct QuitCont {
463 pub exit_code: i32,
464}
465
466impl QuitCont {
467 const TAG: u8 = 0b1000;
468}
469
470impl Cont for QuitCont {
471 #[inline]
472 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
473 self
474 }
475
476 fn as_stack_value(&self) -> &dyn StackValue {
477 self
478 }
479
480 #[inline]
481 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
482 f.write_str("vmc_quit")
483 }
484
485 #[cfg_attr(
486 feature = "tracing",
487 instrument(level = "trace", name = "quit_cont", skip_all)
488 )]
489 fn jump(self: Rc<Self>, _: &mut VmState, exit_code: &mut i32) -> VmResult<Option<RcCont>> {
490 *exit_code = !self.exit_code;
491 Ok(None)
492 }
493}
494
495impl Store for QuitCont {
496 fn store_into(&self, builder: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
497 ok!(builder.store_small_uint(Self::TAG, 4));
498 builder.store_u32(self.exit_code as u32)
499 }
500}
501
502impl Load<'_> for QuitCont {
503 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
504 if ok!(slice.load_small_uint(4)) != Self::TAG {
505 return Err(Error::InvalidTag);
506 }
507
508 Ok(Self {
509 exit_code: ok!(slice.load_u32()) as i32,
510 })
511 }
512}
513
514#[derive(Debug, Copy, Clone)]
516pub struct ExcQuitCont;
517
518impl ExcQuitCont {
519 const TAG: u8 = 0b1001;
520}
521
522impl Cont for ExcQuitCont {
523 #[inline]
524 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
525 self
526 }
527
528 fn as_stack_value(&self) -> &dyn StackValue {
529 self
530 }
531
532 #[inline]
533 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
534 f.write_str("vmc_quit_exc")
535 }
536
537 #[cfg_attr(
538 feature = "tracing",
539 instrument(level = "trace", name = "exc_quit_cont", skip_all)
540 )]
541 fn jump(self: Rc<Self>, state: &mut VmState, exit_code: &mut i32) -> VmResult<Option<RcCont>> {
542 let n = SafeRc::make_mut(&mut state.stack)
543 .pop_smallint_range(0, 0xffff)
544 .unwrap_or_else(|e| e.as_exception() as u32);
545 vm_log_trace!("terminating vm in the default exception handler: n={n}");
546 *exit_code = !(n as i32);
547 Ok(None)
548 }
549}
550
551impl Store for ExcQuitCont {
552 fn store_into(&self, builder: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
553 builder.store_small_uint(Self::TAG, 4)
554 }
555}
556
557impl Load<'_> for ExcQuitCont {
558 #[inline]
559 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
560 if ok!(slice.load_small_uint(4)) == Self::TAG {
561 Ok(Self)
562 } else {
563 Err(Error::InvalidTag)
564 }
565 }
566}
567
568#[derive(Debug, Clone)]
570pub struct PushIntCont {
571 pub value: i32,
572 pub next: RcCont,
573}
574
575impl PushIntCont {
576 const TAG: u8 = 0b1111;
577}
578
579impl Cont for PushIntCont {
580 #[inline]
581 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
582 self
583 }
584
585 fn as_stack_value(&self) -> &dyn StackValue {
586 self
587 }
588
589 #[inline]
590 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
591 f.write_str("vmc_pushint")
592 }
593
594 #[cfg_attr(
595 feature = "tracing",
596 instrument(
597 level = "trace",
598 name = "push_int_cont",
599 fields(value = self.value),
600 skip_all,
601 )
602 )]
603 fn jump(self: Rc<Self>, state: &mut VmState, _: &mut i32) -> VmResult<Option<RcCont>> {
604 ok!(SafeRc::make_mut(&mut state.stack).push_int(self.value));
605 Ok(Some(match Rc::try_unwrap(self) {
606 Ok(this) => this.next,
607 Err(this) => this.next.clone(),
608 }))
609 }
610}
611
612impl Store for PushIntCont {
613 fn store_into(
614 &self,
615 builder: &mut CellBuilder,
616 context: &dyn CellContext,
617 ) -> Result<(), Error> {
618 ok!(builder.store_small_uint(Self::TAG, 4));
619 ok!(builder.store_u32(self.value as u32));
620 builder.store_reference(ok!(CellBuilder::build_from_ext(&*self.next, context)))
621 }
622}
623
624impl Load<'_> for PushIntCont {
625 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
626 if ok!(slice.load_small_uint(4)) != Self::TAG {
627 return Err(Error::InvalidTag);
628 }
629
630 Ok(Self {
631 value: ok!(slice.load_u32()) as i32,
632 next: ok!(load_cont(slice)),
633 })
634 }
635}
636
637#[derive(Debug, Clone)]
640pub struct RepeatCont {
641 pub count: u64,
642 pub body: RcCont,
643 pub after: RcCont,
644}
645
646impl RepeatCont {
647 const TAG: u8 = 0b1010;
648 const MAX_COUNT: u64 = 0x8000000000000000;
649}
650
651impl Cont for RepeatCont {
652 #[inline]
653 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
654 self
655 }
656
657 fn as_stack_value(&self) -> &dyn StackValue {
658 self
659 }
660
661 #[inline]
662 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
663 f.write_str("vmc_repeat")
664 }
665
666 #[cfg_attr(
667 feature = "tracing",
668 instrument(
669 level = "trace",
670 name = "repeat_cont",
671 fields(value = self.count),
672 skip_all,
673 )
674 )]
675 fn jump(mut self: Rc<Self>, state: &mut VmState, _: &mut i32) -> VmResult<Option<RcCont>> {
676 if self.count == 0 {
677 return Ok(Some(self.after.clone()));
678 }
679 if self.body.has_c0() {
680 return Ok(Some(self.body.clone()));
681 }
682
683 let body = self.body.clone();
684 match Rc::get_mut(&mut self) {
685 Some(this) => {
686 this.count -= 1;
687 state.set_c0(RcCont::from(self))
688 }
689 None => state.set_c0(SafeRc::from(RepeatCont {
690 count: self.count - 1,
691 body: self.body.clone(),
692 after: self.after.clone(),
693 })),
694 }
695
696 Ok(Some(body))
697 }
698}
699
700impl Store for RepeatCont {
701 fn store_into(
702 &self,
703 builder: &mut CellBuilder,
704 context: &dyn CellContext,
705 ) -> Result<(), Error> {
706 if self.count >= Self::MAX_COUNT {
707 return Err(Error::IntOverflow);
708 }
709 ok!(builder.store_small_uint(Self::TAG, 4));
710 ok!(builder.store_u64(self.count));
711 ok!(builder.store_reference(ok!(CellBuilder::build_from_ext(&*self.body, context))));
712 builder.store_reference(ok!(CellBuilder::build_from_ext(&*self.after, context)))
713 }
714}
715
716impl Load<'_> for RepeatCont {
717 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
718 if ok!(slice.load_small_uint(4)) != Self::TAG {
719 return Err(Error::InvalidTag);
720 }
721
722 Ok(Self {
723 count: ok!(slice.load_u64()),
724 body: ok!(load_cont(slice)),
725 after: ok!(load_cont(slice)),
726 })
727 }
728}
729
730#[derive(Debug, Clone)]
735pub struct AgainCont {
736 pub body: RcCont,
737}
738
739impl AgainCont {
740 const TAG: u8 = 0b110001;
741}
742
743impl Cont for AgainCont {
744 #[inline]
745 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
746 self
747 }
748
749 fn as_stack_value(&self) -> &dyn StackValue {
750 self
751 }
752
753 #[inline]
754 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
755 f.write_str("vmc_again")
756 }
757
758 #[cfg_attr(
759 feature = "tracing",
760 instrument(level = "trace", name = "again_cont", skip_all)
761 )]
762 fn jump(self: Rc<Self>, state: &mut VmState, _: &mut i32) -> VmResult<Option<RcCont>> {
763 if !self.body.has_c0() {
764 state.set_c0(SafeRc::from(self.clone()))
765 }
766 Ok(Some(self.body.clone()))
767 }
768}
769
770impl Store for AgainCont {
771 fn store_into(
772 &self,
773 builder: &mut CellBuilder,
774 context: &dyn CellContext,
775 ) -> Result<(), Error> {
776 ok!(builder.store_small_uint(Self::TAG, 6));
777 builder.store_reference(ok!(CellBuilder::build_from_ext(&*self.body, context)))
778 }
779}
780
781impl Load<'_> for AgainCont {
782 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
783 if ok!(slice.load_small_uint(6)) != Self::TAG {
784 return Err(Error::InvalidTag);
785 }
786
787 Ok(Self {
788 body: ok!(load_cont(slice)),
789 })
790 }
791}
792
793#[derive(Debug, Clone)]
795pub struct UntilCont {
796 pub body: RcCont,
797 pub after: RcCont,
798}
799
800impl UntilCont {
801 const TAG: u8 = 0b110000;
802}
803
804impl Cont for UntilCont {
805 #[inline]
806 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
807 self
808 }
809
810 fn as_stack_value(&self) -> &dyn StackValue {
811 self
812 }
813
814 #[inline]
815 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
816 f.write_str("vmc_until")
817 }
818
819 #[cfg_attr(
820 feature = "tracing",
821 instrument(level = "trace", name = "until_cont", skip_all)
822 )]
823 fn jump(self: Rc<Self>, state: &mut VmState, _: &mut i32) -> VmResult<Option<RcCont>> {
824 vm_log_trace!("until loop condition end");
825 let terminated = ok!(SafeRc::make_mut(&mut state.stack).pop_bool());
826 if terminated {
827 vm_log_trace!("until loop terminated");
828 return Ok(Some(self.after.clone()));
829 }
830 if !self.body.has_c0() {
831 state.set_c0(RcCont::from(self.clone()));
832 }
833 Ok(Some(self.body.clone()))
834 }
835}
836
837impl Store for UntilCont {
838 fn store_into(
839 &self,
840 builder: &mut CellBuilder,
841 context: &dyn CellContext,
842 ) -> Result<(), Error> {
843 ok!(builder.store_small_uint(Self::TAG, 6));
844 ok!(builder.store_reference(ok!(CellBuilder::build_from_ext(&*self.body, context))));
845 builder.store_reference(ok!(CellBuilder::build_from_ext(&*self.after, context)))
846 }
847}
848
849impl Load<'_> for UntilCont {
850 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
851 if ok!(slice.load_small_uint(6)) != Self::TAG {
852 return Err(Error::InvalidTag);
853 }
854
855 Ok(Self {
856 body: ok!(load_cont(slice)),
857 after: ok!(load_cont(slice)),
858 })
859 }
860}
861
862#[derive(Debug, Clone)]
864pub struct WhileCont {
865 pub check_cond: bool,
866 pub cond: RcCont,
867 pub body: RcCont,
868 pub after: RcCont,
869}
870
871impl WhileCont {
872 const TAG: u8 = 0b11001;
873}
874
875impl Cont for WhileCont {
876 #[inline]
877 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
878 self
879 }
880
881 fn as_stack_value(&self) -> &dyn StackValue {
882 self
883 }
884
885 #[inline]
886 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
887 f.write_str(if self.check_cond {
888 "vmc_while_cond"
889 } else {
890 "vmc_while_body"
891 })
892 }
893
894 #[cfg_attr(
895 feature = "tracing",
896 instrument(
897 level = "trace",
898 name = "while_cont",
899 fields(check_cond = self.check_cond),
900 skip_all,
901 )
902 )]
903 fn jump(mut self: Rc<Self>, state: &mut VmState, _: &mut i32) -> VmResult<Option<RcCont>> {
904 let next = if self.check_cond {
905 vm_log_trace!("while loop condition end");
906 if !ok!(SafeRc::make_mut(&mut state.stack).pop_bool()) {
907 vm_log_trace!("while loop terminated");
908 return Ok(Some(self.after.clone()));
909 }
910 self.body.clone()
911 } else {
912 vm_log_trace!("while loop body end");
913 self.cond.clone()
914 };
915
916 if !next.has_c0() {
917 match Rc::get_mut(&mut self) {
918 Some(this) => {
919 this.check_cond = !this.check_cond;
920 state.set_c0(RcCont::from(self));
921 }
922 None => state.set_c0(SafeRc::from(WhileCont {
923 check_cond: !self.check_cond,
924 cond: self.cond.clone(),
925 body: self.body.clone(),
926 after: self.after.clone(),
927 })),
928 }
929 }
930
931 Ok(Some(next))
932 }
933}
934
935impl Store for WhileCont {
936 fn store_into(
937 &self,
938 builder: &mut CellBuilder,
939 context: &dyn CellContext,
940 ) -> Result<(), Error> {
941 let tag = (Self::TAG << 1) | !self.check_cond as u8;
942 ok!(builder.store_small_uint(tag, 6));
943 ok!(builder.store_reference(ok!(CellBuilder::build_from_ext(&*self.cond, context))));
944 ok!(builder.store_reference(ok!(CellBuilder::build_from_ext(&*self.body, context))));
945 builder.store_reference(ok!(CellBuilder::build_from_ext(&*self.after, context)))
946 }
947}
948
949impl Load<'_> for WhileCont {
950 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
951 if ok!(slice.load_small_uint(5)) != Self::TAG {
952 return Err(Error::InvalidTag);
953 }
954
955 Ok(Self {
956 check_cond: ok!(slice.load_bit()),
957 cond: ok!(load_cont(slice)),
958 body: ok!(load_cont(slice)),
959 after: ok!(load_cont(slice)),
960 })
961 }
962}
963
964#[derive(Debug, Clone)]
966pub struct ArgContExt {
967 pub data: ControlData,
968 pub ext: RcCont,
969}
970
971impl ArgContExt {
972 const TAG: u8 = 0b01;
973}
974
975impl Cont for ArgContExt {
976 #[inline]
977 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
978 self
979 }
980
981 fn as_stack_value(&self) -> &dyn StackValue {
982 self
983 }
984
985 #[inline]
986 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
987 f.write_str("vmc_envelope")
988 }
989
990 #[cfg_attr(
991 feature = "tracing",
992 instrument(level = "trace", name = "arg_cont", skip_all)
993 )]
994 fn jump(self: Rc<Self>, state: &mut VmState, _: &mut i32) -> VmResult<Option<RcCont>> {
995 state.adjust_cr(&self.data.save);
996 if let Some(cp) = self.data.cp {
997 ok!(state.force_cp(cp));
998 }
999
1000 Ok(Some(match Rc::try_unwrap(self) {
1001 Ok(this) => this.ext,
1002 Err(this) => this.ext.clone(),
1003 }))
1004 }
1005
1006 fn get_control_data(&self) -> Option<&ControlData> {
1007 Some(&self.data)
1008 }
1009
1010 fn get_control_data_mut(&mut self) -> Option<&mut ControlData> {
1011 Some(&mut self.data)
1012 }
1013}
1014
1015impl Store for ArgContExt {
1016 fn store_into(
1017 &self,
1018 builder: &mut CellBuilder,
1019 context: &dyn CellContext,
1020 ) -> Result<(), Error> {
1021 ok!(builder.store_small_uint(Self::TAG, 2));
1022 self.ext.store_into(builder, context)
1023 }
1024}
1025
1026impl Load<'_> for ArgContExt {
1027 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
1028 if ok!(slice.load_small_uint(2)) != Self::TAG {
1029 return Err(Error::InvalidTag);
1030 }
1031
1032 Ok(Self {
1033 data: ok!(ControlData::load_from(slice)),
1034 ext: ok!(load_cont(slice)),
1035 })
1036 }
1037}
1038
1039#[derive(Debug, Clone)]
1041pub struct OrdCont {
1042 pub data: ControlData,
1043 pub code: OwnedCellSlice,
1044}
1045
1046impl OrdCont {
1047 const TAG: u8 = 0b00;
1048
1049 pub fn simple(code: OwnedCellSlice, cp: u16) -> Self {
1050 Self {
1051 data: ControlData {
1052 cp: Some(cp),
1053 ..Default::default()
1054 },
1055 code,
1056 }
1057 }
1058}
1059
1060impl Cont for OrdCont {
1061 #[inline]
1062 fn rc_into_dyn(self: Rc<Self>) -> Rc<dyn StackValue> {
1063 self
1064 }
1065
1066 fn as_stack_value(&self) -> &dyn StackValue {
1067 self
1068 }
1069
1070 #[inline]
1071 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1072 f.write_str("vmc_std")
1073 }
1074
1075 #[cfg_attr(
1076 feature = "tracing",
1077 instrument(level = "trace", name = "ord_cont", skip_all)
1078 )]
1079 fn jump(self: Rc<Self>, state: &mut VmState, _: &mut i32) -> VmResult<Option<RcCont>> {
1080 state.adjust_cr(&self.data.save);
1081 let Some(cp) = self.data.cp else {
1082 vm_bail!(InvalidOpcode);
1083 };
1084 ok!(state.set_code(self.code.clone(), cp));
1085 Ok(None)
1086 }
1087
1088 fn get_control_data(&self) -> Option<&ControlData> {
1089 Some(&self.data)
1090 }
1091
1092 fn get_control_data_mut(&mut self) -> Option<&mut ControlData> {
1093 Some(&mut self.data)
1094 }
1095}
1096
1097impl Store for OrdCont {
1098 fn store_into(
1099 &self,
1100 builder: &mut CellBuilder,
1101 context: &dyn CellContext,
1102 ) -> Result<(), Error> {
1103 ok!(builder.store_zeros(2));
1104 ok!(self.data.store_into(builder, context));
1105 store_slice_as_stack_value(&self.code, builder)
1106 }
1107}
1108
1109impl Load<'_> for OrdCont {
1110 fn load_from(slice: &mut CellSlice<'_>) -> Result<Self, Error> {
1111 if ok!(slice.load_small_uint(2)) != Self::TAG {
1112 return Err(Error::InvalidTag);
1113 }
1114
1115 Ok(Self {
1116 data: ok!(ControlData::load_from(slice)),
1117 code: ok!(load_slice_as_stack_value(slice)),
1118 })
1119 }
1120}