@@ -1724,6 +1724,86 @@ impl<'a> Context<'a> {
1724
1724
) ;
1725
1725
}
1726
1726
1727
+ fn expose_make_mut_closure ( & mut self ) -> Result < ( ) , Error > {
1728
+ if !self . should_write_global ( "make_mut_closure" ) {
1729
+ return Ok ( ( ) ) ;
1730
+ }
1731
+
1732
+ let table = self . export_function_table ( ) ?;
1733
+
1734
+ // For mutable closures they can't be invoked recursively.
1735
+ // To handle that we swap out the `this.a` pointer with zero
1736
+ // while we invoke it. If we finish and the closure wasn't
1737
+ // destroyed, then we put back the pointer so a future
1738
+ // invocation can succeed.
1739
+ self . global ( & format ! (
1740
+ "
1741
+ function makeMutClosure(arg0, arg1, dtor, f) {{
1742
+ const state = {{ a: arg0, b: arg1, cnt: 1 }};
1743
+ const real = (...args) => {{
1744
+ // First up with a closure we increment the internal reference
1745
+ // count. This ensures that the Rust closure environment won't
1746
+ // be deallocated while we're invoking it.
1747
+ state.cnt++;
1748
+ const a = state.a;
1749
+ state.a = 0;
1750
+ try {{
1751
+ return f(a, state.b, ...args);
1752
+ }} finally {{
1753
+ if (--state.cnt === 0) wasm.{}.get(dtor)(a, state.b);
1754
+ else state.a = a;
1755
+ }}
1756
+ }};
1757
+ real.original = state;
1758
+ return real;
1759
+ }}
1760
+ " ,
1761
+ table
1762
+ ) ) ;
1763
+
1764
+ Ok ( ( ) )
1765
+ }
1766
+
1767
+ fn expose_make_closure ( & mut self ) -> Result < ( ) , Error > {
1768
+ if !self . should_write_global ( "make_closure" ) {
1769
+ return Ok ( ( ) ) ;
1770
+ }
1771
+
1772
+ let table = self . export_function_table ( ) ?;
1773
+
1774
+ // For shared closures they can be invoked recursively so we
1775
+ // just immediately pass through `this.a`. If we end up
1776
+ // executing the destructor, however, we clear out the
1777
+ // `this.a` pointer to prevent it being used again the
1778
+ // future.
1779
+ self . global ( & format ! (
1780
+ "
1781
+ function makeClosure(arg0, arg1, dtor, f) {{
1782
+ const state = {{ a: arg0, b: arg1, cnt: 1 }};
1783
+ const real = (...args) => {{
1784
+ // First up with a closure we increment the internal reference
1785
+ // count. This ensures that the Rust closure environment won't
1786
+ // be deallocated while we're invoking it.
1787
+ state.cnt++;
1788
+ try {{
1789
+ return f(state.a, state.b, ...args);
1790
+ }} finally {{
1791
+ if (--state.cnt === 0) {{
1792
+ wasm.{}.get(dtor)(state.a, state.b);
1793
+ state.a = 0;
1794
+ }}
1795
+ }}
1796
+ }};
1797
+ real.original = state;
1798
+ return real;
1799
+ }}
1800
+ " ,
1801
+ table
1802
+ ) ) ;
1803
+
1804
+ Ok ( ( ) )
1805
+ }
1806
+
1727
1807
fn global ( & mut self , s : & str ) {
1728
1808
let s = s. trim ( ) ;
1729
1809
@@ -2338,73 +2418,36 @@ impl<'a> Context<'a> {
2338
2418
dtor,
2339
2419
mutable,
2340
2420
adapter,
2341
- nargs,
2421
+ nargs : _ ,
2342
2422
} => {
2343
2423
assert ! ( kind == AdapterJsImportKind :: Normal ) ;
2344
2424
assert ! ( !variadic) ;
2345
2425
assert_eq ! ( args. len( ) , 3 ) ;
2346
- let arg_names = ( 0 ..* nargs)
2347
- . map ( |i| format ! ( "arg{}" , i) )
2348
- . collect :: < Vec < _ > > ( )
2349
- . join ( ", " ) ;
2350
- let mut js = format ! ( "({}) => {{\n " , arg_names) ;
2351
- // First up with a closure we increment the internal reference
2352
- // count. This ensures that the Rust closure environment won't
2353
- // be deallocated while we're invoking it.
2354
- js. push_str ( "state.cnt++;\n " ) ;
2355
-
2356
- let table = self . export_function_table ( ) ?;
2357
- let dtor = format ! ( "wasm.{}.get({})" , table, dtor) ;
2426
+
2358
2427
let call = self . adapter_name ( * adapter) ;
2359
2428
2360
2429
if * mutable {
2361
- // For mutable closures they can't be invoked recursively.
2362
- // To handle that we swap out the `this.a` pointer with zero
2363
- // while we invoke it. If we finish and the closure wasn't
2364
- // destroyed, then we put back the pointer so a future
2365
- // invocation can succeed.
2366
- js. push_str ( "const a = state.a;\n " ) ;
2367
- js. push_str ( "state.a = 0;\n " ) ;
2368
- js. push_str ( "try {\n " ) ;
2369
- js. push_str ( & format ! ( "return {}(a, state.b, {});\n " , call, arg_names) ) ;
2370
- js. push_str ( "} finally {\n " ) ;
2371
- js. push_str ( "if (--state.cnt === 0) " ) ;
2372
- js. push_str ( & dtor) ;
2373
- js. push_str ( "(a, state.b);\n " ) ;
2374
- js. push_str ( "else state.a = a;\n " ) ;
2375
- js. push_str ( "}\n " ) ;
2430
+ self . expose_make_mut_closure ( ) ?;
2431
+
2432
+ Ok ( format ! (
2433
+ "makeMutClosure({arg0}, {arg1}, {dtor}, {call})" ,
2434
+ arg0 = & args[ 0 ] ,
2435
+ arg1 = & args[ 1 ] ,
2436
+ dtor = dtor,
2437
+ call = call,
2438
+ ) )
2439
+
2376
2440
} else {
2377
- // For shared closures they can be invoked recursively so we
2378
- // just immediately pass through `this.a`. If we end up
2379
- // executing the destructor, however, we clear out the
2380
- // `this.a` pointer to prevent it being used again the
2381
- // future.
2382
- js. push_str ( "try {\n " ) ;
2383
- js. push_str ( & format ! (
2384
- "return {}(state.a, state.b, {});\n " ,
2385
- call, arg_names
2386
- ) ) ;
2387
- js. push_str ( "} finally {\n " ) ;
2388
- js. push_str ( "if (--state.cnt === 0) {\n " ) ;
2389
- js. push_str ( & dtor) ;
2390
- js. push_str ( "(state.a, state.b);\n " ) ;
2391
- js. push_str ( "state.a = 0;\n " ) ;
2392
- js. push_str ( "}\n " ) ;
2393
- js. push_str ( "}\n " ) ;
2441
+ self . expose_make_closure ( ) ?;
2442
+
2443
+ Ok ( format ! (
2444
+ "makeClosure({arg0}, {arg1}, {dtor}, {call})" ,
2445
+ arg0 = & args[ 0 ] ,
2446
+ arg1 = & args[ 1 ] ,
2447
+ dtor = dtor,
2448
+ call = call,
2449
+ ) )
2394
2450
}
2395
- js. push_str ( "}\n " ) ;
2396
-
2397
- prelude. push_str ( & format ! (
2398
- "
2399
- const state = {{ a: {arg0}, b: {arg1}, cnt: 1 }};
2400
- const real = {body};
2401
- real.original = state;
2402
- " ,
2403
- body = js,
2404
- arg0 = & args[ 0 ] ,
2405
- arg1 = & args[ 1 ] ,
2406
- ) ) ;
2407
- Ok ( "real" . to_string ( ) )
2408
2451
}
2409
2452
2410
2453
AuxImport :: StructuralMethod ( name) => {
0 commit comments