@@ -152,8 +152,8 @@ def alignment_flags(labels):
152
152
return 4
153
153
```
154
154
155
- Handle types are passed as ` i32 ` indices into the ` HandleTable ` introduced
156
- below.
155
+ Handle types are passed as ` i32 ` indices into the ` Table[HandleElem] `
156
+ introduced below.
157
157
158
158
159
159
### Size
@@ -286,12 +286,41 @@ class ComponentInstance:
286
286
self .may_enter = True
287
287
self .handles = HandleTables()
288
288
```
289
- ` HandleTables ` is defined in terms of a collection of supporting runtime
290
- bookkeeping classes that we'll go through first.
289
+ The ` HandleTables ` object held by ` ComponentInstance ` contains a mapping
290
+ from ` ResourceType ` to ` Table ` s of ` HandleElem ` s (defined next), establishing
291
+ a separate ` i32 ` -indexed array per resource type.
292
+ ``` python
293
+ class HandleTables :
294
+ rt_to_table: MutableMapping[ResourceType, Table[HandleElem]]
291
295
292
- The ` ResourceType ` class represents a resource type that has been defined by
293
- the specific component instance pointed to by ` impl ` with a particular
294
- function closure as the ` dtor ` .
296
+ def __init__ (self ):
297
+ self .rt_to_table = dict ()
298
+
299
+ def table (self , rt ):
300
+ if rt not in self .rt_to_table:
301
+ self .rt_to_table[rt] = Table[HandleElem]()
302
+ return self .rt_to_table[rt]
303
+
304
+ def get (self , rt , i ):
305
+ return self .table(rt).get(i)
306
+ def add (self , rt , h ):
307
+ return self .table(rt).add(h)
308
+ def remove (self , rt , i ):
309
+ return self .table(rt).remove(i)
310
+ ```
311
+ While this Python code performs a dynamic hash-table lookup on each handle
312
+ table access, as we'll see below, the ` rt ` parameter is always statically known
313
+ such that a normal implementation can statically enumerate all ` Table ` objects
314
+ at compile time and then route the calls to ` get ` , ` add ` and ` remove ` to the
315
+ correct ` Table ` at the callsite. The net result is that each component instance
316
+ will contain one handle table per resource type used by the component, with
317
+ each compiled adapter function accessing the correct handle table as-if it were
318
+ a global variable.
319
+
320
+ The ` ResourceType ` class represents a concrete resource type that has been
321
+ created by the component instance ` impl ` . ` ResourceType ` objects are used as
322
+ keys by ` HandleTables ` above and thus we assume that Python object identity
323
+ corresponds to resource type equality, as defined by [ type checking] rules.
295
324
``` python
296
325
class ResourceType (Type ):
297
326
impl: ComponentInstance
@@ -301,9 +330,60 @@ class ResourceType(Type):
301
330
self .impl = impl
302
331
self .dtor = dtor
303
332
```
333
+ The ` Table ` class, used by ` HandleTables ` above, encapsulates a single
334
+ mutable, growable array of generic elements, indexed by Core WebAssembly
335
+ ` i32 ` s.
336
+ ``` python
337
+ ElemT = TypeVar(' ElemT' )
338
+ class Table (Generic[ElemT]):
339
+ array: list[Optional[ElemT]]
340
+ free: list[int ]
304
341
305
- The ` HandleElem ` class represents the elements of the per-component-instance
306
- handle tables (defined next).
342
+ def __init__ (self ):
343
+ self .array = [None ]
344
+ self .free = []
345
+
346
+ def get (self , i ):
347
+ trap_if(i >= len (self .array))
348
+ trap_if(self .array[i] is None )
349
+ return self .array[i]
350
+
351
+ def add (self , e ):
352
+ if self .free:
353
+ i = self .free.pop()
354
+ assert (self .array[i] is None )
355
+ self .array[i] = e
356
+ else :
357
+ i = len (self .array)
358
+ trap_if(i >= 2 ** 30 )
359
+ self .array.append(e)
360
+ return i
361
+
362
+ def remove (self , i ):
363
+ e = self .get(i)
364
+ self .array[i] = None
365
+ self .free.append(i)
366
+ return e
367
+ ```
368
+ ` Table ` maintains a dense array of elements that can contain holes created by
369
+ the ` remove ` method (defined below). When table elements are accessed (e.g., by
370
+ ` canon_lift ` and ` resource.rep ` , below), there are thus both a bounds check and
371
+ hole check necessary. Upon initialization, table element ` 0 ` is allocated and
372
+ set to ` None ` , effectively reserving index ` 0 ` which is both useful for
373
+ catching null/uninitialized accesses and allowing ` 0 ` to serve as a sentinel
374
+ value.
375
+
376
+ The ` add ` and ` remove ` methods work together to maintain a free list of holes
377
+ that are used in preference to growing the table. The free list is represented
378
+ as a Python list here, but an optimizing implementation could instead store the
379
+ free list in the free elements of ` array ` .
380
+
381
+ The limit of ` 2**30 ` ensures that the high 2 bits of table indices are unset
382
+ and available for other use in guest code (e.g., for tagging, packed words or
383
+ sentinel values).
384
+
385
+ The ` HandleElem ` class defines the elements of the per-resource-type ` Table ` s
386
+ stored in ` HandleTables ` :
307
387
``` python
308
388
class HandleElem :
309
389
rep: int
@@ -340,86 +420,6 @@ table only contains `own` or `borrow` handles and then, based on this,
340
420
statically eliminate the ` own ` and the ` lend_count ` xor ` scope ` fields,
341
421
and guards thereof.
342
422
343
- ` HandleTable ` (singular) encapsulates a single mutable, growable array
344
- of handles that all share the same ` ResourceType ` . Defining ` HandleTable ` in
345
- chunks, we start with the fields and ` get ` method:
346
- ``` python
347
- class HandleTable :
348
- array: list[Optional[HandleElem]]
349
- free: list[int ]
350
-
351
- def __init__ (self ):
352
- self .array = [None ]
353
- self .free = []
354
-
355
- def get (self , i ):
356
- trap_if(i >= len (self .array))
357
- trap_if(self .array[i] is None )
358
- return self .array[i]
359
- ```
360
- The ` HandleTable ` class maintains a dense array of handles that can contain
361
- holes created by the ` remove ` method (defined below). When handles are accessed
362
- (by lifting and ` resource.rep ` ), there are thus both a bounds check and hole
363
- check necessary. Upon initialization, table element ` 0 ` is allocated and set to
364
- ` None ` , effectively reserving index ` 0 ` which is both useful for catching
365
- null/uninitialized accesses and allowing ` 0 ` to serve as a sentinel value.
366
-
367
- The ` add ` and ` remove ` methods work together to maintain a free list of holes
368
- that are used in preference to growing the table. The free list is represented
369
- as a Python list here, but an optimizing implementation could instead store the
370
- free list in the free elements of ` array ` .
371
- ``` python
372
- def add (self , h ):
373
- if self .free:
374
- i = self .free.pop()
375
- assert (self .array[i] is None )
376
- self .array[i] = h
377
- else :
378
- i = len (self .array)
379
- trap_if(i >= 2 ** 30 )
380
- self .array.append(h)
381
- return i
382
-
383
- def remove (self , i ):
384
- h = self .get(i)
385
- self .array[i] = None
386
- self .free.append(i)
387
- return h
388
- ```
389
- The handle index limit of ` 2**30 ` ensures that the high 2 bits of handle
390
- indices are unset and available for other use in guest code (e.g., for tagging,
391
- packed words or sentinel values).
392
-
393
- Finally, we can define ` HandleTables ` (plural) as simply a wrapper around
394
- a mutable mapping from ` ResourceType ` to ` HandleTable ` :
395
- ``` python
396
- class HandleTables :
397
- rt_to_table: MutableMapping[ResourceType, HandleTable]
398
-
399
- def __init__ (self ):
400
- self .rt_to_table = dict ()
401
-
402
- def table (self , rt ):
403
- if rt not in self .rt_to_table:
404
- self .rt_to_table[rt] = HandleTable()
405
- return self .rt_to_table[rt]
406
-
407
- def get (self , rt , i ):
408
- return self .table(rt).get(i)
409
- def add (self , rt , h ):
410
- return self .table(rt).add(h)
411
- def remove (self , rt , i ):
412
- return self .table(rt).remove(i)
413
- ```
414
- While this Python code performs a dynamic hash-table lookup on each handle
415
- table access, as we'll see below, the ` rt ` parameter is always statically
416
- known such that a normal implementation can statically enumerate all
417
- ` HandleTable ` objects at compile time and then route the calls to ` get ` ,
418
- ` add ` and ` remove ` to the correct ` HandleTable ` at the callsite. The
419
- net result is that each component instance will contain one handle table per
420
- resource type used by the component, with each compiled adapter function
421
- accessing the correct handle table as-if it were a global variable.
422
-
423
423
424
424
### Loading
425
425
0 commit comments