porffor 0.0.0-1b0a5c6 → 0.0.0-3f87ef7

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/README.md CHANGED
@@ -132,7 +132,6 @@ no particular order and no guarentees, just what could happen soon™
132
132
  - rewrite local indexes per func for smallest local header and remove unused idxs
133
133
  - smarter inline selection (snapshots?)
134
134
  - remove const ifs (`if (true)`, etc)
135
- - use data segments for initing arrays
136
135
 
137
136
  ## porfformance
138
137
  *for the things it supports most of the time*, porffor is blazingly fast compared to most interpreters, and common engines running without JIT. for those with JIT, it is not that much slower like a traditional interpreter would be; mostly the same or a bit faster/slower depending on what.
@@ -158,6 +157,7 @@ mostly for reducing size. do not really care about compiler perf/time as long as
158
157
  - remove unneeded single just used vars
159
158
  - remove unneeded blocks (no `br`s inside)
160
159
  - remove unused imports
160
+ - use data segments for initing arrays/strings
161
161
 
162
162
  ### wasm module
163
163
  - type cache/index (no repeated types)
@@ -1,9 +1,9 @@
1
1
  import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from "./wasmSpec.js";
2
- import { signedLEB128, unsignedLEB128 } from "./encoding.js";
2
+ import { ieee754_binary64, signedLEB128, unsignedLEB128 } from "./encoding.js";
3
3
  import { operatorOpcode } from "./expression.js";
4
4
  import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from "./builtins.js";
5
5
  import { PrototypeFuncs } from "./prototype.js";
6
- import { number, i32x4 } from "./embedding.js";
6
+ import { number, i32x4, enforceOneByte, enforceTwoBytes, enforceFourBytes, enforceEightBytes } from "./embedding.js";
7
7
  import parse from "./parse.js";
8
8
  import * as Rhemyn from "../rhemyn/compile.js";
9
9
 
@@ -1978,10 +1978,25 @@ const StoreOps = {
1978
1978
  i16: Opcodes.i32_store16
1979
1979
  };
1980
1980
 
1981
+ let data = [];
1982
+
1983
+ const compileBytes = (val, itemType, signed = true) => {
1984
+ switch (itemType) {
1985
+ case 'i8': return enforceOneByte(unsignedLEB128(val));
1986
+ case 'i16': return enforceTwoBytes(unsignedLEB128(val));
1987
+ case 'i32': return enforceFourBytes(signedLEB128(val));
1988
+ case 'i64': return enforceEightBytes(signedLEB128(val));
1989
+ case 'f64': return enforceEightBytes(ieee754_binary64(val));
1990
+ }
1991
+ };
1992
+
1981
1993
  const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype) => {
1982
1994
  const out = [];
1983
1995
 
1996
+ let firstAssign = false;
1984
1997
  if (!arrays.has(name) || name === '$undeclared') {
1998
+ firstAssign = true;
1999
+
1985
2000
  // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
1986
2001
  const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
1987
2002
  arrays.set(name, allocPage(`${itemType === 'i16' ? 'string' : 'array'}: ${uniqueName}`, itemType) * pageSize);
@@ -1992,8 +2007,29 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
1992
2007
  const useRawElements = !!decl.rawElements;
1993
2008
  const elements = useRawElements ? decl.rawElements : decl.elements;
1994
2009
 
2010
+ const valtype = itemTypeToValtype[itemType];
1995
2011
  const length = elements.length;
1996
2012
 
2013
+ if (firstAssign && useRawElements) {
2014
+ let bytes = compileBytes(length, 'i32');
2015
+
2016
+ if (!initEmpty) for (let i = 0; i < length; i++) {
2017
+ if (elements[i] == null) continue;
2018
+
2019
+ bytes.push(...compileBytes(elements[i], itemType));
2020
+ }
2021
+
2022
+ data.push({
2023
+ offset: pointer,
2024
+ bytes
2025
+ });
2026
+
2027
+ // local value as pointer
2028
+ out.push(...number(pointer));
2029
+
2030
+ return [ out, pointer ];
2031
+ }
2032
+
1997
2033
  // store length as 0th array
1998
2034
  out.push(
1999
2035
  ...number(0, Valtype.i32),
@@ -2002,7 +2038,6 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
2002
2038
  );
2003
2039
 
2004
2040
  const storeOp = StoreOps[itemType];
2005
- const valtype = itemTypeToValtype[itemType];
2006
2041
 
2007
2042
  if (!initEmpty) for (let i = 0; i < length; i++) {
2008
2043
  if (elements[i] == null) continue;
@@ -2379,6 +2414,7 @@ export default program => {
2379
2414
  typeStates = {};
2380
2415
  arrays = new Map();
2381
2416
  pages = new Map();
2417
+ data = [];
2382
2418
  currentFuncIndex = importedFuncs.length;
2383
2419
 
2384
2420
  globalThis.valtype = 'f64';
@@ -2455,5 +2491,5 @@ export default program => {
2455
2491
  // if blank main func and other exports, remove it
2456
2492
  if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(funcs.length - 1, 1);
2457
2493
 
2458
- return { funcs, globals, tags, exceptions, pages };
2494
+ return { funcs, globals, tags, exceptions, pages, data };
2459
2495
  };
@@ -9,11 +9,15 @@ export const number = (n, valtype = valtypeBinary) => {
9
9
  }
10
10
  };
11
11
 
12
- const enforceTwoBytes = arr => [ arr[0] ?? 0, arr[1] ?? 0, arr[2] ?? 0, arr[3] ?? 0 ];
12
+ export const enforceOneByte = arr => [ arr[0] ?? 0 ];
13
+ export const enforceTwoBytes = arr => [ arr[0] ?? 0, arr[1] ?? 0 ];
14
+ export const enforceFourBytes = arr => [ arr[0] ?? 0, arr[1] ?? 0, arr[2] ?? 0, arr[3] ?? 0 ];
15
+ export const enforceEightBytes = arr => [ arr[0] ?? 0, arr[1] ?? 0, arr[2] ?? 0, arr[3] ?? 0, arr[4] ?? 0, arr[5] ?? 0, arr[6] ?? 0, arr[7] ?? 0 ];
16
+
13
17
  export const i32x4 = (a, b, c, d) => [ [
14
18
  ...Opcodes.v128_const,
15
- ...enforceTwoBytes(signedLEB128(a)),
16
- ...enforceTwoBytes(signedLEB128(b)),
17
- ...enforceTwoBytes(signedLEB128(c)),
18
- ...enforceTwoBytes(signedLEB128(d))
19
+ ...enforceFourBytes(signedLEB128(a)),
20
+ ...enforceFourBytes(signedLEB128(b)),
21
+ ...enforceFourBytes(signedLEB128(c)),
22
+ ...enforceFourBytes(signedLEB128(d))
19
23
  ] ];
package/compiler/index.js CHANGED
@@ -59,7 +59,7 @@ export default (code, flags) => {
59
59
  if (flags.includes('info')) console.log(`1. parsed in ${(performance.now() - t0).toFixed(2)}ms`);
60
60
 
61
61
  const t1 = performance.now();
62
- const { funcs, globals, tags, exceptions, pages } = codeGen(program);
62
+ const { funcs, globals, tags, exceptions, pages, data } = codeGen(program);
63
63
  if (flags.includes('info')) console.log(`2. generated code in ${(performance.now() - t1).toFixed(2)}ms`);
64
64
 
65
65
  if (process.argv.includes('-funcs')) logFuncs(funcs, globals, exceptions);
@@ -71,7 +71,7 @@ export default (code, flags) => {
71
71
  if (process.argv.includes('-opt-funcs')) logFuncs(funcs, globals, exceptions);
72
72
 
73
73
  const t3 = performance.now();
74
- const sections = produceSections(funcs, globals, tags, pages, flags);
74
+ const sections = produceSections(funcs, globals, tags, pages, data, flags);
75
75
  if (flags.includes('info')) console.log(`4. produced sections in ${(performance.now() - t3).toFixed(2)}ms`);
76
76
 
77
77
  if (allocLog) {
@@ -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);
@@ -155,13 +155,24 @@ export default (funcs, globals, tags, pages, flags) => {
155
155
  encodeVector(types)
156
156
  );
157
157
 
158
+ const dataSection = data.length === 0 ? [] : createSection(
159
+ Section.data,
160
+ encodeVector(data.map(x => [ 0x00, Opcodes.i32_const, ...signedLEB128(x.offset), Opcodes.end, ...encodeVector(x.bytes) ]))
161
+ );
162
+
163
+ const dataCountSection = data.length === 0 ? [] : createSection(
164
+ Section.data_count,
165
+ unsignedLEB128(data.length)
166
+ );
167
+
158
168
  if (process.argv.includes('-sections')) console.log({
159
169
  typeSection: typeSection.map(x => x.toString(16)),
160
170
  importSection: importSection.map(x => x.toString(16)),
161
171
  funcSection: funcSection.map(x => x.toString(16)),
162
172
  globalSection: globalSection.map(x => x.toString(16)),
163
173
  exportSection: exportSection.map(x => x.toString(16)),
164
- codeSection: codeSection.map(x => x.toString(16))
174
+ codeSection: codeSection.map(x => x.toString(16)),
175
+ dataSection: dataSection.map(x => x.toString(16)),
165
176
  });
166
177
 
167
178
  return Uint8Array.from([
@@ -175,6 +186,8 @@ export default (funcs, globals, tags, pages, flags) => {
175
186
  ...tagSection,
176
187
  ...globalSection,
177
188
  ...exportSection,
178
- ...codeSection
189
+ ...dataCountSection,
190
+ ...codeSection,
191
+ ...dataSection
179
192
  ]);
180
193
  };
package/compiler/wrap.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import compile from './index.js';
2
2
  import decompile from './decompile.js';
3
- // import fs from 'node:fs';
3
+ import fs from 'node:fs';
4
4
 
5
5
  const bold = x => `\u001b[1m${x}\u001b[0m`;
6
6
 
@@ -29,7 +29,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
29
29
 
30
30
  if (source.includes('export function')) flags.push('module');
31
31
 
32
- // fs.writeFileSync('out.wasm', Buffer.from(wasm));
32
+ fs.writeFileSync('out.wasm', Buffer.from(wasm));
33
33
 
34
34
  times.push(performance.now() - t1);
35
35
  if (flags.includes('info')) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
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-1b0a5c6",
4
+ "version": "0.0.0-3f87ef7",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "dependencies": {