@@ -132,6 +132,40 @@ pub enum AbiVariant {
132
132
GuestExportAsyncStackful ,
133
133
}
134
134
135
+ pub struct FlatTypes < ' a > {
136
+ types : & ' a mut [ WasmType ] ,
137
+ cur : usize ,
138
+ overflow : bool ,
139
+ }
140
+
141
+ impl < ' a > FlatTypes < ' a > {
142
+ pub fn new ( types : & ' a mut [ WasmType ] ) -> FlatTypes < ' a > {
143
+ FlatTypes {
144
+ types,
145
+ cur : 0 ,
146
+ overflow : false ,
147
+ }
148
+ }
149
+
150
+ pub fn push ( & mut self , ty : WasmType ) -> bool {
151
+ match self . types . get_mut ( self . cur ) {
152
+ Some ( next) => {
153
+ * next = ty;
154
+ self . cur += 1 ;
155
+ true
156
+ }
157
+ None => {
158
+ self . overflow = true ;
159
+ false
160
+ }
161
+ }
162
+ }
163
+
164
+ pub fn to_vec ( & self ) -> Vec < WasmType > {
165
+ self . types [ ..self . cur ] . to_vec ( )
166
+ }
167
+ }
168
+
135
169
impl Resolve {
136
170
const MAX_FLAT_PARAMS : usize = 16 ;
137
171
const MAX_FLAT_RESULTS : usize = 1 ;
@@ -150,16 +184,17 @@ impl Resolve {
150
184
} ;
151
185
}
152
186
153
- let mut params = Vec :: new ( ) ;
154
- let mut indirect_params = false ;
155
- for ( _, param) in func. params . iter ( ) {
156
- self . push_flat ( param, & mut params) ;
157
- }
158
-
159
- if params. len ( ) > Self :: MAX_FLAT_PARAMS {
160
- params. truncate ( 0 ) ;
161
- params. push ( WasmType :: Pointer ) ;
162
- indirect_params = true ;
187
+ // Note that one extra parameter is allocated in case a return pointer
188
+ // is needed down below for imports.
189
+ let mut storage = [ WasmType :: I32 ; Self :: MAX_FLAT_PARAMS + 1 ] ;
190
+ let mut params = FlatTypes :: new ( & mut storage) ;
191
+ let ok = self . push_flat_list ( func. params . iter ( ) . map ( |( _, param) | param) , & mut params) ;
192
+ assert_eq ! ( ok, !params. overflow) ;
193
+
194
+ let indirect_params = !ok || params. cur > Self :: MAX_FLAT_PARAMS ;
195
+ if indirect_params {
196
+ params. types [ 0 ] = WasmType :: Pointer ;
197
+ params. cur = 1 ;
163
198
} else {
164
199
if matches ! (
165
200
( & func. kind, variant) ,
@@ -176,23 +211,23 @@ impl Resolve {
176
211
// resource Handles and then use either I32 or Pointer in abi::push_flat().
177
212
// But this contextual information isn't available, yet.
178
213
// See https://github.com/bytecodealliance/wasm-tools/pull/1438 for more details.
179
- assert ! ( matches!( params[ 0 ] , WasmType :: I32 ) ) ;
180
- params[ 0 ] = WasmType :: Pointer ;
214
+ assert ! ( matches!( params. types [ 0 ] , WasmType :: I32 ) ) ;
215
+ params. types [ 0 ] = WasmType :: Pointer ;
181
216
}
182
217
}
183
218
184
219
match variant {
185
220
AbiVariant :: GuestExportAsync => {
186
221
return WasmSignature {
187
- params,
222
+ params : params . to_vec ( ) ,
188
223
indirect_params,
189
224
results : vec ! [ WasmType :: Pointer ] ,
190
225
retptr : false ,
191
226
} ;
192
227
}
193
228
AbiVariant :: GuestExportAsyncStackful => {
194
229
return WasmSignature {
195
- params,
230
+ params : params . to_vec ( ) ,
196
231
indirect_params,
197
232
results : Vec :: new ( ) ,
198
233
retptr : false ,
@@ -201,42 +236,50 @@ impl Resolve {
201
236
_ => { }
202
237
}
203
238
204
- let mut results = Vec :: new ( ) ;
239
+ let mut storage = [ WasmType :: I32 ; Self :: MAX_FLAT_RESULTS ] ;
240
+ let mut results = FlatTypes :: new ( & mut storage) ;
205
241
if let Some ( ty) = & func. result {
206
- self . push_flat ( ty, & mut results)
242
+ self . push_flat ( ty, & mut results) ;
207
243
}
208
244
209
- let mut retptr = false ;
245
+ let retptr = results . overflow ;
210
246
211
247
// Rust/C don't support multi-value well right now, so if a function
212
248
// would have multiple results then instead truncate it. Imports take a
213
249
// return pointer to write into and exports return a pointer they wrote
214
250
// into.
215
- if results. len ( ) > Self :: MAX_FLAT_RESULTS {
216
- retptr = true ;
217
- results. truncate ( 0 ) ;
251
+ if retptr {
252
+ results. cur = 0 ;
218
253
match variant {
219
254
AbiVariant :: GuestImport => {
220
- params. push ( WasmType :: Pointer ) ;
255
+ assert ! ( params. push( WasmType :: Pointer ) ) ;
221
256
}
222
257
AbiVariant :: GuestExport => {
223
- results. push ( WasmType :: Pointer ) ;
258
+ assert ! ( results. push( WasmType :: Pointer ) ) ;
224
259
}
225
260
_ => unreachable ! ( ) ,
226
261
}
227
262
}
228
263
229
264
WasmSignature {
230
- params,
265
+ params : params . to_vec ( ) ,
231
266
indirect_params,
232
- results,
267
+ results : results . to_vec ( ) ,
233
268
retptr,
234
269
}
235
270
}
236
271
272
+ fn push_flat_list < ' a > (
273
+ & self ,
274
+ mut list : impl Iterator < Item = & ' a Type > ,
275
+ result : & mut FlatTypes < ' _ > ,
276
+ ) -> bool {
277
+ list. all ( |ty| self . push_flat ( ty, result) )
278
+ }
279
+
237
280
/// Appends the flat wasm types representing `ty` onto the `result`
238
281
/// list provided.
239
- pub fn push_flat ( & self , ty : & Type , result : & mut Vec < WasmType > ) {
282
+ pub fn push_flat ( & self , ty : & Type , result : & mut FlatTypes < ' _ > ) -> bool {
240
283
match ty {
241
284
Type :: Bool
242
285
| Type :: S8
@@ -251,76 +294,53 @@ impl Resolve {
251
294
Type :: U64 | Type :: S64 => result. push ( WasmType :: I64 ) ,
252
295
Type :: F32 => result. push ( WasmType :: F32 ) ,
253
296
Type :: F64 => result. push ( WasmType :: F64 ) ,
254
- Type :: String => {
255
- result. push ( WasmType :: Pointer ) ;
256
- result. push ( WasmType :: Length ) ;
257
- }
297
+ Type :: String => result. push ( WasmType :: Pointer ) && result. push ( WasmType :: Length ) ,
258
298
259
299
Type :: Id ( id) => match & self . types [ * id] . kind {
260
300
TypeDefKind :: Type ( t) => self . push_flat ( t, result) ,
261
301
262
302
TypeDefKind :: Handle ( Handle :: Own ( _) | Handle :: Borrow ( _) ) => {
263
- result. push ( WasmType :: I32 ) ;
303
+ result. push ( WasmType :: I32 )
264
304
}
265
305
266
306
TypeDefKind :: Resource => todo ! ( ) ,
267
307
268
308
TypeDefKind :: Record ( r) => {
269
- for field in r. fields . iter ( ) {
270
- self . push_flat ( & field. ty , result) ;
271
- }
309
+ self . push_flat_list ( r. fields . iter ( ) . map ( |f| & f. ty ) , result)
272
310
}
273
311
274
- TypeDefKind :: Tuple ( t) => {
275
- for ty in t. types . iter ( ) {
276
- self . push_flat ( ty, result) ;
277
- }
278
- }
312
+ TypeDefKind :: Tuple ( t) => self . push_flat_list ( t. types . iter ( ) , result) ,
279
313
280
314
TypeDefKind :: Flags ( r) => {
281
- for _ in 0 ..r. repr ( ) . count ( ) {
282
- result. push ( WasmType :: I32 ) ;
283
- }
315
+ self . push_flat_list ( ( 0 ..r. repr ( ) . count ( ) ) . map ( |_| & Type :: U32 ) , result)
284
316
}
285
317
286
318
TypeDefKind :: List ( _) => {
287
- result. push ( WasmType :: Pointer ) ;
288
- result. push ( WasmType :: Length ) ;
319
+ result. push ( WasmType :: Pointer ) && result. push ( WasmType :: Length )
289
320
}
290
321
291
322
TypeDefKind :: FixedSizeList ( ty, size) => {
292
- for _ in 0 ..usize:: try_from ( * size)
293
- . unwrap_or ( Self :: MAX_FLAT_PARAMS )
294
- . min ( Self :: MAX_FLAT_PARAMS )
295
- {
296
- self . push_flat ( ty, result) ;
297
- }
323
+ self . push_flat_list ( ( 0 ..* size) . map ( |_| ty) , result)
298
324
}
299
325
300
326
TypeDefKind :: Variant ( v) => {
301
- result. push ( v. tag ( ) . into ( ) ) ;
302
- self . push_flat_variants ( v. cases . iter ( ) . map ( |c| c. ty . as_ref ( ) ) , result) ;
327
+ result. push ( v. tag ( ) . into ( ) )
328
+ && self . push_flat_variants ( v. cases . iter ( ) . map ( |c| c. ty . as_ref ( ) ) , result)
303
329
}
304
330
305
331
TypeDefKind :: Enum ( e) => result. push ( e. tag ( ) . into ( ) ) ,
306
332
307
333
TypeDefKind :: Option ( t) => {
308
- result. push ( WasmType :: I32 ) ;
309
- self . push_flat_variants ( [ None , Some ( t) ] , result) ;
334
+ result. push ( WasmType :: I32 ) && self . push_flat_variants ( [ None , Some ( t) ] , result)
310
335
}
311
336
312
337
TypeDefKind :: Result ( r) => {
313
- result. push ( WasmType :: I32 ) ;
314
- self . push_flat_variants ( [ r. ok . as_ref ( ) , r. err . as_ref ( ) ] , result) ;
338
+ result. push ( WasmType :: I32 )
339
+ && self . push_flat_variants ( [ r. ok . as_ref ( ) , r. err . as_ref ( ) ] , result)
315
340
}
316
341
317
- TypeDefKind :: Future ( _) => {
318
- result. push ( WasmType :: I32 ) ;
319
- }
320
-
321
- TypeDefKind :: Stream ( _) => {
322
- result. push ( WasmType :: I32 ) ;
323
- }
342
+ TypeDefKind :: Future ( _) => result. push ( WasmType :: I32 ) ,
343
+ TypeDefKind :: Stream ( _) => result. push ( WasmType :: I32 ) ,
324
344
325
345
TypeDefKind :: Unknown => unreachable ! ( ) ,
326
346
} ,
@@ -330,10 +350,11 @@ impl Resolve {
330
350
fn push_flat_variants < ' a > (
331
351
& self ,
332
352
tys : impl IntoIterator < Item = Option < & ' a Type > > ,
333
- result : & mut Vec < WasmType > ,
334
- ) {
335
- let mut temp = Vec :: new ( ) ;
336
- let start = result. len ( ) ;
353
+ result : & mut FlatTypes < ' _ > ,
354
+ ) -> bool {
355
+ let mut temp = result. types [ result. cur ..] . to_vec ( ) ;
356
+ let mut temp = FlatTypes :: new ( & mut temp) ;
357
+ let start = result. cur ;
337
358
338
359
// Push each case's type onto a temporary vector, and then
339
360
// merge that vector into our final list starting at
@@ -343,15 +364,27 @@ impl Resolve {
343
364
// `i32` might be the `f32` bitcasted.
344
365
for ty in tys {
345
366
if let Some ( ty) = ty {
346
- self . push_flat ( ty, & mut temp) ;
367
+ if !self . push_flat ( ty, & mut temp) {
368
+ result. overflow = true ;
369
+ return false ;
370
+ }
347
371
348
- for ( i, ty) in temp. drain ( ..) . enumerate ( ) {
349
- match result. get_mut ( start + i) {
350
- Some ( prev) => * prev = join ( * prev, ty) ,
351
- None => result. push ( ty) ,
372
+ for ( i, ty) in temp. types [ ..temp. cur ] . iter ( ) . enumerate ( ) {
373
+ let i = i + start;
374
+ if i < result. cur {
375
+ result. types [ i] = join ( result. types [ i] , * ty) ;
376
+ } else if result. cur == result. types . len ( ) {
377
+ result. overflow = true ;
378
+ return false ;
379
+ } else {
380
+ result. types [ i] = * ty;
381
+ result. cur += 1 ;
352
382
}
353
383
}
384
+ temp. cur = 0 ;
354
385
}
355
386
}
387
+
388
+ true
356
389
}
357
390
}
0 commit comments