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.
@@ -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(ctx) {
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
- ObjectBuiltins.call(this, ctx, Prefs);
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