porffor 0.16.0-594397507 → 0.16.0-5c5338783

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/CONTRIBUTING.md CHANGED
@@ -26,7 +26,7 @@ You can also swap out `node` in the alias to use another runtime like Deno (`den
26
26
 
27
27
  ### Precompile
28
28
 
29
- **If you update any file inside `compiler/builtins` you will need to do this for it to update inside Porffor otherwise your changes will have no effect.** Run `node compiler/precompile.js` to precompile. It may error during this, if so, you might have an error in your code or there could be a compiler error with Porffor (feel free to ask for help as soon as you encounter any errors with it).
29
+ **If you update any file inside `compiler/builtins` you will need to do this for it to update inside Porffor otherwise your changes will have no effect.** Run `./porf precompile` to precompile. It may error during this, if so, you might have an error in your code or there could be a compiler error with Porffor (feel free to ask for help as soon as you encounter any errors with it).
30
30
 
31
31
  <br>
32
32
 
package/compiler/2c.js CHANGED
@@ -29,8 +29,8 @@ typedef double f64;
29
29
  f64 NAN = 0e+0/0e+0;
30
30
 
31
31
  struct ReturnValue {
32
- ${CValtype.f64} value;
33
- ${CValtype.i32} type;
32
+ f64 value;
33
+ i32 type;
34
34
  };\n\n`;
35
35
 
36
36
  // todo: is memcpy/etc safe with host endianness?
@@ -41,60 +41,60 @@ const CMemFuncs = {
41
41
  [Opcodes.i32_store]: {
42
42
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
43
43
  args: ['pointer', 'value'],
44
- argTypes: [CValtype.i32, CValtype.i32],
44
+ argTypes: ['i32', 'i32'],
45
45
  returns: false
46
46
  },
47
47
  [Opcodes.i32_store16]: {
48
48
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
49
49
  args: ['pointer', 'value'],
50
- argTypes: [CValtype.i32, CValtype.i16],
50
+ argTypes: ['i32', 'i16'],
51
51
  returns: false
52
52
  },
53
53
  [Opcodes.i32_store8]: {
54
54
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
55
55
  args: ['pointer', 'value'],
56
- argTypes: [CValtype.i32, CValtype.i8],
56
+ argTypes: ['i32', 'i8'],
57
57
  returns: false
58
58
  },
59
59
 
60
60
  [Opcodes.i32_load]: {
61
- c: `${CValtype.i32} out;
61
+ c: `i32 out;
62
62
  memcpy(&out, _memory + offset + pointer, sizeof(out));
63
63
  return out;`,
64
64
  args: ['pointer'],
65
- argTypes: [CValtype.i32],
66
- returns: CValtype.i32
65
+ argTypes: ['i32'],
66
+ returns: 'i32'
67
67
  },
68
68
  [Opcodes.i32_load16_u]: {
69
- c: `${CValtype.i16} out;
69
+ c: `i16 out;
70
70
  memcpy(&out, _memory + offset + pointer, sizeof(out));
71
71
  return out;`,
72
72
  args: ['pointer'],
73
- argTypes: [CValtype.i32],
74
- returns: CValtype.i32
73
+ argTypes: ['i32'],
74
+ returns: 'i32'
75
75
  },
76
76
  [Opcodes.i32_load8_u]: {
77
- c: `${CValtype.i8} out;
77
+ c: `i8 out;
78
78
  memcpy(&out, _memory + offset + pointer, sizeof(out));
79
79
  return out;`,
80
80
  args: ['pointer'],
81
- argTypes: [CValtype.i32],
82
- returns: CValtype.i32
81
+ argTypes: ['i32'],
82
+ returns: 'i32'
83
83
  },
84
84
 
85
85
  [Opcodes.f64_store]: {
86
86
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
87
87
  args: ['pointer', 'value'],
88
- argTypes: [CValtype.i32, CValtype.f64],
88
+ argTypes: ['i32', 'f64'],
89
89
  returns: false
90
90
  },
91
91
  [Opcodes.f64_load]: {
92
- c: `${CValtype.f64} out;
92
+ c: `f64 out;
93
93
  memcpy(&out, _memory + offset + pointer, sizeof(out));
94
94
  return out;`,
95
95
  args: ['pointer'],
96
- argTypes: [CValtype.i32],
97
- returns: CValtype.f64
96
+ argTypes: ['i32'],
97
+ returns: 'f64'
98
98
  },
99
99
  };
100
100
 
@@ -108,7 +108,7 @@ for (const x in CValtype) {
108
108
 
109
109
  const removeBrackets = str => {
110
110
  // return str;
111
- // if (str.startsWith(`(${CValtype.i32})(${CValtype.u32})`)) return `(${CValtype.i32})(${CValtype.u32})(` + removeBrackets(str.slice(22, -1)) + ')';
111
+ // if (str.startsWith('(i32)(u32)')) return '(i32)(u32)(' + removeBrackets(str.slice(22, -1)) + ')';
112
112
 
113
113
  for (const x in CValtype) {
114
114
  const p = `(${x})`;
@@ -156,7 +156,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
156
156
  }
157
157
 
158
158
  if (data.length > 0) {
159
- prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n'));
159
+ prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n '));
160
160
  }
161
161
 
162
162
  if (importFuncs.find(x => x.name === '__Porffor_readArgv')) {
@@ -168,10 +168,10 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
168
168
 
169
169
  let depth = 1;
170
170
  let brDepth = 0;
171
- const line = (str, semi = true) => out += `${' '.repeat(depth * 2 + brDepth * 2)}${str}${semi ? ';' : ''}\n`;
171
+ const line = (str, semi = true) => out += `${' '.repeat((depth + brDepth) * 2)}${str}${semi ? ';' : ''}\n`;
172
172
  const lines = lines => {
173
173
  for (const x of lines) {
174
- out += `${' '.repeat(depth * 2)}${x}\n`;
174
+ out += `${' '.repeat((depth + brDepth) * 2)}${x}\n`;
175
175
  }
176
176
  };
177
177
 
@@ -219,10 +219,10 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
219
219
 
220
220
  const shouldInline = false; // f.internal;
221
221
  if (f.name === 'main') out += `int main(${prependMain.has('argv') ? 'int argc, char* argv[]' : ''}) {\n`;
222
- else out += `${f.internal ? (returns ? CValtype.f64 : 'void') : 'struct ReturnValue'} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
222
+ else out += `${f.internal ? (returns ? 'f64' : 'void') : 'struct ReturnValue'} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
223
223
 
224
224
  if (f.name === 'main') {
225
- out += [...prependMain.values()].join('\n');
225
+ out += ' ' + [...prependMain.values()].join('\n ');
226
226
  if (prependMain.size > 0) out += '\n\n';
227
227
  }
228
228
 
@@ -283,12 +283,12 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
283
283
  switch (i[1]) {
284
284
  // i32_trunc_sat_f64_s
285
285
  case 0x02:
286
- vals.push(`(${CValtype.i32})(${vals.pop()})`);
286
+ vals.push(`(i32)(${vals.pop()})`);
287
287
  break;
288
288
 
289
289
  // i32_trunc_sat_f64_u
290
290
  case 0x03:
291
- vals.push(`(${CValtype.u32})(${vals.pop()})`);
291
+ vals.push(`(u32)(${vals.pop()})`);
292
292
  break;
293
293
  }
294
294
 
@@ -337,7 +337,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
337
337
 
338
338
  case Opcodes.f64_trunc:
339
339
  // vals.push(`trunc(${vals.pop()})`);
340
- vals.push(`(${CValtype.i32})(${removeBrackets(vals.pop())})`); // this is ~10x faster with clang??
340
+ vals.push(`(i32)(${removeBrackets(vals.pop())})`); // this is ~10x faster with clang??
341
341
  break;
342
342
 
343
343
  case Opcodes.f64_convert_i32_u:
@@ -345,7 +345,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
345
345
  case Opcodes.f64_convert_i64_u:
346
346
  case Opcodes.f64_convert_i64_s:
347
347
  // int to f64
348
- vals.push(`(${CValtype.f64})(${removeBrackets(vals.pop())})`);
348
+ vals.push(`(f64)(${removeBrackets(vals.pop())})`);
349
349
  break;
350
350
 
351
351
  case Opcodes.i32_eqz:
@@ -353,7 +353,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
353
353
  vals.push(`!(${removeBrackets(vals.pop())})`);
354
354
  } else {
355
355
  let cond = '(' + removeBrackets(vals.pop());
356
- if (cond.startsWith(`(${CValtype.i32})`)) cond = `${cond.slice(`(${CValtype.i32})`.length)}) == 0e+0`;
356
+ if (cond.startsWith(`(i32)`)) cond = `${cond.slice(5)} == 0e+0`;
357
357
  else cond += ') == 0';
358
358
  vals.push(cond);
359
359
  }
@@ -368,7 +368,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
368
368
  case Opcodes.if: {
369
369
  let cond = removeBrackets(vals.pop());
370
370
  if (!lastCond) {
371
- if (cond.startsWith(`(${CValtype.i32})`)) cond = `(${cond.slice(`(${CValtype.i32})`.length)}) != 0e+0`;
371
+ if (cond.startsWith(`(i32)`)) cond = `${cond.slice(5)} != 0e+0`;
372
372
  else cond = `(${cond}) != 0`;
373
373
  }
374
374
 
@@ -434,28 +434,16 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
434
434
  const importFunc = importFuncs[i[1]];
435
435
  switch (importFunc.name) {
436
436
  case 'print':
437
- // line(`printf("%f\\n", ${vals.pop()})`);
438
437
  line(`printf("${valtype === 'f64' ? '%g' : '%i'}\\n", ${vals.pop()})`);
439
438
  includes.set('stdio.h', true);
440
439
  break;
441
440
  case 'printChar':
442
- line(`printf("%c", (int)(${vals.pop()}))`);
441
+ line(`putchar((int)(${vals.pop()}))`);
443
442
  includes.set('stdio.h', true);
444
443
  break;
445
444
 
446
445
  case 'time':
447
446
  line(`double _time_out`);
448
- /* platformSpecific(
449
- `FILETIME _time_filetime;
450
- GetSystemTimeAsFileTime(&_time_filetime);
451
-
452
- ULARGE_INTEGER _time_ularge;
453
- _time_ularge.LowPart = _time_filetime.dwLowDateTime;
454
- _time_ularge.HighPart = _time_filetime.dwHighDateTime;
455
- _time_out = (_time_ularge.QuadPart - 116444736000000000i64) / 10000.;`,
456
- `struct timespec _time;
457
- clock_gettime(CLOCK_MONOTONIC, &_time);
458
- _time_out = _time.tv_nsec / 1000000.;`); */
459
447
  platformSpecific(
460
448
  `LARGE_INTEGER _time_freq, _time_t;
461
449
  QueryPerformanceFrequency(&_time_freq);
@@ -470,14 +458,11 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
470
458
  winIncludes.set('windows.h', true);
471
459
  break;
472
460
 
473
- case '__Porffor_readArgv':
474
- includes.set('stdlib.h', true);
475
-
461
+ case '__Porffor_readArgv': {
476
462
  prepend.set('__Porffor_readArgv',
477
- `void __Porffor_readArgv(u32 index, u32 outPtr) {
463
+ `i32 __Porffor_readArgv(u32 index, u32 outPtr) {
478
464
  if (index >= _argc) {
479
- printf("expected %d arguments\\n", index);
480
- exit(1);
465
+ return -1;
481
466
  }
482
467
 
483
468
  char* arg = _argv[index];
@@ -490,23 +475,24 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
490
475
  }
491
476
 
492
477
  memcpy(_memory + outPtr, &read, sizeof(read));
478
+ return read;
493
479
  }`);
494
480
 
495
- line(`__Porffor_readArgv((u32)(${vals.at(-2)}), (u32)(${vals.pop()}))`);
496
- vals.pop();
481
+ const outPtr = vals.pop();
482
+ const index = vals.pop();
483
+ vals.push(`(f64)__Porffor_readArgv((u32)(${index}), (u32)(${outPtr}))`);
497
484
  break;
485
+ }
498
486
 
499
- case '__Porffor_readFile':
487
+ case '__Porffor_readFile': {
500
488
  includes.set('stdio.h', true);
501
- includes.set('stdlib.h', true);
502
489
 
503
490
  prepend.set('__Porffor_readFile',
504
- `void __Porffor_readFile(u32 pathPtr, u32 outPtr) {
491
+ `i32 __Porffor_readFile(u32 pathPtr, u32 outPtr) {
505
492
  char* path = _memory + pathPtr + 4;
506
493
  FILE* fp = fopen(path, "r");
507
494
  if (fp == NULL) {
508
- printf("failed to open file: %s\\n", path);
509
- exit(1);
495
+ return -1;
510
496
  }
511
497
 
512
498
  u32 read = 0;
@@ -519,10 +505,13 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
519
505
  fclose(fp);
520
506
 
521
507
  memcpy(_memory + outPtr, &read, sizeof(read));
508
+ return read;
522
509
  }`);
523
- line(`__Porffor_readFile((u32)(${vals.at(-2)}), (u32)(${vals.pop()}))`);
524
- vals.pop();
510
+ const outPtr = vals.pop();
511
+ const pathPtr = vals.pop();
512
+ vals.push(`(f64)__Porffor_readFile((u32)(${pathPtr}), (u32)(${outPtr}))`);
525
513
  break;
514
+ }
526
515
 
527
516
  default:
528
517
  log.warning('2c', `unimplemented import: ${importFunc.name}`);
@@ -539,9 +528,10 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
539
528
  if (func.internal) {
540
529
  vals.push(`${sanitize(func.name)}(${args.join(', ')})`);
541
530
  } else {
542
- line(`const struct ReturnValue _${retTmpId++} = ${sanitize(func.name)}(${args.join(', ')})`);
543
- vals.push(`_.value`);
544
- vals.push(`_.type`);
531
+ const id = retTmpId++;
532
+ line(`const struct ReturnValue _${id} = ${sanitize(func.name)}(${args.join(', ')})`);
533
+ vals.push(`_${id}.value`);
534
+ vals.push(`_${id}.type`);
545
535
  }
546
536
  } else line(`${sanitize(func.name)}(${args.join(', ')})`);
547
537
 
@@ -571,7 +561,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
571
561
 
572
562
  let cond = removeBrackets(vals.pop());
573
563
  if (!lastCond) {
574
- if (cond.startsWith(`(${CValtype.i32})`)) cond = `(${cond.slice(`(${CValtype.i32})`.length)}) != 0e+0`;
564
+ if (cond.startsWith(`(i32)`)) cond = `${cond.slice(5)} != 0e+0`;
575
565
  else cond = `(${cond}) != 0`;
576
566
  }
577
567
 
@@ -601,8 +591,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
601
591
  const name = invOpcodes[i[0]];
602
592
  const func = CMemFuncs[i[0]];
603
593
  if (!prepend.has(name)) {
604
- prepend.set(name, `${func.returns || 'void'} ${name}(${CValtype.i32} align, ${CValtype.i32} offset, ${func.args.map((x, i) => `${func.argTypes[i]} ${x}`).join(', ')}) {\n ${func.c.replaceAll('\n', '\n ')}\n}\n`);
605
- // generate func c and prepend
594
+ prepend.set(name, `${func.returns || 'void'} ${name}(i32 align, i32 offset, ${func.args.map((x, i) => `${func.argTypes[i]} ${x}`).join(', ')}) {\n ${func.c.replaceAll('\n', '\n ')}\n}\n`);
606
595
  }
607
596
 
608
597
  const immediates = [ i[1], read_unsignedLEB128(i.slice(2)) ];
@@ -637,7 +626,6 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
637
626
  depth = 0;
638
627
 
639
628
  const makeIncludes = includes => [...includes.keys()].map(x => `#include <${x}>\n`).join('');
640
-
641
629
  out = platformSpecific(makeIncludes(winIncludes), makeIncludes(unixIncludes), false) + '\n' + makeIncludes(includes) + '\n' + alwaysPreface + [...prepend.values()].join('\n') + '\n\n' + out;
642
630
 
643
631
  return out.trim();
@@ -0,0 +1,129 @@
1
+ import { Blocktype, Opcodes, PageSize, Valtype } from './wasmSpec.js';
2
+ import { number } from './embedding.js';
3
+ import Prefs from './prefs.js';
4
+
5
+ // we currently have 3 allocators:
6
+ // - static (default): a static/compile-time allocator. fast (no grow/run-time alloc needed) but can break some code
7
+ // - grow: perform a memory.grow every allocation. simple but maybe slow?
8
+ // - chunk: perform large memory.grow's in chunks when needed. needs investigation
9
+
10
+ export default name => {
11
+ switch (name) {
12
+ case 'static': return new StaticAllocator();
13
+ case 'grow': return new GrowAllocator();
14
+ case 'chunk': return new ChunkAllocator();
15
+ default: throw new Error(`unknown allocator: ${name}`);
16
+ }
17
+ };
18
+
19
+ export class StaticAllocator {
20
+ constructor() {
21
+ }
22
+
23
+ allocType(itemType) {
24
+ switch (itemType) {
25
+ case 'i8': return 'bytestring';
26
+ case 'i16': return 'string';
27
+
28
+ default: return 'array';
29
+ }
30
+ }
31
+
32
+ ptr(ind) {
33
+ if (ind === 0) return 4;
34
+ return ind * PageSize;
35
+ }
36
+
37
+ alloc({ scope, pages }, name, { itemType }) {
38
+ const reason = `${this.allocType(itemType)}: ${Prefs.scopedPageNames ? (scope.name + '/') : ''}${name}`;
39
+
40
+ if (pages.has(reason)) return number(this.ptr(pages.get(reason).ind), Valtype.i32);
41
+
42
+ if (reason.startsWith('array:')) pages.hasArray = true;
43
+ if (reason.startsWith('string:')) pages.hasString = true;
44
+ if (reason.startsWith('bytestring:')) pages.hasByteString = true;
45
+ if (reason.includes('string:')) pages.hasAnyString = true;
46
+
47
+ let ind = pages.size;
48
+ pages.set(reason, { ind, type: itemType });
49
+
50
+ scope.pages ??= new Map();
51
+ scope.pages.set(reason, { ind, type: itemType });
52
+
53
+ return number(this.ptr(ind), Valtype.i32);
54
+ }
55
+ }
56
+
57
+ export class GrowAllocator {
58
+ constructor() {
59
+ Prefs.rmUnusedTypes = false;
60
+ }
61
+
62
+ alloc() {
63
+ return [
64
+ // grow by 1 page
65
+ [ Opcodes.i32_const, 1 ],
66
+ [ Opcodes.memory_grow, 0 ], // returns old page count
67
+
68
+ // get ptr (page count * page size)
69
+ number(65536, Valtype.i32)[0],
70
+ [ Opcodes.i32_mul ]
71
+ ];
72
+ }
73
+ }
74
+
75
+ export class ChunkAllocator {
76
+ constructor(chunkSize) {
77
+ Prefs.rmUnusedTypes = false;
78
+
79
+ // todo: what should be the default
80
+ // 16: 1MiB chunks
81
+ // 64KiB * chunk size each growth
82
+ this.chunkSize = chunkSize ?? Prefs.chunkAllocatorSize ?? 16;
83
+ }
84
+
85
+ alloc({ asmFunc, funcIndex, globals }) {
86
+ const func = funcIndex['#chunkallocator_alloc'] ?? asmFunc('#chunkallocator_alloc', {
87
+ wasm: [
88
+ [ Opcodes.global_get, 0 ],
89
+ [ Opcodes.global_get, 1 ],
90
+ [ Opcodes.i32_ge_s ],
91
+ [ Opcodes.if, Valtype.i32 ], // ptr >= next
92
+ // grow by chunk size pages
93
+ [ Opcodes.i32_const, this.chunkSize ],
94
+ [ Opcodes.memory_grow, 0 ],
95
+
96
+ // ptr = prev memory size * PageSize
97
+ number(65536, Valtype.i32)[0],
98
+ [ Opcodes.i32_mul ],
99
+ [ Opcodes.global_set, 0 ],
100
+
101
+ // next = ptr + ((chunkSize - 1) * PageSize)
102
+ [ Opcodes.global_get, 0 ],
103
+ number(65536 * (this.chunkSize - 1), Valtype.i32)[0],
104
+ [ Opcodes.i32_add ],
105
+ [ Opcodes.global_set, 1 ],
106
+
107
+ // return ptr
108
+ [ Opcodes.global_get, 0 ],
109
+ [ Opcodes.else ],
110
+ // return ptr = ptr + PageSize
111
+ [ Opcodes.global_get, 0 ],
112
+ number(65536, Valtype.i32)[0],
113
+ [ Opcodes.i32_add ],
114
+ [ Opcodes.global_set, 0 ],
115
+ [ Opcodes.global_get, 0 ],
116
+ [ Opcodes.end ],
117
+ ],
118
+ params: [],
119
+ locals: [],
120
+ globals: [ Valtype.i32, Valtype.i32 ],
121
+ globalNames: ['#chunkallocator_ptr', '#chunkallocator_next'],
122
+ returns: [ Valtype.i32 ],
123
+ }).index;
124
+
125
+ return [
126
+ [ Opcodes.call, func ]
127
+ ];
128
+ }
129
+ }
@@ -21,7 +21,7 @@ const chHint = (topTier, baselineTier, strategy) => {
21
21
  return (strategy | (baselineTier << 2) | (topTier << 4));
22
22
  };
23
23
 
24
- export default (funcs, globals, tags, pages, data, flags) => {
24
+ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) => {
25
25
  const types = [], typeCache = {};
26
26
 
27
27
  const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
@@ -44,7 +44,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
44
44
 
45
45
  let importFuncs = [];
46
46
 
47
- if (optLevel < 1 || !Prefs.treeshakeWasmImports) {
47
+ if (optLevel < 1 || !Prefs.treeshakeWasmImports || noTreeshake) {
48
48
  importFuncs = importedFuncs;
49
49
  } else {
50
50
  let imports = new Map();
@@ -94,7 +94,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
94
94
 
95
95
  const importSection = importFuncs.length === 0 ? [] : createSection(
96
96
  Section.import,
97
- encodeVector(importFuncs.map(x => [ 0, ...encodeString(x.import), ExportDesc.func, getType(new Array(x.params).fill(x.name.startsWith('profile') ? Valtype.i32 : valtypeBinary), new Array(x.returns).fill(valtypeBinary)) ]))
97
+ encodeVector(importFuncs.map(x => [ 0, ...encodeString(x.import), ExportDesc.func, getType(typeof x.params === 'object' ? x.params : new Array(x.params).fill(valtypeBinary), new Array(x.returns).fill(valtypeBinary)) ]))
98
98
  );
99
99
 
100
100
  const funcSection = createSection(
@@ -116,7 +116,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
116
116
  ] ])
117
117
  );
118
118
 
119
- if (pages.has('func argc lut')) {
119
+ if (pages.has('func argc lut') && !data.addedFuncArgcLut) {
120
120
  // generate func argc lut data
121
121
  const bytes = [];
122
122
  for (let i = 0; i < funcs.length; i++) {
@@ -128,6 +128,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
128
128
  offset: pages.get('func argc lut').ind * pageSize,
129
129
  bytes
130
130
  });
131
+ data.addedFuncArgcLut = true;
131
132
  }
132
133
 
133
134
  // const t0 = performance.now();
@@ -239,7 +240,13 @@ export default (funcs, globals, tags, pages, data, flags) => {
239
240
 
240
241
  const dataSection = data.length === 0 ? [] : createSection(
241
242
  Section.data,
242
- encodeVector(data.map(x => [ 0x00, Opcodes.i32_const, ...signedLEB128(x.offset), Opcodes.end, ...encodeVector(x.bytes) ]))
243
+ encodeVector(data.map(x => {
244
+ // type: active
245
+ if (x.offset != null) return [ 0x00, Opcodes.i32_const, ...signedLEB128(x.offset), Opcodes.end, ...encodeVector(x.bytes) ];
246
+
247
+ // type: passive
248
+ return [ 0x01, ...encodeVector(x.bytes) ];
249
+ }))
243
250
  );
244
251
 
245
252
  const dataCountSection = data.length === 0 ? [] : createSection(
@@ -171,12 +171,11 @@ export const __Array_prototype_filter = (_this: any[], callbackFn: any) => {
171
171
  };
172
172
 
173
173
  export const __Array_prototype_map = (_this: any[], callbackFn: any) => {
174
- const out: any[] = [];
175
-
176
- const len: i32 = _this.length;
177
174
  let i: i32 = 0;
175
+ const len: i32 = _this.length;
176
+ const out: any[] = new Array(len);
178
177
  while (i < len) {
179
- out.push(callbackFn(_this[i], i++, _this));
178
+ out[i] = callbackFn(_this[i], i++, _this);
180
179
  }
181
180
 
182
181
  return out;
@@ -722,12 +722,9 @@ export const __Porffor_date_allocate = (): Date => {
722
722
  const hack: bytestring = '';
723
723
 
724
724
  if (hack.length == 0) {
725
- hack.length = Porffor.wasm`i32.const 1
726
- memory.grow 0
727
- drop
728
- memory.size 0
725
+ hack.length = Porffor.wasm`
729
726
  i32.const 1
730
- i32.sub
727
+ memory.grow 0
731
728
  i32.const 65536
732
729
  i32.mul
733
730
  i32.from_u`;
@@ -56,6 +56,9 @@ type PorfforGlobal = {
56
56
 
57
57
  s(...args: any): string;
58
58
  bs(...args: any): bytestring;
59
+
60
+ readArgv(index: i32, out: bytestring): i32;
61
+ readFile(path: bytestring, out: bytestring): i32;
59
62
  };
60
63
 
61
64
  declare global {
@@ -2,12 +2,9 @@ import type {} from './porffor.d.ts';
2
2
 
3
3
  // dark wasm magic for dealing with memory, sorry.
4
4
  export const __Porffor_allocate = (): number => {
5
- Porffor.wasm`i32.const 1
6
- memory.grow 0
7
- drop
8
- memory.size 0
5
+ Porffor.wasm`
9
6
  i32.const 1
10
- i32.sub
7
+ memory.grow 0
11
8
  i32.const 65536
12
9
  i32.mul
13
10
  i32.from_u