porffor 0.2.0-767de65 → 0.2.0-80c08d4

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.
@@ -1,4 +1,4 @@
1
- // @porf -funsafe-no-unlikely-proto-checks -valtype=i32
1
+ // @porf --funsafe-no-unlikely-proto-checks --valtype=i32
2
2
 
3
3
  import type {} from './porffor';
4
4
 
@@ -1,4 +1,4 @@
1
- // @porf -funsafe-no-unlikely-proto-checks
1
+ // @porf --funsafe-no-unlikely-proto-checks
2
2
 
3
3
  // radix: number|any for rawType check
4
4
  // export const parseInt = (input: string|bytestring, radix: number|any): f64 => {
@@ -1,4 +1,4 @@
1
- // // @porf -funsafe-no-unlikely-proto-checks
1
+ // @porf --funsafe-no-unlikely-proto-checks
2
2
 
3
3
  // radix: number|any for rawType check
4
4
  export const __Number_prototype_toString = (_this: number, radix: number|any) => {
@@ -7,23 +7,40 @@ type PorfforGlobal = {
7
7
  wasm: {
8
8
  (...args: any[]): any;
9
9
  i32: {
10
- or(a: i32, b: i32): i32;
11
-
12
10
  load(pointer: i32, align: i32, offset: i32): i32;
13
11
  store(pointer: i32, value: i32, align: i32, offset: i32): i32;
14
12
  load8_u(pointer: i32, align: i32, offset: i32): i32;
15
13
  store8(pointer: i32, value: i32, align: i32, offset: i32): i32;
16
14
  load16_u(pointer: i32, align: i32, offset: i32): i32;
17
15
  store16(pointer: i32, value: i32, align: i32, offset: i32): i32;
16
+ const(value: i32): i32;
17
+ }
18
+
19
+ f64: {
20
+ load(pointer: i32, align: i32, offset: i32): i32;
21
+ store(pointer: i32, value: f64, align: i32, offset: i32): f64;
18
22
  }
19
23
  }
20
24
 
21
- // randomInt(): i32;
22
25
  randomByte(): i32;
23
26
 
24
27
  type(x: any): bytestring;
25
28
  rawType(x: any): i32;
26
- TYPES: Record<string, i32>;
29
+ TYPES: {
30
+ number: i32;
31
+ boolean: i32;
32
+ string: i32;
33
+ undefined: i32;
34
+ object: i32;
35
+ function: i32;
36
+ symbol: i32;
37
+ bigint: i32;
38
+
39
+ _array: i32;
40
+ _regexp: i32;
41
+ _bytestring: i32;
42
+ _date: i32;
43
+ }
27
44
 
28
45
  fastOr(...args: any): boolean;
29
46
  fastAnd(...args: any): boolean;
@@ -1,4 +1,4 @@
1
- // @porf -funsafe-no-unlikely-proto-checks -valtype=i32
1
+ // @porf --funsafe-no-unlikely-proto-checks --valtype=i32
2
2
 
3
3
  export const __String_fromCharCode = (code: i32) => {
4
4
  // todo: support >1 arg
@@ -1,4 +1,4 @@
1
- // // @porf -funsafe-no-unlikely-proto-checks -valtype=i32
1
+ // // @porf --funsafe-no-unlikely-proto-checks --valtype=i32
2
2
 
3
3
  export const __Boolean_prototype_toString = (_this: boolean) => {
4
4
  let out: bytestring = '';
@@ -23,6 +23,12 @@ export const importedFuncs = [
23
23
  params: 0,
24
24
  returns: 1
25
25
  },
26
+ {
27
+ name: 'timeOrigin',
28
+ import: 'u',
29
+ params: 0,
30
+ returns: 1
31
+ },
26
32
  {
27
33
  name: 'profile1',
28
34
  import: 'y',
@@ -140,6 +146,10 @@ export const BuiltinVars = function() {
140
146
  for (const x in TYPES) {
141
147
  this['__Porffor_TYPES_' + x] = number(TYPES[x]);
142
148
  }
149
+
150
+ this.__performance_timeOrigin = [
151
+ [ Opcodes.call, importedFuncs.timeOrigin ]
152
+ ];
143
153
  };
144
154
 
145
155
  export const BuiltinFuncs = function() {
@@ -206,7 +216,7 @@ export const BuiltinFuncs = function() {
206
216
  };
207
217
 
208
218
 
209
- this.__console_log = {
219
+ this.__Porffor_print = {
210
220
  params: [ valtypeBinary, Valtype.i32 ],
211
221
  typedParams: true,
212
222
  locals: [ Valtype.i32, Valtype.i32 ],
@@ -358,10 +368,7 @@ export const BuiltinFuncs = function() {
358
368
  [ Opcodes.local_get, 0 ],
359
369
  [ Opcodes.call, importedFuncs.print ],
360
370
  ]
361
- }, Blocktype.void),
362
-
363
- ...char('\n'),
364
- [ Opcodes.call, importedFuncs.printChar ]
371
+ }, Blocktype.void)
365
372
  ]
366
373
  };
367
374
 
@@ -908,27 +915,6 @@ export const BuiltinFuncs = function() {
908
915
  ]
909
916
  };
910
917
 
911
- // this.__Porffor_randomInt = {
912
- // params: [],
913
- // locals: prng.locals,
914
- // localNames: [ 's1', 's0' ],
915
- // globals: prng.globals,
916
- // globalNames: [ 'state0', 'state1' ],
917
- // globalInits: [ prngSeed0, prngSeed1 ],
918
- // returns: [ Valtype.i32 ],
919
- // wasm: [
920
- // ...prng.wasm,
921
-
922
- // ...(prng.returns === Valtype.i64 ? [
923
- // // the lowest bits of the output generated by xorshift128+ have low quality
924
- // ...number(56, Valtype.i64),
925
- // [ Opcodes.i64_shr_u ],
926
-
927
- // [ Opcodes.i32_wrap_i64 ],
928
- // ] : []),
929
- // ]
930
- // };
931
-
932
918
  this.__Porffor_randomByte = {
933
919
  params: [],
934
920
  locals: prng.locals,
@@ -201,7 +201,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
201
201
  }
202
202
 
203
203
  let inst = Opcodes[asm[0].replace('.', '_')];
204
- if (!inst) throw new Error(`inline asm: inst ${asm[0]} not found`);
204
+ if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
205
205
 
206
206
  if (!Array.isArray(inst)) inst = [ inst ];
207
207
  const immediates = asm.slice(1).map(x => {
@@ -210,7 +210,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
210
210
  return int;
211
211
  });
212
212
 
213
- out.push([ ...inst, ...immediates ]);
213
+ out.push([ ...inst, ...immediates.flatMap(x => signedLEB128(x)) ]);
214
214
  }
215
215
 
216
216
  return out;
@@ -460,7 +460,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
460
460
  const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
461
461
  const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
462
462
 
463
- if (assign) {
463
+ if (assign && Prefs.aotPointerOpt) {
464
464
  const pointer = scope.arrays?.get(name ?? '$undeclared');
465
465
 
466
466
  return [
@@ -1273,6 +1273,18 @@ const getNodeType = (scope, node) => {
1273
1273
  return TYPES.number;
1274
1274
  }
1275
1275
 
1276
+ if (node.type === 'NewExpression' && builtinFuncs[name + '$constructor']) {
1277
+ if (builtinFuncs[name + '$constructor'].typedReturns) {
1278
+ if (scope.locals['#last_type']) return getLastType(scope);
1279
+
1280
+ // presume
1281
+ // todo: warn here?
1282
+ return TYPES.number;
1283
+ }
1284
+
1285
+ return builtinFuncs[name + '$constructor'].returnType ?? TYPES.number;
1286
+ }
1287
+
1276
1288
  const func = funcs.find(x => x.name === name);
1277
1289
 
1278
1290
  if (func) {
@@ -1460,16 +1472,23 @@ const countLeftover = wasm => {
1460
1472
  if (depth === 0)
1461
1473
  if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
1462
1474
  else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x0a)) {}
1463
- else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const].includes(inst[0])) count++;
1475
+ else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const, Opcodes.memory_size].includes(inst[0])) count++;
1464
1476
  else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
1465
1477
  else if (Opcodes.memory_copy[0] === inst[0] && Opcodes.memory_copy[1] === inst[1]) count -= 3;
1466
1478
  else if (inst[0] === Opcodes.return) count = 0;
1467
1479
  else if (inst[0] === Opcodes.call) {
1468
1480
  let func = funcs.find(x => x.index === inst[1]);
1469
- if (func) {
1470
- count -= func.params.length;
1471
- } else count--;
1472
- if (func) count += func.returns.length;
1481
+ if (inst[1] === -1) {
1482
+ // todo: count for calling self
1483
+ } else if (!func && inst[1] < importedFuncs.length) {
1484
+ count -= importedFuncs[inst[1]].params;
1485
+ count += importedFuncs[inst[1]].returns;
1486
+ } else {
1487
+ if (func) {
1488
+ count -= func.params.length;
1489
+ } else count--;
1490
+ if (func) count += func.returns.length;
1491
+ }
1473
1492
  } else count--;
1474
1493
 
1475
1494
  // console.log(count, decompile([ inst ]).slice(0, -1));
@@ -1627,18 +1646,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1627
1646
  // megahack for /regex/.func()
1628
1647
  const funcName = decl.callee.property.name;
1629
1648
  if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
1630
- const func = Rhemyn[funcName](decl.callee.object.regex.pattern, currentFuncIndex++);
1649
+ const regex = decl.callee.object.regex.pattern;
1650
+ const rhemynName = `regex_${funcName}_${regex}`;
1631
1651
 
1632
- funcIndex[func.name] = func.index;
1633
- funcs.push(func);
1652
+ if (!funcIndex[rhemynName]) {
1653
+ const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
1654
+
1655
+ funcIndex[func.name] = func.index;
1656
+ funcs.push(func);
1657
+ }
1634
1658
 
1659
+ const idx = funcIndex[rhemynName];
1635
1660
  return [
1636
1661
  // make string arg
1637
1662
  ...generate(scope, decl.arguments[0]),
1663
+ Opcodes.i32_to_u,
1664
+ ...getNodeType(scope, decl.arguments[0]),
1638
1665
 
1639
1666
  // call regex func
1640
- Opcodes.i32_to_u,
1641
- [ Opcodes.call, func.index ],
1667
+ [ Opcodes.call, idx ],
1642
1668
  Opcodes.i32_from_u,
1643
1669
 
1644
1670
  ...number(TYPES.boolean, Valtype.i32),
@@ -1678,6 +1704,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1678
1704
 
1679
1705
  protoBC[type] = generateCall(scope, {
1680
1706
  callee: {
1707
+ type: 'Identifier',
1681
1708
  name: x
1682
1709
  },
1683
1710
  arguments: [ target, ...decl.arguments ],
@@ -1800,20 +1827,20 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1800
1827
  idx = funcIndex[name];
1801
1828
 
1802
1829
  // infer arguments types from builtins params
1803
- const func = funcs.find(x => x.name === name);
1804
- for (let i = 0; i < decl.arguments.length; i++) {
1805
- const arg = decl.arguments[i];
1806
- if (!arg.name) continue;
1807
-
1808
- const local = scope.locals[arg.name];
1809
- if (!local) continue;
1810
-
1811
- local.type = func.params[i];
1812
- if (local.type === Valtype.v128) {
1813
- // specify vec subtype inferred from last vec type in function name
1814
- local.vecType = name.split('_').reverse().find(x => x.includes('x'));
1815
- }
1816
- }
1830
+ // const func = funcs.find(x => x.name === name);
1831
+ // for (let i = 0; i < decl.arguments.length; i++) {
1832
+ // const arg = decl.arguments[i];
1833
+ // if (!arg.name) continue;
1834
+
1835
+ // const local = scope.locals[arg.name];
1836
+ // if (!local) continue;
1837
+
1838
+ // local.type = func.params[i];
1839
+ // if (local.type === Valtype.v128) {
1840
+ // // specify vec subtype inferred from last vec type in function name
1841
+ // local.vecType = name.split('_').reverse().find(x => x.includes('x'));
1842
+ // }
1843
+ // }
1817
1844
  }
1818
1845
 
1819
1846
  if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
@@ -1826,28 +1853,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1826
1853
  if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
1827
1854
  const wasmOps = {
1828
1855
  // pointer, align, offset
1829
- i32_load: { imms: 2, args: 1, returns: 1 },
1856
+ i32_load: { imms: 2, args: [ true ], returns: 1 },
1830
1857
  // pointer, value, align, offset
1831
- i32_store: { imms: 2, args: 2, returns: 0 },
1858
+ i32_store: { imms: 2, args: [ true, true ], returns: 0 },
1832
1859
  // pointer, align, offset
1833
- i32_load8_u: { imms: 2, args: 1, returns: 1 },
1860
+ i32_load8_u: { imms: 2, args: [ true ], returns: 1 },
1834
1861
  // pointer, value, align, offset
1835
- i32_store8: { imms: 2, args: 2, returns: 0 },
1862
+ i32_store8: { imms: 2, args: [ true, true ], returns: 0 },
1836
1863
  // pointer, align, offset
1837
- i32_load16_u: { imms: 2, args: 1, returns: 1 },
1864
+ i32_load16_u: { imms: 2, args: [ true ], returns: 1 },
1838
1865
  // pointer, value, align, offset
1839
- i32_store16: { imms: 2, args: 2, returns: 0 },
1866
+ i32_store16: { imms: 2, args: [ true, true ], returns: 0 },
1840
1867
 
1841
1868
  // pointer, align, offset
1842
- f64_load: { imms: 2, args: 1, returns: 1 },
1869
+ f64_load: { imms: 2, args: [ true ], returns: 0 }, // 0 due to not i32
1843
1870
  // pointer, value, align, offset
1844
- f64_store: { imms: 2, args: 2, returns: 0 },
1871
+ f64_store: { imms: 2, args: [ true, false ], returns: 0 },
1845
1872
 
1846
1873
  // value
1847
- i32_const: { imms: 1, args: 0, returns: 1 },
1848
-
1849
- // a, b
1850
- i32_or: { imms: 0, args: 2, returns: 1 },
1874
+ i32_const: { imms: 1, args: [], returns: 1 },
1851
1875
  };
1852
1876
 
1853
1877
  const opName = name.slice('__Porffor_wasm_'.length);
@@ -1856,13 +1880,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1856
1880
  const op = wasmOps[opName];
1857
1881
 
1858
1882
  const argOut = [];
1859
- for (let i = 0; i < op.args; i++) argOut.push(
1883
+ for (let i = 0; i < op.args.length; i++) argOut.push(
1860
1884
  ...generate(scope, decl.arguments[i]),
1861
- Opcodes.i32_to
1885
+ ...(op.args[i] ? [ Opcodes.i32_to ] : [])
1862
1886
  );
1863
1887
 
1864
1888
  // literals only
1865
- const imms = decl.arguments.slice(op.args).map(x => x.value);
1889
+ const imms = decl.arguments.slice(op.args.length).map(x => x.value);
1866
1890
 
1867
1891
  return [
1868
1892
  ...argOut,
@@ -1937,7 +1961,20 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1937
1961
  const generateNew = (scope, decl, _global, _name) => {
1938
1962
  // hack: basically treat this as a normal call for builtins for now
1939
1963
  const name = mapName(decl.callee.name);
1964
+
1940
1965
  if (internalConstrs[name] && !internalConstrs[name].notConstr) return internalConstrs[name].generate(scope, decl, _global, _name);
1966
+
1967
+ if (builtinFuncs[name + '$constructor']) {
1968
+ // custom ...$constructor override builtin func
1969
+ return generateCall(scope, {
1970
+ ...decl,
1971
+ callee: {
1972
+ type: 'Identifier',
1973
+ name: name + '$constructor'
1974
+ }
1975
+ }, _global, _name);
1976
+ }
1977
+
1941
1978
  if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet`); // return todo(scope, `new statement is not supported yet (new ${unhackName(name)})`);
1942
1979
 
1943
1980
  return generateCall(scope, decl, _global, _name);
@@ -2128,8 +2165,8 @@ const addVarMetadata = (scope, name, global = false, metadata = {}) => {
2128
2165
 
2129
2166
  const typeAnnoToPorfType = x => {
2130
2167
  if (!x) return null;
2131
- if (TYPES[x] != null) return TYPES[x];
2132
- if (TYPES['_' + x] != null) return TYPES['_' + x];
2168
+ if (TYPES[x.toLowerCase()] != null) return TYPES[x.toLowerCase()];
2169
+ if (TYPES['_' + x.toLowerCase()] != null) return TYPES['_' + x.toLowerCase()];
2133
2170
 
2134
2171
  switch (x) {
2135
2172
  case 'i32':
@@ -2172,6 +2209,7 @@ const generateVar = (scope, decl) => {
2172
2209
 
2173
2210
  // global variable if in top scope (main) and var ..., or if wanted
2174
2211
  const global = topLevel || decl._bare; // decl.kind === 'var';
2212
+ const target = global ? globals : scope.locals;
2175
2213
 
2176
2214
  for (const x of decl.declarations) {
2177
2215
  const name = mapName(x.id.name);
@@ -2193,17 +2231,29 @@ const generateVar = (scope, decl) => {
2193
2231
  continue; // always ignore
2194
2232
  }
2195
2233
 
2234
+ // // generate init before allocating var
2235
+ // let generated;
2236
+ // if (x.init) generated = generate(scope, x.init, global, name);
2237
+
2196
2238
  const typed = typedInput && x.id.typeAnnotation;
2197
- let idx = allocVar(scope, name, global, !typed);
2239
+ let idx = allocVar(scope, name, global, !(typed && extractTypeAnnotation(x.id).type != null));
2198
2240
 
2199
2241
  if (typed) {
2200
2242
  addVarMetadata(scope, name, global, extractTypeAnnotation(x.id));
2201
2243
  }
2202
2244
 
2203
2245
  if (x.init) {
2204
- out = out.concat(generate(scope, x.init, global, name));
2205
-
2206
- out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2246
+ const generated = generate(scope, x.init, global, name);
2247
+ if (scope.arrays?.get(name) != null) {
2248
+ // hack to set local as pointer before
2249
+ out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2250
+ if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
2251
+ generated.pop();
2252
+ out = out.concat(generated);
2253
+ } else {
2254
+ out = out.concat(generated);
2255
+ out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2256
+ }
2207
2257
  out.push(...setType(scope, name, getNodeType(scope, x.init)));
2208
2258
  }
2209
2259
 
@@ -2230,6 +2280,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2230
2280
  return [];
2231
2281
  }
2232
2282
 
2283
+ const op = decl.operator.slice(0, -1) || '=';
2284
+
2233
2285
  // hack: .length setter
2234
2286
  if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
2235
2287
  const name = decl.left.object.name;
@@ -2238,14 +2290,20 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2238
2290
  const aotPointer = Prefs.aotPointerOpt && pointer != null;
2239
2291
 
2240
2292
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2293
+ const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2241
2294
 
2242
2295
  return [
2243
2296
  ...(aotPointer ? number(0, Valtype.i32) : [
2244
2297
  ...generate(scope, decl.left.object),
2245
2298
  Opcodes.i32_to_u
2246
2299
  ]),
2300
+ ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2247
2301
 
2248
- ...generate(scope, decl.right),
2302
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2303
+ [ Opcodes.local_get, pointerTmp ],
2304
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
2305
+ Opcodes.i32_from_u
2306
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
2249
2307
  [ Opcodes.local_tee, newValueTmp ],
2250
2308
 
2251
2309
  Opcodes.i32_to_u,
@@ -2255,8 +2313,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2255
2313
  ];
2256
2314
  }
2257
2315
 
2258
- const op = decl.operator.slice(0, -1) || '=';
2259
-
2260
2316
  // arr[i]
2261
2317
  if (decl.left.type === 'MemberExpression' && decl.left.computed) {
2262
2318
  const name = decl.left.object.name;
@@ -3060,12 +3116,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3060
3116
  // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
3061
3117
  const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
3062
3118
 
3063
- if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${scope.name} | ${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
3119
+ if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType) * pageSize);
3064
3120
  else scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
3065
3121
  }
3066
3122
 
3067
3123
  const pointer = scope.arrays.get(name);
3068
3124
 
3125
+ const local = global ? globals[name] : scope.locals[name];
3126
+
3069
3127
  const useRawElements = !!decl.rawElements;
3070
3128
  const elements = useRawElements ? decl.rawElements : decl.elements;
3071
3129
 
@@ -3098,11 +3156,22 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3098
3156
  return [ out, pointer ];
3099
3157
  }
3100
3158
 
3159
+ const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3160
+ if (pointerTmp != null) {
3161
+ out.push(
3162
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3163
+ Opcodes.i32_to_u,
3164
+ [ Opcodes.local_set, pointerTmp ]
3165
+ );
3166
+ }
3167
+
3168
+ const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3169
+
3101
3170
  // store length as 0th array
3102
3171
  out.push(
3103
- ...number(0, Valtype.i32),
3172
+ ...pointerWasm,
3104
3173
  ...number(length, Valtype.i32),
3105
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
3174
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3106
3175
  );
3107
3176
 
3108
3177
  const storeOp = StoreOps[itemType];
@@ -3111,14 +3180,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3111
3180
  if (elements[i] == null) continue;
3112
3181
 
3113
3182
  out.push(
3114
- ...number(0, Valtype.i32),
3183
+ ...pointerWasm,
3115
3184
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3116
- [ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
3185
+ [ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
3117
3186
  );
3118
3187
  }
3119
3188
 
3120
3189
  // local value as pointer
3121
- out.push(...number(pointer));
3190
+ out.push(...pointerWasm, Opcodes.i32_from_u);
3122
3191
 
3123
3192
  return [ out, pointer ];
3124
3193
  };
@@ -3473,6 +3542,8 @@ const internalConstrs = {
3473
3542
  );
3474
3543
  }
3475
3544
 
3545
+ out.push(Opcodes.i32_from_u);
3546
+
3476
3547
  return out;
3477
3548
  },
3478
3549
  type: TYPES.boolean,
@@ -3491,6 +3562,8 @@ const internalConstrs = {
3491
3562
  );
3492
3563
  }
3493
3564
 
3565
+ out.push(Opcodes.i32_from_u);
3566
+
3494
3567
  return out;
3495
3568
  },
3496
3569
  type: TYPES.boolean,
@@ -3545,6 +3618,39 @@ const internalConstrs = {
3545
3618
  type: TYPES.number,
3546
3619
  notConstr: true,
3547
3620
  length: 2
3621
+ },
3622
+
3623
+ __console_log: {
3624
+ generate: (scope, decl) => {
3625
+ const out = [];
3626
+
3627
+ for (let i = 0; i < decl.arguments.length; i++) {
3628
+ out.push(
3629
+ ...generateCall(scope, {
3630
+ callee: {
3631
+ type: 'Identifier',
3632
+ name: '__Porffor_print'
3633
+ },
3634
+ arguments: [ decl.arguments[i] ]
3635
+ }),
3636
+
3637
+ // print space
3638
+ ...number(32),
3639
+ [ Opcodes.call, importedFuncs.printChar ]
3640
+ );
3641
+ }
3642
+
3643
+ // print newline
3644
+ out.push(
3645
+ ...number(10),
3646
+ [ Opcodes.call, importedFuncs.printChar ]
3647
+ );
3648
+
3649
+ return out;
3650
+ },
3651
+ type: TYPES.undefined,
3652
+ notConstr: true,
3653
+ length: 0
3548
3654
  }
3549
3655
  };
3550
3656
 
@@ -3579,7 +3685,7 @@ export default program => {
3579
3685
 
3580
3686
  globalThis.valtype = 'f64';
3581
3687
 
3582
- const valtypeOpt = process.argv.find(x => x.startsWith('-valtype='));
3688
+ const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
3583
3689
  if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
3584
3690
 
3585
3691
  globalThis.valtypeBinary = Valtype[valtype];
@@ -3587,7 +3693,7 @@ export default program => {
3587
3693
  const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
3588
3694
 
3589
3695
  globalThis.pageSize = PageSize;
3590
- const pageSizeOpt = process.argv.find(x => x.startsWith('-page-size='));
3696
+ const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
3591
3697
  if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
3592
3698
 
3593
3699
  // set generic opcodes for current valtype
@@ -110,7 +110,6 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
110
110
 
111
111
  out += '\n';
112
112
  lastInst = inst;
113
- i++;
114
113
  }
115
114
 
116
115
  return highlightAsm(out);