1
1
use std:: convert:: TryFrom ;
2
2
use std:: mem:: MaybeUninit ;
3
+ use std:: sync:: Mutex ;
3
4
4
5
use anyhow:: anyhow;
5
6
use anyhow:: Error ;
@@ -134,6 +135,19 @@ fn is_trap_deterministic(trap: &Error) -> bool {
134
135
}
135
136
}
136
137
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
+
137
151
#[ derive( Copy , Clone ) ]
138
152
pub struct ExperimentalFeatures {
139
153
pub allow_non_deterministic_ipfs : bool ,
@@ -154,19 +168,15 @@ pub struct AscHeapCtx {
154
168
// is zeroed when initialized or grown.
155
169
memory : Memory ,
156
170
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 : Mutex < Arena > ,
162
172
}
163
173
164
174
impl AscHeapCtx {
165
175
pub ( crate ) fn new (
166
176
instance : & wasmtime:: Instance ,
167
177
ctx : & mut WasmInstanceContext < ' _ > ,
168
178
api_version : Version ,
169
- ) -> anyhow:: Result < AscHeapCtx > {
179
+ ) -> anyhow:: Result < Arc < AscHeapCtx > > {
170
180
// Provide access to the WASM runtime linear memory
171
181
let memory = instance
172
182
. get_memory ( ctx. as_context_mut ( ) , "memory" )
@@ -194,14 +204,33 @@ impl AscHeapCtx {
194
204
) ,
195
205
} ;
196
206
197
- Ok ( AscHeapCtx {
207
+ Ok ( Arc :: new ( AscHeapCtx {
198
208
memory_allocate,
199
209
memory,
200
- arena_start_ptr : 0 ,
201
- arena_free_size : 0 ,
210
+ arena : Mutex :: new ( Arena :: new ( ) ) ,
202
211
api_version,
203
212
id_of_type,
204
- } )
213
+ } ) )
214
+ }
215
+
216
+ fn arena_start_ptr ( & self ) -> i32 {
217
+ self . arena . lock ( ) . unwrap ( ) . start
218
+ }
219
+
220
+ fn arena_free_size ( & self ) -> i32 {
221
+ self . arena . lock ( ) . unwrap ( ) . size
222
+ }
223
+
224
+ fn set_arena ( & self , start_ptr : i32 , size : i32 ) {
225
+ let mut arena = self . arena . lock ( ) . unwrap ( ) ;
226
+ arena. start = start_ptr;
227
+ arena. size = size;
228
+ }
229
+
230
+ fn allocated ( & self , size : i32 ) {
231
+ let mut arena = self . arena . lock ( ) . unwrap ( ) ;
232
+ arena. start += size;
233
+ arena. size -= size;
205
234
}
206
235
}
207
236
@@ -229,21 +258,20 @@ impl AscHeap for WasmInstanceContext<'_> {
229
258
static MIN_ARENA_SIZE : i32 = 10_000 ;
230
259
231
260
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 ( ) {
233
262
// Allocate a new arena. Any free space left in the previous arena is left unused. This
234
263
// 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 ) ;
236
265
237
266
// Unwrap: This may panic if more memory needs to be requested from the OS and that
238
267
// fails. This error is not deterministic since it depends on the operating conditions
239
268
// 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
242
271
. call ( self . as_context_mut ( ) , arena_size)
243
272
. unwrap ( ) ;
244
- self . asc_heap_mut ( ) . arena_free_size = arena_size;
245
273
246
- match & self . asc_heap_ref ( ) . api_version {
274
+ match & self . asc_heap ( ) . api_version {
247
275
version if * version <= Version :: new ( 0 , 0 , 4 ) => { }
248
276
_ => {
249
277
// This arithmetic is done because when you call AssemblyScripts's `__alloc`
@@ -252,27 +280,27 @@ impl AscHeap for WasmInstanceContext<'_> {
252
280
// `mmInfo` has size of 4, and everything allocated on AssemblyScript memory
253
281
// should have alignment of 16, this means we need to do a 12 offset on these
254
282
// 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 ;
257
285
}
258
286
} ;
287
+ self . asc_heap ( ) . set_arena ( start_ptr, arena_size) ;
259
288
} ;
260
289
261
- let ptr = self . asc_heap_ref ( ) . arena_start_ptr as usize ;
290
+ let ptr = self . asc_heap ( ) . arena_start_ptr ( ) as usize ;
262
291
263
292
// Unwrap: We have just allocated enough space for `bytes`.
264
- let memory = self . asc_heap_ref ( ) . memory ;
293
+ let memory = self . asc_heap ( ) . memory ;
265
294
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) ;
268
296
269
297
Ok ( ptr as u32 )
270
298
}
271
299
272
300
fn read_u32 ( & self , offset : u32 , gas : & GasCounter ) -> Result < u32 , DeterministicHostError > {
273
301
gas. consume_host_fn_with_metrics ( Gas :: new ( GAS_COST_LOAD as u64 * 4 ) , "read_u32" ) ?;
274
302
let mut bytes = [ 0 ; 4 ] ;
275
- self . asc_heap_ref ( )
303
+ self . asc_heap ( )
276
304
. memory
277
305
. read ( self , offset as usize , & mut bytes)
278
306
. map_err ( |_| {
@@ -302,7 +330,7 @@ impl AscHeap for WasmInstanceContext<'_> {
302
330
303
331
// TODO: Do we still need this? Can we use read directly?
304
332
let src = self
305
- . asc_heap_ref ( )
333
+ . asc_heap ( )
306
334
. memory
307
335
. data ( self )
308
336
. get ( offset..)
@@ -317,11 +345,11 @@ impl AscHeap for WasmInstanceContext<'_> {
317
345
}
318
346
319
347
fn api_version ( & self ) -> Version {
320
- self . asc_heap_ref ( ) . api_version . clone ( )
348
+ self . asc_heap ( ) . api_version . clone ( )
321
349
}
322
350
323
351
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 func = self . asc_heap ( ) . id_of_type . clone ( ) . unwrap ( ) ;
325
353
326
354
// Unwrap ok because it's only called on correct apiVersion, look for AscPtr::generate_header
327
355
func. call ( self . as_context_mut ( ) , type_id_index as u32 )
0 commit comments