porffor 0.60.7 → 0.60.9
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 +1 -3
- package/compiler/2c.js +2 -2
- package/compiler/assemble.js +16 -3
- package/compiler/builtins/regexp.ts +180 -36
- package/compiler/builtins.js +348 -6
- package/compiler/builtins_precompiled.js +1099 -1099
- package/compiler/codegen.js +78 -12
- package/compiler/cyclone.js +2 -2
- package/compiler/disassemble.js +2 -2
- package/compiler/encoding.js +22 -4
- package/compiler/expression.js +0 -25
- package/compiler/opt.js +15 -15
- package/compiler/precompile.js +3 -3
- package/compiler/wrap.js +4 -1
- package/package.json +2 -2
- package/runtime/index.js +1 -1
- package/AGENTS.md +0 -20
- package/compiler/allocator.js +0 -65
- package/compiler/builtins_objects.js +0 -349
package/compiler/builtins.js
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import * as PrecompiledBuiltins from './builtins_precompiled.js';
|
2
|
-
import ObjectBuiltins from './builtins_objects.js';
|
3
2
|
import { PageSize, Blocktype, Opcodes, Valtype } from './wasmSpec.js';
|
4
3
|
import { TYPES, TYPE_NAMES } from './types.js';
|
5
4
|
import { number, unsignedLEB128 } from './encoding.js';
|
@@ -62,7 +61,7 @@ export const createImport = (name, params, returns, js = null, c = null) => {
|
|
62
61
|
export const UNDEFINED = 0;
|
63
62
|
export const NULL = 0;
|
64
63
|
|
65
|
-
export const BuiltinVars = function(
|
64
|
+
export const BuiltinVars = function({ builtinFuncs }) {
|
66
65
|
this.undefined = () => [ number(UNDEFINED) ];
|
67
66
|
this.undefined.type = TYPES.undefined;
|
68
67
|
|
@@ -121,7 +120,350 @@ export const BuiltinVars = function(ctx) {
|
|
121
120
|
this[`__Symbol_${x}`].type = TYPES.symbol;
|
122
121
|
}
|
123
122
|
|
124
|
-
|
123
|
+
// builtin objects
|
124
|
+
const makePrefix = name => (name.startsWith('__') ? '' : '__') + name + '_';
|
125
|
+
|
126
|
+
const done = new Set();
|
127
|
+
const object = (name, props) => {
|
128
|
+
done.add(name);
|
129
|
+
const prefix = name === 'globalThis' ? '' : makePrefix(name);
|
130
|
+
|
131
|
+
// already a func
|
132
|
+
const existingFunc = builtinFuncs[name];
|
133
|
+
|
134
|
+
builtinFuncs['#get_' + name] = {
|
135
|
+
params: [],
|
136
|
+
locals: [ Valtype.i32 ],
|
137
|
+
returns: [ Valtype.i32 ],
|
138
|
+
returnType: TYPES.object,
|
139
|
+
wasm: (scope, { allocPage, makeString, generate, getNodeType, builtin, funcRef, glbl }) => {
|
140
|
+
if (globalThis.precompile) return [ [ 'get object', name ] ];
|
141
|
+
|
142
|
+
// todo/perf: precompute bytes here instead of calling real funcs if we really care about perf later
|
143
|
+
|
144
|
+
let ptr;
|
145
|
+
if (existingFunc) {
|
146
|
+
ptr = funcRef(name)[0][1];
|
147
|
+
} else {
|
148
|
+
ptr = allocPage(scope, `builtin object: ${name}`);
|
149
|
+
}
|
150
|
+
|
151
|
+
const getPtr = glbl(Opcodes.global_get, `getptr_${name}`, Valtype.i32)[0];
|
152
|
+
const out = [
|
153
|
+
// check if already made/cached
|
154
|
+
getPtr,
|
155
|
+
[ Opcodes.if, Blocktype.void ],
|
156
|
+
getPtr,
|
157
|
+
[ Opcodes.return ],
|
158
|
+
[ Opcodes.end ],
|
159
|
+
|
160
|
+
// set cache & ptr for use
|
161
|
+
number(ptr, Valtype.i32),
|
162
|
+
[ Opcodes.local_tee, 0 ],
|
163
|
+
glbl(Opcodes.global_set, `getptr_${name}`, Valtype.i32)[0],
|
164
|
+
|
165
|
+
[ Opcodes.local_get, 0 ],
|
166
|
+
Opcodes.i32_from_u,
|
167
|
+
number(existingFunc ? TYPES.function : TYPES.object, Valtype.i32),
|
168
|
+
[ Opcodes.call, builtin('__Porffor_object_underlying') ],
|
169
|
+
[ Opcodes.drop ],
|
170
|
+
[ Opcodes.local_set, 0 ]
|
171
|
+
];
|
172
|
+
|
173
|
+
for (const x in props) {
|
174
|
+
let value = {
|
175
|
+
type: 'Identifier',
|
176
|
+
name: prefix + x
|
177
|
+
};
|
178
|
+
|
179
|
+
if (x === '__proto__') {
|
180
|
+
out.push(
|
181
|
+
[ Opcodes.local_get, 0 ],
|
182
|
+
number(TYPES.object, Valtype.i32),
|
183
|
+
|
184
|
+
...generate(scope, value),
|
185
|
+
Opcodes.i32_to_u,
|
186
|
+
...getNodeType(scope, value),
|
187
|
+
|
188
|
+
[ Opcodes.call, builtin('__Porffor_object_setPrototype') ]
|
189
|
+
);
|
190
|
+
continue;
|
191
|
+
}
|
192
|
+
|
193
|
+
let add = true;
|
194
|
+
if (existingFunc && (x === 'prototype' || x === 'constructor')) add = false;
|
195
|
+
|
196
|
+
let flags = 0b0000;
|
197
|
+
const d = props[x];
|
198
|
+
if (d.configurable) flags |= 0b0010;
|
199
|
+
if (d.enumerable) flags |= 0b0100;
|
200
|
+
if (d.writable) flags |= 0b1000;
|
201
|
+
|
202
|
+
out.push(
|
203
|
+
[ Opcodes.local_get, 0 ],
|
204
|
+
number(TYPES.object, Valtype.i32),
|
205
|
+
|
206
|
+
...makeString(scope, x),
|
207
|
+
Opcodes.i32_to_u,
|
208
|
+
number(TYPES.bytestring, Valtype.i32),
|
209
|
+
|
210
|
+
...generate(scope, value),
|
211
|
+
...getNodeType(scope, value),
|
212
|
+
|
213
|
+
number(flags, Valtype.i32),
|
214
|
+
number(TYPES.number, Valtype.i32),
|
215
|
+
|
216
|
+
[ Opcodes.call, builtin(add ? '__Porffor_object_fastAdd' : '__Porffor_object_define') ]
|
217
|
+
);
|
218
|
+
}
|
219
|
+
|
220
|
+
// return ptr
|
221
|
+
out.push(getPtr);
|
222
|
+
return out;
|
223
|
+
}
|
224
|
+
};
|
225
|
+
|
226
|
+
this[name] = (scope, { builtin }) => [
|
227
|
+
[ Opcodes.call, builtin('#get_' + name) ],
|
228
|
+
Opcodes.i32_from_u
|
229
|
+
];
|
230
|
+
this[name].type = existingFunc ? TYPES.function : TYPES.object;
|
231
|
+
|
232
|
+
for (const x in props) {
|
233
|
+
const d = props[x];
|
234
|
+
const k = prefix + x;
|
235
|
+
|
236
|
+
if (Object.hasOwn(d, 'value') && !Object.hasOwn(builtinFuncs, k) && !Object.hasOwn(this, k)) {
|
237
|
+
if (Array.isArray(d.value) || typeof d.value === 'function') {
|
238
|
+
this[k] = d.value;
|
239
|
+
continue;
|
240
|
+
}
|
241
|
+
|
242
|
+
if (typeof d.value === 'number') {
|
243
|
+
this[k] = [ number(d.value) ];
|
244
|
+
this[k].type = TYPES.number;
|
245
|
+
continue;
|
246
|
+
}
|
247
|
+
|
248
|
+
if (typeof d.value === 'string') {
|
249
|
+
this[k] = (scope, { makeString }) => makeString(scope, d.value);
|
250
|
+
this[k].type = TYPES.bytestring;
|
251
|
+
continue;
|
252
|
+
}
|
253
|
+
|
254
|
+
if (d.value === null) {
|
255
|
+
this[k] = this.null;
|
256
|
+
continue;
|
257
|
+
}
|
258
|
+
|
259
|
+
throw new Error(`unsupported value type (${typeof d.value})`);
|
260
|
+
}
|
261
|
+
}
|
262
|
+
};
|
263
|
+
|
264
|
+
const props = (base, vals) => {
|
265
|
+
const out = {};
|
266
|
+
|
267
|
+
if (Array.isArray(vals)) {
|
268
|
+
// array of keys with no value
|
269
|
+
for (const x of vals) {
|
270
|
+
out[x] = {
|
271
|
+
...base
|
272
|
+
};
|
273
|
+
}
|
274
|
+
} else for (const x in vals) {
|
275
|
+
// object of key values
|
276
|
+
out[x] = {
|
277
|
+
...base,
|
278
|
+
value: vals[x]
|
279
|
+
};
|
280
|
+
}
|
281
|
+
|
282
|
+
return out;
|
283
|
+
};
|
284
|
+
|
285
|
+
const builtinFuncKeys = Object.keys(builtinFuncs);
|
286
|
+
const autoFuncKeys = name => {
|
287
|
+
const prefix = makePrefix(name);
|
288
|
+
return builtinFuncKeys.filter(x => x.startsWith(prefix)).map(x => x.slice(prefix.length)).filter(x => !x.startsWith('prototype_'));
|
289
|
+
};
|
290
|
+
const autoFuncs = name => ({
|
291
|
+
...props({
|
292
|
+
writable: true,
|
293
|
+
enumerable: false,
|
294
|
+
configurable: true
|
295
|
+
}, autoFuncKeys(name)),
|
296
|
+
...(this[`__${name}_prototype`] ? {
|
297
|
+
prototype: {
|
298
|
+
writable: false,
|
299
|
+
enumerable: false,
|
300
|
+
configurable: false
|
301
|
+
}
|
302
|
+
} : {})
|
303
|
+
});
|
304
|
+
|
305
|
+
object('Math', {
|
306
|
+
...props({
|
307
|
+
writable: false,
|
308
|
+
enumerable: false,
|
309
|
+
configurable: false
|
310
|
+
}, {
|
311
|
+
E: Math.E,
|
312
|
+
LN10: Math.LN10,
|
313
|
+
LN2: Math.LN2,
|
314
|
+
LOG10E: Math.LOG10E,
|
315
|
+
LOG2E: Math.LOG2E,
|
316
|
+
PI: Math.PI,
|
317
|
+
SQRT1_2: Math.SQRT1_2,
|
318
|
+
SQRT2: Math.SQRT2,
|
319
|
+
|
320
|
+
// https://github.com/rwaldron/proposal-math-extensions/issues/10
|
321
|
+
RAD_PER_DEG: Math.PI / 180,
|
322
|
+
DEG_PER_RAD: 180 / Math.PI
|
323
|
+
}),
|
324
|
+
|
325
|
+
...autoFuncs('Math')
|
326
|
+
});
|
327
|
+
|
328
|
+
// automatically generate objects for prototypes
|
329
|
+
for (const x of builtinFuncKeys.reduce((acc, x) => {
|
330
|
+
const ind = x.indexOf('_prototype_');
|
331
|
+
if (ind === -1) return acc;
|
332
|
+
|
333
|
+
acc.add(x.slice(0, ind + 10));
|
334
|
+
return acc;
|
335
|
+
}, new Set())) {
|
336
|
+
const props = autoFuncs(x);
|
337
|
+
|
338
|
+
// special case: Object.prototype.__proto__ = null
|
339
|
+
if (x === '__Object_prototype') {
|
340
|
+
Object.defineProperty(props, '__proto__', { value: { value: null, configurable: true }, enumerable: true });
|
341
|
+
}
|
342
|
+
|
343
|
+
// special case: Function.prototype.length = 0
|
344
|
+
// special case: Function.prototype.name = ''
|
345
|
+
if (x === '__Function_prototype') {
|
346
|
+
props.length = { value: 0, configurable: true };
|
347
|
+
props.name = { value: '', configurable: true };
|
348
|
+
}
|
349
|
+
|
350
|
+
// add constructor for constructors
|
351
|
+
const name = x.slice(2, x.indexOf('_', 2));
|
352
|
+
if (builtinFuncs[name]?.constr) {
|
353
|
+
const value = (scope, { funcRef }) => funcRef(name);
|
354
|
+
value.type = TYPES.function;
|
355
|
+
|
356
|
+
props.constructor = {
|
357
|
+
value,
|
358
|
+
writable: true,
|
359
|
+
enumerable: false,
|
360
|
+
configurable: true
|
361
|
+
};
|
362
|
+
}
|
363
|
+
|
364
|
+
object(x, props);
|
365
|
+
}
|
366
|
+
|
367
|
+
|
368
|
+
object('Number', {
|
369
|
+
...props({
|
370
|
+
writable: false,
|
371
|
+
enumerable: false,
|
372
|
+
configurable: false
|
373
|
+
}, {
|
374
|
+
NaN: NaN,
|
375
|
+
POSITIVE_INFINITY: Infinity,
|
376
|
+
NEGATIVE_INFINITY: -Infinity,
|
377
|
+
MAX_VALUE: valtype === 'i32' ? 2147483647 : 1.7976931348623157e+308,
|
378
|
+
MIN_VALUE: valtype === 'i32' ? -2147483648 : 5e-324,
|
379
|
+
MAX_SAFE_INTEGER: valtype === 'i32' ? 2147483647 : 9007199254740991,
|
380
|
+
MIN_SAFE_INTEGER: valtype === 'i32' ? -2147483648 : -9007199254740991,
|
381
|
+
EPSILON: 2.220446049250313e-16
|
382
|
+
}),
|
383
|
+
|
384
|
+
...autoFuncs('Number')
|
385
|
+
});
|
386
|
+
|
387
|
+
// these technically not spec compliant as it should be classes or non-enumerable but eh
|
388
|
+
object('navigator', {
|
389
|
+
...props({
|
390
|
+
writable: false,
|
391
|
+
enumerable: true,
|
392
|
+
configurable: false
|
393
|
+
}, {
|
394
|
+
userAgent: `Porffor/${globalThis.version}`
|
395
|
+
})
|
396
|
+
});
|
397
|
+
|
398
|
+
for (const x of [
|
399
|
+
'console',
|
400
|
+
'crypto',
|
401
|
+
'performance',
|
402
|
+
]) {
|
403
|
+
object(x, props({
|
404
|
+
writable: true,
|
405
|
+
enumerable: true,
|
406
|
+
configurable: true
|
407
|
+
}, autoFuncKeys(x).slice(0, 12)));
|
408
|
+
}
|
409
|
+
|
410
|
+
for (const x of [ 'Array', 'ArrayBuffer', 'Atomics', 'Date', 'Error', 'JSON', 'Object', 'Promise', 'Reflect', 'String', 'Symbol', 'Uint8Array', 'Int8Array', 'Uint8ClampedArray', 'Uint16Array', 'Int16Array', 'Uint32Array', 'Int32Array', 'Float32Array', 'Float64Array', 'BigInt64Array', 'BigUint64Array', 'SharedArrayBuffer', 'BigInt', 'Boolean', 'DataView', 'AggregateError', 'TypeError', 'ReferenceError', 'SyntaxError', 'RangeError', 'EvalError', 'URIError', 'Function', 'Map', 'RegExp', 'Set', 'WeakMap', 'WeakRef', 'WeakSet' ]) {
|
411
|
+
object(x, autoFuncs(x));
|
412
|
+
}
|
413
|
+
|
414
|
+
const enumerableGlobals = [ 'atob', 'btoa', 'performance', 'crypto', 'navigator' ];
|
415
|
+
object('globalThis', {
|
416
|
+
// 19.1 Value Properties of the Global Object
|
417
|
+
// https://tc39.es/ecma262/#sec-value-properties-of-the-global-object
|
418
|
+
// 19.1.1 globalThis
|
419
|
+
globalThis: {
|
420
|
+
writable: true,
|
421
|
+
enumerable: false,
|
422
|
+
configurable: true
|
423
|
+
},
|
424
|
+
|
425
|
+
// 19.1.2 Infinity
|
426
|
+
// 19.1.3 NaN
|
427
|
+
// 19.1.4 undefined
|
428
|
+
...props({
|
429
|
+
writable: false,
|
430
|
+
enumerable: false,
|
431
|
+
configurable: false
|
432
|
+
}, [ 'Infinity', 'NaN', 'undefined' ]),
|
433
|
+
|
434
|
+
// 19.2 Function Properties of the Global Object
|
435
|
+
// https://tc39.es/ecma262/#sec-function-properties-of-the-global-object
|
436
|
+
// 19.3 Constructor Properties of the Global Object
|
437
|
+
// https://tc39.es/ecma262/#sec-constructor-properties-of-the-global-object
|
438
|
+
...props({
|
439
|
+
writable: true,
|
440
|
+
enumerable: false,
|
441
|
+
configurable: true
|
442
|
+
}, builtinFuncKeys.filter(x => !x.startsWith('__') && !enumerableGlobals.includes(x) && !x.startsWith('f64') && !x.startsWith('i32'))),
|
443
|
+
|
444
|
+
...props({
|
445
|
+
writable: true,
|
446
|
+
enumerable: true,
|
447
|
+
configurable: true
|
448
|
+
}, enumerableGlobals)
|
449
|
+
});
|
450
|
+
|
451
|
+
if (Prefs.logMissingObjects) for (const x of Object.keys(builtinFuncs).concat(Object.keys(this))) {
|
452
|
+
if (!x.startsWith('__')) continue;
|
453
|
+
const name = x.split('_').slice(2, -1).join('_');
|
454
|
+
|
455
|
+
let t = globalThis;
|
456
|
+
for (const x of name.split('_')) {
|
457
|
+
t = t[x];
|
458
|
+
if (!t) break;
|
459
|
+
}
|
460
|
+
if (!t) continue;
|
461
|
+
|
462
|
+
if (!done.has(name) && !done.has('__' + name)) {
|
463
|
+
console.log(name, !!builtinFuncs[name]);
|
464
|
+
done.add(name);
|
465
|
+
}
|
466
|
+
}
|
125
467
|
};
|
126
468
|
|
127
469
|
export const BuiltinFuncs = function() {
|
@@ -820,7 +1162,7 @@ export const BuiltinFuncs = function() {
|
|
820
1162
|
number(funcs.bytesPerFuncLut(), Valtype.i32)
|
821
1163
|
] ],
|
822
1164
|
[ Opcodes.i32_mul ],
|
823
|
-
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocLargePage(scope, 'func lut')) ]
|
1165
|
+
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocLargePage(scope, '#func lut')) ]
|
824
1166
|
],
|
825
1167
|
table: true
|
826
1168
|
};
|
@@ -837,7 +1179,7 @@ export const BuiltinFuncs = function() {
|
|
837
1179
|
[ Opcodes.i32_mul ],
|
838
1180
|
number(2, Valtype.i32),
|
839
1181
|
[ Opcodes.i32_add ],
|
840
|
-
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocLargePage(scope, 'func lut')) ]
|
1182
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocLargePage(scope, '#func lut')) ]
|
841
1183
|
],
|
842
1184
|
table: true
|
843
1185
|
};
|
@@ -854,7 +1196,7 @@ export const BuiltinFuncs = function() {
|
|
854
1196
|
[ Opcodes.i32_mul ],
|
855
1197
|
number(3, Valtype.i32),
|
856
1198
|
[ Opcodes.i32_add ],
|
857
|
-
number(allocLargePage(scope, 'func lut'), Valtype.i32),
|
1199
|
+
number(allocLargePage(scope, '#func lut'), Valtype.i32),
|
858
1200
|
[ Opcodes.i32_add ]
|
859
1201
|
],
|
860
1202
|
table: true
|