@@ -1537,7 +1537,7 @@ validation specifies:
1537
1537
* if a ` post-return ` is present, it has type ` (func (param flatten_functype($ft).results)) `
1538
1538
1539
1539
When instantiating component instance ` $inst ` :
1540
- * Define ` $f ` to be the closure ` lambda args: canon_lift($opts, $inst, $callee, $ft, args )`
1540
+ * Define ` $f ` to be the partially-bound closure ` canon_lift($opts, $inst, $callee, $ft) `
1541
1541
1542
1542
Thus, ` $f ` captures ` $opts ` , ` $inst ` , ` $callee ` and ` $ft ` in a closure which
1543
1543
can be subsequently exported or passed into a child instance (via ` with ` ). If
@@ -1555,20 +1555,18 @@ component*.
1555
1555
1556
1556
Given the above closure arguments, ` canon_lift ` is defined:
1557
1557
``` python
1558
- def canon_lift (opts , inst , callee , ft , args ):
1558
+ def canon_lift (opts , inst , callee , ft , start_thunk , return_thunk ):
1559
1559
export_call = ExportCall(opts, inst)
1560
1560
trap_if(not inst.may_enter)
1561
1561
1562
- flat_args = lower_values(export_call, MAX_FLAT_PARAMS , args , ft.param_types())
1562
+ flat_args = lower_values(export_call, MAX_FLAT_PARAMS , start_thunk() , ft.param_types())
1563
1563
flat_results = call_and_trap_on_throw(callee, flat_args)
1564
- results = lift_values(export_call, MAX_FLAT_RESULTS , CoreValueIter(flat_results), ft.result_types())
1564
+ return_thunk( lift_values(export_call, MAX_FLAT_RESULTS , CoreValueIter(flat_results), ft.result_types() ))
1565
1565
1566
- def post_return ():
1567
- if opts.post_return is not None :
1568
- call_and_trap_on_throw(opts.post_return, flat_results)
1569
- export_call.exit()
1566
+ if opts.post_return is not None :
1567
+ call_and_trap_on_throw(opts.post_return, flat_results)
1570
1568
1571
- return (results, post_return )
1569
+ export_call.exit( )
1572
1570
1573
1571
def call_and_trap_on_throw (callee , args ):
1574
1572
try :
@@ -1581,10 +1579,11 @@ boundaries. Thus, if a component wishes to signal an error, it must use some
1581
1579
sort of explicit type such as ` result ` (whose ` error ` case particular language
1582
1580
bindings may choose to map to and from exceptions).
1583
1581
1584
- The contract assumed by ` canon_lift ` (and ensured by ` canon_lower ` below) is
1585
- that the caller of ` canon_lift ` * must* call ` post_return ` right after lowering
1586
- ` result ` . This ensures that ` post_return ` can be used to perform cleanup
1587
- actions after the lowering is complete.
1582
+ The ` start_thunk ` and ` return_thunk ` are used to model the interleaving of
1583
+ reading arguments out of the caller's stack and memory and writing results
1584
+ back into the caller's stack and memory. After the results have been copied
1585
+ from the callee's memory into the caller's memory, the callee's ` post_return `
1586
+ function is called to allow the callee to reclaim any memory.
1588
1587
1589
1588
1590
1589
### ` canon lower `
@@ -1600,11 +1599,9 @@ where `$callee` has type `$ft`, validation specifies:
1600
1599
* there is no ` post-return ` in ` $opts `
1601
1600
1602
1601
When instantiating component instance ` $inst ` :
1603
- * Define ` $f ` to be the closure: ` lambda args: canon_lower($opts, $inst, $callee, $ft, args )`
1602
+ * Define ` $f ` to be the partially-bound closure: ` canon_lower($opts, $inst, $callee, $ft) `
1604
1603
1605
- Thus, from the perspective of Core WebAssembly, ` $f ` is a [ function instance]
1606
- containing a ` hostfunc ` that closes over ` $opts ` , ` $inst ` , ` $callee ` and ` $ft `
1607
- and, when called from Core WebAssembly code, calls ` canon_lower ` , which is defined as:
1604
+ where ` canon_lower ` is defined:
1608
1605
``` python
1609
1606
def canon_lower (opts , inst , callee , calling_import , ft , flat_args ):
1610
1607
import_call = ImportCall(opts, inst)
@@ -1615,30 +1612,23 @@ def canon_lower(opts, inst, callee, calling_import, ft, flat_args):
1615
1612
inst.may_enter = False
1616
1613
1617
1614
flat_args = CoreValueIter(flat_args)
1618
- args = lift_values(import_call, MAX_FLAT_PARAMS , flat_args, ft.param_types())
1615
+ flat_results = None
1619
1616
1620
- results, post_return = callee(args)
1617
+ def start_thunk ():
1618
+ return lift_values(import_call, MAX_FLAT_PARAMS , flat_args, ft.param_types())
1621
1619
1622
- flat_results = lower_values(import_call, MAX_FLAT_RESULTS , results, ft.result_types(), flat_args)
1620
+ def return_thunk (results ):
1621
+ nonlocal flat_results
1622
+ flat_results = lower_values(import_call, MAX_FLAT_RESULTS , results, ft.result_types(), flat_args)
1623
1623
1624
- post_return()
1625
- import_call.exit()
1624
+ callee(start_thunk, return_thunk)
1626
1625
1627
1626
if calling_import:
1628
1627
inst.may_enter = True
1629
1628
1629
+ import_call.exit()
1630
1630
return flat_results
1631
1631
```
1632
- The definitions of ` canon_lift ` and ` canon_lower ` are mostly symmetric
1633
- (swapping lifting and lowering), with a few exceptions (in ` flatten_functype ` ,
1634
- as defined above):
1635
- * The caller does not need a ` post-return ` function since the Core WebAssembly
1636
- caller simply regains control when ` canon_lower ` returns, allowing it to free
1637
- (or not) any memory passed as ` flat_args ` .
1638
- * When handling the too-many-flat-values case, instead of relying on ` realloc ` ,
1639
- the caller pass in a pointer to caller-allocated memory as a final
1640
- ` i32 ` parameter.
1641
-
1642
1632
Since any cross-component call necessarily transits through a statically-known
1643
1633
` canon_lower ` +` canon_lift ` call pair, an AOT compiler can fuse ` canon_lift ` and
1644
1634
` canon_lower ` into a single, efficient trampoline. In the future this may allow
0 commit comments