@@ -1456,7 +1456,7 @@ impl Bindgen for FunctionBindgen<'_> {
14561456 const started = await task.enter();
14571457 if (!started) {{
14581458 {debug_log_fn}('[Instruction::AsyncTaskReturn] failed to enter task', {{
1459- taskID: preparedTask .id(),
1459+ taskID: task .id(),
14601460 subtaskID: currentSubtask?.id(),
14611461 }});
14621462 throw new Error("failed to enter task");
@@ -1646,7 +1646,7 @@ impl Bindgen for FunctionBindgen<'_> {
16461646 const started = await task.enter({{ isHost: hostProvided }});
16471647 if (!started) {{
16481648 {debug_log_fn}('[Instruction::CallInterface] failed to enter task', {{
1649- taskID: preparedTask .id(),
1649+ taskID: task .id(),
16501650 subtaskID: currentSubtask?.id(),
16511651 }});
16521652 throw new Error("failed to enter task");
@@ -2612,84 +2612,92 @@ impl Bindgen for FunctionBindgen<'_> {
26122612 }
26132613
26142614 Instruction :: FutureLift { payload, ty } => {
2615- let future_ty = & crate :: dealias ( self . resolve , * ty) ;
2616-
2617- // TODO: we must generate the lifting function *before* function bindgen happens
2618- // (see commented async param lift code generation), because inside here
2619- // we do not have access to the interface types required to generate
2620- //
2621- // Alternatively, we can implement gen_flat_{lift,lower}_fn_js_expr for
2622- // TypeDefs with a resolve as well (and make sure the code works with either)
2623- //
2624- // TODO(breaking): consider adding more information to bindgen (pointer to component types?)
2625- match payload {
2626- Some ( payload_ty) => {
2627- match payload_ty {
2628- // TODO: reuse existing lifts
2629- Type :: Bool
2630- | Type :: U8
2631- | Type :: U16
2632- | Type :: U32
2633- | Type :: U64
2634- | Type :: S8
2635- | Type :: S16
2636- | Type :: S32
2637- | Type :: S64
2638- | Type :: F32
2639- | Type :: F64
2640- | Type :: Char
2641- | Type :: String
2642- | Type :: ErrorContext => uwriteln ! (
2643- self . src,
2644- "const payloadLiftFn = () => {{ throw new Error('lift for {payload_ty:?}'); }}" ,
2645- ) ,
2646- Type :: Id ( payload_ty_id) => {
2647- if self . resource_map . contains_key ( payload_ty_id) {
2648- let ResourceTable { data, .. } =
2649- & self . resource_map [ payload_ty_id] ;
2650- uwriteln ! (
2651- self . src,
2652- "const payloadLiftFn = () => {{ throw new Error('lift for {} (identifier {})'); }}" ,
2653- payload_ty_id. index( ) ,
2654- match data {
2655- ResourceData :: Host { local_name, .. } => local_name,
2656- ResourceData :: Guest { resource_name, .. } =>
2657- resource_name,
2658- }
2659- ) ;
2660- } else {
2661- // TODO: generate lift fns (see TODO above)
2662- // NOTE: the missing type here is normally a result with nested types...
2663- // the resource_map may not be indexing these properly
2664- //
2665- // eprintln!("warning: missing resource map def {:#?}", self.resolve.types[*payload_ty_id]);
2666- }
2667- }
2668- } ;
2615+ let future_new_from_lift_fn = self . intrinsic ( Intrinsic :: AsyncFuture (
2616+ AsyncFutureIntrinsic :: FutureNewFromLift ,
2617+ ) ) ;
26692618
2670- // // TODO: save payload type size below and more information about the type w/ the future?
2671- // let payload_ty_size = self.sizes.size(payload_ty).size_wasm32();
2619+ // We must look up the type idx to find the future
2620+ let type_id = & crate :: dealias ( self . resolve , * ty) ;
2621+ let ResourceTable {
2622+ imported : true ,
2623+ data :
2624+ ResourceData :: Guest {
2625+ extra :
2626+ Some ( ResourceExtraData :: Future {
2627+ table_idx : future_table_idx_ty,
2628+ elem_ty : future_element_ty,
2629+ } ) ,
2630+ ..
2631+ } ,
2632+ } = self
2633+ . resource_map
2634+ . get ( type_id)
2635+ . expect ( "missing resource mapping for future lift" )
2636+ else {
2637+ unreachable ! ( "invalid resource table observed during future lift" ) ;
2638+ } ;
26722639
2673- // NOTE: here, rather than create a new `Future` "resource" using the saved
2674- // ResourceData, we use the future.new intrinsic directly.
2675- //
2676- // TODO: differentiate "locally" created futures and futures that are lifted in?
2677- //
2678- let tmp = self . tmp ( ) ;
2679- let result_var = format ! ( "futureResult{tmp}" ) ;
2680- let component_idx = self . canon_opts . instance . as_u32 ( ) ;
2681- let future_new_fn =
2682- self . intrinsic ( Intrinsic :: AsyncFuture ( AsyncFutureIntrinsic :: FutureNew ) ) ;
2683- uwriteln ! (
2684- self . src,
2685- "const {result_var} = {future_new_fn}({{ componentIdx: {component_idx}, futureTypeRep: {} }});" ,
2686- future_ty. index( ) ,
2687- ) ;
2688- results. push ( result_var. clone ( ) ) ;
2640+ // if a future element is present, it should match the payload we're getting
2641+ let ( lift_fn_js, lower_fn_js) = match future_element_ty {
2642+ Some ( PayloadTypeMetadata {
2643+ ty,
2644+ lift_js_expr,
2645+ lower_js_expr,
2646+ ..
2647+ } ) => {
2648+ assert_eq ! ( Some ( * ty) , * * payload, "future element type mismatch" ) ;
2649+ ( lift_js_expr. to_string ( ) , lower_js_expr. to_string ( ) )
26892650 }
2651+ None => (
2652+ "() => {{ throw new Error('no lift fn'); }}" . into ( ) ,
2653+ "() => {{ throw new Error('no lower fn'); }}" . into ( ) ,
2654+ ) ,
2655+ } ;
2656+ if let Some ( PayloadTypeMetadata { ty, .. } ) = future_element_ty {
2657+ assert_eq ! ( Some ( * ty) , * * payload, "future element type mismatch" ) ;
2658+ }
2659+
2660+ let tmp = self . tmp ( ) ;
2661+ let result_var = format ! ( "futureResult{tmp}" ) ;
26902662
2691- None => unreachable ! ( "future with no payload unsupported" ) ,
2663+ // We only need to attempt to do an immediate lift in non-async cases,
2664+ // as the return of the function execution ('above' in the code)
2665+ // will be the future idx
2666+ if !self . is_async {
2667+ // If we're dealing with a sync function, we can use the return directly
2668+ let arg_future_end_idx = operands
2669+ . first ( )
2670+ . expect ( "unexpectedly missing future end return arg in FutureLift" ) ;
2671+
2672+ let ( payload_ty_size32_js, payload_ty_align32_js) =
2673+ if let Some ( payload_ty) = payload {
2674+ (
2675+ self . sizes . size ( payload_ty) . size_wasm32 ( ) . to_string ( ) ,
2676+ self . sizes . align ( payload_ty) . align_wasm32 ( ) . to_string ( ) ,
2677+ )
2678+ } else {
2679+ ( "null" . into ( ) , "null" . into ( ) )
2680+ } ;
2681+
2682+ let future_table_idx = future_table_idx_ty. as_u32 ( ) ;
2683+ let component_idx = self . canon_opts . instance . as_u32 ( ) ;
2684+
2685+ uwriteln ! (
2686+ self . src,
2687+ "
2688+ const {result_var} = {future_new_from_lift_fn}({{
2689+ componentIdx: {component_idx},
2690+ futureTableIdx: {future_table_idx},
2691+ futureEndWaitableIdx: {arg_future_end_idx},
2692+ payloadLiftFn: {lift_fn_js},
2693+ payloadLowerFn: {lower_fn_js},
2694+ payloadTypeSize32: {payload_ty_size32_js},
2695+ payloadTypeAlign32: {payload_ty_align32_js},
2696+ }});" ,
2697+ ) ;
26922698 }
2699+
2700+ results. push ( result_var. clone ( ) ) ;
26932701 }
26942702
26952703 Instruction :: StreamLower { ty, .. } => {
@@ -2928,7 +2936,6 @@ impl Bindgen for FunctionBindgen<'_> {
29282936 } ;
29292937
29302938 let stream_table_idx = stream_table_idx_ty. as_u32 ( ) ;
2931- let is_unit_stream = payload. is_none ( ) ;
29322939
29332940 uwriteln ! (
29342941 self . src,
@@ -2941,7 +2948,6 @@ impl Bindgen for FunctionBindgen<'_> {
29412948 payloadLowerFn: {lower_fn_js},
29422949 payloadTypeSize32: {payload_ty_size32_js},
29432950 payloadTypeAlign32: {payload_ty_align32_js},
2944- isUnitStream: {is_unit_stream},
29452951 }});" ,
29462952 ) ;
29472953 }
0 commit comments