Skip to content

Commit cb2f11e

Browse files
fix(bindgen): fix task.return param spill check
1 parent 68ab1f5 commit cb2f11e

3 files changed

Lines changed: 45 additions & 27 deletions

File tree

crates/js-component-bindgen/src/intrinsics/lift.rs

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -842,25 +842,41 @@ impl LiftIntrinsic {
842842
843843
let liftResults;
844844
if (knownLen !== undefined) {{ // list with known length
845-
846845
if (ctx.useDirectParams) {{
847-
// list with known length w/ direct params
848-
const dataPtr = ctx.params[0];
849-
ctx.params = ctx.params.slice(1);
850-
851-
// TODO(???): is it possible for all values to come in from params?
846+
if (ctx.memory === null) {{
847+
// If this lift should be using direct params,
848+
// and the memory is missing, we are in the case where
849+
// a fixed length list (or other value) is being passed only
850+
// via parameters to the function.
851+
//
852+
// Normally, we would expect to use the direct parameters as a
853+
// memory location + size, but in this case, *all* values are being passed directly,
854+
// via params.
855+
//
856+
{debug_log_fn}('memory unexpectedly missing while lifting unknown length list', {{ ctx }});
857+
liftResults = [ctx.params.slice(0, knownLen), ctx];
858+
ctx.params = ctx.params.slice(knownLen);
859+
}} else {{
860+
// in-memory list with unknown length w/ direct params
861+
const dataPtr = ctx.params[0];
862+
ctx.params = ctx.params.slice(1);
863+
864+
ctx.useDirectParams = false;
865+
const originalPtr = ctx.storagePtr;
866+
ctx.storageLen = knownLen * elemSize32;
867+
868+
liftResults = readValuesAndReset(ctx, originalPtr, dataPtr, knownLen);
869+
870+
ctx.useDirectParams = true;
871+
ctx.storagePtr = undefined;
872+
ctx.storageLen = undefined;
873+
}}
874+
}} else {{ // indirect params
875+
if (ctx.memory === null) {{
876+
{debug_log_fn}('memory unexpectedly missing while lifting known length list', {{ knownLen, ctx }});
877+
throw new Error(`memory missing while lifting known length (${{knownLen}}) list`);
878+
}}
852879
853-
ctx.useDirectParams = false;
854-
const originalPtr = ctx.storagePtr;
855-
ctx.storageLen = knownLen * elemSize32;
856-
857-
liftResults = readValuesAndReset(ctx, originalPtr, dataPtr, knownLen);
858-
859-
ctx.useDirectParams = true;
860-
ctx.storagePtr = null;
861-
ctx.storageLen = null;
862-
863-
}} else {{
864880
ctx.storageLen = knownLen * elemSize32;
865881
liftResults = readValuesAndReset(ctx, null, ctx.storagePtr, knownLen);
866882
}}
@@ -880,8 +896,8 @@ impl LiftIntrinsic {
880896
liftResults = readValuesAndReset(ctx, originalPtr, dataPtr, len);
881897
882898
ctx.useDirectParams = true;
883-
ctx.storagePtr = null;
884-
ctx.storageLen = null;
899+
ctx.storagePtr = undefined;
900+
ctx.storageLen = undefined;
885901
886902
}} else {{
887903
// unknown length list ptr w/ in-memory params

crates/js-component-bindgen/src/intrinsics/p3/async_task.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,6 @@ impl AsyncTaskIntrinsic {
454454
function {task_return_fn}(ctx) {{
455455
const {{
456456
componentIdx,
457-
useDirectParams,
458457
getMemoryFn,
459458
memoryIdx,
460459
callbackFnIdx,
@@ -464,6 +463,7 @@ impl AsyncTaskIntrinsic {
464463
}} = ctx;
465464
const params = [...arguments].slice(1);
466465
const memory = getMemoryFn();
466+
let useDirectParams = ctx.useDirectParams;
467467
468468
const {{ taskID }} = {get_global_current_task_meta_fn}(componentIdx);
469469
@@ -511,6 +511,10 @@ impl AsyncTaskIntrinsic {
511511
512512
let liftCtx = {{ memory, useDirectParams, params, componentIdx, stringEncoding }};
513513
if (!useDirectParams) {{
514+
if (!ctx.memory) {{
515+
{debug_log_fn}('missing memory despite indirect param usage', {{ useDirectParams, liftCtx, ctx }});
516+
throw new Error('missing memory despite indirect param usage');
517+
}}
514518
liftCtx.storagePtr = params[0];
515519
liftCtx.storageLen = params[1];
516520
}}
@@ -519,7 +523,7 @@ impl AsyncTaskIntrinsic {
519523
{debug_log_fn}('[{task_return_fn}()] lifting results out of memory', {{ liftCtx }});
520524
for (const liftFn of liftFns) {{
521525
if (liftCtx.storageLen !== undefined && liftCtx.storageLen <= 0) {{
522-
{debug_log_fn}("[{task_return_fn}()] ran out of range while writing");
526+
{debug_log_fn}(`[{task_return_fn}()] ran out of range while writing storageLen = [${{liftCtx.storageLen}}]`);
523527
throw new Error('ran out of storage while writing');
524528
}}
525529
const [ val, newLiftCtx ] = liftFn(liftCtx);

crates/js-component-bindgen/src/transpile_bindgen.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,9 @@ use crate::{
5555
requires_async_porcelain, source, uwrite, uwriteln,
5656
};
5757

58-
/// Number of flat parameters allowed before spilling over to memory
59-
/// for an async function
60-
///
61-
/// See [`wit-bindgen-core`] and the Component Model spec
62-
const MAX_ASYNC_FLAT_PARAMS: usize = 4;
58+
/// Size of flat parameters that can be sent, for example via the `task.return`
59+
/// intrinsic, when returning from an async func
60+
const MAX_FLAT_PARAMS: usize = 16;
6361

6462
#[derive(Debug, Default, Clone)]
6563
pub struct TranspileOpts {
@@ -2530,7 +2528,7 @@ impl<'a> Instantiator<'a, '_> {
25302528
.unwrap_or(0)
25312529
})
25322530
.sum();
2533-
let use_direct_params = result_flat_param_total < MAX_ASYNC_FLAT_PARAMS;
2531+
let use_direct_params = result_flat_param_total < MAX_FLAT_PARAMS;
25342532

25352533
// Build up a list of all the lifting functions that will be needed for the types
25362534
// that are actually being passed through task.return

0 commit comments

Comments
 (0)