@@ -45,8 +45,9 @@ pub enum ResourceData {
45
45
///
46
46
/// For a given resource id {x}, the local variables are assumed:
47
47
/// - handleTable{x}
48
- /// - captureTable{x} (only for imported tables)
49
- /// - captureCnt{x} (only for imported tables)
48
+ /// - captureTable{x} (rep to instance map for captured imported tables, only for JS import bindgen,
49
+ /// not hybrid)
50
+ /// - captureCnt{x} for assigning capture rep
50
51
///
51
52
/// For component-defined resources:
52
53
/// - finalizationRegistry{x}
@@ -1045,17 +1046,6 @@ impl Bindgen for FunctionBindgen<'_> {
1045
1046
self . bind_results ( sig_results_length, results) ;
1046
1047
uwriteln ! ( self . src, "{}({});" , self . callee, operands. join( ", " ) ) ;
1047
1048
1048
- if !self . cur_resource_borrows . is_empty ( ) {
1049
- uwriteln ! (
1050
- self . src,
1051
- "if ({}) {{
1052
- throw new Error('Resource error: borrows were not dropped');
1053
- }}" ,
1054
- self . cur_resource_borrows. join( " || " )
1055
- ) ;
1056
- self . cur_resource_borrows = Vec :: new ( ) ;
1057
- }
1058
-
1059
1049
if let Some ( prefix) = self . tracing_prefix {
1060
1050
let to_result_string = self . intrinsic ( Intrinsic :: ToResultString ) ;
1061
1051
uwriteln ! (
@@ -1196,16 +1186,16 @@ impl Bindgen for FunctionBindgen<'_> {
1196
1186
let id = id. as_u32 ( ) ;
1197
1187
let symbol_dispose = self . intrinsic ( Intrinsic :: SymbolDispose ) ;
1198
1188
let rsc_table_remove = self . intrinsic ( Intrinsic :: ResourceTableRemove ) ;
1189
+ let rep = format ! ( "rep{}" , self . tmp( ) ) ;
1199
1190
if !imported {
1200
- let rep = format ! ( "rep{}" , self . tmp( ) ) ;
1201
1191
let symbol_resource_handle =
1202
1192
self . intrinsic ( Intrinsic :: SymbolResourceHandle ) ;
1203
- let rsc_table_get = self . intrinsic ( Intrinsic :: ResourceTableGet ) ;
1193
+ let rsc_flag = self . intrinsic ( Intrinsic :: ResourceTableFlag ) ;
1204
1194
uwrite ! (
1205
1195
self . src,
1206
1196
"var {rsc} = new.target === {local_name} ? this : Object.create({local_name}.prototype);
1207
- var {rep} = {rsc_table_get}( handleTable{id}, {handle}).rep ;
1208
- Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {rep} }});
1197
+ var {rep} = handleTable{id}[( {handle} << 1) + 1] & ~{rsc_flag} ;
1198
+ Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {rep} }});
1209
1199
" ,
1210
1200
) ;
1211
1201
if is_own {
@@ -1239,15 +1229,39 @@ impl Bindgen for FunctionBindgen<'_> {
1239
1229
) ) ;
1240
1230
}
1241
1231
} else {
1242
- // imported handles lift as instance capture from a previous lowering
1243
- let rsc_table_get = self . intrinsic ( Intrinsic :: ResourceTableGet ) ;
1244
- uwriteln ! ( self . src, "var {rsc} = captureTable{id}.get({rsc_table_get}(handleTable{id}, {handle}).rep);" ) ;
1245
- // an own lifting is a transfer to JS, so handle is implicitly dropped
1232
+ // imported handles either lift as instance capture from a previous lowering,
1233
+ // or we create a new JS class to represent it
1234
+ let rsc_flag = self . intrinsic ( Intrinsic :: ResourceTableFlag ) ;
1235
+ let symbol_resource_rep = self . intrinsic ( Intrinsic :: SymbolResourceRep ) ;
1236
+ let symbol_resource_handle =
1237
+ self . intrinsic ( Intrinsic :: SymbolResourceHandle ) ;
1238
+ uwriteln ! (
1239
+ self . src,
1240
+ "var {rep} = handleTable{id}[({handle} << 1) + 1] & ~{rsc_flag};"
1241
+ ) ;
1242
+ uwriteln ! ( self . src,
1243
+ "var {rsc} = captureTable{id}.get({rep});
1244
+ if (!{rsc}) {{
1245
+ {rsc} = Object.create({local_name}.prototype);
1246
+ Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {handle} }});
1247
+ Object.defineProperty({rsc}, {symbol_resource_rep}, {{ writable: true, value: {rep} }});
1248
+ }}"
1249
+ ) ;
1246
1250
if is_own {
1251
+ // an own lifting is a transfer to JS, so existing own handle is implicitly dropped
1247
1252
uwriteln ! (
1248
1253
self . src,
1249
- "captureTable{id}.delete({rsc_table_remove}(handleTable{id}, {handle}).rep);"
1254
+ "else {{
1255
+ captureTable{id}.delete({rep});
1256
+ }}
1257
+ {rsc_table_remove}(handleTable{id}, {handle});"
1250
1258
) ;
1259
+ } else {
1260
+ // if lifting a borrow, that was not previously captured, create the class
1261
+ self . cur_resource_borrows . push ( format ! (
1262
+ "{}[{symbol_resource_handle}] = null;" ,
1263
+ rsc. to_string( )
1264
+ ) ) ;
1251
1265
}
1252
1266
}
1253
1267
}
@@ -1318,78 +1332,72 @@ impl Bindgen for FunctionBindgen<'_> {
1318
1332
ResourceData :: Host { id, local_name, .. } => {
1319
1333
let id = id. as_u32 ( ) ;
1320
1334
if !imported {
1321
- let rep = format ! ( "rep{}" , self . tmp( ) ) ;
1322
-
1323
1335
uwriteln ! (
1324
1336
self . src,
1325
- "var {rep} = {op}[{symbol_resource_handle}];
1326
- if ({rep} === null) {{
1327
- throw new Error('Resource error: \" {class_name}\" lifetime expired.');
1328
- }}
1329
- if ({rep} === undefined) {{
1337
+ "var {handle} = {op}[{symbol_resource_handle}];
1338
+ if (!{handle}) {{
1330
1339
throw new Error('Resource error: Not a valid \" {class_name}\" resource.');
1331
1340
}}
1332
1341
" ,
1333
1342
) ;
1334
1343
1335
- // Own resources of own components lowered into the component
1336
- // still need handle table tracking of their rep value, by creating
1337
- // a new handle for this.
1338
- // The class representation of that own resource is still disposed
1339
- // though, and their finalizers deregistered as well.
1340
1344
if is_own {
1341
1345
let empty_func = self . intrinsic ( Intrinsic :: EmptyFunc ) ;
1342
- let rsc_table_create_own =
1343
- self . intrinsic ( Intrinsic :: ResourceTableCreateOwn ) ;
1344
1346
uwriteln ! (
1345
1347
self . src,
1346
- "var {handle} = {rsc_table_create_own}(handleTable{id}, {rep});
1347
- finalizationRegistry{id}.unregister({op});
1348
+ "finalizationRegistry{id}.unregister({op});
1348
1349
{op}[{symbol_dispose}] = {empty_func};
1349
1350
{op}[{symbol_resource_handle}] = null;"
1350
1351
) ;
1351
- } else {
1352
- // it is only in the local borrow case where we can simplify the handle
1353
- // to just be the original rep value and don't need to track an
1354
- // explicit handle lifetime.
1355
- uwriteln ! ( self . src, "var {handle} = {rep};" ) ;
1356
1352
}
1357
1353
} else {
1358
- // imported resources are always given a unique handle
1354
+ // imported resources may already have a handle if they were constructed
1355
+ // by a component and then passed out
1359
1356
uwriteln ! (
1360
1357
self . src,
1361
1358
"if (!({op} instanceof {local_name})) {{
1362
1359
throw new Error('Resource error: Not a valid \" {class_name}\" resource.');
1363
1360
}}
1364
- captureTable{id}.set(++captureCnt{id}, {op});"
1361
+ var {handle} = {op}[{symbol_resource_handle}];
1362
+ "
1365
1363
) ;
1364
+ // otherwise, in hybrid bindgen we check for a Symbol.for('cabiRep')
1365
+ // to get the resource rep
1366
+ // fall back to assign a new rep in the capture table, when the imported
1367
+ // resource was constructed externally
1366
1368
if is_own {
1367
- let rsc_table_create_own =
1369
+ let symbol_resource_rep =
1370
+ self . intrinsic ( Intrinsic :: SymbolResourceRep ) ;
1371
+ let rsc_table_create =
1368
1372
self . intrinsic ( Intrinsic :: ResourceTableCreateOwn ) ;
1369
1373
uwriteln ! (
1370
1374
self . src,
1371
- "var {handle} = {rsc_table_create_own}(handleTable{id}, captureCnt{id});" ,
1375
+ "if (!{handle}) {{
1376
+ let rep = {op}[{symbol_resource_rep}];
1377
+ if (!rep) {{
1378
+ captureTable{id}.set(++captureCnt{id}, {op});
1379
+ rep = captureCnt{id};
1380
+ }} else {{
1381
+ {op}[{symbol_resource_rep}] = null;
1382
+ }}
1383
+ {handle} = {rsc_table_create}(handleTable{id}, rep);
1384
+ }}"
1372
1385
) ;
1373
1386
} else {
1374
- let rsc_table_create_borrow =
1387
+ let symbol_resource_rep =
1388
+ self . intrinsic ( Intrinsic :: SymbolResourceRep ) ;
1389
+ let rsc_table_create =
1375
1390
self . intrinsic ( Intrinsic :: ResourceTableCreateBorrow ) ;
1376
1391
uwriteln ! (
1377
1392
self . src,
1378
- "var {handle} = {rsc_table_create_borrow}(handleTable{id}, captureCnt{id});" ,
1393
+ "if (!{handle}) {{
1394
+ if (!{op}[{symbol_resource_rep}]) {{
1395
+ captureTable{id}.set(++captureCnt{id}, {op});
1396
+ }}
1397
+ {handle} = {rsc_table_create}(handleTable{id}, {op}[{symbol_resource_rep}] || captureCnt{id});
1398
+ }}"
1379
1399
) ;
1380
- }
1381
-
1382
- // track lowered borrows to ensure they are dropped
1383
- // cur_resource_borrows can be reused because:
1384
- // - it is not possible to have a Wasm call that lifts a a borrow handle argument
1385
- // and wasm calls cannot return borrow handles for lifting
1386
- // - conversely, it is not possible to have a JS call that lowers a borrow handle argument
1387
- // and JS calls cannot return borrows for lowering
1388
- if !is_own && !self . valid_lifting_optimization {
1389
- let rsc_table_get = self . intrinsic ( Intrinsic :: ResourceTableGet ) ;
1390
- self . cur_resource_borrows
1391
- . push ( format ! ( "{rsc_table_get}(handleTable{id}, {handle})" ) ) ;
1392
- }
1400
+ } ;
1393
1401
}
1394
1402
}
1395
1403
0 commit comments