Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion runtime/src/cabi/handles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ export class Table<T> {
free: number[] = [];

get(i: number): T {
trapIf(i >= this.array.length, "table index out of range");
// Indices are u32; a negative i is out of range, and JS `array[-1]` is
// `undefined`, not the `null` sentinel.
trapIf(i < 0 || i >= this.array.length, "table index out of range");
trapIf(this.array[i] === null, "table entry empty");
return this.array[i]!;
}
Expand Down
34 changes: 23 additions & 11 deletions runtime/src/intrinsics/async_builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,12 @@ export function createWaitableSetWait(
// (line 2414).
const cancellable = opts.cancellable;
return (si?: number, ptr?: number) => {
// Guest-supplied index/pointer are u32; core wasm delivers i32 args
// signed (F3, R2). Normalize at the entry boundary.
si = (si ?? 0) >>> 0;
ptr = (ptr ?? 0) >>> 0;
trapIf(!inst.mayLeave, "waitable-set.wait: cannot leave component instance");
const wset = requireWaitableSet(inst, si ?? 0, "waitable-set.wait");
const wset = requireWaitableSet(inst, si, "waitable-set.wait");
const task = currentTask() as Task;
let event: EventTuple;
if (task.deliverPendingCancel(cancellable)) {
Expand Down Expand Up @@ -330,7 +334,7 @@ export function createWaitableSetWait(
const ev: EventTuple = cancelled
? [EventCode.TASK_CANCELLED, 0, 0]
: wset.getPendingEvent();
return unpackEvent(opts, inst, ptr ?? 0, ev);
return unpackEvent(opts, inst, ptr, ev);
},
onSettled: () => {
wset.numWaiting -= 1;
Expand All @@ -343,7 +347,7 @@ export function createWaitableSetWait(
"instead)",
);
}
return unpackEvent(opts, inst, ptr ?? 0, event);
return unpackEvent(opts, inst, ptr, event);
};
}

Expand All @@ -357,18 +361,22 @@ export function createWaitableSetPoll(
/** See `createWaitableSetWait`: `cancellable` is an option, not a decl field. */
const cancellable = opts.cancellable;
return (si?: number, ptr?: number) => {
si = (si ?? 0) >>> 0;
ptr = (ptr ?? 0) >>> 0;
trapIf(!inst.mayLeave, "waitable-set.poll: cannot leave component instance");
const wset = requireWaitableSet(inst, si ?? 0, "waitable-set.poll");
const wset = requireWaitableSet(inst, si, "waitable-set.poll");
const event = wset.poll(currentTask(), cancellable);
return unpackEvent(opts, inst, ptr ?? 0, event);
return unpackEvent(opts, inst, ptr, event);
};
}

/** definitions.py `canon_waitable_set_drop` (line 2441). */
export function createWaitableSetDrop(inst: ComponentInstanceState): CoreFn {
return (i?: number) => {
// Guest-supplied index is u32; core wasm delivers i32 args signed (F3, R2).
i = (i ?? 0) >>> 0;
trapIf(!inst.mayLeave, "waitable-set.drop: cannot leave component instance");
const wset = inst.handles.remove(i ?? 0);
const wset = inst.handles.remove(i);
trapIf(
!(wset instanceof WaitableSet),
"waitable-set.drop: handle is not a waitable set",
Expand All @@ -380,8 +388,10 @@ export function createWaitableSetDrop(inst: ComponentInstanceState): CoreFn {
/** definitions.py `canon_waitable_join` (line 2451). */
export function createWaitableJoin(inst: ComponentInstanceState): CoreFn {
return (wi?: number, si?: number) => {
wi = (wi ?? 0) >>> 0;
si = (si ?? 0) >>> 0;
trapIf(!inst.mayLeave, "waitable.join: cannot leave component instance");
const w = inst.handles.get(wi ?? 0);
const w = inst.handles.get(wi);
trapIf(!(w instanceof Waitable), "waitable.join: handle is not a waitable");
trapIf(
(w as Waitable).hasSyncWaiter,
Expand All @@ -392,11 +402,11 @@ export function createWaitableJoin(inst: ComponentInstanceState): CoreFn {
"waitable cannot be used synchronously while added to a waitable set " +
"(waitable.join)",
);
if ((si ?? 0) === 0) {
if (si === 0) {
(w as Waitable).join(null);
return;
}
const wset = requireWaitableSet(inst, si!, "waitable.join");
const wset = requireWaitableSet(inst, si, "waitable.join");
(w as Waitable).join(wset);
};
}
Expand All @@ -408,8 +418,9 @@ export function createWaitableJoin(inst: ComponentInstanceState): CoreFn {
/** definitions.py `canon_subtask_drop` (line 2494). */
export function createSubtaskDrop(inst: ComponentInstanceState): CoreFn {
return (i?: number) => {
i = (i ?? 0) >>> 0;
trapIf(!inst.mayLeave, "subtask.drop: cannot leave component instance");
const s = inst.handles.remove(i ?? 0);
const s = inst.handles.remove(i);
trapIf(!(s instanceof Subtask), "subtask.drop: handle is not a subtask");
(s as Subtask).drop();
};
Expand Down Expand Up @@ -454,6 +465,7 @@ export function createSubtaskCancel(
): CoreFn {
const async_ = decl.async === true;
return (i?: number) => {
i = (i ?? 0) >>> 0;
// The handle table is the **declared** instance's, not
// `current_thread().task.inst`. definitions.py `canon_subtask_cancel`
// (line 2469) uses the latter because the reference has no fused
Expand All @@ -468,7 +480,7 @@ export function createSubtaskCancel(
// correction already applied to every other instance-scoped built-in —
// see this module's header.
trapIf(!inst.mayLeave, "subtask.cancel: cannot leave component instance");
const subtask = inst.handles.get(i ?? 0);
const subtask = inst.handles.get(i);
trapIf(
!(subtask instanceof Subtask),
"subtask.cancel: handle is not a subtask",
Expand Down
77 changes: 45 additions & 32 deletions runtime/src/intrinsics/stream_builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,8 @@ function dropEnd(
hi: number,
what: string,
): void {
// Guest-supplied index is u32; core wasm delivers i32 args signed (F3, R2).
hi = hi >>> 0;
trapIf(!inst.mayLeave, `${what}: cannot leave component instance`);
const e = inst.handles.remove(hi);
trapIf(!(e instanceof EndT), `${what}: wrong end type for this handle`);
Expand Down Expand Up @@ -523,9 +525,11 @@ export function createErrorContextNew(
): CoreFn {
const opts = ctx.options(decl.options);
return (ptr?: number, taggedCodeUnits?: number) => {
ptr = (ptr ?? 0) >>> 0;
taggedCodeUnits = (taggedCodeUnits ?? 0) >>> 0;
trapIf(!inst.mayLeave, "error-context.new: cannot leave component instance");
const cx = new LiftLowerContext(cabiOptions(opts), inst, null);
const s = loadStringFromRange(cx, ptr ?? 0, taggedCodeUnits ?? 0);
const s = loadStringFromRange(cx, ptr, taggedCodeUnits);
return inst.handles.add(new ErrorContext(s));
};
}
Expand All @@ -538,17 +542,19 @@ export function createErrorContextDebugMessage(
): CoreFn {
const opts = ctx.options(decl.options);
return (i?: number, ptr?: number) => {
i = (i ?? 0) >>> 0;
ptr = (ptr ?? 0) >>> 0;
trapIf(
!inst.mayLeave,
"error-context.debug-message: cannot leave component instance",
);
const e = inst.handles.get(i ?? 0);
const e = inst.handles.get(i);
trapIf(
!(e instanceof ErrorContext),
errorContextTrapMessage("error-context.debug-message", e),
);
const cx = new LiftLowerContext(cabiOptions(opts), inst, null);
storeString(cx, (e as ErrorContext).debugMessage, ptr ?? 0);
storeString(cx, (e as ErrorContext).debugMessage, ptr);
};
}

Expand All @@ -557,11 +563,12 @@ export function createErrorContextDrop(
inst: ComponentInstanceState,
): CoreFn {
return (i?: number) => {
i = (i ?? 0) >>> 0;
trapIf(
!inst.mayLeave,
"error-context.drop: cannot leave component instance",
);
const e = inst.handles.remove(i ?? 0);
const e = inst.handles.remove(i);
trapIf(
!(e instanceof ErrorContext),
errorContextTrapMessage("error-context.drop", e),
Expand Down Expand Up @@ -589,9 +596,9 @@ export function createStreamRead(
elem,
opts,
inst,
i: i ?? 0,
ptr: ptr ?? 0,
n: n ?? 0,
i: (i ?? 0) >>> 0,
ptr: (ptr ?? 0) >>> 0,
n: (n ?? 0) >>> 0,
});
}

Expand All @@ -611,9 +618,9 @@ export function createStreamWrite(
elem,
opts,
inst,
i: i ?? 0,
ptr: ptr ?? 0,
n: n ?? 0,
i: (i ?? 0) >>> 0,
ptr: (ptr ?? 0) >>> 0,
n: (n ?? 0) >>> 0,
});
}

Expand All @@ -633,8 +640,8 @@ export function createFutureRead(
elem,
opts,
inst,
i: i ?? 0,
ptr: ptr ?? 0,
i: (i ?? 0) >>> 0,
ptr: (ptr ?? 0) >>> 0,
});
}

Expand All @@ -654,8 +661,8 @@ export function createFutureWrite(
elem,
opts,
inst,
i: i ?? 0,
ptr: ptr ?? 0,
i: (i ?? 0) >>> 0,
ptr: (ptr ?? 0) >>> 0,
});
}

Expand All @@ -673,7 +680,7 @@ export function createStreamCancelRead(
elem,
inst,
async_: d.async === true,
i: i ?? 0,
i: (i ?? 0) >>> 0,
what: "stream.cancel-read",
});
}
Expand All @@ -692,7 +699,7 @@ export function createStreamCancelWrite(
elem,
inst,
async_: d.async === true,
i: i ?? 0,
i: (i ?? 0) >>> 0,
what: "stream.cancel-write",
});
}
Expand All @@ -711,7 +718,7 @@ export function createFutureCancelRead(
elem,
inst,
async_: d.async === true,
i: i ?? 0,
i: (i ?? 0) >>> 0,
what: "future.cancel-read",
});
}
Expand All @@ -730,7 +737,7 @@ export function createFutureCancelWrite(
elem,
inst,
async_: d.async === true,
i: i ?? 0,
i: (i ?? 0) >>> 0,
what: "future.cancel-write",
});
}
Expand Down Expand Up @@ -861,29 +868,35 @@ function transferAsyncEnd(input: {
}

export function createStreamTransfer(ctx: AsyncTransferContext): CoreFn {
return (srcIdx?: number, srcTable?: number, dstTable?: number) =>
transferAsyncEnd({
return (srcIdx?: number, srcTable?: number, dstTable?: number) => {
srcTable = (srcTable ?? 0) >>> 0;
dstTable = (dstTable ?? 0) >>> 0;
return transferAsyncEnd({
EndT: ReadableStreamEnd as unknown as EndCtor,
srcInst: ctx.streamTableInstance(srcTable ?? 0),
dstInst: ctx.streamTableInstance(dstTable ?? 0),
srcElem: ctx.streamElem(srcTable ?? 0),
dstElem: ctx.streamElem(dstTable ?? 0),
srcIdx: srcIdx ?? 0,
srcInst: ctx.streamTableInstance(srcTable),
dstInst: ctx.streamTableInstance(dstTable),
srcElem: ctx.streamElem(srcTable),
dstElem: ctx.streamElem(dstTable),
srcIdx: (srcIdx ?? 0) >>> 0,
what: "stream",
});
};
}

export function createFutureTransfer(ctx: AsyncTransferContext): CoreFn {
return (srcIdx?: number, srcTable?: number, dstTable?: number) =>
transferAsyncEnd({
return (srcIdx?: number, srcTable?: number, dstTable?: number) => {
srcTable = (srcTable ?? 0) >>> 0;
dstTable = (dstTable ?? 0) >>> 0;
return transferAsyncEnd({
EndT: ReadableFutureEnd as unknown as EndCtor,
srcInst: ctx.futureTableInstance(srcTable ?? 0),
dstInst: ctx.futureTableInstance(dstTable ?? 0),
srcElem: ctx.futureElem(srcTable ?? 0),
dstElem: ctx.futureElem(dstTable ?? 0),
srcIdx: srcIdx ?? 0,
srcInst: ctx.futureTableInstance(srcTable),
dstInst: ctx.futureTableInstance(dstTable),
srcElem: ctx.futureElem(srcTable),
dstElem: ctx.futureElem(dstTable),
srcIdx: (srcIdx ?? 0) >>> 0,
what: "future",
});
};
}

/**
Expand Down
Loading
Loading