1+ use std:: cell:: RefCell ;
12use std:: convert:: TryFrom ;
23use std:: mem:: MaybeUninit ;
34
@@ -134,6 +135,19 @@ fn is_trap_deterministic(trap: &Error) -> bool {
134135 }
135136}
136137
138+ struct Arena {
139+ // First free byte in the current arena. Set on the first call to `raw_new`.
140+ start : i32 ,
141+ // Number of free bytes starting from `arena_start_ptr`.
142+ size : i32 ,
143+ }
144+
145+ impl Arena {
146+ fn new ( ) -> Self {
147+ Self { start : 0 , size : 0 }
148+ }
149+ }
150+
137151#[ derive( Copy , Clone ) ]
138152pub struct ExperimentalFeatures {
139153 pub allow_non_deterministic_ipfs : bool ,
@@ -154,19 +168,15 @@ pub struct AscHeapCtx {
154168 // is zeroed when initialized or grown.
155169 memory : Memory ,
156170
157- // First free byte in the current arena. Set on the first call to `raw_new`.
158- arena_start_ptr : i32 ,
159-
160- // Number of free bytes starting from `arena_start_ptr`.
161- arena_free_size : i32 ,
171+ arena : RefCell < Arena > ,
162172}
163173
164174impl AscHeapCtx {
165175 pub ( crate ) fn new (
166176 instance : & wasmtime:: Instance ,
167177 ctx : & mut WasmInstanceContext < ' _ > ,
168178 api_version : Version ,
169- ) -> anyhow:: Result < AscHeapCtx > {
179+ ) -> anyhow:: Result < Arc < AscHeapCtx > > {
170180 // Provide access to the WASM runtime linear memory
171181 let memory = instance
172182 . get_memory ( ctx. as_context_mut ( ) , "memory" )
@@ -194,14 +204,33 @@ impl AscHeapCtx {
194204 ) ,
195205 } ;
196206
197- Ok ( AscHeapCtx {
207+ Ok ( Arc :: new ( AscHeapCtx {
198208 memory_allocate,
199209 memory,
200- arena_start_ptr : 0 ,
201- arena_free_size : 0 ,
210+ arena : RefCell :: new ( Arena :: new ( ) ) ,
202211 api_version,
203212 id_of_type,
204- } )
213+ } ) )
214+ }
215+
216+ fn arena_start_ptr ( & self ) -> i32 {
217+ self . arena . borrow ( ) . start
218+ }
219+
220+ fn arena_free_size ( & self ) -> i32 {
221+ self . arena . borrow ( ) . size
222+ }
223+
224+ fn set_arena ( & self , start_ptr : i32 , size : i32 ) {
225+ let mut arena = self . arena . borrow_mut ( ) ;
226+ arena. start = start_ptr;
227+ arena. size = size;
228+ }
229+
230+ fn allocated ( & self , size : i32 ) {
231+ let mut arena = self . arena . borrow_mut ( ) ;
232+ arena. start += size;
233+ arena. size -= size;
205234 }
206235}
207236
@@ -229,21 +258,20 @@ impl AscHeap for WasmInstanceContext<'_> {
229258 static MIN_ARENA_SIZE : i32 = 10_000 ;
230259
231260 let size = i32:: try_from ( bytes. len ( ) ) . unwrap ( ) ;
232- if size > self . asc_heap_ref ( ) . arena_free_size {
261+ if size > self . asc_heap ( ) . arena_free_size ( ) {
233262 // Allocate a new arena. Any free space left in the previous arena is left unused. This
234263 // causes at most half of memory to be wasted, which is acceptable.
235- let arena_size = size. max ( MIN_ARENA_SIZE ) ;
264+ let mut arena_size = size. max ( MIN_ARENA_SIZE ) ;
236265
237266 // Unwrap: This may panic if more memory needs to be requested from the OS and that
238267 // fails. This error is not deterministic since it depends on the operating conditions
239268 // of the node.
240- let memory_allocate = self . asc_heap_ref ( ) . memory_allocate . clone ( ) ;
241- self . asc_heap_mut ( ) . arena_start_ptr = memory_allocate
269+ let memory_allocate = & self . asc_heap ( ) . cheap_clone ( ) . memory_allocate ;
270+ let mut start_ptr = memory_allocate
242271 . call ( self . as_context_mut ( ) , arena_size)
243272 . unwrap ( ) ;
244- self . asc_heap_mut ( ) . arena_free_size = arena_size;
245273
246- match & self . asc_heap_ref ( ) . api_version {
274+ match & self . asc_heap ( ) . api_version {
247275 version if * version <= Version :: new ( 0 , 0 , 4 ) => { }
248276 _ => {
249277 // This arithmetic is done because when you call AssemblyScripts's `__alloc`
@@ -252,27 +280,27 @@ impl AscHeap for WasmInstanceContext<'_> {
252280 // `mmInfo` has size of 4, and everything allocated on AssemblyScript memory
253281 // should have alignment of 16, this means we need to do a 12 offset on these
254282 // big chunks of untyped allocation.
255- self . asc_heap_mut ( ) . arena_start_ptr += 12 ;
256- self . asc_heap_mut ( ) . arena_free_size -= 12 ;
283+ start_ptr += 12 ;
284+ arena_size -= 12 ;
257285 }
258286 } ;
287+ self . asc_heap ( ) . set_arena ( start_ptr, arena_size) ;
259288 } ;
260289
261- let ptr = self . asc_heap_ref ( ) . arena_start_ptr as usize ;
290+ let ptr = self . asc_heap ( ) . arena_start_ptr ( ) as usize ;
262291
263292 // Unwrap: We have just allocated enough space for `bytes`.
264- let memory = self . asc_heap_ref ( ) . memory ;
293+ let memory = self . asc_heap ( ) . memory ;
265294 memory. write ( self . as_context_mut ( ) , ptr, bytes) . unwrap ( ) ;
266- self . asc_heap_mut ( ) . arena_start_ptr += size;
267- self . asc_heap_mut ( ) . arena_free_size -= size;
295+ self . asc_heap ( ) . allocated ( size) ;
268296
269297 Ok ( ptr as u32 )
270298 }
271299
272300 fn read_u32 ( & self , offset : u32 , gas : & GasCounter ) -> Result < u32 , DeterministicHostError > {
273301 gas. consume_host_fn_with_metrics ( Gas :: new ( GAS_COST_LOAD as u64 * 4 ) , "read_u32" ) ?;
274302 let mut bytes = [ 0 ; 4 ] ;
275- self . asc_heap_ref ( )
303+ self . asc_heap ( )
276304 . memory
277305 . read ( self , offset as usize , & mut bytes)
278306 . map_err ( |_| {
@@ -302,7 +330,7 @@ impl AscHeap for WasmInstanceContext<'_> {
302330
303331 // TODO: Do we still need this? Can we use read directly?
304332 let src = self
305- . asc_heap_ref ( )
333+ . asc_heap ( )
306334 . memory
307335 . data ( self )
308336 . get ( offset..)
@@ -317,11 +345,12 @@ impl AscHeap for WasmInstanceContext<'_> {
317345 }
318346
319347 fn api_version ( & self ) -> Version {
320- self . asc_heap_ref ( ) . api_version . clone ( )
348+ self . asc_heap ( ) . api_version . clone ( )
321349 }
322350
323351 fn asc_type_id ( & mut self , type_id_index : IndexForAscTypeId ) -> Result < u32 , HostExportError > {
324- let func = self . asc_heap_ref ( ) . id_of_type . clone ( ) . unwrap ( ) ;
352+ let asc_heap = self . asc_heap ( ) . cheap_clone ( ) ;
353+ let func = asc_heap. id_of_type . as_ref ( ) . unwrap ( ) ;
325354
326355 // Unwrap ok because it's only called on correct apiVersion, look for AscPtr::generate_header
327356 func. call ( self . as_context_mut ( ) , type_id_index as u32 )
0 commit comments