porffor 0.41.6 → 0.42.0

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.
@@ -48,20 +48,111 @@ const cacheAst = (decl, wasm) => {
48
48
  return wasm;
49
49
  };
50
50
 
51
+ let indirectFuncs = [];
51
52
  const funcRef = func => {
52
- // generate func
53
53
  func.generate?.();
54
54
 
55
55
  if (globalThis.precompile) return [
56
56
  [ Opcodes.const, 'funcref', func.name ]
57
57
  ];
58
58
 
59
+ const wrapperArgc = Prefs.indirectWrapperArgc ?? 8;
60
+ if (!func.wrapperFunc) {
61
+ const locals = {}, params = [];
62
+ for (let i = 0; i < wrapperArgc + 2; i++) {
63
+ params.push(valtypeBinary, Valtype.i32);
64
+ locals[i * 2] = { idx: i * 2, type: valtypeBinary };
65
+ locals[i * 2 + 1] = { idx: i * 2 + 1, type: Valtype.i32 };
66
+ }
67
+ let localInd = (wrapperArgc + 2) * 2;
68
+
69
+ const wasm = [];
70
+ const offset = func.constr ? 0 : 4;
71
+ for (let i = 0; i < func.params.length; i++) {
72
+ if (func.internal && func.name.includes('_prototype_') && i < 2) {
73
+ // special case: use real this for prototype internals
74
+ wasm.push(
75
+ [ Opcodes.local_get, 2 + i ],
76
+ ...(i % 2 === 0 && func.params[i] === Valtype.i32 ? [ Opcodes.i32_to ]: [])
77
+ );
78
+ } else {
79
+ wasm.push(
80
+ [ Opcodes.local_get, offset + (!func.internal || func.typedParams ? i : i * 2) ],
81
+ ...(i % 2 === 0 && func.params[i] === Valtype.i32 ? [ Opcodes.i32_to ]: [])
82
+ );
83
+ }
84
+ }
85
+
86
+ wasm.push([ Opcodes.call, func.index ]);
87
+
88
+ if (func.returns[0] === Valtype.i32) {
89
+ if (func.returns.length === 2) {
90
+ const localIdx = localInd++;
91
+ locals[localIdx] = { idx: localIdx, type: Valtype.i32 };
92
+
93
+ wasm.push(
94
+ [ Opcodes.local_set, localIdx ],
95
+ Opcodes.i32_from,
96
+ [ Opcodes.local_get, localIdx ]
97
+ );
98
+ } else {
99
+ wasm.push(Opcodes.i32_from);
100
+ }
101
+ }
102
+
103
+ if (func.returns.length === 1) {
104
+ // add built-in returnType if only returns a value
105
+ wasm.push(...number(func.returnType ?? TYPES.number, Valtype.i32));
106
+ }
107
+
108
+ const name = '#indirect_' + func.name;
109
+ const wrapperFunc = {
110
+ name,
111
+ params,
112
+ locals, localInd,
113
+ returns: [ valtypeBinary, Valtype.i32 ],
114
+ wasm,
115
+ constr: true,
116
+ internal: true,
117
+ indirect: true
118
+ };
119
+
120
+ indirectFuncs.push(wrapperFunc);
121
+
122
+ wrapperFunc.jsLength = countLength(func);
123
+ func.wrapperFunc = wrapperFunc;
124
+
125
+ if (!func.constr) {
126
+ // check not being constructed
127
+ wasm.unshift(
128
+ [ Opcodes.local_get, 0 ], // new.target value
129
+ Opcodes.i32_to_u,
130
+ [ Opcodes.if, Blocktype.void ], // if value is non-zero
131
+ ...internalThrow(wrapperFunc, 'TypeError', `${unhackName(func.name)} is not a constructor`), // throw type error
132
+ [ Opcodes.end ]
133
+ );
134
+ }
135
+ }
136
+
59
137
  return [
60
138
  [ Opcodes.const, func.index - importedFuncs.length ]
61
- // [ Opcodes.const, func.index - importedFuncs.length, 'funcref' ]
62
139
  ];
63
140
  };
64
141
 
142
+ const forceDuoValtype = (scope, wasm, forceValtype) => [
143
+ ...wasm,
144
+ ...(valtypeBinary === Valtype.i32 && forceValtype === Valtype.f64 ? [
145
+ [ Opcodes.local_set, localTmp(scope, '#swap', Valtype.i32) ],
146
+ [ Opcodes.f64_convert_i32_s ],
147
+ [ Opcodes.local_get, localTmp(scope, '#swap', Valtype.i32) ]
148
+ ] : []),
149
+ ...(valtypeBinary === Valtype.f64 && forceValtype === Valtype.i32 ? [
150
+ [ Opcodes.local_set, localTmp(scope, '#swap', Valtype.i32) ],
151
+ Opcodes.i32_trunc_sat_f64_s,
152
+ [ Opcodes.local_get, localTmp(scope, '#swap', Valtype.i32) ]
153
+ ] : [])
154
+ ];
155
+
65
156
  const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
66
157
  if (astCache.has(decl)) return astCache.get(decl);
67
158
 
@@ -245,7 +336,7 @@ const internalThrow = (scope, constructor, message, expectsValue = Prefs.alwaysV
245
336
  ]
246
337
  }
247
338
  }),
248
- ...(expectsValue ? number(UNDEFINED) : [])
339
+ ...(expectsValue ? number(UNDEFINED, typeof expectsValue === 'number' ? expectsValue : valtypeBinary) : [])
249
340
  ];
250
341
 
251
342
  const generateIdent = (scope, decl) => {
@@ -2167,102 +2258,45 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2167
2258
  } else {
2168
2259
  if (!Prefs.indirectCalls) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true);
2169
2260
 
2170
- // todo: only works when function uses typedParams and typedReturns
2171
-
2172
- const indirectMode = Prefs.indirectCallMode ?? 'vararg';
2173
- // options: vararg, strict
2174
- // - strict: simpler, smaller size usage, no func lut needed.
2175
- // ONLY works when arg count of call == arg count of function being called
2176
- // - vararg: large size usage, cursed.
2177
- // works when arg count of call != arg count of function being called*
2178
- // * most of the time, some edgecases
2179
-
2180
2261
  funcs.table = true;
2181
2262
  scope.table = true;
2182
2263
 
2183
2264
  let args = decl.arguments;
2184
- let locals = [];
2185
-
2186
- if (indirectMode === 'vararg') {
2187
- const minArgc = Prefs.indirectCallMinArgc ?? 5;
2188
-
2189
- if (args.length < minArgc) {
2190
- args = args.concat(new Array(minArgc - args.length).fill(DEFAULT_VALUE()));
2191
- }
2265
+ const wrapperArgc = Prefs.indirectWrapperArgc ?? 8;
2266
+ if (args.length < wrapperArgc) {
2267
+ args = args.concat(new Array(wrapperArgc - args.length).fill(DEFAULT_VALUE()));
2192
2268
  }
2193
2269
 
2194
2270
  for (let i = 0; i < args.length; i++) {
2195
2271
  const arg = args[i];
2196
- out = out.concat(generate(scope, arg));
2197
- out = out.concat(getNodeType(scope, arg));
2198
-
2199
- if (indirectMode === 'vararg') {
2200
- const typeLocal = localTmp(scope, `#indirect_arg${i}_type`, Valtype.i32);
2201
- const valLocal = localTmp(scope, `#indirect_arg${i}_val`);
2202
-
2203
- locals.push([valLocal, typeLocal]);
2204
-
2205
- out.push(
2206
- [ Opcodes.local_set, typeLocal ],
2207
- [ Opcodes.local_set, valLocal ]
2208
- );
2209
- }
2272
+ out = out.concat(generate(scope, arg), valtypeBinary === Valtype.i32 && scope.locals[arg.name]?.type !== Valtype.f64 ? [ [ Opcodes.f64_convert_i32_s ] ] : [], getNodeType(scope, arg));
2210
2273
  }
2211
2274
 
2212
- if (indirectMode === 'strict') {
2213
- return [
2214
- ...generate(scope, decl.callee),
2215
- [ Opcodes.local_set, localTmp(scope, '#indirect_callee') ],
2275
+ let knownThis = undefined, getCallee = undefined;
2276
+ const calleeLocal = localTmp(scope, '#indirect_callee');
2216
2277
 
2217
- ...typeSwitch(scope, getNodeType(scope, decl.callee), {
2218
- [TYPES.function]: () => [
2219
- ...out,
2278
+ // hack: this should be more thorough, Function.bind, etc
2279
+ if (decl.callee.type === 'MemberExpression' && !decl._new) {
2280
+ const thisLocal = localTmp(scope, '#indirect_caller');
2281
+ const thisLocalType = localTmp(scope, '#indirect_caller#type', Valtype.i32);
2220
2282
 
2221
- [ Opcodes.local_get, localTmp(scope, '#indirect_callee') ],
2222
- ...generate(scope, decl.callee),
2223
- Opcodes.i32_to_u,
2224
- [ Opcodes.call_indirect, args.length, 0 ],
2225
- ...setLastType(scope)
2226
- ],
2227
- default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
2228
- })
2283
+ knownThis = [
2284
+ [ Opcodes.local_get, thisLocal ],
2285
+ [ Opcodes.local_get, thisLocalType ]
2229
2286
  ];
2230
- }
2231
-
2232
- // hi, I will now explain how vararg mode works:
2233
- // wasm's indirect_call instruction requires you know the func type at compile-time
2234
- // since we have varargs (variable argument count), we do not know it.
2235
- // we could just store args in memory and not use wasm func args,
2236
- // but that is slow (probably) and breaks js exports.
2237
- // instead, we generate every* possibility of argc and use different indirect_call
2238
- // ops for each one, with type depending on argc for that branch.
2239
- // then we load the argc for the wanted function from a memory lut,
2240
- // and call the branch with the matching argc we require.
2241
- // sorry, yes it is very cursed (and size inefficient), but indirect calls
2242
- // are kind of rare anyway (mostly callbacks) so I am not concerned atm.
2243
- // *for argc 0-3, in future (todo:) the max number should be
2244
- // dynamically changed to the max argc of any func in the js file.
2245
-
2246
- const funcLocal = localTmp(scope, '#indirect_func', Valtype.i32);
2247
- const flags = localTmp(scope, '#indirect_flags', Valtype.i32);
2248
-
2249
- let knownThis = undefined;
2250
- let getCalleeObj = undefined;
2251
- let initCalleeObj = undefined;
2252
-
2253
- // hack: this should be more thorough, Function.bind, etc
2254
- if (decl.callee.type == 'MemberExpression' && !decl._new) {
2255
- const callee = localTmp(scope, '#indirect_callee_obj', Valtype.f64);
2256
- initCalleeObj = [
2287
+ getCallee = [
2257
2288
  ...generate(scope, decl.callee.object),
2258
- [ Opcodes.local_set, callee ]
2259
- ];
2260
- getCalleeObj = [
2261
- [ Opcodes.local_get, callee ]
2262
- ];
2263
- knownThis = [
2264
- [ Opcodes.local_get, callee ],
2265
- ...getNodeType(scope, decl.callee.object)
2289
+ [ Opcodes.local_set, thisLocal ],
2290
+ ...getNodeType(scope, decl.callee.object),
2291
+ [ Opcodes.local_set, thisLocalType ],
2292
+
2293
+ ...generate(scope, {
2294
+ type: 'MemberExpression',
2295
+ object: { type: 'Identifier', name: '#indirect_caller' },
2296
+ property: decl.callee.property,
2297
+ computed: decl.callee.computed,
2298
+ optional: decl.callee.optional
2299
+ })
2266
2300
  ];
2267
2301
  }
2268
2302
 
@@ -2278,152 +2312,29 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2278
2312
  }
2279
2313
 
2280
2314
  const newTargetWasm = decl._newTargetWasm ?? createNewTarget(scope, decl, [
2281
- [ Opcodes.local_get, funcLocal ],
2282
- Opcodes.i32_from_u
2315
+ [ Opcodes.local_get, calleeLocal ]
2283
2316
  ], callAsNew);
2284
- const thisWasm = knownThis ?? createThisArg(scope, decl);
2285
-
2286
- const gen = argc => {
2287
- const argsOut = [];
2288
- for (let i = 0; i < argc; i++) {
2289
- argsOut.push(
2290
- [ Opcodes.local_get, locals[i][0] ],
2291
- [ Opcodes.local_get, locals[i][1] ]
2292
- );
2293
- }
2294
-
2295
- const checkFlag = (flag, pass, fail) => [
2296
- [ Opcodes.local_get, flags ],
2297
- ...number(flag, Valtype.i32),
2298
- [ Opcodes.i32_and ],
2299
- [ Opcodes.if, valtypeBinary ],
2300
- ...pass,
2301
- [ Opcodes.else ],
2302
- ...fail,
2303
- [ Opcodes.end ]
2304
- ];
2305
-
2306
- // todo: i'm sure this could be made better somehow, probably only with #96?
2307
- return checkFlag(0b1,
2308
- // no type return
2309
- checkFlag(0b10, [
2310
- // no type return & constr
2311
- ...newTargetWasm,
2312
- ...thisWasm,
2313
- ...argsOut,
2314
- [ Opcodes.local_get, funcLocal ],
2315
- [ Opcodes.call_indirect, argc + 2, 0, 'no_type_return' ],
2316
- ], [
2317
- // no type return & not constr
2318
- ...argsOut,
2319
- [ Opcodes.local_get, funcLocal ],
2320
- [ Opcodes.call_indirect, argc, 0, 'no_type_return' ]
2321
- ]),
2322
-
2323
- // type return
2324
- checkFlag(0b10, [
2325
- // type return & constr
2326
- ...newTargetWasm,
2327
- ...thisWasm,
2328
- ...argsOut,
2329
- [ Opcodes.local_get, funcLocal ],
2330
- [ Opcodes.call_indirect, argc + 2, 0 ],
2331
- ...setLastType(scope),
2332
- ], [
2333
- // type return
2334
- ...argsOut,
2335
- [ Opcodes.local_get, funcLocal ],
2336
- [ Opcodes.call_indirect, argc, 0 ],
2337
- ...setLastType(scope),
2338
- ])
2339
- );
2340
- };
2341
-
2342
- const tableBc = {};
2343
- for (let i = 0; i <= args.length; i++) {
2344
- tableBc[i] = gen(i);
2345
- }
2346
-
2347
- // todo/perf: check if we should use br_table here or just generate our own big if..elses
2317
+ const thisWasm = decl._thisWasm ?? knownThis ?? createThisArg(scope, decl);
2348
2318
 
2349
2319
  return [
2350
- ...(getCalleeObj ? [
2351
- ...initCalleeObj,
2352
- ...generate(scope, callee, false, undefined, getCalleeObj)
2353
- ]: generate(scope, callee)),
2354
- [ Opcodes.local_set, localTmp(scope, '#indirect_callee') ],
2320
+ ...(getCallee ? getCallee : generate(scope, callee)),
2321
+ [ Opcodes.local_set, calleeLocal ],
2355
2322
 
2356
2323
  ...typeSwitch(scope, getNodeType(scope, callee), {
2357
2324
  [TYPES.function]: () => [
2325
+ ...forceDuoValtype(scope, newTargetWasm, Valtype.f64),
2326
+ ...forceDuoValtype(scope, thisWasm, Valtype.f64),
2358
2327
  ...out,
2359
2328
 
2360
- [ Opcodes.local_get, localTmp(scope, '#indirect_callee') ],
2329
+ [ Opcodes.local_get, calleeLocal ],
2361
2330
  Opcodes.i32_to_u,
2362
- [ Opcodes.local_set, funcLocal ],
2363
-
2364
- // get if func we are calling is a constructor or not
2365
- [ Opcodes.local_get, funcLocal ],
2366
- ...number(64, Valtype.i32),
2367
- [ Opcodes.i32_mul ],
2368
- ...number(4, Valtype.i32),
2369
- [ Opcodes.i32_add ],
2370
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')), 'read func lut' ],
2371
- [ Opcodes.local_set, flags ],
2372
-
2373
- // check if non-constructor was called with new, if so throw
2374
- ...(callAsNew ? [
2375
- [ Opcodes.local_get, flags ],
2376
- ...number(0b10, Valtype.i32),
2377
- [ Opcodes.i32_and ],
2378
- [ Opcodes.i32_eqz ],
2379
- [ Opcodes.if, Blocktype.void ],
2380
- ...internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`),
2381
- [ Opcodes.end ],
2382
- ] : []),
2383
-
2384
- // [ Opcodes.local_get, funcLocal ],
2385
- // Opcodes.i32_from_u,
2386
- // [ Opcodes.call, 0 ],
2387
-
2388
- // ...number(32),
2389
- // [ Opcodes.call, 1 ],
2390
-
2391
- // [ Opcodes.local_get, funcLocal ],
2392
- // ...number(64, Valtype.i32),
2393
- // [ Opcodes.i32_mul ],
2394
- // [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')), 'read func lut' ],
2395
- // Opcodes.i32_from_u,
2396
- // [ Opcodes.call, 0 ],
2397
-
2398
- // [ Opcodes.local_get, funcLocal ],
2399
- // [ Opcodes.call, includeBuiltin(scope, '__Porffor_funcLut_name').index ],
2400
- // Opcodes.i32_from_u,
2401
- // ...number(TYPES.bytestring, Valtype.i32),
2402
- // [ Opcodes.call, includeBuiltin(scope, '__Porffor_printString').index ],
2403
- // [ Opcodes.drop ],
2404
- // [ Opcodes.drop ],
2405
-
2406
- // ...number(10),
2407
- // [ Opcodes.call, 1 ],
2408
-
2409
- ...brTable([
2410
- // get argc of func we are calling
2411
- [ Opcodes.local_get, funcLocal ],
2412
- ...number(64, Valtype.i32),
2413
- [ Opcodes.i32_mul ],
2414
- [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')), 'read func lut' ]
2415
- ], tableBc, valtypeBinary)
2331
+ [ Opcodes.call_indirect, args.length + 2, 0 ],
2332
+ ...setLastType(scope)
2416
2333
  ],
2417
2334
 
2418
- ...(decl.optional ? {
2419
- [TYPES.undefined]: [
2420
- ...number(UNDEFINED),
2421
- ...setLastType(scope, TYPES.undefined)
2422
- ]
2423
- } : {}),
2424
-
2425
- default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
2426
- })
2335
+ default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, Valtype.f64)
2336
+ }, Valtype.f64),
2337
+ ...(valtypeBinary === Valtype.i32 && scope.returns[0] !== Valtype.f64 ? [ [ Opcodes.f64_convert_i32_s ] ] : [])
2427
2338
  ];
2428
2339
  }
2429
2340
 
@@ -2455,16 +2366,12 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2455
2366
  paramOffset += 4;
2456
2367
  }
2457
2368
 
2458
- if (func && !func.hasRestArgument && args.length < paramCount) {
2369
+ if (func && args.length < paramCount) {
2459
2370
  // too little args, push undefineds
2460
- args = args.concat(new Array(paramCount - args.length).fill(DEFAULT_VALUE()));
2371
+ args = args.concat(new Array(paramCount - (func.hasRestArgument ? 1 : 0) - args.length).fill(DEFAULT_VALUE()));
2461
2372
  }
2462
2373
 
2463
2374
  if (func && func.hasRestArgument) {
2464
- if (args.length < paramCount) {
2465
- args = args.concat(new Array(paramCount - 1 - args.length).fill(DEFAULT_VALUE()));
2466
- }
2467
-
2468
2375
  const restArgs = args.slice(paramCount - 1);
2469
2376
  args = args.slice(0, paramCount - 1);
2470
2377
  args.push({
@@ -2478,13 +2385,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2478
2385
  args = args.slice(0, paramCount);
2479
2386
  }
2480
2387
 
2481
- if (func && func.throws) scope.throws = true;
2482
-
2483
2388
  for (let i = 0; i < args.length; i++) {
2484
2389
  const arg = args[i];
2485
2390
  if (Array.isArray(arg)) {
2486
2391
  // if wasm, just append it
2487
2392
  out = out.concat(arg);
2393
+
2394
+ if (valtypeBinary !== Valtype.i32 &&
2395
+ (func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.i32)
2396
+ ) {
2397
+ out.push(...forceDuoValtype(scope, [], Valtype.i32));
2398
+ }
2399
+
2488
2400
  continue;
2489
2401
  }
2490
2402
 
@@ -3755,8 +3667,11 @@ const generateUnary = (scope, decl) => {
3755
3667
  case 'delete': {
3756
3668
  if (decl.argument.type === 'MemberExpression') {
3757
3669
  const object = decl.argument.object;
3758
- const property = getProperty(decl.argument);
3759
3670
 
3671
+ // disallow `delete super.*`
3672
+ if (object.type === 'Super') return internalThrow(scope, 'ReferenceError', 'Cannot delete super property', true);
3673
+
3674
+ const property = getProperty(decl.argument);
3760
3675
  if (property.value === 'length' || property.value === 'name') scope.noFastFuncMembers = true;
3761
3676
 
3762
3677
  return [
@@ -4690,8 +4605,6 @@ const generateLabel = (scope, decl) => {
4690
4605
  };
4691
4606
 
4692
4607
  const generateThrow = (scope, decl) => {
4693
- scope.throws = true;
4694
-
4695
4608
  let exceptionMode = Prefs.exceptionMode ?? 'stack';
4696
4609
  if (globalThis.precompile) exceptionMode = decl.argument.callee != null ? 'lut' : 'stack';
4697
4610
 
@@ -5149,11 +5062,7 @@ const toPropertyKey = (scope, wasm, type, computed = false, i32Conv = false) =>
5149
5062
  ...wasm,
5150
5063
  ...type,
5151
5064
  [ Opcodes.call, includeBuiltin(scope, '__ecma262_ToPropertyKey').index ],
5152
- ...(i32Conv ? [
5153
- [ Opcodes.local_set, localTmp(scope, '#swap', Valtype.i32) ],
5154
- Opcodes.i32_to_u,
5155
- [ Opcodes.local_get, localTmp(scope, '#swap', Valtype.i32) ]
5156
- ] : [])
5065
+ ...(i32Conv ? forceDuoValtype(scope, [], Valtype.i32) : [])
5157
5066
  ] : [
5158
5067
  ...wasm,
5159
5068
  ...(i32Conv ? [ Opcodes.i32_to_u ] : []),
@@ -5288,18 +5197,17 @@ const countLength = (func, name = undefined) => {
5288
5197
 
5289
5198
  const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) => {
5290
5199
  let final = [], finalEnd, extraBC = {};
5291
- const name = decl.object.name;
5200
+ let name = decl.object.name;
5292
5201
 
5293
5202
  // todo: handle globalThis.foo
5294
5203
 
5295
5204
  // hack: .name
5296
5205
  if (decl.property.name === 'name' && hasFuncWithName(name) && !scope.noFastFuncMembers) {
5297
- let nameProp = name;
5298
-
5299
5206
  // eg: __String_prototype_toLowerCase -> toLowerCase
5300
- if (nameProp.startsWith('__')) nameProp = nameProp.split('_').pop();
5207
+ if (name.startsWith('__')) name = name.split('_').pop();
5208
+ if (name.startsWith('#')) name = '';
5301
5209
 
5302
- return withType(scope, makeString(scope, nameProp, _global, _name, true), TYPES.bytestring);
5210
+ return withType(scope, makeString(scope, name, _global, _name, true), TYPES.bytestring);
5303
5211
  }
5304
5212
 
5305
5213
  const object = decl.object;
@@ -5713,16 +5621,7 @@ const generateClass = (scope, decl) => {
5713
5621
  type: 'Identifier',
5714
5622
  name
5715
5623
  };
5716
- const proto = {
5717
- type: 'MemberExpression',
5718
- object: root,
5719
- property: {
5720
- type: 'Identifier',
5721
- name: 'prototype'
5722
- },
5723
- computed: false,
5724
- optional: false
5725
- };
5624
+ const proto = getObjProp(root, 'prototype');
5726
5625
 
5727
5626
  const [ func, out ] = generateFunc(scope, {
5728
5627
  ...(body.find(x => x.kind === 'constructor')?.value ?? {
@@ -5749,7 +5648,7 @@ const generateClass = (scope, decl) => {
5749
5648
  // Bar.__proto__ = Foo
5750
5649
  // Bar.prototype.__proto__ = Foo.prototype
5751
5650
  ...generate(scope, setObjProp(root, '__proto__', decl.superClass)),
5752
- ...generate(scope, setObjProp(getObjProp(root, 'prototype'), '__proto__', getObjProp(decl.superClass, 'prototype')))
5651
+ ...generate(scope, setObjProp(proto, '__proto__', getObjProp(decl.superClass, 'prototype')))
5753
5652
  );
5754
5653
  }
5755
5654
 
@@ -6278,6 +6177,18 @@ const generateFunc = (scope, decl) => {
6278
6177
  func.params = Object.values(func.locals).map(x => x.type);
6279
6178
  func.jsLength = jsLength;
6280
6179
 
6180
+ if (globalThis.valtypeOverrides) {
6181
+ if (globalThis.valtypeOverrides.returns[name]) func.returns = globalThis.valtypeOverrides.returns[name];
6182
+ if (globalThis.valtypeOverrides.params[name]) {
6183
+ func.params = globalThis.valtypeOverrides.params[name];
6184
+
6185
+ const localsVals = Object.values(func.locals);
6186
+ for (let i = 0; i < func.params.length; i++) {
6187
+ localsVals[i].type = func.params[i];
6188
+ }
6189
+ }
6190
+ }
6191
+
6281
6192
  // force generate for main
6282
6193
  if (name === 'main') func.generate();
6283
6194
 
@@ -6420,7 +6331,7 @@ export default program => {
6420
6331
  };
6421
6332
  tags = [];
6422
6333
  exceptions = [];
6423
- funcs = [];
6334
+ funcs = []; indirectFuncs = [];
6424
6335
  funcIndex = {};
6425
6336
  depth = [];
6426
6337
  pages = new Map();
@@ -6475,6 +6386,7 @@ export default program => {
6475
6386
  // todo: these should just be deleted once able
6476
6387
  for (let i = 0; i < funcs.length; i++) {
6477
6388
  const f = funcs[i];
6389
+
6478
6390
  if (f.wasm) {
6479
6391
  // run callbacks
6480
6392
  const wasm = f.wasm;
@@ -6531,9 +6443,15 @@ export default program => {
6531
6443
  // }
6532
6444
  // }
6533
6445
 
6534
- delete globals['#ind'];
6446
+ // add indirect funcs to end of funcs
6447
+ for (let i = 0; i < indirectFuncs.length; i++) {
6448
+ const f = indirectFuncs[i];
6449
+ f.index = currentFuncIndex++;
6450
+ }
6451
+
6452
+ funcs.push(...indirectFuncs);
6535
6453
 
6536
- // console.log([...usedTypes].map(x => TYPE_NAMES[x]));
6454
+ delete globals['#ind'];
6537
6455
 
6538
6456
  return { funcs, globals, tags, exceptions, pages, data };
6539
6457
  };
@@ -13,6 +13,26 @@ const __dirname = fileURLToPath(new URL('.', import.meta.url));
13
13
  globalThis.precompileCompilerPath = __dirname;
14
14
  globalThis.precompile = true;
15
15
 
16
+ globalThis.valtypeOverrides = {
17
+ returns: {
18
+ __Porffor_object_get: [ Valtype.f64, Valtype.i32 ],
19
+ __Porffor_object_getExplicit: [ Valtype.f64, Valtype.i32 ],
20
+ __Porffor_object_readValue: [ Valtype.f64, Valtype.i32 ],
21
+ __Porffor_object_set: [ Valtype.f64, Valtype.i32 ],
22
+ __Porffor_object_setStrict: [ Valtype.f64, Valtype.i32 ],
23
+ __Porffor_object_packAccessor: [ Valtype.f64, Valtype.i32 ]
24
+ },
25
+ params: {
26
+ __Porffor_object_set: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
27
+ __Porffor_object_setStrict: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
28
+ __Porffor_object_expr_init: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
29
+ __Porffor_object_expr_initWithFlags: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32, Valtype.i32, Valtype.i32 ],
30
+ __Porffor_object_class_value: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
31
+ __Porffor_object_class_method: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
32
+ __Porffor_object_define: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32, Valtype.i32, Valtype.i32 ],
33
+ }
34
+ };
35
+
16
36
  const argv = process.argv.slice();
17
37
 
18
38
  const timing = {};
@@ -50,25 +70,6 @@ const compile = async (file, _funcs) => {
50
70
  return acc;
51
71
  }, {});
52
72
 
53
- const returnOverrides = {
54
- __Porffor_object_get: [ Valtype.f64, Valtype.i32 ],
55
- __Porffor_object_getExplicit: [ Valtype.f64, Valtype.i32 ],
56
- __Porffor_object_readValue: [ Valtype.f64, Valtype.i32 ],
57
- __Porffor_object_set: [ Valtype.f64, Valtype.i32 ],
58
- __Porffor_object_setStrict: [ Valtype.f64, Valtype.i32 ],
59
- __Porffor_object_packAccessor: [ Valtype.f64, Valtype.i32 ]
60
- };
61
-
62
- const paramOverrides = {
63
- __Porffor_object_set: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
64
- __Porffor_object_setStrict: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
65
- __Porffor_object_expr_init: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
66
- __Porffor_object_expr_initWithFlags: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32, Valtype.i32, Valtype.i32 ],
67
- __Porffor_object_class_value: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
68
- __Porffor_object_class_method: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
69
- __Porffor_object_define: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32, Valtype.i32, Valtype.i32 ],
70
- };
71
-
72
73
  const main = funcs.find(x => x.name === 'main');
73
74
  const exports = funcs.filter(x => x.export && x.name !== 'main');
74
75
  for (const x of exports) {
@@ -84,9 +85,6 @@ const compile = async (file, _funcs) => {
84
85
  }).filter(x => x);
85
86
  }
86
87
 
87
- if (returnOverrides[x.name]) x.returns = returnOverrides[x.name];
88
- if (paramOverrides[x.name]) x.params = paramOverrides[x.name];
89
-
90
88
  const rewriteWasm = (x, wasm, rewriteLocals = false) => {
91
89
  const locals = Object.keys(x.locals).reduce((acc, y) => {
92
90
  acc[x.locals[y].idx] = { ...x.locals[y], name: y };
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.41.6+eb38ba00c",
4
+ "version": "0.42.0+93da2c806",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/runner/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.41.6+eb38ba00c';
3
+ globalThis.version = '0.42.0+93da2c806';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
@@ -167,7 +167,7 @@ try {
167
167
  }
168
168
  } catch (e) {
169
169
  let out = e;
170
- if (!process.argv.includes('-d') && Object.getPrototypeOf(e).message != null) out = `${e.constructor.name}${e.message != null ? `: ${e.message}` : ''}`;
170
+ if (!process.argv.includes('-d') && Object.getPrototypeOf(e).message != null) out = `${e.name}${e.message != null ? `: ${e.message}` : ''}`;
171
171
  console.error(out);
172
172
  }
173
173