Skip to content

Commit b881699

Browse files
committed
fix(wasm-canvas): stop duplicate wasm_push_key; tune statement yields
wasm_push_key no longer pushes to wasm_key_ring when gfx_vs is set; GET consumed queue then ring, doubling keys (skipped RETURN waits). Relax execute_statement (128) and run_program (32) yields so pause/resume test passes; MID$/LEFT$/RIGHT$ yields unchanged. Add examples/wasm_canvas_hang_probe.bas for isolated hang/GET checks.
1 parent 2bde3ce commit b881699

3 files changed

Lines changed: 52 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
### Unreleased
44

5+
- **WASM canvas yields**: **`execute_statement`** / **`run_program`** yield intervals relaxed (**128** / **32** statements) so **pause → resume** keeps advancing tight **`FOR`** loops in tests; **string-builtin** yields still cover **`trek.bas`**-style **`MID$`** storms.
6+
7+
- **Canvas `wasm_push_key` duplicate keys**: **`wasm_push_key`** was enqueueing every byte into **both** the **GFX key queue** and **`wasm_key_ring`**. **`GET`** consumed the queue first, then **`read_single_char_nonblock`** read the **same** byte again from the ring → **double keypresses** and **skipped “press RETURN”** waits in **`trek.bas`**. **Canvas GFX** now pushes **only** to the **GFX queue** (ring used when **`gfx_vs`** is unset).
8+
59
- **WASM canvas trek / string builtins**: **`trek.bas`** SRS **`PRINT`** evaluates **`MID$` / `LEFT$` / `RIGHT$`** hundreds of times **inside one** **`PRINT`** (few **`gfx_put_byte`** calls until the line ends). **Canvas WASM** now yields every **64** **`MID$`/`LEFT$`/`RIGHT$`** completions, plus periodic yields in **`INSTR`** / **`REPLACE`** scans and **`STRING$`** expansion.
610

711
- **WASM canvas trek / compound lines**: **`wasm_stmt_budget`** in **`run_program`** advances once per **`execute_statement` chain** from a source line, but **`trek.bas`** can run **hundreds** of **`:`**-separated statements (**`LET`**, **`IF`**, **`GOTO`**) without **`PRINT`** → no **`gfx_put_byte`** yield → tab **unresponsive**. **`execute_statement`** now yields every **4** statements (**pause**, **`wasm_gfx_refresh_js`**, **`emscripten_sleep(0)`**) when **`__EMSCRIPTEN__` + `GFX_VIDEO`**.

basic.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,7 +1353,8 @@ static void wasm_canvas_sync_charset_from_options(void);
13531353
EMSCRIPTEN_KEEPALIVE void wasm_push_key(unsigned int code)
13541354
{
13551355
unsigned char b = (unsigned char)(code & 0xFF);
1356-
wasm_key_push_byte(b);
1356+
/* Canvas: GET uses gfx key queue only. Pushing to wasm_key_ring too would
1357+
* deliver the same key twice (queue first, then ring in read_single_char_nonblock). */
13571358
if (gfx_vs) {
13581359
uint8_t next = (uint8_t)(gfx_vs->key_q_tail + 1);
13591360
if (next >= (uint8_t)sizeof(gfx_vs->key_queue)) {
@@ -1363,6 +1364,8 @@ EMSCRIPTEN_KEEPALIVE void wasm_push_key(unsigned int code)
13631364
gfx_vs->key_queue[gfx_vs->key_q_tail] = b;
13641365
gfx_vs->key_q_tail = next;
13651366
}
1367+
} else {
1368+
wasm_key_push_byte(b);
13661369
}
13671370
}
13681371
#endif
@@ -8043,7 +8046,8 @@ static void execute_statement(char **p)
80438046
}
80448047
#if defined(__EMSCRIPTEN__) && defined(GFX_VIDEO)
80458048
wasm_gfx_stmt_exec_budget++;
8046-
if ((wasm_gfx_stmt_exec_budget & 3u) == 0u) {
8049+
/* Rare: tight FOR/NEXT (pause/resume test) must advance POKE every few ms when unpaused. */
8050+
if ((wasm_gfx_stmt_exec_budget & 127u) == 0u) {
80478051
wasm_browser_pause_point();
80488052
if (!halted) {
80498053
wasm_gfx_refresh_js();
@@ -9006,8 +9010,8 @@ static void run_program(const char *script_path_arg, int nargs, char **args)
90069010
#if defined(__EMSCRIPTEN__)
90079011
wasm_stmt_budget++;
90089012
#if defined(GFX_VIDEO)
9009-
/* Compound lines (trek.bas) run many statements before next line; yield often. */
9010-
if ((wasm_stmt_budget & 7) == 0) {
9013+
/* Compound lines (trek.bas): yield without slowing tight FOR/NEXT too much. */
9014+
if ((wasm_stmt_budget & 31) == 0) {
90119015
wasm_browser_pause_point();
90129016
if (halted) {
90139017
break;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
REM --- Paste into canvas.html; click canvas before GET tests ---
2+
REM --- Use Stop if a phase hangs; note which phase in bug reports ---
3+
4+
REM Phase A: GET echo (one key per line; should NOT skip prompts)
5+
REM 10 PRINT "PHASE A: type 3 keys (e.g. a b c), each should print once"
6+
REM 20 GET K$
7+
REM 30 IF K$="" THEN 20
8+
REM 40 PRINT K$
9+
REM 50 GOTO 20
10+
11+
REM Phase B: MID$ storm (similar workload to trek SRS inner loop)
12+
10 PRINT "PHASE B: MID$ x2000 — should finish without freezing"
13+
20 Q$=STRING$(200,"x")
14+
30 FOR I=1 TO 2000
15+
40 A$=MID$(Q$,1,1)
16+
50 NEXT I
17+
60 PRINT "OK B"
18+
70 END
19+
20+
REM Phase C: STRING$ + PRINT (gfx_put_byte yields)
21+
REM 10 PRINT "PHASE C: long PRINT"
22+
REM 20 PRINT STRING$(3000,".")
23+
REM 30 PRINT "OK C"
24+
REM 40 END
25+
26+
REM Phase D: tight FOR no PRINT (statement-level yields only)
27+
REM 10 PRINT "PHASE D: FOR 2M POKE only"
28+
REM 20 FOR I=1 TO 2000000
29+
REM 30 POKE 1024,(I AND 255)
30+
REM 40 NEXT I
31+
REM 50 PRINT "OK D"
32+
REM 60 END
33+
34+
REM Phase E: trek-style GET loop (press RETURN to exit)
35+
REM 10 PRINT "PHASE E: press RETURN once to continue"
36+
REM 20 GET K$
37+
REM 30 IF K$="" THEN 20
38+
REM 40 IF ASC(K$)<>13 THEN 20
39+
REM 50 PRINT "OK E"
40+
REM 60 END

0 commit comments

Comments
 (0)