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.
Files changed (38) hide show
  1. package/README.md +4 -2
  2. package/dist/clang/app.d.ts +4 -1
  3. package/dist/clang/app.js +159 -117
  4. package/dist/clang/index.d.ts +1 -0
  5. package/dist/clang/index.js +80 -2
  6. package/dist/debug/expression.js +135 -19
  7. package/dist/debug/index.d.ts +1 -1
  8. package/dist/debug/index.js +1 -1
  9. package/dist/debug/language/index.d.ts +1 -0
  10. package/dist/debug/language/index.js +1 -0
  11. package/dist/debug/language/python.d.ts +2 -0
  12. package/dist/debug/language/python.js +14 -0
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.js +1 -1
  15. package/dist/playground/clang.d.ts +5 -2
  16. package/dist/playground/clang.js +44 -18
  17. package/dist/playground/index.d.ts +2 -1
  18. package/dist/playground/index.js +7 -1
  19. package/dist/playground/java.d.ts +28 -0
  20. package/dist/playground/java.js +135 -0
  21. package/dist/playground/javaStdin.d.ts +8 -0
  22. package/dist/playground/javaStdin.js +90 -0
  23. package/dist/playground/options.d.ts +10 -0
  24. package/dist/playground/python.d.ts +15 -5
  25. package/dist/playground/python.js +98 -21
  26. package/dist/playground/sandbox.d.ts +3 -1
  27. package/dist/playground/stdinBuffer.d.ts +7 -0
  28. package/dist/playground/stdinBuffer.js +100 -0
  29. package/dist/playground/teavmConfig.d.ts +3 -0
  30. package/dist/playground/teavmConfig.js +14 -0
  31. package/dist/playground/worker/clang.js +2 -20
  32. package/dist/playground/worker/java.d.ts +1 -0
  33. package/dist/playground/worker/java.js +248 -0
  34. package/dist/playground/worker/python.js +253 -27
  35. package/dist/terminal/Terminal.svelte +41 -11
  36. package/dist/terminal/Terminal.svelte.d.ts +2 -1
  37. package/dist/terminal/types.d.ts +3 -2
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -2,8 +2,10 @@
2
2
 
3
3
  ![wasm-idle](static/image.jpeg)
4
4
 
5
- Executes C++, Python Code with working stdio.
5
+ Executes C++, Python, and Java code with working stdio.
6
6
 
7
7
  Refer to src/lib/clang.
8
8
 
9
- Powered by [wasm-clang](https://github.com/binji/wasm-clang) and Pyodide.
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.
@@ -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
- __wasm_idle_debug_enter(functionId: number): number;
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
- __wasm_idle_debug_enter(functionId) {
72
- const session = this.debugSession;
73
- if (!session?.buffer)
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(session.buffer, 0);
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(session.buffer, 0, sequence, 100);
195
+ Atomics.wait(buffer, 0, sequence, 100);
297
196
  if (session.interruptBuffer?.[0] === 2)
298
197
  throw new AbortError();
299
- const command = Atomics.exchange(session.buffer, 1, 0);
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;
@@ -49,6 +49,7 @@ export default class Clang {
49
49
  }[];
50
50
  }) => void;
51
51
  debugVariableMetadata: Record<number, DebugVariableMetadata[]>;
52
+ debugGlobalMetadata: DebugVariableMetadata[];
52
53
  debugFunctionMetadata: Record<number, string>;
53
54
  lastBuildKey: string;
54
55
  path: string;
@@ -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();