porffor 0.2.0-1afe9b8 → 0.2.0-2b0f14b

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/compiler/2c.js CHANGED
@@ -1,24 +1,107 @@
1
- import { read_ieee754_binary64, read_signedLEB128 } from './encoding.js';
1
+ import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from './encoding.js';
2
2
  import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
3
3
  import { operatorOpcode } from './expression.js';
4
4
  import { log } from "./log.js";
5
5
 
6
6
  const CValtype = {
7
- i8: 'char',
8
- i16: 'unsigned short', // presume all i16 stuff is unsigned
9
- i32: 'long',
10
- i32_u: 'unsigned long',
11
- i64: 'long long',
12
- i64_u: 'unsigned long long',
7
+ i8: 'i8',
8
+ i16: 'i16',
9
+ i32: 'i32',
10
+ u32: 'u32',
11
+ i64: 'i64',
12
+ u64: 'u64',
13
13
 
14
- f32: 'float',
15
- f64: 'double',
14
+ f32: 'f32',
15
+ f64: 'f64',
16
16
 
17
17
  undefined: 'void'
18
18
  };
19
19
 
20
+ const alwaysPreface = `typedef unsigned char i8;
21
+ typedef unsigned short i16;
22
+ typedef long i32;
23
+ typedef unsigned long u32;
24
+ typedef long long i64;
25
+ typedef unsigned long long u64;
26
+ typedef float f32;
27
+ typedef double f64;
28
+
29
+ f64 NAN = 0e+0/0e+0;
30
+
31
+ struct ReturnValue {
32
+ ${CValtype.f64} value;
33
+ ${CValtype.i32} type;
34
+ };
35
+ \n`;
36
+
37
+ // todo: is memcpy/etc safe with host endianness?
38
+
39
+ // all:
40
+ // immediates: ['align', 'offset']
41
+ const CMemFuncs = {
42
+ [Opcodes.i32_store]: {
43
+ c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
44
+ args: ['pointer', 'value'],
45
+ argTypes: [CValtype.i32, CValtype.i32],
46
+ returns: false
47
+ },
48
+ [Opcodes.i32_store16]: {
49
+ c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
50
+ args: ['pointer', 'value'],
51
+ argTypes: [CValtype.i32, CValtype.i16],
52
+ returns: false
53
+ },
54
+ [Opcodes.i32_store8]: {
55
+ c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
56
+ args: ['pointer', 'value'],
57
+ argTypes: [CValtype.i32, CValtype.i8],
58
+ returns: false
59
+ },
60
+
61
+ [Opcodes.i32_load]: {
62
+ c: `${CValtype.i32} out;
63
+ memcpy(&out, _memory + offset + pointer, sizeof(out));
64
+ return out;`,
65
+ args: ['pointer'],
66
+ argTypes: [CValtype.i32],
67
+ returns: CValtype.i32
68
+ },
69
+ [Opcodes.i32_load16_u]: {
70
+ c: `${CValtype.i16} out;
71
+ memcpy(&out, _memory + offset + pointer, sizeof(out));
72
+ return out;`,
73
+ args: ['pointer'],
74
+ argTypes: [CValtype.i32],
75
+ returns: CValtype.i32
76
+ },
77
+ [Opcodes.i32_load8_u]: {
78
+ c: `${CValtype.i8} out;
79
+ memcpy(&out, _memory + offset + pointer, sizeof(out));
80
+ return out;`,
81
+ args: ['pointer'],
82
+ argTypes: [CValtype.i32],
83
+ returns: CValtype.i32
84
+ },
85
+
86
+ [Opcodes.f64_store]: {
87
+ c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
88
+ args: ['pointer', 'value'],
89
+ argTypes: [CValtype.i32, CValtype.f64],
90
+ returns: false
91
+ },
92
+ [Opcodes.f64_load]: {
93
+ c: `${CValtype.f64} out;
94
+ memcpy(&out, _memory + offset + pointer, sizeof(out));
95
+ return out;`,
96
+ args: ['pointer'],
97
+ argTypes: [CValtype.i32],
98
+ returns: CValtype.f64
99
+ },
100
+ };
101
+
20
102
  const inv = (obj, keyMap = x => x) => Object.keys(obj).reduce((acc, x) => { acc[keyMap(obj[x])] = x; return acc; }, {});
21
103
  const invOpcodes = inv(Opcodes);
104
+ const invValtype = inv(Valtype);
22
105
 
23
106
  for (const x in CValtype) {
24
107
  if (Valtype[x]) CValtype[Valtype[x]] = CValtype[x];
@@ -36,11 +119,18 @@ const todo = msg => {
36
119
  };
37
120
 
38
121
  const removeBrackets = str => {
39
- if (str.startsWith('(long)(unsigned long)')) return '(long)(unsigned long)(' + removeBrackets(str.slice(22, -1)) + ')';
122
+ // return str;
123
+ // if (str.startsWith(`(${CValtype.i32})(${CValtype.u32})`)) return `(${CValtype.i32})(${CValtype.u32})(` + removeBrackets(str.slice(22, -1)) + ')';
124
+
125
+ for (const x in CValtype) {
126
+ const p = `(${x})`;
127
+ if (str.startsWith(p)) return p + removeBrackets(str.slice(p.length));
128
+ }
129
+
40
130
  return str.startsWith('(') && str.endsWith(')') ? str.slice(1, -1) : str;
41
131
  };
42
132
 
43
- export default ({ funcs, globals, tags, exceptions, pages }) => {
133
+ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
44
134
  const invOperatorOpcode = Object.values(operatorOpcode).reduce((acc, x) => {
45
135
  for (const k in x) {
46
136
  acc[x[k]] = k;
@@ -56,12 +146,10 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
56
146
  }
57
147
 
58
148
  const includes = new Map(), unixIncludes = new Map(), winIncludes = new Map();
149
+ const prepend = new Map(), prependMain = new Map();
59
150
 
60
- // TODO: make type i16
61
- let out = `struct ReturnValue {
62
- ${CValtype.f64} value;
63
- ${CValtype.i32} type;
64
- };\n\n`;
151
+ // presume all <i32 work is unsigned
152
+ let out = ``;
65
153
 
66
154
  for (const x in globals) {
67
155
  const g = globals[x];
@@ -70,6 +158,15 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
70
158
  out += ';\n';
71
159
  }
72
160
 
161
+ if (pages.size > 0) {
162
+ prepend.set('_memory', `char _memory[${pages.size * pageSize}];\n`);
163
+ includes.set('string.h', true);
164
+ }
165
+
166
+ if (data.length > 0) {
167
+ prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n'));
168
+ }
169
+
73
170
  // for (const [ x, p ] of pages) {
74
171
  // out += `${CValtype[p.type]} ${x.replace(': ', '_').replace(/[^0-9a-zA-Z_]/g, '')}[100]`;
75
172
  // out += ';\n';
@@ -78,7 +175,8 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
78
175
  if (out) out += '\n';
79
176
 
80
177
  let depth = 1;
81
- const line = (str, semi = true) => out += `${' '.repeat(depth * 2)}${str}${semi ? ';' : ''}\n`;
178
+ let brDepth = 0;
179
+ const line = (str, semi = true) => out += `${' '.repeat(depth * 2 + brDepth * 2)}${str}${semi ? ';' : ''}\n`;
82
180
  const lines = lines => {
83
181
  for (const x of lines) {
84
182
  out += `${' '.repeat(depth * 2)}${x}\n`;
@@ -111,6 +209,8 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
111
209
  return tmp;
112
210
  };
113
211
 
212
+ let brId = 0;
213
+
114
214
  for (const f of funcs) {
115
215
  depth = 1;
116
216
 
@@ -124,7 +224,12 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
124
224
  const returns = f.returns.length > 0;
125
225
 
126
226
  const shouldInline = f.internal;
127
- out += `${f.name === 'main' ? 'int' : (f.internal ? (returns ? 'double' : 'void') : 'struct ReturnValue')} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
227
+ out += `${f.name === 'main' ? 'int' : (f.internal ? (returns ? CValtype.f64 : 'void') : 'struct ReturnValue')} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
228
+
229
+ if (f.name === 'main') {
230
+ out += [...prependMain.values()].join('\n');
231
+ if (prependMain.size > 0) out += '\n\n';
232
+ }
128
233
 
129
234
  const localKeys = Object.keys(f.locals).sort((a, b) => f.locals[a].idx - f.locals[b].idx).slice(f.params.length).sort((a, b) => f.locals[a].idx - f.locals[b].idx);
130
235
  for (const x of localKeys) {
@@ -134,11 +239,58 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
134
239
 
135
240
  if (localKeys.length !== 0) out += '\n';
136
241
 
242
+ const rets = [];
243
+ const runOnEnd = [];
244
+
137
245
  let vals = [];
138
- const endNeedsCurly = [], ignoreEnd = [];
139
- let beginLoop = false, lastCond = false, ifTernary = false;
246
+ const endNeedsCurly = [];
247
+ const brs = [];
248
+ let lastCond = false;
249
+
250
+ // let brDepth = 0;
251
+
252
+ const blockStart = (i, loop) => {
253
+ // reset "stack"
254
+ // vals = [];
255
+
256
+ rets.push(i[1]);
257
+
258
+ const br = brId++;
259
+ brs.push(br);
260
+ if (loop) {
261
+ line(`j${br}:;`, false);
262
+ runOnEnd.push(null);
263
+ } else {
264
+ runOnEnd.push(() => line(`j${br}:;`, false));
265
+ }
266
+
267
+ if (i[1] !== Blocktype.void) line(`${CValtype[i[1]]} _r${br}`);
268
+
269
+ brDepth++;
270
+ };
271
+
272
+ const highlight = i => {
273
+ const surrounding = 6;
274
+
275
+ const decomp = decompile(f.wasm.slice(i - surrounding, i + surrounding + 1), '', 0, f.locals, f.params, f.returns, funcs, globals, exceptions).slice(0, -1).split('\n');
276
+
277
+ const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
278
+ let longest = 0;
279
+ for (let j = 0; j < decomp.length; j++) {
280
+ longest = Math.max(longest, noAnsi(decomp[j]).length);
281
+ }
282
+
283
+ const middle = Math.floor(decomp.length / 2);
284
+ decomp[middle] = `\x1B[47m\x1B[30m${noAnsi(decomp[middle])}${'\u00a0'.repeat(longest - noAnsi(decomp[middle]).length)}\x1B[0m`;
285
+
286
+ console.log('\x1B[90m...\x1B[0m');
287
+ console.log(decomp.join('\n'));
288
+ console.log('\x1B[90m...\x1B[0m\n');
289
+ };
290
+
140
291
  for (let _ = 0; _ < f.wasm.length; _++) {
141
292
  const i = f.wasm[_];
293
+ if (!i || !i[0]) continue;
142
294
 
143
295
  if (invOperatorOpcode[i[0]]) {
144
296
  const b = vals.pop();
@@ -160,12 +312,12 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
160
312
  switch (i[1]) {
161
313
  // i32_trunc_sat_f64_s
162
314
  case 0x02:
163
- vals.push(`(${CValtype.i32})${vals.pop()}`);
315
+ vals.push(`(${CValtype.i32})(${vals.pop()})`);
164
316
  break;
165
317
 
166
318
  // i32_trunc_sat_f64_u
167
319
  case 0x03:
168
- vals.push(`(${CValtype.i32})(${CValtype.i32_u})${vals.pop()}`);
320
+ vals.push(`(${CValtype.u32})(${vals.pop()})`);
169
321
  break;
170
322
  }
171
323
 
@@ -176,12 +328,19 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
176
328
  switch (i[0]) {
177
329
  case Opcodes.i32_const:
178
330
  case Opcodes.i64_const:
179
- vals.push(read_signedLEB128(i.slice(1)).toString());
331
+ // vals.push(read_signedLEB128(i.slice(1)).toString());
332
+ vals.push(new String(read_signedLEB128(i.slice(1)).toString()));
333
+ vals.at(-1).offset = _;
180
334
  break;
181
335
 
182
- case Opcodes.f64_const:
183
- vals.push(read_ieee754_binary64(i.slice(1)).toExponential());
336
+ case Opcodes.f64_const: {
337
+ // const val = read_ieee754_binary64(i.slice(1)).toExponential();
338
+ const val = new String(read_ieee754_binary64(i.slice(1)).toExponential());
339
+ // vals.push(val == 'NaN' ? 'NAN' : val);
340
+ vals.push(val == 'NaN' ? new String('NAN') : val);
341
+ vals.at(-1).offset = _;
184
342
  break;
343
+ }
185
344
 
186
345
  case Opcodes.local_get:
187
346
  vals.push(`${invLocals[i[1]]}`);
@@ -192,9 +351,9 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
192
351
  break;
193
352
 
194
353
  case Opcodes.local_tee:
195
- // line(`${invLocals[i[1]]} = ${removeBrackets(vals.pop())}`);
196
- // vals.push(`${invLocals[i[1]]}`);
197
- vals.push(`((${invLocals[i[1]]} = ${vals.pop()}))`);
354
+ line(`${invLocals[i[1]]} = ${removeBrackets(vals.pop())}`);
355
+ vals.push(`${invLocals[i[1]]}`);
356
+ // vals.push(`((${invLocals[i[1]]} = ${vals.pop()}))`);
198
357
  break;
199
358
 
200
359
  case Opcodes.global_get:
@@ -207,78 +366,102 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
207
366
 
208
367
  case Opcodes.f64_trunc:
209
368
  // vals.push(`trunc(${vals.pop()})`);
210
- vals.push(`(int)(${removeBrackets(vals.pop())})`); // this is ~10x faster with clang??
369
+ vals.push(`(${CValtype.i32})(${removeBrackets(vals.pop())})`); // this is ~10x faster with clang??
211
370
  break;
212
371
 
213
372
  case Opcodes.f64_convert_i32_u:
214
373
  case Opcodes.f64_convert_i32_s:
215
374
  case Opcodes.f64_convert_i64_u:
216
375
  case Opcodes.f64_convert_i64_s:
217
- // int to double
218
- vals.push(`(double)${vals.pop()}`);
376
+ // int to f64
377
+ vals.push(`(${CValtype.f64})(${removeBrackets(vals.pop())})`);
219
378
  break;
220
379
 
380
+ case Opcodes.i32_eqz:
381
+ if (lastCond) {
382
+ vals.push(`!(${removeBrackets(vals.pop())})`);
383
+ } else {
384
+ let cond = '(' + removeBrackets(vals.pop());
385
+ if (cond.startsWith(`(${CValtype.i32})`)) cond = `${cond.slice(`(${CValtype.i32})`.length)}) == 0e+0`;
386
+ else cond += ') == 0';
387
+ vals.push(cond);
388
+ }
389
+ lastCond = true;
390
+ continue;
391
+
221
392
  case Opcodes.return:
222
393
  // line(`return${returns ? ` ${removeBrackets(vals.pop())}` : ''}`);
223
394
  line(`return${returns ? ` (struct ReturnValue){ ${removeBrackets(vals.pop())}, ${removeBrackets(vals.pop())} }` : ''}`);
224
395
  break;
225
396
 
226
- case Opcodes.if:
397
+ case Opcodes.if: {
227
398
  let cond = removeBrackets(vals.pop());
228
399
  if (!lastCond) {
229
- if (cond.startsWith('(long)')) cond = `${cond.slice(6)} == 1e+0`;
230
- else cond += ' == 1';
400
+ if (cond.startsWith(`(${CValtype.i32})`)) cond = `(${cond.slice(`(${CValtype.i32})`.length)}) != 0e+0`;
401
+ else cond = `(${cond}) != 0`;
231
402
  }
232
403
 
233
- ifTernary = i[1] !== Blocktype.void;
234
- if (ifTernary) {
235
- ifTernary = cond;
236
- break;
237
- }
238
-
239
- if (beginLoop) {
240
- beginLoop = false;
241
- line(`while (${cond}) {`, false);
242
-
243
- depth++;
244
- endNeedsCurly.push(true);
245
- ignoreEnd.push(false, true);
246
- break;
247
- }
404
+ line(`// if ${invValtype[i[1]] ?? ''}`, false);
405
+ blockStart(i, false);
248
406
 
249
407
  line(`if (${cond}) {`, false);
250
408
 
251
409
  depth++;
252
410
  endNeedsCurly.push(true);
253
- ignoreEnd.push(false);
254
411
  break;
412
+ }
255
413
 
256
- case Opcodes.else:
257
- if (ifTernary) break;
414
+ case Opcodes.else: {
415
+ const br = brs.at(-1);
416
+ const ret = rets.at(-1);
417
+ if (ret && ret !== Blocktype.void) {
418
+ // console.log(vals, ret);
419
+ // console.log(decompile(f.wasm.slice(_ - 5, _ + 1)));
420
+ if (vals.length > 0) line(`_r${br} = ${removeBrackets(vals.pop())}`);
421
+ // vals.push(`_r${br}`);
422
+ }
258
423
 
259
424
  depth--;
260
425
  line(`} else {`, false);
261
426
  depth++;
427
+
428
+ // reset "stack"
429
+ // vals = [];
262
430
  break;
431
+ }
263
432
 
264
- case Opcodes.loop:
265
- // not doing properly, fake a while loop
266
- beginLoop = true;
433
+ case Opcodes.loop: {
434
+ line(`// loop ${invValtype[i[1]] ?? ''}`, false);
435
+ blockStart(i, true);
436
+ endNeedsCurly.push(false);
267
437
  break;
438
+ }
268
439
 
269
- case Opcodes.end:
270
- if (ignoreEnd.pop()) break;
440
+ case Opcodes.end: {
441
+ const br = brs.pop();
442
+ const ret = rets.pop();
443
+ if (ret && ret !== Blocktype.void) {
444
+ // console.log(vals, ret);
445
+ // console.log(decompile(f.wasm.slice(_ - 5, _ + 1)));
446
+ if (vals.length > 0) line(`_r${br} = ${removeBrackets(vals.pop())}`);
447
+ vals.push(`_r${br}`);
448
+ }
271
449
 
272
- if (ifTernary) {
273
- const b = vals.pop();
274
- const a = vals.pop();
275
- vals.push(`${ifTernary} ? ${a} : ${b}`);
276
- break;
450
+ const enc = endNeedsCurly.pop() === true;
451
+ if (enc) {
452
+ depth--;
453
+ line('}', false);
277
454
  }
278
455
 
279
- depth--;
280
- if (endNeedsCurly.pop() === true) line('}', false);
456
+ brDepth--;
457
+
458
+ line(`// end`, false);
459
+
460
+ const roe = runOnEnd.pop();
461
+ if (roe) roe();
462
+
281
463
  break;
464
+ }
282
465
 
283
466
  case Opcodes.call:
284
467
  let func = funcs.find(x => x.index === i[1]);
@@ -286,7 +469,8 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
286
469
  const importFunc = importFuncs[i[1]];
287
470
  switch (importFunc.name) {
288
471
  case 'print':
289
- line(`printf("%f\\n", ${vals.pop()})`);
472
+ // line(`printf("%f\\n", ${vals.pop()})`);
473
+ line(`printf("${valtype === 'f64' ? '%g' : '%i'}\\n", ${vals.pop()})`);
290
474
  includes.set('stdio.h', true);
291
475
  break;
292
476
  case 'printChar':
@@ -349,13 +533,74 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
349
533
  vals.pop();
350
534
  break;
351
535
 
352
- case Opcodes.br:
353
- // ignore
354
- // reset "stack"
355
- vals = [];
536
+ case Opcodes.block:
537
+ line(`// block ${invValtype[i[1]] ?? ''}`, false);
538
+ blockStart(i, false);
539
+ endNeedsCurly.push(false);
540
+ break;
541
+
542
+ case Opcodes.br: {
543
+ const ret = rets[brDepth - i[1] - 1];
544
+ // console.log(rets, brDepth, i[1], brDepth - i[1] - 1, ret, vals);
545
+ if (ret !== Blocktype.void) line(`_r${brs[brDepth - i[1] - 1]} = ${removeBrackets(vals.pop())}`);
546
+ line(`goto j${brs[brDepth - i[1] - 1]}`);
547
+
548
+ // // reset "stack"
549
+ // vals = [];
550
+ break;
551
+ }
552
+
553
+ case Opcodes.br_if: {
554
+ const ret = rets[brDepth - i[1] - 1];
555
+ // console.log(rets, brDepth, i[1], brDepth - i[1] - 1, ret, vals);
556
+
557
+ let cond = removeBrackets(vals.pop());
558
+ if (!lastCond) {
559
+ if (cond.startsWith(`(${CValtype.i32})`)) cond = `(${cond.slice(`(${CValtype.i32})`.length)}) != 0e+0`;
560
+ else cond = `(${cond}) != 0`;
561
+ }
562
+
563
+ line(`if (${cond}) {`, false);
564
+ depth++;
565
+ if (ret !== Blocktype.void) line(`_r${brs[brDepth - i[1] - 1]} = ${removeBrackets(vals.at(-1))}`);
566
+ line(`goto j${brs[brDepth - i[1] - 1]}`);
567
+ depth--;
568
+ line(`}`, false);
569
+
570
+ break;
571
+ }
572
+
573
+ case Opcodes.throw: {
574
+ const id = vals.pop();
575
+
576
+ line(`printf("Uncaught ${exceptions[id].constructor}: ${exceptions[id].message}\\n")`);
577
+ line(`exit(1)`);
578
+
579
+ includes.set('stdlib.h', true);
580
+
356
581
  break;
582
+ }
357
583
 
358
584
  default:
585
+ if (CMemFuncs[i[0]]) {
586
+ const name = invOpcodes[i[0]];
587
+ const func = CMemFuncs[i[0]];
588
+ if (!prepend.has(name)) {
589
+ 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`);
590
+ // generate func c and prepend
591
+ }
592
+
593
+ const immediates = [ i[1], read_unsignedLEB128(i.slice(2)) ];
594
+
595
+ let args = [];
596
+ for (let j = 0; j < func.args.length; j++) args.unshift(removeBrackets(vals.pop()));
597
+
598
+ if (func.returns !== false) {
599
+ vals.push(`${name}(${immediates[0]}, ${immediates[1]}, ${args.join(', ')})`);
600
+ } else line(`${name}(${immediates[0]}, ${immediates[1]}, ${args.join(', ')})`);
601
+ break;
602
+ }
603
+
359
604
  log.warning('2c', `unimplemented op: ${invOpcodes[i[0]]}`);
360
605
  // todo(`unimplemented op: ${invOpcodes[i[0]]}`);
361
606
  }
@@ -379,7 +624,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
379
624
 
380
625
  const makeIncludes = includes => [...includes.keys()].map(x => `#include <${x}>\n`).join('');
381
626
 
382
- out = platformSpecific(makeIncludes(winIncludes), makeIncludes(unixIncludes), false) + '\n' + makeIncludes(includes) + '\n' + out;
627
+ out = alwaysPreface + platformSpecific(makeIncludes(winIncludes), makeIncludes(unixIncludes), false) + '\n' + makeIncludes(includes) + '\n' + [...prepend.values()].join('\n') + '\n\n' + out;
383
628
 
384
- return out;
629
+ return out.trim();
385
630
  };
@@ -696,6 +696,32 @@ export const BuiltinFuncs = function() {
696
696
  }
697
697
  };
698
698
 
699
+ const localIsOneOf = (getter, arr, valtype = valtypeBinary) => {
700
+ const out = [];
701
+
702
+ for (let i = 0; i < arr.length; i++) {
703
+ out.push(...getter, ...number(arr[i], valtype), valtype === Valtype.f64 ? [ Opcodes.f64_eq ] : [ Opcodes.i32_eq ]);
704
+ if (i !== 0) out.push([ Opcodes.i32_or ]);
705
+ }
706
+
707
+ return out;
708
+ };
709
+
710
+ this.__Porffor_pointer = {
711
+ params: [ valtypeBinary, Valtype.i32 ],
712
+ typedParams: true,
713
+ locals: [ Valtype.i32, Valtype.i32 ],
714
+ returns: [ valtypeBinary ],
715
+ wasm: (scope, { TYPES }) => [
716
+ ...localIsOneOf([ [ Opcodes.local_get, 1 ] ], [ TYPES.string, TYPES._array, TYPES._bytestring ], Valtype.i32),
717
+ [ Opcodes.if, valtypeBinary ],
718
+ [ Opcodes.local_get, 0 ],
719
+ [ Opcodes.else ],
720
+ ...number(NaN),
721
+ [ Opcodes.end ]
722
+ ]
723
+ };
724
+
699
725
 
700
726
  this.__SIMD_i32x4_load = {
701
727
  params: [ Valtype.i32 ],
@@ -160,7 +160,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
160
160
 
161
161
  case 'TaggedTemplateExpression': {
162
162
  const funcs = {
163
- asm: str => {
163
+ __Porffor_asm: str => {
164
164
  let out = [];
165
165
 
166
166
  for (const line of str.split('\n')) {
@@ -194,8 +194,21 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
194
194
  }
195
195
 
196
196
  return out;
197
- }
198
- }
197
+ },
198
+
199
+ __Porffor_bs: str => [
200
+ ...makeString(scope, str, undefined, undefined, true),
201
+
202
+ ...number(TYPES._bytestring, Valtype.i32),
203
+ setLastType(scope)
204
+ ],
205
+ __Porffor_s: str => [
206
+ ...makeString(scope, str, undefined, undefined, false),
207
+
208
+ ...number(TYPES.string, Valtype.i32),
209
+ setLastType(scope)
210
+ ],
211
+ };
199
212
 
200
213
  const name = decl.tag.name;
201
214
  // hack for inline asm
@@ -912,7 +925,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
912
925
  [ Opcodes.i32_or ],
913
926
  [ Opcodes.if, Blocktype.void ],
914
927
  ...number(0, Valtype.i32),
915
- [ Opcodes.br, 1 ],
928
+ [ Opcodes.br, 2 ],
916
929
  [ Opcodes.end ],
917
930
 
918
931
  ...compareStrings(scope, [ [ Opcodes.local_get, tmpLeft ] ], [ [ Opcodes.local_get, tmpRight ] ]),
@@ -2721,7 +2734,7 @@ const byteStringable = str => {
2721
2734
  return true;
2722
2735
  };
2723
2736
 
2724
- const makeString = (scope, str, global = false, name = '$undeclared') => {
2737
+ const makeString = (scope, str, global = false, name = '$undeclared', forceBytestring = undefined) => {
2725
2738
  const rawElements = new Array(str.length);
2726
2739
  let byteStringable = process.argv.includes('-bytestring');
2727
2740
  for (let i = 0; i < str.length; i++) {
@@ -2731,6 +2744,8 @@ const makeString = (scope, str, global = false, name = '$undeclared') => {
2731
2744
  if (byteStringable && c > 0xFF) byteStringable = false;
2732
2745
  }
2733
2746
 
2747
+ if (byteStringable && forceBytestring === false) byteStringable = false;
2748
+
2734
2749
  return makeArray(scope, {
2735
2750
  rawElements
2736
2751
  }, global, name, false, byteStringable ? 'i8' : 'i16')[0];
package/compiler/index.js CHANGED
@@ -68,11 +68,17 @@ export default (code, flags) => {
68
68
  console.log([...pages.keys()].map(x => `\x1B[36m - ${x}\x1B[0m`).join('\n') + '\n');
69
69
  }
70
70
 
71
- const out = { wasm: sections, funcs, globals, tags, exceptions, pages };
71
+ const out = { wasm: sections, funcs, globals, tags, exceptions, pages, data };
72
72
 
73
73
  const target = getArg('target') ?? getArg('t') ?? 'wasm';
74
74
  const outFile = getArg('o');
75
75
 
76
+ if (target === 'wasm' && outFile) {
77
+ writeFileSync(outFile, Buffer.from(sections));
78
+
79
+ if (process.version) process.exit();
80
+ }
81
+
76
82
  if (target === 'c') {
77
83
  const c = toc(out);
78
84
  out.c = c;
@@ -87,11 +93,16 @@ export default (code, flags) => {
87
93
  }
88
94
 
89
95
  if (target === 'native') {
90
- const compiler = getArg('compiler') ?? 'clang';
96
+ let compiler = getArg('compiler') ?? 'clang';
91
97
  const cO = getArg('cO') ?? 'Ofast';
92
98
 
99
+ if (compiler === 'zig') compiler = [ 'zig', 'cc' ];
100
+ else compiler = [ compiler ];
101
+
93
102
  const tmpfile = 'tmp.c';
94
- const args = [ compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native' ];
103
+ // const args = [ compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native', '-s', '-fno-unwind-tables', '-fno-asynchronous-unwind-tables', '-ffunction-sections', '-fdata-sections', '-Wl', '-fno-ident', '-fno-exceptions', '-ffast-math' ];
104
+ // const args = [ ...compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native', '-s', '-ffast-math', '-fno-exceptions', '-target', 'x86_64-linux' ];
105
+ const args = [ ...compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native', '-s', '-ffast-math', '-fno-exceptions' ];
95
106
 
96
107
  const c = toc(out);
97
108
  writeFileSync(tmpfile, c);
package/filesize.cmd ADDED
@@ -0,0 +1,2 @@
1
+ @echo off
2
+ echo %~z1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "a basic experimental wip aot optimizing js -> wasm engine/compiler/runtime in js",
4
- "version": "0.2.0-1afe9b8",
4
+ "version": "0.2.0-2b0f14b",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "dependencies": {
package/runner/index.js CHANGED
@@ -15,9 +15,22 @@ if (process.argv.includes('-compile-hints')) {
15
15
  // --experimental-wasm-return-call (on by default)
16
16
  }
17
17
 
18
- const file = process.argv.slice(2).find(x => x[0] !== '-');
18
+ let file = process.argv.slice(2).find(x => x[0] !== '-');
19
+ if (['run', 'wasm', 'native', 'c'].includes(file)) {
20
+ if (['wasm', 'native', 'c'].includes(file)) {
21
+ process.argv.push(`-target=${file}`);
22
+ }
23
+
24
+ file = process.argv.slice(process.argv.indexOf(file) + 1).find(x => x[0] !== '-');
25
+
26
+ const nonOptOutFile = process.argv.slice(process.argv.indexOf(file) + 1).find(x => x[0] !== '-');
27
+ if (nonOptOutFile) {
28
+ process.argv.push(`-o=${nonOptOutFile}`);
29
+ }
30
+ }
31
+
19
32
  if (!file) {
20
- if (process.argv.includes('-v')) {
33
+ if (process.argv.includes('-v') || process.argv.includes('--version')) {
21
34
  // just print version
22
35
  console.log((await import('./version.js')).default);
23
36
  process.exit(0);
package/r.js DELETED
@@ -1,4 +0,0 @@
1
- var supreme = 5
2
- var count;
3
-
4
- for(count=0;;) {console.log(count); if (count===supreme)break;else count++; }