@astrojs/compiler 0.10.1 → 0.11.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.
@@ -151,64 +151,53 @@ const decoder = new TextDecoder('utf-8');
151
151
  let logLine = [];
152
152
  export default class Go {
153
153
  constructor() {
154
- this._callbackTimeouts = new Map();
155
- this._nextCallbackTimeoutID = 1;
156
- const mem = () => {
157
- // The buffer may change when requesting more memory.
158
- return new DataView(this._inst.exports.memory.buffer);
154
+ this.argv = ['js'];
155
+ this.env = {};
156
+ this.exit = (code) => {
157
+ if (code !== 0) {
158
+ console.warn('exit code:', code);
159
+ }
159
160
  };
161
+ this._exitPromise = new Promise((resolve) => {
162
+ this._resolveExitPromise = resolve;
163
+ });
164
+ this._pendingEvent = null;
165
+ this._scheduledTimeouts = new Map();
166
+ this._nextCallbackTimeoutID = 1;
160
167
  const setInt64 = (addr, v) => {
161
- mem().setUint32(addr + 0, v, true);
162
- mem().setUint32(addr + 4, Math.floor(v / 4294967296), true);
168
+ this.mem.setUint32(addr + 0, v, true);
169
+ this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
163
170
  };
164
171
  const getInt64 = (addr) => {
165
- const low = mem().getUint32(addr + 0, true);
166
- const high = mem().getInt32(addr + 4, true);
172
+ const low = this.mem.getUint32(addr + 0, true);
173
+ const high = this.mem.getInt32(addr + 4, true);
167
174
  return low + high * 4294967296;
168
175
  };
169
176
  const loadValue = (addr) => {
170
- const f = mem().getFloat64(addr, true);
177
+ const f = this.mem.getFloat64(addr, true);
171
178
  if (f === 0) {
172
179
  return undefined;
173
180
  }
174
181
  if (!isNaN(f)) {
175
182
  return f;
176
183
  }
177
- const id = mem().getUint32(addr, true);
184
+ const id = this.mem.getUint32(addr, true);
178
185
  return this._values[id];
179
186
  };
180
187
  const storeValue = (addr, v) => {
181
188
  const nanHead = 0x7ff80000;
182
- if (typeof v === 'number') {
189
+ if (typeof v === 'number' && v !== 0) {
183
190
  if (isNaN(v)) {
184
- mem().setUint32(addr + 4, nanHead, true);
185
- mem().setUint32(addr, 0, true);
186
- return;
187
- }
188
- if (v === 0) {
189
- mem().setUint32(addr + 4, nanHead, true);
190
- mem().setUint32(addr, 1, true);
191
+ this.mem.setUint32(addr + 4, nanHead, true);
192
+ this.mem.setUint32(addr, 0, true);
191
193
  return;
192
194
  }
193
- mem().setFloat64(addr, v, true);
195
+ this.mem.setFloat64(addr, v, true);
194
196
  return;
195
197
  }
196
- switch (v) {
197
- case undefined:
198
- mem().setFloat64(addr, 0, true);
199
- return;
200
- case null:
201
- mem().setUint32(addr + 4, nanHead, true);
202
- mem().setUint32(addr, 2, true);
203
- return;
204
- case true:
205
- mem().setUint32(addr + 4, nanHead, true);
206
- mem().setUint32(addr, 3, true);
207
- return;
208
- case false:
209
- mem().setUint32(addr + 4, nanHead, true);
210
- mem().setUint32(addr, 4, true);
211
- return;
198
+ if (v === undefined) {
199
+ this.mem.setFloat64(addr, 0, true);
200
+ return;
212
201
  }
213
202
  let id = this._ids.get(v);
214
203
  if (id === undefined) {
@@ -221,8 +210,13 @@ export default class Go {
221
210
  this._ids.set(v, id);
222
211
  }
223
212
  this._goRefCounts[id]++;
224
- let typeFlag = 1;
213
+ let typeFlag = 0;
225
214
  switch (typeof v) {
215
+ case 'object':
216
+ if (v !== null) {
217
+ typeFlag = 1;
218
+ }
219
+ break;
226
220
  case 'string':
227
221
  typeFlag = 2;
228
222
  break;
@@ -233,84 +227,105 @@ export default class Go {
233
227
  typeFlag = 4;
234
228
  break;
235
229
  }
236
- mem().setUint32(addr + 4, nanHead | typeFlag, true);
237
- mem().setUint32(addr, id, true);
230
+ this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
231
+ this.mem.setUint32(addr, id, true);
238
232
  };
239
- const loadSlice = (array, len, cap) => {
240
- return new Uint8Array(this._inst.exports.memory.buffer, array, len);
233
+ const loadSlice = (addr) => {
234
+ const array = getInt64(addr + 0);
235
+ const len = getInt64(addr + 8);
236
+ return new Uint8Array(this._inst.exports.mem.buffer, array, len);
241
237
  };
242
- const loadSliceOfValues = (array, len, cap) => {
238
+ const loadSliceOfValues = (addr) => {
239
+ const array = getInt64(addr + 0);
240
+ const len = getInt64(addr + 8);
243
241
  const a = new Array(len);
244
242
  for (let i = 0; i < len; i++) {
245
243
  a[i] = loadValue(array + i * 8);
246
244
  }
247
245
  return a;
248
246
  };
249
- const loadString = (ptr, len) => {
250
- return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len));
247
+ const loadString = (addr) => {
248
+ const saddr = getInt64(addr + 0);
249
+ const len = getInt64(addr + 8);
250
+ return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
251
251
  };
252
252
  const timeOrigin = Date.now() - performance.now();
253
253
  this.importObject = {
254
- wasi_snapshot_preview1: {
255
- // https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_write
256
- fd_write: function (fd, iovs_ptr, iovs_len, nwritten_ptr) {
257
- let nwritten = 0;
258
- if (fd == 1) {
259
- for (let iovs_i = 0; iovs_i < iovs_len; iovs_i++) {
260
- let iov_ptr = iovs_ptr + iovs_i * 8; // assuming wasm32
261
- let ptr = mem().getUint32(iov_ptr + 0, true);
262
- let len = mem().getUint32(iov_ptr + 4, true);
263
- for (let i = 0; i < len; i++) {
264
- let c = mem().getUint8(ptr + i);
265
- if (c == 13) {
266
- // CR
267
- // ignore
268
- }
269
- else if (c == 10) {
270
- // LF
271
- // write line
272
- let line = decoder.decode(new Uint8Array(logLine));
273
- logLine = [];
274
- console.log(line);
275
- }
276
- else {
277
- logLine.push(c);
278
- }
279
- }
280
- }
281
- }
282
- else {
283
- console.error('invalid file descriptor:', fd);
284
- }
285
- mem().setUint32(nwritten_ptr, nwritten, true);
286
- return 0;
254
+ go: {
255
+ // Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
256
+ // may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
257
+ // function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
258
+ // This changes the SP, thus we have to update the SP used by the imported function.
259
+ // func wasmExit(code int32)
260
+ 'runtime.wasmExit': (sp) => {
261
+ sp >>>= 0;
262
+ const code = this.mem.getInt32(sp + 8, true);
263
+ this.exited = true;
264
+ delete this._inst;
265
+ delete this._values;
266
+ delete this._goRefCounts;
267
+ delete this._ids;
268
+ delete this._idPool;
269
+ this.exit(code);
287
270
  },
288
- proc_exit: (code) => {
289
- if (globalThis.process) {
290
- // Node.js
291
- process.exit(code);
292
- }
293
- else {
294
- // Can't exit in a browser.
295
- throw 'trying to exit with code ' + code;
296
- }
271
+ // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
272
+ 'runtime.wasmWrite': (sp) => {
273
+ sp >>>= 0;
274
+ const fd = getInt64(sp + 8);
275
+ const p = getInt64(sp + 16);
276
+ const n = this.mem.getInt32(sp + 24, true);
277
+ fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
297
278
  },
298
- },
299
- env: {
300
- // func ticks() float64
301
- 'runtime.ticks': () => {
302
- return timeOrigin + performance.now();
279
+ // func resetMemoryDataView()
280
+ 'runtime.resetMemoryDataView': (sp) => {
281
+ sp >>>= 0;
282
+ this.mem = new DataView(this._inst.exports.mem.buffer);
283
+ },
284
+ // func nanotime1() int64
285
+ 'runtime.nanotime1': (sp) => {
286
+ sp >>>= 0;
287
+ setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
288
+ },
289
+ // func walltime() (sec int64, nsec int32)
290
+ 'runtime.walltime': (sp) => {
291
+ sp >>>= 0;
292
+ const msec = new Date().getTime();
293
+ setInt64(sp + 8, msec / 1000);
294
+ this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
295
+ },
296
+ // func scheduleTimeoutEvent(delay int64) int32
297
+ 'runtime.scheduleTimeoutEvent': (sp) => {
298
+ sp >>>= 0;
299
+ const id = this._nextCallbackTimeoutID;
300
+ this._nextCallbackTimeoutID++;
301
+ this._scheduledTimeouts.set(id, setTimeout(() => {
302
+ this._resume();
303
+ while (this._scheduledTimeouts.has(id)) {
304
+ // for some reason Go failed to register the timeout event, log and try again
305
+ // (temporary workaround for https://github.com/golang/go/issues/28975)
306
+ console.warn('scheduleTimeoutEvent: missed timeout event');
307
+ this._resume();
308
+ }
309
+ }, getInt64(sp + 8) + 1 // setTimeout has been seen to fire up to 1 millisecond early
310
+ ));
311
+ this.mem.setInt32(sp + 16, id, true);
303
312
  },
304
- // func sleepTicks(timeout float64)
305
- 'runtime.sleepTicks': (timeout) => {
306
- // Do not sleep, only reactivate scheduler after the given timeout.
307
- setTimeout(this._inst.exports.go_scheduler, timeout);
313
+ // func clearTimeoutEvent(id int32)
314
+ 'runtime.clearTimeoutEvent': (sp) => {
315
+ sp >>>= 0;
316
+ const id = this.mem.getInt32(sp + 8, true);
317
+ clearTimeout(this._scheduledTimeouts.get(id));
318
+ this._scheduledTimeouts.delete(id);
319
+ },
320
+ // func getRandomData(r []byte)
321
+ 'runtime.getRandomData': (sp) => {
322
+ sp >>>= 0;
323
+ globalThis.crypto.getRandomValues(loadSlice(sp + 8));
308
324
  },
309
325
  // func finalizeRef(v ref)
310
- 'syscall/js.finalizeRef': (v_addr) => {
311
- // Note: TinyGo does not support finalizers so this is only called
312
- // for one specific case, by js.go:jsString.
313
- const id = mem().getUint32(v_addr, true);
326
+ 'syscall/js.finalizeRef': (sp) => {
327
+ sp >>>= 0;
328
+ const id = this.mem.getUint32(sp + 8, true);
314
329
  this._goRefCounts[id]--;
315
330
  if (this._goRefCounts[id] === 0) {
316
331
  const v = this._values[id];
@@ -320,136 +335,152 @@ export default class Go {
320
335
  }
321
336
  },
322
337
  // func stringVal(value string) ref
323
- 'syscall/js.stringVal': (ret_ptr, value_ptr, value_len) => {
324
- const s = loadString(value_ptr, value_len);
325
- storeValue(ret_ptr, s);
338
+ 'syscall/js.stringVal': (sp) => {
339
+ sp >>>= 0;
340
+ storeValue(sp + 24, loadString(sp + 8));
326
341
  },
327
342
  // func valueGet(v ref, p string) ref
328
- 'syscall/js.valueGet': (retval, v_addr, p_ptr, p_len) => {
329
- let prop = loadString(p_ptr, p_len);
330
- let value = loadValue(v_addr);
331
- let result = Reflect.get(value, prop);
332
- storeValue(retval, result);
343
+ 'syscall/js.valueGet': (sp) => {
344
+ sp >>>= 0;
345
+ const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
346
+ sp = this._inst.exports.getsp() >>> 0; // see comment above
347
+ storeValue(sp + 32, result);
333
348
  },
334
349
  // func valueSet(v ref, p string, x ref)
335
- 'syscall/js.valueSet': (v_addr, p_ptr, p_len, x_addr) => {
336
- const v = loadValue(v_addr);
337
- const p = loadString(p_ptr, p_len);
338
- const x = loadValue(x_addr);
339
- Reflect.set(v, p, x);
350
+ 'syscall/js.valueSet': (sp) => {
351
+ sp >>>= 0;
352
+ Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
340
353
  },
341
354
  // func valueDelete(v ref, p string)
342
- 'syscall/js.valueDelete': (v_addr, p_ptr, p_len) => {
343
- const v = loadValue(v_addr);
344
- const p = loadString(p_ptr, p_len);
345
- Reflect.deleteProperty(v, p);
355
+ 'syscall/js.valueDelete': (sp) => {
356
+ sp >>>= 0;
357
+ Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
346
358
  },
347
359
  // func valueIndex(v ref, i int) ref
348
- 'syscall/js.valueIndex': (ret_addr, v_addr, i) => {
349
- storeValue(ret_addr, Reflect.get(loadValue(v_addr), i));
360
+ 'syscall/js.valueIndex': (sp) => {
361
+ sp >>>= 0;
362
+ storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
350
363
  },
351
364
  // valueSetIndex(v ref, i int, x ref)
352
- 'syscall/js.valueSetIndex': (v_addr, i, x_addr) => {
353
- Reflect.set(loadValue(v_addr), i, loadValue(x_addr));
365
+ 'syscall/js.valueSetIndex': (sp) => {
366
+ sp >>>= 0;
367
+ Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
354
368
  },
355
369
  // func valueCall(v ref, m string, args []ref) (ref, bool)
356
- 'syscall/js.valueCall': (ret_addr, v_addr, m_ptr, m_len, args_ptr, args_len, args_cap) => {
357
- const v = loadValue(v_addr);
358
- const name = loadString(m_ptr, m_len);
359
- const args = loadSliceOfValues(args_ptr, args_len, args_cap);
370
+ 'syscall/js.valueCall': (sp) => {
371
+ sp >>>= 0;
360
372
  try {
361
- const m = Reflect.get(v, name);
362
- storeValue(ret_addr, Reflect.apply(m, v, args));
363
- mem().setUint8(ret_addr + 8, 1);
373
+ const v = loadValue(sp + 8);
374
+ const m = Reflect.get(v, loadString(sp + 16));
375
+ const args = loadSliceOfValues(sp + 32);
376
+ const result = Reflect.apply(m, v, args);
377
+ sp = this._inst.exports.getsp() >>> 0; // see comment above
378
+ storeValue(sp + 56, result);
379
+ this.mem.setUint8(sp + 64, 1);
364
380
  }
365
381
  catch (err) {
366
- storeValue(ret_addr, err);
367
- mem().setUint8(ret_addr + 8, 0);
382
+ sp = this._inst.exports.getsp() >>> 0; // see comment above
383
+ storeValue(sp + 56, err);
384
+ this.mem.setUint8(sp + 64, 0);
368
385
  }
369
386
  },
370
387
  // func valueInvoke(v ref, args []ref) (ref, bool)
371
- 'syscall/js.valueInvoke': (ret_addr, v_addr, args_ptr, args_len, args_cap) => {
388
+ 'syscall/js.valueInvoke': (sp) => {
389
+ sp >>>= 0;
372
390
  try {
373
- const v = loadValue(v_addr);
374
- const args = loadSliceOfValues(args_ptr, args_len, args_cap);
375
- storeValue(ret_addr, Reflect.apply(v, undefined, args));
376
- mem().setUint8(ret_addr + 8, 1);
391
+ const v = loadValue(sp + 8);
392
+ const args = loadSliceOfValues(sp + 16);
393
+ const result = Reflect.apply(v, undefined, args);
394
+ sp = this._inst.exports.getsp() >>> 0; // see comment above
395
+ storeValue(sp + 40, result);
396
+ this.mem.setUint8(sp + 48, 1);
377
397
  }
378
398
  catch (err) {
379
- storeValue(ret_addr, err);
380
- mem().setUint8(ret_addr + 8, 0);
399
+ sp = this._inst.exports.getsp() >>> 0; // see comment above
400
+ storeValue(sp + 40, err);
401
+ this.mem.setUint8(sp + 48, 0);
381
402
  }
382
403
  },
383
404
  // func valueNew(v ref, args []ref) (ref, bool)
384
- 'syscall/js.valueNew': (ret_addr, v_addr, args_ptr, args_len, args_cap) => {
385
- const v = loadValue(v_addr);
386
- const args = loadSliceOfValues(args_ptr, args_len, args_cap);
405
+ 'syscall/js.valueNew': (sp) => {
406
+ sp >>>= 0;
387
407
  try {
388
- storeValue(ret_addr, Reflect.construct(v, args));
389
- mem().setUint8(ret_addr + 8, 1);
408
+ const v = loadValue(sp + 8);
409
+ const args = loadSliceOfValues(sp + 16);
410
+ const result = Reflect.construct(v, args);
411
+ sp = this._inst.exports.getsp() >>> 0; // see comment above
412
+ storeValue(sp + 40, result);
413
+ this.mem.setUint8(sp + 48, 1);
390
414
  }
391
415
  catch (err) {
392
- storeValue(ret_addr, err);
393
- mem().setUint8(ret_addr + 8, 0);
416
+ sp = this._inst.exports.getsp() >>> 0; // see comment above
417
+ storeValue(sp + 40, err);
418
+ this.mem.setUint8(sp + 48, 0);
394
419
  }
395
420
  },
396
421
  // func valueLength(v ref) int
397
- 'syscall/js.valueLength': (v_addr) => {
398
- return loadValue(v_addr).length;
422
+ 'syscall/js.valueLength': (sp) => {
423
+ sp >>>= 0;
424
+ setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
399
425
  },
400
426
  // valuePrepareString(v ref) (ref, int)
401
- 'syscall/js.valuePrepareString': (ret_addr, v_addr) => {
402
- const s = String(loadValue(v_addr));
403
- const str = encoder.encode(s);
404
- storeValue(ret_addr, str);
405
- setInt64(ret_addr + 8, str.length);
427
+ 'syscall/js.valuePrepareString': (sp) => {
428
+ sp >>>= 0;
429
+ const str = encoder.encode(String(loadValue(sp + 8)));
430
+ storeValue(sp + 16, str);
431
+ setInt64(sp + 24, str.length);
406
432
  },
407
433
  // valueLoadString(v ref, b []byte)
408
- 'syscall/js.valueLoadString': (v_addr, slice_ptr, slice_len, slice_cap) => {
409
- const str = loadValue(v_addr);
410
- loadSlice(slice_ptr, slice_len, slice_cap).set(str);
434
+ 'syscall/js.valueLoadString': (sp) => {
435
+ sp >>>= 0;
436
+ const str = loadValue(sp + 8);
437
+ loadSlice(sp + 16).set(str);
411
438
  },
412
439
  // func valueInstanceOf(v ref, t ref) bool
413
- 'syscall/js.valueInstanceOf': (v_addr, t_addr) => {
414
- return loadValue(v_addr) instanceof loadValue(t_addr);
440
+ 'syscall/js.valueInstanceOf': (sp) => {
441
+ sp >>>= 0;
442
+ this.mem.setUint8(sp + 24, loadValue(sp + 8) instanceof loadValue(sp + 16) ? 1 : 0);
415
443
  },
416
444
  // func copyBytesToGo(dst []byte, src ref) (int, bool)
417
- 'syscall/js.copyBytesToGo': (ret_addr, dest_addr, dest_len, dest_cap, source_addr) => {
418
- let num_bytes_copied_addr = ret_addr;
419
- let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
420
- const dst = loadSlice(dest_addr, dest_len);
421
- const src = loadValue(source_addr);
422
- if (!(src instanceof Uint8Array)) {
423
- mem().setUint8(returned_status_addr, 0); // Return "not ok" status
445
+ 'syscall/js.copyBytesToGo': (sp) => {
446
+ sp >>>= 0;
447
+ const dst = loadSlice(sp + 8);
448
+ const src = loadValue(sp + 32);
449
+ if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
450
+ this.mem.setUint8(sp + 48, 0);
424
451
  return;
425
452
  }
426
453
  const toCopy = src.subarray(0, dst.length);
427
454
  dst.set(toCopy);
428
- setInt64(num_bytes_copied_addr, toCopy.length);
429
- mem().setUint8(returned_status_addr, 1); // Return "ok" status
455
+ setInt64(sp + 40, toCopy.length);
456
+ this.mem.setUint8(sp + 48, 1);
430
457
  },
431
- // copyBytesToJS(dst ref, src []byte) (int, bool)
432
- // Originally copied from upstream Go project, then modified:
433
- // https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416
434
- 'syscall/js.copyBytesToJS': (ret_addr, dest_addr, source_addr, source_len, source_cap) => {
435
- let num_bytes_copied_addr = ret_addr;
436
- let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
437
- const dst = loadValue(dest_addr);
438
- const src = loadSlice(source_addr, source_len);
439
- if (!(dst instanceof Uint8Array)) {
440
- mem().setUint8(returned_status_addr, 0); // Return "not ok" status
458
+ // func copyBytesToJS(dst ref, src []byte) (int, bool)
459
+ 'syscall/js.copyBytesToJS': (sp) => {
460
+ sp >>>= 0;
461
+ const dst = loadValue(sp + 8);
462
+ const src = loadSlice(sp + 16);
463
+ if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
464
+ this.mem.setUint8(sp + 48, 0);
441
465
  return;
442
466
  }
443
467
  const toCopy = src.subarray(0, dst.length);
444
468
  dst.set(toCopy);
445
- setInt64(num_bytes_copied_addr, toCopy.length);
446
- mem().setUint8(returned_status_addr, 1); // Return "ok" status
469
+ setInt64(sp + 40, toCopy.length);
470
+ this.mem.setUint8(sp + 48, 1);
471
+ },
472
+ debug: (value) => {
473
+ console.log(value);
447
474
  },
448
475
  },
449
476
  };
450
477
  }
451
478
  async run(instance) {
479
+ if (!(instance instanceof WebAssembly.Instance)) {
480
+ throw new Error('Go.run: WebAssembly.Instance expected');
481
+ }
452
482
  this._inst = instance;
483
+ this.mem = new DataView(this._inst.exports.mem.buffer);
453
484
  this._values = [
454
485
  // JS values that Go currently has references to, indexed by reference id
455
486
  NaN,
@@ -460,26 +491,52 @@ export default class Go {
460
491
  globalThis,
461
492
  this,
462
493
  ];
463
- this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
464
- this._ids = new Map(); // mapping from JS values to reference ids
494
+ this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
495
+ this._ids = new Map([
496
+ // mapping from JS values to reference ids
497
+ [0, 1],
498
+ [null, 2],
499
+ [true, 3],
500
+ [false, 4],
501
+ [globalThis, 5],
502
+ [this, 6],
503
+ ]);
465
504
  this._idPool = []; // unused ids that have been garbage collected
466
505
  this.exited = false; // whether the Go program has exited
467
- const mem = new DataView(this._inst.exports.memory.buffer);
468
- while (true) {
469
- const callbackPromise = new Promise((resolve) => {
470
- this._resolveCallbackPromise = () => {
471
- if (this.exited) {
472
- throw new Error('bad callback: Go program has already exited');
473
- }
474
- setTimeout(resolve, 0); // make sure it is asynchronous
475
- };
476
- });
477
- this._inst.exports._start();
478
- if (this.exited) {
479
- break;
506
+ // Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
507
+ let offset = 4096;
508
+ const strPtr = (str) => {
509
+ const ptr = offset;
510
+ const bytes = encoder.encode(str + '\0');
511
+ new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
512
+ offset += bytes.length;
513
+ if (offset % 8 !== 0) {
514
+ offset += 8 - (offset % 8);
480
515
  }
481
- await callbackPromise;
516
+ return ptr;
517
+ };
518
+ const argc = this.argv.length;
519
+ const argvPtrs = [];
520
+ this.argv.forEach((arg) => {
521
+ argvPtrs.push(strPtr(arg));
522
+ });
523
+ argvPtrs.push(0);
524
+ const keys = Object.keys(this.env).sort();
525
+ keys.forEach((key) => {
526
+ argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
527
+ });
528
+ argvPtrs.push(0);
529
+ const argv = offset;
530
+ argvPtrs.forEach((ptr) => {
531
+ this.mem.setUint32(offset, ptr, true);
532
+ this.mem.setUint32(offset + 4, 0, true);
533
+ offset += 8;
534
+ });
535
+ this._inst.exports.run(argc, argv);
536
+ if (this.exited) {
537
+ this._resolveExitPromise();
482
538
  }
539
+ await this._exitPromise;
483
540
  }
484
541
  _resume() {
485
542
  if (this.exited) {
package/node/index.js CHANGED
@@ -27,13 +27,7 @@ const startRunningService = async () => {
27
27
  const go = new Go();
28
28
  const wasm = await instantiateWASM(fileURLToPath(new URL('../astro.wasm', import.meta.url)), go.importObject);
29
29
  go.run(wasm.instance);
30
- const apiKeys = new Set(['transform']);
31
- const service = Object.create(null);
32
- for (const key of apiKeys.values()) {
33
- const globalKey = `__astro_${key}`;
34
- service[key] = globalThis[globalKey];
35
- delete globalThis[globalKey];
36
- }
30
+ const service = globalThis['@astrojs/compiler'];
37
31
  longLivedService = {
38
32
  transform: (input, options) => new Promise((resolve) => resolve(service.transform(input, options || {}))),
39
33
  };
@@ -1,5 +1,33 @@
1
1
  export default class Go {
2
- importObject: Record<string, any>;
2
+ importObject: {
3
+ go: {
4
+ 'runtime.wasmExit': (sp: any) => void;
5
+ 'runtime.wasmWrite': (sp: any) => void;
6
+ 'runtime.resetMemoryDataView': (sp: any) => void;
7
+ 'runtime.nanotime1': (sp: any) => void;
8
+ 'runtime.walltime': (sp: any) => void;
9
+ 'runtime.scheduleTimeoutEvent': (sp: any) => void;
10
+ 'runtime.clearTimeoutEvent': (sp: any) => void;
11
+ 'runtime.getRandomData': (sp: any) => void;
12
+ 'syscall/js.finalizeRef': (sp: any) => void;
13
+ 'syscall/js.stringVal': (sp: any) => void;
14
+ 'syscall/js.valueGet': (sp: any) => void;
15
+ 'syscall/js.valueSet': (sp: any) => void;
16
+ 'syscall/js.valueDelete': (sp: any) => void;
17
+ 'syscall/js.valueIndex': (sp: any) => void;
18
+ 'syscall/js.valueSetIndex': (sp: any) => void;
19
+ 'syscall/js.valueCall': (sp: any) => void;
20
+ 'syscall/js.valueInvoke': (sp: any) => void;
21
+ 'syscall/js.valueNew': (sp: any) => void;
22
+ 'syscall/js.valueLength': (sp: any) => void;
23
+ 'syscall/js.valuePrepareString': (sp: any) => void;
24
+ 'syscall/js.valueLoadString': (sp: any) => void;
25
+ 'syscall/js.valueInstanceOf': (sp: any) => void;
26
+ 'syscall/js.copyBytesToGo': (sp: any) => void;
27
+ 'syscall/js.copyBytesToJS': (sp: any) => void;
28
+ debug: (value: any) => void;
29
+ };
30
+ };
3
31
  constructor();
4
32
  run(instance: any): Promise<void>;
5
33
  private _resume;