wasm-idle 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/clang/app.d.ts +4 -1
- package/dist/clang/app.js +159 -117
- package/dist/clang/index.d.ts +1 -0
- package/dist/clang/index.js +80 -2
- package/dist/debug/expression.js +135 -19
- package/dist/debug/index.d.ts +1 -1
- package/dist/debug/index.js +1 -1
- package/dist/debug/language/index.d.ts +1 -0
- package/dist/debug/language/index.js +1 -0
- package/dist/debug/language/python.d.ts +2 -0
- package/dist/debug/language/python.js +14 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/playground/clang.d.ts +5 -2
- package/dist/playground/clang.js +44 -18
- package/dist/playground/index.d.ts +2 -1
- package/dist/playground/index.js +7 -1
- package/dist/playground/java.d.ts +28 -0
- package/dist/playground/java.js +135 -0
- package/dist/playground/javaStdin.d.ts +8 -0
- package/dist/playground/javaStdin.js +90 -0
- package/dist/playground/options.d.ts +10 -0
- package/dist/playground/python.d.ts +15 -5
- package/dist/playground/python.js +98 -21
- package/dist/playground/sandbox.d.ts +3 -1
- package/dist/playground/stdinBuffer.d.ts +7 -0
- package/dist/playground/stdinBuffer.js +100 -0
- package/dist/playground/teavmConfig.d.ts +3 -0
- package/dist/playground/teavmConfig.js +14 -0
- package/dist/playground/worker/clang.js +2 -20
- package/dist/playground/worker/java.d.ts +1 -0
- package/dist/playground/worker/java.js +248 -0
- package/dist/playground/worker/python.js +253 -27
- package/dist/terminal/Terminal.svelte +41 -11
- package/dist/terminal/Terminal.svelte.d.ts +2 -1
- package/dist/terminal/types.d.ts +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
Executes C++, Python
|
|
5
|
+
Executes C++, Python, and Java code with working stdio.
|
|
6
6
|
|
|
7
7
|
Refer to src/lib/clang.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Java uses TeaVM's browser compiler/runtime. TeaVM compiler/runtime/classlib assets are bundled under `static/teavm/` by default, and the asset base URL can be overridden with `PUBLIC_TEAVM_BASE_URL`.
|
|
10
|
+
|
|
11
|
+
Powered by [wasm-clang](https://github.com/binji/wasm-clang), Pyodide, and TeaVM.
|
package/dist/clang/app.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ interface DebugSession {
|
|
|
18
18
|
nextLineFunctionId: number;
|
|
19
19
|
nextLineLine: number;
|
|
20
20
|
variableMetadata: Record<number, DebugVariableMetadata[]>;
|
|
21
|
+
globalVariableMetadata: DebugVariableMetadata[];
|
|
21
22
|
functionMetadata: Record<number, string>;
|
|
22
23
|
frames: Array<{
|
|
23
24
|
functionId: number;
|
|
@@ -25,6 +26,7 @@ interface DebugSession {
|
|
|
25
26
|
line: number;
|
|
26
27
|
values: Map<number, string>;
|
|
27
28
|
}>;
|
|
29
|
+
globalValues: Map<number, string>;
|
|
28
30
|
onPause?: (event: {
|
|
29
31
|
type: 'pause';
|
|
30
32
|
line: number;
|
|
@@ -50,7 +52,8 @@ export default class App {
|
|
|
50
52
|
constructor(module: WebAssembly.Module, memfs: MemFS, name: string, ...args: string[]);
|
|
51
53
|
run(): Promise<boolean | undefined>;
|
|
52
54
|
proc_exit(code: number): void;
|
|
53
|
-
|
|
55
|
+
private pauseDebugSession;
|
|
56
|
+
__wasm_idle_debug_enter(functionId: number, line: number): number;
|
|
54
57
|
__wasm_idle_debug_leave(functionId: number): number;
|
|
55
58
|
__wasm_idle_debug_value_num(functionId: number, slot: number, value: number): number;
|
|
56
59
|
__wasm_idle_debug_value_bool(functionId: number, slot: number, value: number): number;
|
package/dist/clang/app.js
CHANGED
|
@@ -68,119 +68,9 @@ export default class App {
|
|
|
68
68
|
proc_exit(code) {
|
|
69
69
|
throw new ProcExit(code);
|
|
70
70
|
}
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
if (!
|
|
74
|
-
return ESUCCESS;
|
|
75
|
-
session.callDepth += 1;
|
|
76
|
-
session.currentFunctionId = functionId;
|
|
77
|
-
session.frames.push({
|
|
78
|
-
functionId,
|
|
79
|
-
functionName: session.functionMetadata[functionId] || `fn_${functionId}`,
|
|
80
|
-
line: 0,
|
|
81
|
-
values: new Map()
|
|
82
|
-
});
|
|
83
|
-
this.trace(`enter(function=${functionId}, depth=${session.callDepth})`);
|
|
84
|
-
return ESUCCESS;
|
|
85
|
-
}
|
|
86
|
-
__wasm_idle_debug_leave(functionId) {
|
|
87
|
-
const session = this.debugSession;
|
|
88
|
-
if (!session?.buffer)
|
|
89
|
-
return ESUCCESS;
|
|
90
|
-
this.trace(`leave(function=${functionId}, depth=${session.callDepth})`);
|
|
91
|
-
session.callDepth = Math.max(0, session.callDepth - 1);
|
|
92
|
-
if (session.currentFunctionId === functionId)
|
|
93
|
-
session.currentFunctionId = 0;
|
|
94
|
-
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
95
|
-
if (session.frames[index]?.functionId === functionId) {
|
|
96
|
-
session.frames.splice(index, 1);
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return ESUCCESS;
|
|
101
|
-
}
|
|
102
|
-
__wasm_idle_debug_value_num(functionId, slot, value) {
|
|
103
|
-
const session = this.debugSession;
|
|
104
|
-
if (!session?.buffer)
|
|
105
|
-
return ESUCCESS;
|
|
106
|
-
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
107
|
-
const frame = session.frames[index];
|
|
108
|
-
if (frame?.functionId !== functionId)
|
|
109
|
-
continue;
|
|
110
|
-
frame.values.set(slot, Number.isInteger(value) ? String(value) : `${value}`);
|
|
111
|
-
break;
|
|
112
|
-
}
|
|
113
|
-
return ESUCCESS;
|
|
114
|
-
}
|
|
115
|
-
__wasm_idle_debug_value_bool(functionId, slot, value) {
|
|
116
|
-
const session = this.debugSession;
|
|
117
|
-
if (!session?.buffer)
|
|
118
|
-
return ESUCCESS;
|
|
119
|
-
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
120
|
-
const frame = session.frames[index];
|
|
121
|
-
if (frame?.functionId !== functionId)
|
|
122
|
-
continue;
|
|
123
|
-
frame.values.set(slot, value ? 'true' : 'false');
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
return ESUCCESS;
|
|
127
|
-
}
|
|
128
|
-
__wasm_idle_debug_value_addr(functionId, slot, value) {
|
|
129
|
-
const session = this.debugSession;
|
|
130
|
-
if (!session?.buffer)
|
|
131
|
-
return ESUCCESS;
|
|
132
|
-
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
133
|
-
const frame = session.frames[index];
|
|
134
|
-
if (frame?.functionId !== functionId)
|
|
135
|
-
continue;
|
|
136
|
-
frame.values.set(slot, String(value >>> 0));
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
return ESUCCESS;
|
|
140
|
-
}
|
|
141
|
-
__wasm_idle_debug_value_text(functionId, slot, ptr, len) {
|
|
142
|
-
const session = this.debugSession;
|
|
143
|
-
if (!session?.buffer)
|
|
144
|
-
return ESUCCESS;
|
|
145
|
-
this.mem?.check?.();
|
|
146
|
-
const text = this.mem?.readStr ? this.mem.readStr(ptr, len) : '?';
|
|
147
|
-
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
148
|
-
const frame = session.frames[index];
|
|
149
|
-
if (frame?.functionId !== functionId)
|
|
150
|
-
continue;
|
|
151
|
-
frame.values.set(slot, text);
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
return ESUCCESS;
|
|
155
|
-
}
|
|
156
|
-
__wasm_idle_debug_line(functionId, line) {
|
|
157
|
-
const session = this.debugSession;
|
|
158
|
-
if (!session?.buffer)
|
|
159
|
-
return ESUCCESS;
|
|
160
|
-
if (session.resumeSkipActive) {
|
|
161
|
-
if (functionId === session.resumeSkipFunctionId && line === session.resumeSkipLine) {
|
|
162
|
-
return ESUCCESS;
|
|
163
|
-
}
|
|
164
|
-
session.resumeSkipActive = false;
|
|
165
|
-
session.resumeSkipFunctionId = 0;
|
|
166
|
-
session.resumeSkipLine = 0;
|
|
167
|
-
}
|
|
168
|
-
let reason = '';
|
|
169
|
-
if (session.pauseOnEntry)
|
|
170
|
-
reason = 'entry';
|
|
171
|
-
else if (session.breakpoints.has(line))
|
|
172
|
-
reason = 'breakpoint';
|
|
173
|
-
else if (session.stepArmed)
|
|
174
|
-
reason = 'step';
|
|
175
|
-
else if (session.nextLineArmed &&
|
|
176
|
-
functionId === session.nextLineFunctionId &&
|
|
177
|
-
line !== session.nextLineLine) {
|
|
178
|
-
reason = 'nextLine';
|
|
179
|
-
}
|
|
180
|
-
else if (session.stepOutArmed && session.callDepth <= session.stepOutDepth) {
|
|
181
|
-
reason = 'stepOut';
|
|
182
|
-
}
|
|
183
|
-
if (!reason)
|
|
71
|
+
pauseDebugSession(session, functionId, line, reason) {
|
|
72
|
+
const buffer = session.buffer;
|
|
73
|
+
if (!buffer)
|
|
184
74
|
return ESUCCESS;
|
|
185
75
|
session.currentFunctionId = functionId;
|
|
186
76
|
session.currentLine = line;
|
|
@@ -280,23 +170,32 @@ export default class App {
|
|
|
280
170
|
const value = frame?.values.get(variable.slot) ?? '?';
|
|
281
171
|
return [{ name: variable.name, value }];
|
|
282
172
|
}) || [];
|
|
173
|
+
const localNames = new Set(locals.map((variable) => variable.name));
|
|
174
|
+
const globals = (session.globalVariableMetadata || []).flatMap((variable) => {
|
|
175
|
+
if (localNames.has(variable.name))
|
|
176
|
+
return [];
|
|
177
|
+
if (line < variable.fromLine || line > variable.toLine)
|
|
178
|
+
return [];
|
|
179
|
+
const value = session.globalValues?.get(variable.slot) ?? '?';
|
|
180
|
+
return [{ name: variable.name, value }];
|
|
181
|
+
}) || [];
|
|
283
182
|
session.onPause?.({
|
|
284
183
|
type: 'pause',
|
|
285
184
|
line,
|
|
286
185
|
reason,
|
|
287
|
-
locals,
|
|
186
|
+
locals: [...locals, ...globals],
|
|
288
187
|
callStack: [...session.frames]
|
|
289
188
|
.reverse()
|
|
290
189
|
.map((stackFrame) => ({ functionName: stackFrame.functionName, line: stackFrame.line }))
|
|
291
190
|
});
|
|
292
|
-
const sequence = Atomics.load(
|
|
191
|
+
const sequence = Atomics.load(buffer, 0);
|
|
293
192
|
while (true) {
|
|
294
193
|
if (session.interruptBuffer?.[0] === 2)
|
|
295
194
|
throw new AbortError();
|
|
296
|
-
Atomics.wait(
|
|
195
|
+
Atomics.wait(buffer, 0, sequence, 100);
|
|
297
196
|
if (session.interruptBuffer?.[0] === 2)
|
|
298
197
|
throw new AbortError();
|
|
299
|
-
const command = Atomics.exchange(
|
|
198
|
+
const command = Atomics.exchange(buffer, 1, 0);
|
|
300
199
|
if (command === 1) {
|
|
301
200
|
session.resumeSkipActive = true;
|
|
302
201
|
session.resumeSkipFunctionId = session.currentFunctionId;
|
|
@@ -329,6 +228,149 @@ export default class App {
|
|
|
329
228
|
}
|
|
330
229
|
}
|
|
331
230
|
}
|
|
231
|
+
__wasm_idle_debug_enter(functionId, line) {
|
|
232
|
+
const session = this.debugSession;
|
|
233
|
+
if (!session?.buffer)
|
|
234
|
+
return ESUCCESS;
|
|
235
|
+
session.callDepth += 1;
|
|
236
|
+
session.currentFunctionId = functionId;
|
|
237
|
+
session.currentLine = line;
|
|
238
|
+
session.frames.push({
|
|
239
|
+
functionId,
|
|
240
|
+
functionName: session.functionMetadata[functionId] || `fn_${functionId}`,
|
|
241
|
+
line,
|
|
242
|
+
values: new Map()
|
|
243
|
+
});
|
|
244
|
+
this.trace(`enter(function=${functionId}, line=${line}, depth=${session.callDepth})`);
|
|
245
|
+
if (session.pauseOnEntry) {
|
|
246
|
+
return this.pauseDebugSession(session, functionId, line, 'entry');
|
|
247
|
+
}
|
|
248
|
+
if (session.stepArmed) {
|
|
249
|
+
return this.pauseDebugSession(session, functionId, line, 'step');
|
|
250
|
+
}
|
|
251
|
+
return ESUCCESS;
|
|
252
|
+
}
|
|
253
|
+
__wasm_idle_debug_leave(functionId) {
|
|
254
|
+
const session = this.debugSession;
|
|
255
|
+
if (!session?.buffer)
|
|
256
|
+
return ESUCCESS;
|
|
257
|
+
this.trace(`leave(function=${functionId}, depth=${session.callDepth})`);
|
|
258
|
+
if (session.nextLineArmed && functionId === session.nextLineFunctionId) {
|
|
259
|
+
session.nextLineArmed = false;
|
|
260
|
+
session.stepArmed = true;
|
|
261
|
+
}
|
|
262
|
+
session.callDepth = Math.max(0, session.callDepth - 1);
|
|
263
|
+
if (session.currentFunctionId === functionId)
|
|
264
|
+
session.currentFunctionId = 0;
|
|
265
|
+
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
266
|
+
if (session.frames[index]?.functionId === functionId) {
|
|
267
|
+
session.frames.splice(index, 1);
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return ESUCCESS;
|
|
272
|
+
}
|
|
273
|
+
__wasm_idle_debug_value_num(functionId, slot, value) {
|
|
274
|
+
const session = this.debugSession;
|
|
275
|
+
if (!session?.buffer)
|
|
276
|
+
return ESUCCESS;
|
|
277
|
+
if (functionId === 0) {
|
|
278
|
+
session.globalValues.set(slot, Number.isInteger(value) ? String(value) : `${value}`);
|
|
279
|
+
return ESUCCESS;
|
|
280
|
+
}
|
|
281
|
+
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
282
|
+
const frame = session.frames[index];
|
|
283
|
+
if (frame?.functionId !== functionId)
|
|
284
|
+
continue;
|
|
285
|
+
frame.values.set(slot, Number.isInteger(value) ? String(value) : `${value}`);
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
return ESUCCESS;
|
|
289
|
+
}
|
|
290
|
+
__wasm_idle_debug_value_bool(functionId, slot, value) {
|
|
291
|
+
const session = this.debugSession;
|
|
292
|
+
if (!session?.buffer)
|
|
293
|
+
return ESUCCESS;
|
|
294
|
+
if (functionId === 0) {
|
|
295
|
+
session.globalValues.set(slot, value ? 'true' : 'false');
|
|
296
|
+
return ESUCCESS;
|
|
297
|
+
}
|
|
298
|
+
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
299
|
+
const frame = session.frames[index];
|
|
300
|
+
if (frame?.functionId !== functionId)
|
|
301
|
+
continue;
|
|
302
|
+
frame.values.set(slot, value ? 'true' : 'false');
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
return ESUCCESS;
|
|
306
|
+
}
|
|
307
|
+
__wasm_idle_debug_value_addr(functionId, slot, value) {
|
|
308
|
+
const session = this.debugSession;
|
|
309
|
+
if (!session?.buffer)
|
|
310
|
+
return ESUCCESS;
|
|
311
|
+
if (functionId === 0) {
|
|
312
|
+
session.globalValues.set(slot, String(value >>> 0));
|
|
313
|
+
return ESUCCESS;
|
|
314
|
+
}
|
|
315
|
+
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
316
|
+
const frame = session.frames[index];
|
|
317
|
+
if (frame?.functionId !== functionId)
|
|
318
|
+
continue;
|
|
319
|
+
frame.values.set(slot, String(value >>> 0));
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
return ESUCCESS;
|
|
323
|
+
}
|
|
324
|
+
__wasm_idle_debug_value_text(functionId, slot, ptr, len) {
|
|
325
|
+
const session = this.debugSession;
|
|
326
|
+
if (!session?.buffer)
|
|
327
|
+
return ESUCCESS;
|
|
328
|
+
this.mem?.check?.();
|
|
329
|
+
const text = this.mem?.readStr ? this.mem.readStr(ptr, len) : '?';
|
|
330
|
+
if (functionId === 0) {
|
|
331
|
+
session.globalValues.set(slot, text);
|
|
332
|
+
return ESUCCESS;
|
|
333
|
+
}
|
|
334
|
+
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
335
|
+
const frame = session.frames[index];
|
|
336
|
+
if (frame?.functionId !== functionId)
|
|
337
|
+
continue;
|
|
338
|
+
frame.values.set(slot, text);
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
return ESUCCESS;
|
|
342
|
+
}
|
|
343
|
+
__wasm_idle_debug_line(functionId, line) {
|
|
344
|
+
const session = this.debugSession;
|
|
345
|
+
if (!session?.buffer)
|
|
346
|
+
return ESUCCESS;
|
|
347
|
+
if (session.resumeSkipActive) {
|
|
348
|
+
if (functionId === session.resumeSkipFunctionId && line === session.resumeSkipLine) {
|
|
349
|
+
return ESUCCESS;
|
|
350
|
+
}
|
|
351
|
+
session.resumeSkipActive = false;
|
|
352
|
+
session.resumeSkipFunctionId = 0;
|
|
353
|
+
session.resumeSkipLine = 0;
|
|
354
|
+
}
|
|
355
|
+
let reason = '';
|
|
356
|
+
if (session.pauseOnEntry)
|
|
357
|
+
reason = 'entry';
|
|
358
|
+
else if (session.breakpoints.has(line))
|
|
359
|
+
reason = 'breakpoint';
|
|
360
|
+
else if (session.stepArmed)
|
|
361
|
+
reason = 'step';
|
|
362
|
+
else if (session.nextLineArmed &&
|
|
363
|
+
functionId === session.nextLineFunctionId &&
|
|
364
|
+
line !== session.nextLineLine) {
|
|
365
|
+
reason = 'nextLine';
|
|
366
|
+
}
|
|
367
|
+
else if (session.stepOutArmed && session.callDepth <= session.stepOutDepth) {
|
|
368
|
+
reason = 'stepOut';
|
|
369
|
+
}
|
|
370
|
+
if (!reason)
|
|
371
|
+
return ESUCCESS;
|
|
372
|
+
return this.pauseDebugSession(session, functionId, line, reason);
|
|
373
|
+
}
|
|
332
374
|
environ_sizes_get(environ_count_out, environ_buf_size_out) {
|
|
333
375
|
this.mem.check();
|
|
334
376
|
let size = 0;
|
package/dist/clang/index.d.ts
CHANGED
package/dist/clang/index.js
CHANGED
|
@@ -52,6 +52,7 @@ export default class Clang {
|
|
|
52
52
|
debugInterruptBuffer;
|
|
53
53
|
onDebugEvent;
|
|
54
54
|
debugVariableMetadata = {};
|
|
55
|
+
debugGlobalMetadata = [];
|
|
55
56
|
debugFunctionMetadata = {};
|
|
56
57
|
lastBuildKey = '';
|
|
57
58
|
path;
|
|
@@ -136,18 +137,21 @@ export default class Clang {
|
|
|
136
137
|
let nextFunctionId = 1;
|
|
137
138
|
let nextVariableSlot = 1;
|
|
138
139
|
let currentFunctionVariables = new Map();
|
|
140
|
+
let globalVariables = new Map();
|
|
139
141
|
let currentFunctionContainers = new Map();
|
|
140
142
|
let inBlockComment = false;
|
|
141
143
|
let pendingFunctionHeader;
|
|
142
144
|
this.debugVariableMetadata = {};
|
|
145
|
+
this.debugGlobalMetadata = [];
|
|
143
146
|
this.debugFunctionMetadata = {};
|
|
147
|
+
const globalInitialization = [];
|
|
144
148
|
const instrumented = [
|
|
145
149
|
'#include <map>',
|
|
146
150
|
'#include <set>',
|
|
147
151
|
'#include <string>',
|
|
148
152
|
'#include <type_traits>',
|
|
149
153
|
'#include <vector>',
|
|
150
|
-
'extern "C" __attribute__((import_module("env"), import_name("__wasm_idle_debug_enter"))) void __wasm_idle_debug_enter(int functionId);',
|
|
154
|
+
'extern "C" __attribute__((import_module("env"), import_name("__wasm_idle_debug_enter"))) void __wasm_idle_debug_enter(int functionId, int line);',
|
|
151
155
|
'extern "C" __attribute__((import_module("env"), import_name("__wasm_idle_debug_leave"))) void __wasm_idle_debug_leave(int functionId);',
|
|
152
156
|
'extern "C" __attribute__((import_module("env"), import_name("__wasm_idle_debug_value_num"))) void __wasm_idle_debug_value_num(int functionId, int slot, double value);',
|
|
153
157
|
'extern "C" __attribute__((import_module("env"), import_name("__wasm_idle_debug_value_bool"))) void __wasm_idle_debug_value_bool(int functionId, int slot, int value);',
|
|
@@ -235,10 +239,64 @@ export default class Clang {
|
|
|
235
239
|
analysisLine = analysisLine.slice(0, lineComment);
|
|
236
240
|
const normalized = analysisLine.trim();
|
|
237
241
|
const inFunctionBody = functionDepth > 0 && braceDepth >= functionDepth;
|
|
242
|
+
const isTopLevelDeclarationContext = functionDepth === 0 &&
|
|
243
|
+
braceDepth === 0 &&
|
|
244
|
+
!normalized.includes('(') &&
|
|
245
|
+
!normalized.startsWith('#');
|
|
238
246
|
const controlHeaderWithoutInlineBlock = /^(while|if|for)\s*\(/.test(normalized) && !normalized.includes('{');
|
|
239
247
|
const leadingInstrumentation = [];
|
|
240
248
|
const trailingInstrumentation = [];
|
|
241
249
|
const declaredContainerNames = new Set();
|
|
250
|
+
const globalDeclarationMatch = isTopLevelDeclarationContext &&
|
|
251
|
+
normalized.match(/^(?:const\s+)?(?:(?:unsigned|signed)\s+)?(?:(?:short|long long|long)\s+)?(int|float|double|bool|char)\s+(.+);$/);
|
|
252
|
+
if (globalDeclarationMatch) {
|
|
253
|
+
const kind = globalDeclarationMatch[1] === 'bool' ? 'bool' : 'number';
|
|
254
|
+
const declarations = [];
|
|
255
|
+
let declarationBuffer = '';
|
|
256
|
+
let declarationBraceDepth = 0;
|
|
257
|
+
for (const character of globalDeclarationMatch[2]) {
|
|
258
|
+
if (character === ',' && declarationBraceDepth === 0) {
|
|
259
|
+
if (declarationBuffer.trim())
|
|
260
|
+
declarations.push(declarationBuffer.trim());
|
|
261
|
+
declarationBuffer = '';
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (character === '{')
|
|
265
|
+
declarationBraceDepth += 1;
|
|
266
|
+
if (character === '}')
|
|
267
|
+
declarationBraceDepth = Math.max(0, declarationBraceDepth - 1);
|
|
268
|
+
declarationBuffer += character;
|
|
269
|
+
}
|
|
270
|
+
if (declarationBuffer.trim())
|
|
271
|
+
declarations.push(declarationBuffer.trim());
|
|
272
|
+
for (const declaration of declarations) {
|
|
273
|
+
const [left] = declaration.split('=');
|
|
274
|
+
const declarator = left?.trim() || '';
|
|
275
|
+
if (/[*&\[]/.test(declarator))
|
|
276
|
+
continue;
|
|
277
|
+
const name = declarator.match(/([A-Za-z_]\w*)\s*$/)?.[1];
|
|
278
|
+
if (!name)
|
|
279
|
+
continue;
|
|
280
|
+
const slot = nextVariableSlot++;
|
|
281
|
+
globalVariables.set(name, {
|
|
282
|
+
slot,
|
|
283
|
+
kind,
|
|
284
|
+
fromLine: index + 1,
|
|
285
|
+
toLine: Number.MAX_SAFE_INTEGER
|
|
286
|
+
});
|
|
287
|
+
this.debugGlobalMetadata = [
|
|
288
|
+
...this.debugGlobalMetadata,
|
|
289
|
+
{
|
|
290
|
+
slot,
|
|
291
|
+
name,
|
|
292
|
+
kind,
|
|
293
|
+
fromLine: index + 1,
|
|
294
|
+
toLine: Number.MAX_SAFE_INTEGER
|
|
295
|
+
}
|
|
296
|
+
];
|
|
297
|
+
globalInitialization.push(`${kind === 'bool' ? '__wasm_idle_debug_value_bool' : '__wasm_idle_debug_value_num'}(0, ${slot}, ${name});`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
242
300
|
if (inFunctionBody &&
|
|
243
301
|
normalized &&
|
|
244
302
|
!normalized.startsWith('#') &&
|
|
@@ -432,6 +490,16 @@ export default class Clang {
|
|
|
432
490
|
break;
|
|
433
491
|
}
|
|
434
492
|
}
|
|
493
|
+
for (const [name, variable] of globalVariables) {
|
|
494
|
+
if (currentFunctionVariables.has(name) || currentFunctionContainers.has(name))
|
|
495
|
+
continue;
|
|
496
|
+
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
497
|
+
if (new RegExp(`(?:^|[^\\w])(?:\\+\\+|--)\\s*${escapedName}\\b`).test(normalized) ||
|
|
498
|
+
new RegExp(`\\b${escapedName}\\s*(?:[+\\-*/%]?=|\\+\\+|--)`).test(normalized) ||
|
|
499
|
+
new RegExp(`&\\s*${escapedName}\\b`).test(normalized)) {
|
|
500
|
+
trailingInstrumentation.push(`${indent}${variable.kind === 'bool' ? '__wasm_idle_debug_value_bool' : '__wasm_idle_debug_value_num'}(0, ${variable.slot}, ${name});`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
435
503
|
}
|
|
436
504
|
if (closeIndex > openIndex) {
|
|
437
505
|
const conditionSource = line.slice(openIndex + 1, closeIndex);
|
|
@@ -516,7 +584,7 @@ export default class Clang {
|
|
|
516
584
|
nextVariableSlot = 1;
|
|
517
585
|
currentFunctionVariables = new Map();
|
|
518
586
|
currentFunctionContainers = new Map();
|
|
519
|
-
instrumented.push(`${indent} __wasm_idle_debug_enter(${currentFunctionId});`);
|
|
587
|
+
instrumented.push(`${indent} __wasm_idle_debug_enter(${currentFunctionId}, ${index + 1});`);
|
|
520
588
|
const parameterSource = startsInlineFunctionBody
|
|
521
589
|
? normalized.slice(normalized.indexOf('(') + 1, normalized.lastIndexOf(')'))
|
|
522
590
|
: pendingFunctionHeader?.parameters || '';
|
|
@@ -629,10 +697,18 @@ export default class Clang {
|
|
|
629
697
|
currentFunctionContainers = new Map();
|
|
630
698
|
}
|
|
631
699
|
}
|
|
700
|
+
if (globalInitialization.length) {
|
|
701
|
+
instrumented.push('struct __wasm_idle_debug_globals_init {');
|
|
702
|
+
instrumented.push(' __wasm_idle_debug_globals_init() {');
|
|
703
|
+
instrumented.push(...globalInitialization.map((line) => ` ${line}`));
|
|
704
|
+
instrumented.push(' }');
|
|
705
|
+
instrumented.push('} __wasm_idle_debug_globals_init_instance;');
|
|
706
|
+
}
|
|
632
707
|
source = instrumented.join('\n');
|
|
633
708
|
}
|
|
634
709
|
else {
|
|
635
710
|
this.debugVariableMetadata = {};
|
|
711
|
+
this.debugGlobalMetadata = [];
|
|
636
712
|
}
|
|
637
713
|
const code = toUtf8(source);
|
|
638
714
|
await this.ready;
|
|
@@ -689,8 +765,10 @@ export default class Clang {
|
|
|
689
765
|
nextLineFunctionId: 0,
|
|
690
766
|
nextLineLine: 0,
|
|
691
767
|
variableMetadata: this.debugVariableMetadata,
|
|
768
|
+
globalVariableMetadata: this.debugGlobalMetadata,
|
|
692
769
|
functionMetadata: this.debugFunctionMetadata,
|
|
693
770
|
frames: [],
|
|
771
|
+
globalValues: new Map(),
|
|
694
772
|
onPause: (event) => this.onDebugEvent?.(event)
|
|
695
773
|
};
|
|
696
774
|
const instantiate = +new Date();
|