You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
for await runs its body as concurrent tasks: iterations interleave and lose writes #498
The body of a for await loop runs as concurrent tasks, not one iteration at a time. Iterations interleave, and writes from one iteration are lost to another, under gc, rc and none.
Six JIT runs per model on main with #440 (PR #497) applied:
Output
gc
rc
none
<7><8><9> 3
1
3
4
<7<8><9> 3 (interleaved)
1
<7><9> 2, <8><9> 2, ><9> 2 (a push lost)
4
<7> 3, <8> 3, <9> 3 (appends lost)
3
1
no output at all, exit 0
1
In TypeScript, the body of a for await runs one iteration at a time, in order: the next value is not requested until the body has finished.
Cause
MLIRGenImpl::mlirGen(ForStatement) (lib/TypeScript/MLIRGenStatements.cpp), when the loop has await:
creates an async.create_group before the loop;
wraps each iteration's body in its own async.execute, and adds its token to the group with async.add_to_group;
waits for the whole group once after the loop, with async.await_all.
So every iteration's body is started as a task without waiting for the previous one. The bodies run concurrently on the async runtime's threads, and race on whatever they share: here log, a string rebuilt by +=, and keep.push, which can reallocate the array.
Fix
Await each iteration's token before going on to the next iteration (async.await on the execute's token in the loop body, as await does since #440), and drop the group and the async.await_all. Then the next value is requested only after the body is done.
Found while working on #440 (listed there under "Also seen").
Activity
break and continue in a for await body, and nested for await (#502) (#…