porffor 0.0.0-e6047ea → 0.0.0-e975d7a

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.
@@ -23,6 +23,9 @@ const TYPES = {
23
23
 
24
24
  export const PrototypeFuncs = function() {
25
25
  const noUnlikelyChecks = process.argv.includes('-funsafe-no-unlikely-proto-checks');
26
+ let zeroChecks = process.argv.find(x => x.startsWith('-funsafe-zero-proto-checks='));
27
+ if (zeroChecks) zeroChecks = zeroChecks.split('=')[1].split(',').reduce((acc, x) => { acc[x.toLowerCase()] = true; return acc; }, {});
28
+ else zeroChecks = {};
26
29
 
27
30
  this[TYPES._array] = {
28
31
  // lX = local accessor of X ({ get, set }), iX = local index of X, wX = wasm ops of X
@@ -36,7 +39,7 @@ export const PrototypeFuncs = function() {
36
39
  [ Opcodes.i32_lt_s ],
37
40
  [ Opcodes.if, Blocktype.void ],
38
41
  [ Opcodes.local_get, iTmp ],
39
- ...length.cachedI32,
42
+ ...length.getCachedI32(),
40
43
  [ Opcodes.i32_add ],
41
44
  [ Opcodes.local_set, iTmp ],
42
45
  [ Opcodes.end ],
@@ -47,7 +50,7 @@ export const PrototypeFuncs = function() {
47
50
  [ Opcodes.i32_lt_s ],
48
51
 
49
52
  [ Opcodes.local_get, iTmp ],
50
- ...length.cachedI32,
53
+ ...length.getCachedI32(),
51
54
  [ Opcodes.i32_ge_s ],
52
55
  [ Opcodes.i32_or ],
53
56
 
@@ -67,7 +70,7 @@ export const PrototypeFuncs = function() {
67
70
  // todo: only for 1 argument
68
71
  push: (pointer, length, wNewMember) => [
69
72
  // get memory offset of array at last index (length)
70
- ...length.cachedI32,
73
+ ...length.getCachedI32(),
71
74
  ...number(ValtypeSize[valtype], Valtype.i32),
72
75
  [ Opcodes.i32_mul ],
73
76
 
@@ -79,17 +82,17 @@ export const PrototypeFuncs = function() {
79
82
 
80
83
  // bump array length by 1 and return it
81
84
  ...length.setI32([
82
- ...length.cachedI32,
85
+ ...length.getCachedI32(),
83
86
  ...number(1, Valtype.i32),
84
87
  [ Opcodes.i32_add ]
85
88
  ]),
86
89
 
87
- ...length.get
90
+ ...length.get()
88
91
  ],
89
92
 
90
93
  pop: (pointer, length) => [
91
94
  // if length == 0, noop
92
- ...length.cachedI32,
95
+ ...length.getCachedI32(),
93
96
  [ Opcodes.i32_eqz ],
94
97
  [ Opcodes.if, Blocktype.void ],
95
98
  ...number(UNDEFINED),
@@ -100,13 +103,13 @@ export const PrototypeFuncs = function() {
100
103
 
101
104
  // decrement length by 1
102
105
  ...length.setI32([
103
- ...length.cachedI32,
106
+ ...length.getCachedI32(),
104
107
  ...number(1, Valtype.i32),
105
108
  [ Opcodes.i32_sub ]
106
109
  ]),
107
110
 
108
111
  // load last element
109
- ...length.cachedI32,
112
+ ...length.getCachedI32(),
110
113
  ...number(ValtypeSize[valtype], Valtype.i32),
111
114
  [ Opcodes.i32_mul ],
112
115
 
@@ -115,7 +118,7 @@ export const PrototypeFuncs = function() {
115
118
 
116
119
  shift: (pointer, length) => [
117
120
  // if length == 0, noop
118
- ...length.cachedI32,
121
+ ...length.getCachedI32(),
119
122
  Opcodes.i32_eqz,
120
123
  [ Opcodes.if, Blocktype.void ],
121
124
  ...number(UNDEFINED),
@@ -126,7 +129,7 @@ export const PrototypeFuncs = function() {
126
129
 
127
130
  // decrement length by 1
128
131
  ...length.setI32([
129
- ...length.cachedI32,
132
+ ...length.getCachedI32(),
130
133
  ...number(1, Valtype.i32),
131
134
  [ Opcodes.i32_sub ]
132
135
  ]),
@@ -140,14 +143,69 @@ export const PrototypeFuncs = function() {
140
143
  ...number(pointer + ValtypeSize.i32 + ValtypeSize[valtype], Valtype.i32), // src = base array index + length size + an index
141
144
  ...number(pageSize - ValtypeSize.i32 - ValtypeSize[valtype], Valtype.i32), // size = PageSize - length size - an index
142
145
  [ ...Opcodes.memory_copy, 0x00, 0x00 ]
146
+ ],
147
+
148
+ fill: (pointer, length, wElement, iTmp) => [
149
+ ...wElement,
150
+ [ Opcodes.local_set, iTmp ],
151
+
152
+ // use cached length i32 as pointer
153
+ ...length.getCachedI32(),
154
+
155
+ // length - 1 for indexes
156
+ ...number(1, Valtype.i32),
157
+ [ Opcodes.i32_sub ],
158
+
159
+ // * sizeof value
160
+ ...number(ValtypeSize[valtype], Valtype.i32),
161
+ [ Opcodes.i32_mul ],
162
+
163
+ ...length.setCachedI32(),
164
+
165
+ ...(noUnlikelyChecks ? [] : [
166
+ ...length.getCachedI32(),
167
+ ...number(0, Valtype.i32),
168
+ [ Opcodes.i32_lt_s ],
169
+ [ Opcodes.if, Blocktype.void ],
170
+ ...number(pointer),
171
+ [ Opcodes.br, 1 ],
172
+ [ Opcodes.end ]
173
+ ]),
174
+
175
+ [ Opcodes.loop, Blocktype.void ],
176
+
177
+ // set element using pointer
178
+ ...length.getCachedI32(),
179
+ [ Opcodes.local_get, iTmp ],
180
+ [ Opcodes.store, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32) ],
181
+
182
+ // pointer - sizeof value
183
+ ...length.getCachedI32(),
184
+ ...number(ValtypeSize[valtype], Valtype.i32),
185
+ [ Opcodes.i32_sub ],
186
+
187
+ ...length.setCachedI32(),
188
+
189
+ // if pointer >= 0, loop
190
+ ...length.getCachedI32(),
191
+ ...number(0, Valtype.i32),
192
+ [ Opcodes.i32_ge_s ],
193
+ [ Opcodes.br_if, 0 ],
194
+
195
+ [ Opcodes.end ],
196
+
197
+ // return this array
198
+ ...number(pointer)
143
199
  ]
144
200
  };
145
201
 
146
202
  this[TYPES._array].at.local = Valtype.i32;
147
203
  this[TYPES._array].push.noArgRetLength = true;
204
+ this[TYPES._array].fill.local = valtypeBinary;
205
+ this[TYPES._array].fill.returnType = TYPES._array;
148
206
 
149
207
  this[TYPES.string] = {
150
- at: (pointer, length, wIndex, iTmp, arrayShell) => {
208
+ at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
151
209
  const [ newOut, newPointer ] = arrayShell(1, 'i16');
152
210
 
153
211
  return [
@@ -166,7 +224,7 @@ export const PrototypeFuncs = function() {
166
224
  [ Opcodes.i32_lt_s ],
167
225
  [ Opcodes.if, Blocktype.void ],
168
226
  [ Opcodes.local_get, iTmp ],
169
- ...length.cachedI32,
227
+ ...length.getCachedI32(),
170
228
  [ Opcodes.i32_add ],
171
229
  [ Opcodes.local_set, iTmp ],
172
230
  [ Opcodes.end ],
@@ -177,7 +235,7 @@ export const PrototypeFuncs = function() {
177
235
  [ Opcodes.i32_lt_s ],
178
236
 
179
237
  [ Opcodes.local_get, iTmp ],
180
- ...length.cachedI32,
238
+ ...length.getCachedI32(),
181
239
  [ Opcodes.i32_ge_s ],
182
240
  [ Opcodes.i32_or ],
183
241
 
@@ -202,7 +260,7 @@ export const PrototypeFuncs = function() {
202
260
  },
203
261
 
204
262
  // todo: out of bounds properly
205
- charAt: (pointer, length, wIndex, _, arrayShell) => {
263
+ charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
206
264
  const [ newOut, newPointer ] = arrayShell(1, 'i16');
207
265
 
208
266
  return [
@@ -233,39 +291,120 @@ export const PrototypeFuncs = function() {
233
291
  return [
234
292
  ...wIndex,
235
293
  Opcodes.i32_to,
236
- [ Opcodes.local_set, iTmp ],
237
294
 
238
- // index < 0
239
- ...(noUnlikelyChecks ? [] : [
295
+ ...(zeroChecks.charcodeat ? [] : [
296
+ [ Opcodes.local_set, iTmp ],
297
+
298
+ // index < 0
299
+ ...(noUnlikelyChecks ? [] : [
300
+ [ Opcodes.local_get, iTmp ],
301
+ ...number(0, Valtype.i32),
302
+ [ Opcodes.i32_lt_s ],
303
+ ]),
304
+
305
+ // index >= length
306
+ [ Opcodes.local_get, iTmp ],
307
+ ...length.getCachedI32(),
308
+ [ Opcodes.i32_ge_s ],
309
+
310
+ ...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
311
+ [ Opcodes.if, Blocktype.void ],
312
+ ...number(NaN),
313
+ [ Opcodes.br, 1 ],
314
+ [ Opcodes.end ],
315
+
240
316
  [ Opcodes.local_get, iTmp ],
241
- ...number(0, Valtype.i32),
242
- [ Opcodes.i32_lt_s ],
243
317
  ]),
244
318
 
245
- // index >= length
319
+ ...number(ValtypeSize.i16, Valtype.i32),
320
+ [ Opcodes.i32_mul ],
321
+
322
+ // load current string ind {arg}
323
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32) ],
324
+ Opcodes.i32_from_u
325
+ ];
326
+ },
327
+
328
+ isWellFormed: (pointer, length, wIndex, iTmp, iTmp2, arrayShell, { wellFormed } = {}) => {
329
+ // aot approx metadata
330
+ if (wellFormed != null) return number(wellFormed ? 1 : 0);
331
+
332
+ return [
333
+ // note: we cannot presume it begins as 0 in case it was used previously
334
+ ...number(0, Valtype.i32),
335
+ [ Opcodes.local_set, iTmp ],
336
+
337
+ [ Opcodes.loop, Blocktype.void ],
338
+
339
+ [ Opcodes.block, Blocktype.void ],
340
+
246
341
  [ Opcodes.local_get, iTmp ],
247
- ...length.cachedI32,
342
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32) ],
343
+ [ Opcodes.local_set, iTmp2 ],
344
+
345
+ // if not surrogate, continue
346
+ [ Opcodes.local_get, iTmp2 ],
347
+ ...number(0xF800, Valtype.i32),
348
+ [ Opcodes.i32_and ],
349
+ ...number(0xD800, Valtype.i32),
350
+ [ Opcodes.i32_ne ],
351
+ [ Opcodes.br_if, 0 ],
352
+
353
+ // if not leading surrogate, return false
354
+ [ Opcodes.local_get, iTmp2 ],
355
+ ...number(0xDC00, Valtype.i32),
248
356
  [ Opcodes.i32_ge_s ],
357
+ [ Opcodes.if, Blocktype.void ],
358
+ ...number(0),
359
+ [ Opcodes.br, 3 ],
360
+ [ Opcodes.end ],
249
361
 
250
- ...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
362
+ // if not followed by trailing surrogate, return false
363
+ [ Opcodes.local_get, iTmp ],
364
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32 + ValtypeSize.i16) ],
365
+ ...number(0xFC00, Valtype.i32),
366
+ [ Opcodes.i32_and ],
367
+ ...number(0xDC00, Valtype.i32),
368
+ [ Opcodes.i32_ne ],
251
369
  [ Opcodes.if, Blocktype.void ],
252
- ...number(NaN),
253
- [ Opcodes.br, 1 ],
370
+ ...number(0),
371
+ [ Opcodes.br, 3 ],
254
372
  [ Opcodes.end ],
255
373
 
374
+ // bump index again since gone through two valid chars
256
375
  [ Opcodes.local_get, iTmp ],
257
376
  ...number(ValtypeSize.i16, Valtype.i32),
377
+ [ Opcodes.i32_add ],
378
+ [ Opcodes.local_set, iTmp ],
379
+
380
+ [ Opcodes.end ],
381
+
382
+ // bump pointer and loop if not at the end
383
+ [ Opcodes.local_get, iTmp ],
384
+ ...number(ValtypeSize.i16, Valtype.i32),
385
+ [ Opcodes.i32_add ],
386
+ [ Opcodes.local_tee, iTmp ],
387
+
388
+ ...length.getCachedI32(),
389
+ ...number(ValtypeSize.i16, Valtype.i32),
258
390
  [ Opcodes.i32_mul ],
391
+ [ Opcodes.i32_ne ],
392
+ [ Opcodes.br_if, 0 ],
259
393
 
260
- // load current string ind {arg}
261
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32) ],
262
- Opcodes.i32_from_u
263
- ];
264
- },
394
+ [ Opcodes.end ],
395
+
396
+ // return true
397
+ ...number(1)
398
+ ]
399
+ }
265
400
  };
266
401
 
267
402
  this[TYPES.string].at.local = Valtype.i32;
268
403
  this[TYPES.string].at.returnType = TYPES.string;
269
404
  this[TYPES.string].charAt.returnType = TYPES.string;
270
405
  this[TYPES.string].charCodeAt.local = Valtype.i32;
406
+
407
+ this[TYPES.string].isWellFormed.local = Valtype.i32;
408
+ this[TYPES.string].isWellFormed.local2 = Valtype.i32;
409
+ this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
271
410
  };
@@ -1,5 +1,5 @@
1
1
  import { Valtype, FuncType, Empty, ExportDesc, Section, Magic, ModuleVersion, Opcodes, PageSize } from './wasmSpec.js';
2
- import { encodeVector, encodeString, encodeLocal } from './encoding.js';
2
+ import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128 } from './encoding.js';
3
3
  import { number } from './embedding.js';
4
4
  import { importedFuncs } from './builtins.js';
5
5
 
@@ -20,7 +20,7 @@ const chHint = (topTier, baselineTier, strategy) => {
20
20
  return (strategy | (baselineTier << 2) | (topTier << 4));
21
21
  };
22
22
 
23
- export default (funcs, globals, tags, pages, flags) => {
23
+ export default (funcs, globals, tags, pages, data, flags) => {
24
24
  const types = [], typeCache = {};
25
25
 
26
26
  const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
@@ -105,6 +105,8 @@ export default (funcs, globals, tags, pages, flags) => {
105
105
 
106
106
  const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, x.index ]);
107
107
 
108
+ if (process.argv.includes('-always-memory') && pages.size === 0) pages.set('-always-memory', 0);
109
+
108
110
  const usesMemory = pages.size > 0;
109
111
  const memorySection = !usesMemory ? [] : createSection(
110
112
  Section.memory,
@@ -155,13 +157,24 @@ export default (funcs, globals, tags, pages, flags) => {
155
157
  encodeVector(types)
156
158
  );
157
159
 
160
+ const dataSection = data.length === 0 ? [] : createSection(
161
+ Section.data,
162
+ encodeVector(data.map(x => [ 0x00, Opcodes.i32_const, ...signedLEB128(x.offset), Opcodes.end, ...encodeVector(x.bytes) ]))
163
+ );
164
+
165
+ const dataCountSection = data.length === 0 ? [] : createSection(
166
+ Section.data_count,
167
+ unsignedLEB128(data.length)
168
+ );
169
+
158
170
  if (process.argv.includes('-sections')) console.log({
159
171
  typeSection: typeSection.map(x => x.toString(16)),
160
172
  importSection: importSection.map(x => x.toString(16)),
161
173
  funcSection: funcSection.map(x => x.toString(16)),
162
174
  globalSection: globalSection.map(x => x.toString(16)),
163
175
  exportSection: exportSection.map(x => x.toString(16)),
164
- codeSection: codeSection.map(x => x.toString(16))
176
+ codeSection: codeSection.map(x => x.toString(16)),
177
+ dataSection: dataSection.map(x => x.toString(16)),
165
178
  });
166
179
 
167
180
  return Uint8Array.from([
@@ -175,6 +188,8 @@ export default (funcs, globals, tags, pages, flags) => {
175
188
  ...tagSection,
176
189
  ...globalSection,
177
190
  ...exportSection,
178
- ...codeSection
191
+ ...dataCountSection,
192
+ ...codeSection,
193
+ ...dataSection
179
194
  ]);
180
195
  };
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.0.0-e6047ea",
4
+ "version": "0.0.0-e975d7a",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "dependencies": {
package/r.js CHANGED
@@ -1 +1,39 @@
1
- print(performance.now());
1
+ compareArray.isSameValue = function(a, b) {
2
+ if (a === 0 && b === 0) return 1 / a === 1 / b;
3
+ if (a !== a && b !== b) return true;
4
+
5
+ return a === b;
6
+ };
7
+
8
+ function compareArray(a, b) {
9
+ // if either are nullish
10
+ if (a == null || b == null) return false;
11
+
12
+ // megahack: all arrays from now on will be >0 pointer
13
+ const _hack = '';
14
+
15
+ // hack: enforce type inference of being arrays
16
+ a ??= [];
17
+ b ??= [];
18
+
19
+ if (b.length !== a.length) {
20
+ return false;
21
+ }
22
+
23
+ for (var i = 0; i < a.length; i++) {
24
+ if (!compareArray.isSameValue(b[i], a[i])) {
25
+ return false;
26
+ }
27
+ }
28
+
29
+ return true;
30
+ }
31
+
32
+ console.log(compareArray(null, []));
33
+ console.log(compareArray(undefined, []));
34
+
35
+ console.log(compareArray([], []));
36
+ console.log(compareArray([ 1 ], []));
37
+ console.log(compareArray([ 1 ], [ 1 ]));
38
+ console.log(compareArray([ 1, 2 ], [ 1 ]));
39
+ console.log(compareArray([ 1, 2 ], [ 1, 2 ]));
package/runner/index.js CHANGED
@@ -34,12 +34,14 @@ const source = fs.readFileSync(file, 'utf8');
34
34
 
35
35
  let cache = '';
36
36
  const print = str => {
37
- cache += str;
37
+ /* cache += str;
38
38
 
39
39
  if (str === '\n') {
40
40
  process.stdout.write(cache);
41
41
  cache = '';
42
- }
42
+ } */
43
+
44
+ process.stdout.write(str);
43
45
  };
44
46
 
45
47
  try {
package/runner/info.js CHANGED
@@ -36,7 +36,7 @@ const print = str => {
36
36
  };
37
37
 
38
38
  const t0 = performance.now();
39
- const { wasm, exports } = await compile(source, raw ? [ 'module' ] : [ 'module', 'info' ], {}, print);
39
+ const { wasm, exports, pages } = await compile(source, raw ? [ 'module' ] : [ 'module', 'info' ], {}, print);
40
40
 
41
41
  if (!raw && typeof Deno === 'undefined') fs.writeFileSync('out.wasm', Buffer.from(wasm));
42
42
 
@@ -51,4 +51,39 @@ if (!process.argv.includes('-no-run')) {
51
51
  }
52
52
 
53
53
  if (!raw) console.log(bold(`wasm binary is ${wasm.byteLength} bytes`));
54
- if (!raw) console.log(`total: ${(performance.now() - t0).toFixed(2)}ms`);
54
+ if (!raw) console.log(`total: ${(performance.now() - t0).toFixed(2)}ms`);
55
+
56
+ if (!raw && process.argv.includes('-mem') && exports.$) {
57
+ console.log();
58
+
59
+ let lastMemory, lastPages;
60
+ const PageSize = 65536;
61
+ const memoryToString = mem => {
62
+ let out = '';
63
+ const pages = lastPages.length;
64
+ const wasmPages = mem.buffer.byteLength / PageSize;
65
+
66
+ out += `\x1B[1mallocated ${mem.buffer.byteLength / 1024}KiB\x1B[0m for ${pages} things using ${wasmPages} Wasm page${wasmPages === 1 ? '' : 's'}\n`;
67
+
68
+ const buf = new Uint8Array(mem.buffer);
69
+
70
+ for (let i = 0; i < pages; i++) {
71
+ out += `\x1B[36m${lastPages[i]}\x1B[2m | \x1B[0m`;
72
+
73
+ for (let j = 0; j < 50; j++) {
74
+ const val = buf[i * pageSize + j];
75
+ if (val === 0) out += '\x1B[2m';
76
+ out += val.toString(16).padStart(2, '0');
77
+ if (val === 0) out += '\x1B[0m';
78
+ out += ' ';
79
+ }
80
+ out += '\n';
81
+ }
82
+
83
+ return out;
84
+ };
85
+
86
+ lastPages = [...pages.keys()];
87
+ lastMemory = exports.$;
88
+ console.log(memoryToString(lastMemory));
89
+ }