@@ -2,6 +2,7 @@ use crate::{
22 core:: { ReadAs , UntypedVal , WriteAs } ,
33 engine:: {
44 executor:: { handler:: utils:: extract_mem0, CodeMap } ,
5+ utils:: unreachable_unchecked,
56 StackConfig ,
67 } ,
78 errors:: HostError ,
@@ -251,6 +252,22 @@ impl Stack {
251252 } ;
252253 Some ( ( ip, sp, mem0, mem0_len, instance) )
253254 }
255+
256+ pub fn replace_frame (
257+ & mut self ,
258+ callee_ip : Ip ,
259+ callee_params : BoundedSlotSpan ,
260+ callee_size : usize ,
261+ callee_instance : Option < NonNull < InstanceEntity > > ,
262+ ) -> Result < Sp , TrapCode > {
263+ let params_start = usize:: from ( u16:: from ( callee_params. span ( ) . head ( ) ) ) ;
264+ let params_len = callee_params. len ( ) ;
265+ let start = self . frames . replace ( callee_ip, callee_instance) ?;
266+ let sp = self
267+ . values
268+ . replace ( start, callee_size, params_start, params_len) ?;
269+ Ok ( sp)
270+ }
254271}
255272
256273#[ derive( Debug ) ]
@@ -302,6 +319,36 @@ impl ValueStack {
302319 let sp = self . sp ( start) ;
303320 Ok ( sp)
304321 }
322+
323+ fn replace (
324+ & mut self ,
325+ start : usize ,
326+ len_slots : usize ,
327+ params_start : usize ,
328+ params_len : u16 ,
329+ ) -> Result < Sp , TrapCode > {
330+ debug_assert ! ( params_start <= len_slots) ;
331+ debug_assert ! ( params_start + usize :: from( params_len) <= len_slots) ;
332+ if len_slots == 0 {
333+ return Ok ( Sp :: null ( ) ) ;
334+ }
335+ let Some ( end) = start. checked_add ( len_slots) else {
336+ return Err ( TrapCode :: StackOverflow ) ;
337+ } ;
338+ if end > self . max_height {
339+ return Err ( TrapCode :: StackOverflow ) ;
340+ }
341+ self . cells . resize_with ( end, UntypedVal :: default) ;
342+ let Some ( cells) = self . cells . get_mut ( start..end) else {
343+ unsafe { unreachable_unchecked ! ( ) }
344+ } ;
345+ let params_end = params_start. wrapping_add ( usize:: from ( params_len) ) ;
346+ cells. copy_within ( params_start..params_end, 0 ) ;
347+ let locals_start = start. wrapping_add ( usize:: from ( params_len) ) ;
348+ cells[ locals_start..] . fill_with ( UntypedVal :: default) ;
349+ let sp = self . sp ( start) ;
350+ Ok ( sp)
351+ }
305352}
306353
307354#[ derive( Debug ) ]
@@ -384,6 +431,27 @@ impl CallStack {
384431 }
385432 Some ( ( ip, start, popped. instance ) )
386433 }
434+
435+ fn replace (
436+ & mut self ,
437+ callee_ip : Ip ,
438+ instance : Option < NonNull < InstanceEntity > > ,
439+ ) -> Result < usize , TrapCode > {
440+ let Some ( caller_frame) = self . frames . last_mut ( ) else {
441+ unsafe { unreachable_unchecked ! ( "missing caller frame on the call stack" ) }
442+ } ;
443+ let prev_instance = match instance {
444+ Some ( instance) => self . instance . replace ( instance) ,
445+ None => self . instance ,
446+ } ;
447+ let start = caller_frame. start ;
448+ * caller_frame = Frame {
449+ start,
450+ ip : callee_ip,
451+ instance : prev_instance,
452+ } ;
453+ Ok ( start)
454+ }
387455}
388456
389457#[ derive( Debug ) ]
0 commit comments