@@ -2,7 +2,10 @@ use crate::{
22 core:: { ReadAs , UntypedVal , WriteAs } ,
33 engine:: {
44 executor:: {
5- handler:: { dispatch:: ExecutionOutcome , utils:: extract_mem0} ,
5+ handler:: {
6+ dispatch:: { Control , ExecutionOutcome } ,
7+ utils:: extract_mem0,
8+ } ,
69 CodeMap ,
710 } ,
811 utils:: unreachable_unchecked,
@@ -252,6 +255,8 @@ pub struct Stack {
252255 frames : CallStack ,
253256}
254257
258+ type ReturnCallHost = Control < ( Ip , Sp , Inst ) , Sp > ;
259+
255260impl Stack {
256261 pub fn new ( config : & StackConfig ) -> Self {
257262 Self {
@@ -276,6 +281,17 @@ impl Stack {
276281 self . values . capacity ( )
277282 }
278283
284+ pub fn return_prepare_host_frame < ' a > (
285+ & ' a mut self ,
286+ callee_params : BoundedSlotSpan ,
287+ results_len : u16 ,
288+ caller_instance : Inst ,
289+ ) -> Result < ( ReturnCallHost , FuncInOut < ' a > ) , TrapCode > {
290+ let ( callee_start, caller) = self . frames . return_prepare_host_frame ( caller_instance) ;
291+ self . values
292+ . return_prepare_host_frame ( caller, callee_start, callee_params, results_len)
293+ }
294+
279295 pub fn prepare_host_frame < ' a > (
280296 & ' a mut self ,
281297 caller_ip : Option < Ip > ,
@@ -376,6 +392,57 @@ impl ValueStack {
376392 }
377393 }
378394
395+ /// # Note
396+ ///
397+ /// In the following code, `callee` represents the called host function frame
398+ /// and `caller` represents the caller of the caller of the host function, a.k.a.
399+ /// the caller's caller.
400+ fn return_prepare_host_frame < ' a > (
401+ & ' a mut self ,
402+ caller : Option < ( Ip , usize , Inst ) > ,
403+ callee_start : usize ,
404+ callee_params : BoundedSlotSpan ,
405+ results_len : u16 ,
406+ ) -> Result < ( ReturnCallHost , FuncInOut < ' a > ) , TrapCode > {
407+ let caller_start = caller. map ( |( _, start, _) | start) . unwrap_or ( 0 ) ;
408+ let params_offset = usize:: from ( u16:: from ( callee_params. span ( ) . head ( ) ) ) ;
409+ let params_len = usize:: from ( callee_params. len ( ) ) ;
410+ let results_len = usize:: from ( results_len) ;
411+ let callee_size = params_len. max ( results_len) ;
412+ if callee_size == 0 {
413+ let sp = match caller {
414+ Some ( _) if caller_start != callee_start => self . sp ( caller_start) ,
415+ _ => Sp :: dangling ( ) ,
416+ } ;
417+ let inout = FuncInOut :: new ( & mut [ ] , 0 , 0 ) ;
418+ let control = match caller {
419+ Some ( ( ip, _, instance) ) => ReturnCallHost :: Continue ( ( ip, sp, instance) ) ,
420+ None => ReturnCallHost :: Break ( sp) ,
421+ } ;
422+ return Ok ( ( control, inout) ) ;
423+ }
424+ let Some ( params_start) = callee_start. checked_add ( params_offset) else {
425+ return Err ( TrapCode :: StackOverflow ) ;
426+ } ;
427+ let Some ( params_end) = params_start. checked_add ( params_len) else {
428+ return Err ( TrapCode :: StackOverflow ) ;
429+ } ;
430+ self . cells
431+ . copy_within ( params_start..params_end, callee_start) ;
432+ let Some ( callee_end) = callee_start. checked_add ( callee_size) else {
433+ return Err ( TrapCode :: StackOverflow ) ;
434+ } ;
435+ self . cells . resize ( callee_end, UntypedVal :: default ( ) ) ;
436+ let caller_sp = self . sp ( caller_start) ;
437+ let cells = & mut self . cells [ callee_start..] ;
438+ let inout = FuncInOut :: new ( cells, params_len, results_len) ;
439+ let control = match caller {
440+ Some ( ( ip, _, instance) ) => ReturnCallHost :: Continue ( ( ip, caller_sp, instance) ) ,
441+ None => ReturnCallHost :: Break ( caller_sp) ,
442+ } ;
443+ Ok ( ( control, inout) )
444+ }
445+
379446 fn prepare_host_frame < ' a > (
380447 & ' a mut self ,
381448 caller_start : usize ,
@@ -504,6 +571,26 @@ impl CallStack {
504571 self . top_start ( )
505572 }
506573
574+ /// # Note
575+ ///
576+ /// In the following code, `callee` represents the called host function frame
577+ /// and `caller` represents the caller of the caller of the host function, a.k.a.
578+ /// the caller's caller.
579+ pub fn return_prepare_host_frame (
580+ & mut self ,
581+ callee_instance : Inst ,
582+ ) -> ( usize , Option < ( Ip , usize , Inst ) > ) {
583+ let callee_start = self . top_start ( ) ;
584+ let caller = match self . pop ( ) {
585+ Some ( ( ip, start, instance) ) => {
586+ let instance = instance. unwrap_or ( callee_instance) ;
587+ Some ( ( ip, start, instance) )
588+ }
589+ None => None ,
590+ } ;
591+ ( callee_start, caller)
592+ }
593+
507594 #[ inline( always) ]
508595 fn push (
509596 & mut self ,
0 commit comments