porffor 0.55.22 → 0.55.24
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/compiler/allocator.js +1 -1
- package/compiler/builtins/_internal_object.ts +568 -285
- package/compiler/builtins/bigint.ts +2 -2
- package/compiler/builtins/console.ts +1 -1
- package/compiler/builtins/function.ts +1 -1
- package/compiler/builtins/object.ts +46 -51
- package/compiler/builtins/object_prototypeWithHidden.js +47 -0
- package/compiler/builtins/reflect.ts +4 -4
- package/compiler/builtins/z_ecma262.ts +3 -0
- package/compiler/builtins_precompiled.js +575 -554
- package/compiler/codegen.js +86 -216
- package/compiler/precompile.js +6 -5
- package/compiler/prototype.js +80 -66
- package/compiler/wrap.js +3 -4
- package/package.json +1 -1
- package/r.cjs +30 -6
- package/runner/flamegraph.js +13 -13
- package/runner/index.js +1 -1
    
        package/compiler/codegen.js
    CHANGED
    
    | @@ -848,13 +848,6 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod | |
| 848 848 | 
             
                  ] ] ] : []),
         | 
| 849 849 |  | 
| 850 850 | 
             
                  [ 'default', def ]
         | 
| 851 | 
            -
             | 
| 852 | 
            -
                  // [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
         | 
| 853 | 
            -
                  // [ 'default', [
         | 
| 854 | 
            -
                  //   // other types are always truthy
         | 
| 855 | 
            -
                  //   ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
         | 
| 856 | 
            -
                  //   number(1, intOut ? Valtype.i32 : valtypeBinary)
         | 
| 857 | 
            -
                  // ] ]
         | 
| 858 851 | 
             
                ], intOut ? Valtype.i32 : valtypeBinary)
         | 
| 859 852 | 
             
              ];
         | 
| 860 853 | 
             
            };
         | 
| @@ -921,13 +914,6 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode | |
| 921 914 | 
             
                  ] ] ] : []),
         | 
| 922 915 |  | 
| 923 916 | 
             
                  [ 'default', def ]
         | 
| 924 | 
            -
             | 
| 925 | 
            -
                  // [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
         | 
| 926 | 
            -
                  // [ 'default', [
         | 
| 927 | 
            -
                  //   // other types are always truthy
         | 
| 928 | 
            -
                  //   ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
         | 
| 929 | 
            -
                  //   number(0, intOut ? Valtype.i32 : valtypeBinary)
         | 
| 930 | 
            -
                  // ] ]
         | 
| 931 917 | 
             
                ], intOut ? Valtype.i32 : valtypeBinary)
         | 
| 932 918 | 
             
              ];
         | 
| 933 919 | 
             
            };
         | 
| @@ -1539,7 +1525,7 @@ const getNodeType = (scope, node) => { | |
| 1539 1525 | 
             
                  return getType(scope, node.name);
         | 
| 1540 1526 | 
             
                }
         | 
| 1541 1527 |  | 
| 1542 | 
            -
                if (node.type === 'ObjectExpression') {
         | 
| 1528 | 
            +
                if (node.type === 'ObjectExpression' || node.type === 'Super') {
         | 
| 1543 1529 | 
             
                  return TYPES.object;
         | 
| 1544 1530 | 
             
                }
         | 
| 1545 1531 |  | 
| @@ -1571,24 +1557,6 @@ const getNodeType = (scope, node) => { | |
| 1571 1557 | 
             
                  if (Object.hasOwn(builtinFuncs, name) && builtinFuncs[name].returnType != null) return builtinFuncs[name].returnType;
         | 
| 1572 1558 | 
             
                  if (Object.hasOwn(internalConstrs, name) && internalConstrs[name].type != null) return internalConstrs[name].type;
         | 
| 1573 1559 |  | 
| 1574 | 
            -
                  // check if this is a prototype function
         | 
| 1575 | 
            -
                  // if so and there is only one impl (eg charCodeAt)
         | 
| 1576 | 
            -
                  // or all impls have the same return type
         | 
| 1577 | 
            -
                  // use that return type as that is the only possibility
         | 
| 1578 | 
            -
                  // (if non-matching type it would error out)
         | 
| 1579 | 
            -
                  if (name.startsWith('__')) {
         | 
| 1580 | 
            -
                    const spl = name.slice(2).split('_');
         | 
| 1581 | 
            -
             | 
| 1582 | 
            -
                    const func = spl[spl.length - 1];
         | 
| 1583 | 
            -
                    const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
         | 
| 1584 | 
            -
                    if (
         | 
| 1585 | 
            -
                      protoFuncs.length === 1 ||
         | 
| 1586 | 
            -
                      (protoFuncs.length > 1 && protoFuncs.every(x => x.returnType === protoFuncs[0].returnType))
         | 
| 1587 | 
            -
                    ) {
         | 
| 1588 | 
            -
                      if (protoFuncs[0].returnType != null) return protoFuncs[0].returnType;
         | 
| 1589 | 
            -
                    }
         | 
| 1590 | 
            -
                  }
         | 
| 1591 | 
            -
             | 
| 1592 1560 | 
             
                  if (name.startsWith('__Porffor_wasm_')) {
         | 
| 1593 1561 | 
             
                    // todo: return undefined for non-returning ops
         | 
| 1594 1562 | 
             
                    return TYPES.number;
         | 
| @@ -1741,7 +1709,6 @@ const getNodeType = (scope, node) => { | |
| 1741 1709 | 
             
              if (guess != null) out.guess = typeof guess === 'number' ? [ number(guess, Valtype.i32) ] : guess;
         | 
| 1742 1710 |  | 
| 1743 1711 | 
             
              typeUsed(scope, knownType(scope, out));
         | 
| 1744 | 
            -
             | 
| 1745 1712 | 
             
              return out;
         | 
| 1746 1713 | 
             
            };
         | 
| 1747 1714 |  | 
| @@ -1860,29 +1827,6 @@ const createNewTarget = (scope, decl, idx = 0, force = false) => { | |
| 1860 1827 | 
             
              ];
         | 
| 1861 1828 | 
             
            };
         | 
| 1862 1829 |  | 
| 1863 | 
            -
            const makeObject = (scope, obj) => {
         | 
| 1864 | 
            -
              const properties = [];
         | 
| 1865 | 
            -
              for (const x in obj) {
         | 
| 1866 | 
            -
                properties.push({
         | 
| 1867 | 
            -
                  type: 'Property',
         | 
| 1868 | 
            -
                  method: false,
         | 
| 1869 | 
            -
                  shorthand: false,
         | 
| 1870 | 
            -
                  computed: false,
         | 
| 1871 | 
            -
                  key: {
         | 
| 1872 | 
            -
                    type: 'Identifier',
         | 
| 1873 | 
            -
                    name: x
         | 
| 1874 | 
            -
                  },
         | 
| 1875 | 
            -
                  value: obj[x],
         | 
| 1876 | 
            -
                  kind: 'init'
         | 
| 1877 | 
            -
                });
         | 
| 1878 | 
            -
              }
         | 
| 1879 | 
            -
             | 
| 1880 | 
            -
              return generate(scope, {
         | 
| 1881 | 
            -
                type: 'ObjectExpression',
         | 
| 1882 | 
            -
                properties
         | 
| 1883 | 
            -
              });
         | 
| 1884 | 
            -
            };
         | 
| 1885 | 
            -
             | 
| 1886 1830 | 
             
            const getObjProp = (obj, prop) => {
         | 
| 1887 1831 | 
             
              if (typeof obj === 'string') obj = {
         | 
| 1888 1832 | 
             
                type: 'Identifier',
         | 
| @@ -1932,8 +1876,6 @@ const aliasPrimObjsBC = bc => { | |
| 1932 1876 | 
             
              const add = (x, y) => {
         | 
| 1933 1877 | 
             
                if (bc[x] == null) return;
         | 
| 1934 1878 |  | 
| 1935 | 
            -
                // bc[`${x},${y}`] = original;
         | 
| 1936 | 
            -
             | 
| 1937 1879 | 
             
                // intentionally duplicate to avoid extra bc for prim objs as rarely used
         | 
| 1938 1880 | 
             
                bc[y] = bc[x];
         | 
| 1939 1881 | 
             
              };
         | 
| @@ -1967,32 +1909,22 @@ const createThisArg = (scope, decl) => { | |
| 1967 1909 | 
             
                  number(TYPES.object, Valtype.i32)
         | 
| 1968 1910 | 
             
                ];
         | 
| 1969 1911 |  | 
| 1970 | 
            -
                // create new object with  | 
| 1912 | 
            +
                // create new object with prototype set to callee prototype
         | 
| 1971 1913 | 
             
                const tmp = localTmp(scope, '#this_create_tmp');
         | 
| 1972 1914 | 
             
                const proto = getObjProp(decl.callee, 'prototype');
         | 
| 1973 1915 |  | 
| 1974 1916 | 
             
                return [
         | 
| 1975 | 
            -
                   | 
| 1917 | 
            +
                  [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
         | 
| 1918 | 
            +
                  Opcodes.i32_from_u,
         | 
| 1976 1919 | 
             
                  [ Opcodes.local_tee, tmp ],
         | 
| 1977 1920 | 
             
                  Opcodes.i32_to_u,
         | 
| 1978 | 
            -
             | 
| 1979 1921 | 
             
                  number(TYPES.object, Valtype.i32),
         | 
| 1980 1922 |  | 
| 1981 | 
            -
                  ...generate(scope, {
         | 
| 1982 | 
            -
                    type: 'Literal',
         | 
| 1983 | 
            -
                    value: '__proto__'
         | 
| 1984 | 
            -
                  }),
         | 
| 1985 | 
            -
                  Opcodes.i32_to_u,
         | 
| 1986 | 
            -
                  number(TYPES.bytestring, Valtype.i32),
         | 
| 1987 | 
            -
             | 
| 1988 1923 | 
             
                  ...generate(scope, proto),
         | 
| 1924 | 
            +
                  Opcodes.i32_to_u,
         | 
| 1989 1925 | 
             
                  ...getNodeType(scope, proto),
         | 
| 1990 1926 |  | 
| 1991 | 
            -
                   | 
| 1992 | 
            -
                  number(0b1000, Valtype.i32),
         | 
| 1993 | 
            -
                  number(TYPES.number, Valtype.i32),
         | 
| 1994 | 
            -
             | 
| 1995 | 
            -
                  [ Opcodes.call, includeBuiltin(scope, '__Porffor_object_expr_initWithFlags').index ],
         | 
| 1927 | 
            +
                  [ Opcodes.call, includeBuiltin(scope, '__Porffor_object_setPrototype').index ],
         | 
| 1996 1928 |  | 
| 1997 1929 | 
             
                  [ Opcodes.local_get, tmp ],
         | 
| 1998 1930 | 
             
                  number(TYPES.object, Valtype.i32)
         | 
| @@ -2353,30 +2285,34 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => { | |
| 2353 2285 | 
             
                      const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${protoName}_tmp2`, protoFunc.local2) : -1;
         | 
| 2354 2286 |  | 
| 2355 2287 | 
             
                      let optUnused = false;
         | 
| 2356 | 
            -
                      const protoOut = protoFunc( | 
| 2357 | 
            -
                         | 
| 2358 | 
            -
                         | 
| 2359 | 
            -
             | 
| 2360 | 
            -
             | 
| 2361 | 
            -
             | 
| 2362 | 
            -
             | 
| 2363 | 
            -
             | 
| 2364 | 
            -
             | 
| 2365 | 
            -
             | 
| 2366 | 
            -
             | 
| 2367 | 
            -
             | 
| 2368 | 
            -
                         | 
| 2369 | 
            -
                         | 
| 2370 | 
            -
             | 
| 2371 | 
            -
             | 
| 2372 | 
            -
             | 
| 2373 | 
            -
                         | 
| 2288 | 
            +
                      const protoOut = protoFunc({
         | 
| 2289 | 
            +
                        pointer: getPointer,
         | 
| 2290 | 
            +
                        length: {
         | 
| 2291 | 
            +
                          getCachedI32: () => [ [ Opcodes.local_get, lengthLocal ] ],
         | 
| 2292 | 
            +
                          setCachedI32: () => [ [ Opcodes.local_set, lengthLocal ] ],
         | 
| 2293 | 
            +
                          get: () => ArrayUtil.getLength(getPointer),
         | 
| 2294 | 
            +
                          getI32: () => ArrayUtil.getLengthI32(getPointer),
         | 
| 2295 | 
            +
                          set: value => ArrayUtil.setLength(getPointer, value),
         | 
| 2296 | 
            +
                          setI32: value => ArrayUtil.setLengthI32(getPointer, value)
         | 
| 2297 | 
            +
                        },
         | 
| 2298 | 
            +
                        arg: generate(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
         | 
| 2299 | 
            +
                        argType: getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
         | 
| 2300 | 
            +
                        iTmp: protoLocal,
         | 
| 2301 | 
            +
                        iTmp2: protoLocal2,
         | 
| 2302 | 
            +
                        alloc: bytes => [
         | 
| 2303 | 
            +
                          number(bytes, Valtype.i32),
         | 
| 2304 | 
            +
                          [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ]
         | 
| 2305 | 
            +
                        ],
         | 
| 2306 | 
            +
                        unusedValue: () => {
         | 
| 2307 | 
            +
                          optUnused = true;
         | 
| 2308 | 
            +
                          return unusedValue;
         | 
| 2309 | 
            +
                        },
         | 
| 2310 | 
            +
                        setType: type => setLastType(scope, type)
         | 
| 2374 2311 | 
             
                      });
         | 
| 2375 2312 |  | 
| 2376 2313 | 
             
                      return [
         | 
| 2377 2314 | 
             
                        [ Opcodes.block, unusedValue ? Blocktype.void : valtypeBinary ],
         | 
| 2378 2315 | 
             
                          ...protoOut,
         | 
| 2379 | 
            -
                          ...(unusedValue && optUnused ? [] : (protoFunc.returnType != null ? setLastType(scope, protoFunc.returnType) : setLastType(scope))),
         | 
| 2380 2316 | 
             
                          ...(unusedValue && !optUnused ? [ [ Opcodes.drop ] ] : []),
         | 
| 2381 2317 | 
             
                        [ Opcodes.end ]
         | 
| 2382 2318 | 
             
                      ];
         | 
| @@ -2774,8 +2710,19 @@ const generateThis = (scope, decl) => { | |
| 2774 2710 | 
             
              ];
         | 
| 2775 2711 | 
             
            };
         | 
| 2776 2712 |  | 
| 2777 | 
            -
            const generateSuper = (scope, decl) => generate(scope,
         | 
| 2778 | 
            -
               | 
| 2713 | 
            +
            const generateSuper = (scope, decl) => generate(scope, {
         | 
| 2714 | 
            +
              type: 'CallExpression',
         | 
| 2715 | 
            +
              callee: { type: 'Identifier', name: '__Porffor_object_getPrototype' },
         | 
| 2716 | 
            +
              arguments: [
         | 
| 2717 | 
            +
                {
         | 
| 2718 | 
            +
                  type: 'CallExpression',
         | 
| 2719 | 
            +
                  callee: { type: 'Identifier', name: '__Porffor_object_getPrototype' },
         | 
| 2720 | 
            +
                  arguments: [
         | 
| 2721 | 
            +
                    { type: 'ThisExpression', _noGlobalThis: true }
         | 
| 2722 | 
            +
                  ]
         | 
| 2723 | 
            +
                }
         | 
| 2724 | 
            +
              ]
         | 
| 2725 | 
            +
            });
         | 
| 2779 2726 |  | 
| 2780 2727 | 
             
            // bad hack for undefined and null working without additional logic
         | 
| 2781 2728 | 
             
            const DEFAULT_VALUE = () => ({
         | 
| @@ -3160,8 +3107,6 @@ const extractTypeAnnotation = decl => { | |
| 3160 3107 | 
             
              const typeName = type;
         | 
| 3161 3108 | 
             
              type = typeAnnoToPorfType(type);
         | 
| 3162 3109 |  | 
| 3163 | 
            -
              // if (decl.name) console.log(decl.name, { type, elementType });
         | 
| 3164 | 
            -
             | 
| 3165 3110 | 
             
              return { type, typeName, elementType };
         | 
| 3166 3111 | 
             
            };
         | 
| 3167 3112 |  | 
| @@ -3587,6 +3532,8 @@ const memberTmpNames = scope => { | |
| 3587 3532 |  | 
| 3588 3533 | 
             
            // COCTC: cross-object compile-time cache
         | 
| 3589 3534 | 
             
            const coctcOffset = prop => {
         | 
| 3535 | 
            +
              if (!Prefs.coctc) return 0;
         | 
| 3536 | 
            +
             | 
| 3590 3537 | 
             
              if (typeof prop === 'object') {
         | 
| 3591 3538 | 
             
                if (
         | 
| 3592 3539 | 
             
                  prop.computed || prop.optional ||
         | 
| @@ -3727,7 +3674,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => { | |
| 3727 3674 | 
             
                // todo/perf: use i32 object (and prop?) locals
         | 
| 3728 3675 | 
             
                const { objectTmp, propertyTmp, objectGet, propertyGet } = memberTmpNames(scope);
         | 
| 3729 3676 |  | 
| 3730 | 
            -
                const useCoctc =  | 
| 3677 | 
            +
                const useCoctc = coctcOffset(decl.left) > 0;
         | 
| 3731 3678 | 
             
                if (useCoctc) valueUnused = false;
         | 
| 3732 3679 |  | 
| 3733 3680 | 
             
                // opt: do not mark prototype funcs as referenced to optimize this in them
         | 
| @@ -4173,7 +4120,7 @@ const generateUnary = (scope, decl) => { | |
| 4173 4120 | 
             
                    const property = getProperty(decl.argument);
         | 
| 4174 4121 | 
             
                    if (property.value === 'length' || property.value === 'name') scope.noFastFuncMembers = true;
         | 
| 4175 4122 |  | 
| 4176 | 
            -
                    const useCoctc =  | 
| 4123 | 
            +
                    const useCoctc = coctcOffset(decl.argument) > 0;
         | 
| 4177 4124 | 
             
                    const objectTmp = useCoctc && localTmp(scope, '#coctc_object', Valtype.i32);
         | 
| 4178 4125 |  | 
| 4179 4126 | 
             
                    const out = [
         | 
| @@ -4887,7 +4834,7 @@ const generateForIn = (scope, decl) => { | |
| 4887 4834 |  | 
| 4888 4835 | 
             
                // get length
         | 
| 4889 4836 | 
             
                [ Opcodes.local_get, pointer ],
         | 
| 4890 | 
            -
                [ Opcodes. | 
| 4837 | 
            +
                [ Opcodes.i32_load16_u, 0, 0 ],
         | 
| 4891 4838 | 
             
                [ Opcodes.local_tee, length ],
         | 
| 4892 4839 |  | 
| 4893 4840 | 
             
                [ Opcodes.if, Blocktype.void ]
         | 
| @@ -4920,7 +4867,7 @@ const generateForIn = (scope, decl) => { | |
| 4920 4867 |  | 
| 4921 4868 | 
             
                // read key
         | 
| 4922 4869 | 
             
                [ Opcodes.local_get, pointer ],
         | 
| 4923 | 
            -
                [ Opcodes.i32_load, 0,  | 
| 4870 | 
            +
                [ Opcodes.i32_load, 0, 12 ],
         | 
| 4924 4871 | 
             
                [ Opcodes.local_tee, tmp ],
         | 
| 4925 4872 |  | 
| 4926 4873 | 
             
                ...setType(scope, tmpName, [
         | 
| @@ -4952,7 +4899,7 @@ const generateForIn = (scope, decl) => { | |
| 4952 4899 | 
             
                // todo/perf: do not read key for non-enumerables
         | 
| 4953 4900 | 
             
                // only run body if entry is enumerable
         | 
| 4954 4901 | 
             
                [ Opcodes.local_get, pointer ],
         | 
| 4955 | 
            -
                [ Opcodes.i32_load8_u, 0,  | 
| 4902 | 
            +
                [ Opcodes.i32_load8_u, 0, 24 ],
         | 
| 4956 4903 | 
             
                [ Opcodes.i32_const, 0b0100 ],
         | 
| 4957 4904 | 
             
                [ Opcodes.i32_and ],
         | 
| 4958 4905 | 
             
                [ Opcodes.if, Blocktype.void ],
         | 
| @@ -4960,9 +4907,9 @@ const generateForIn = (scope, decl) => { | |
| 4960 4907 | 
             
                [ Opcodes.drop ],
         | 
| 4961 4908 | 
             
                [ Opcodes.end ],
         | 
| 4962 4909 |  | 
| 4963 | 
            -
                // increment pointer by  | 
| 4910 | 
            +
                // increment pointer by 18
         | 
| 4964 4911 | 
             
                [ Opcodes.local_get, pointer ],
         | 
| 4965 | 
            -
                number( | 
| 4912 | 
            +
                number(18, Valtype.i32),
         | 
| 4966 4913 | 
             
                [ Opcodes.i32_add ],
         | 
| 4967 4914 | 
             
                [ Opcodes.local_set, pointer ],
         | 
| 4968 4915 |  | 
| @@ -5694,7 +5641,7 @@ const generateMember = (scope, decl, _global, _name) => { | |
| 5694 5641 |  | 
| 5695 5642 | 
             
                const out = [
         | 
| 5696 5643 | 
             
                  ...generate(scope, object),
         | 
| 5697 | 
            -
                  Opcodes.i32_to_u | 
| 5644 | 
            +
                  Opcodes.i32_to_u
         | 
| 5698 5645 | 
             
                ];
         | 
| 5699 5646 |  | 
| 5700 5647 | 
             
                if (Prefs.fastLength) {
         | 
| @@ -5721,7 +5668,7 @@ const generateMember = (scope, decl, _global, _name) => { | |
| 5721 5668 | 
             
                  ...out,
         | 
| 5722 5669 | 
             
                  [ Opcodes.local_set, tmp ],
         | 
| 5723 5670 |  | 
| 5724 | 
            -
                  ... | 
| 5671 | 
            +
                  ...type,
         | 
| 5725 5672 | 
             
                  number(TYPE_FLAGS.length, Valtype.i32),
         | 
| 5726 5673 | 
             
                  [ Opcodes.i32_and ],
         | 
| 5727 5674 | 
             
                  [ Opcodes.if, valtypeBinary ],
         | 
| @@ -5743,6 +5690,8 @@ const generateMember = (scope, decl, _global, _name) => { | |
| 5743 5690 |  | 
| 5744 5691 | 
             
              // todo/perf: use i32 object (and prop?) locals
         | 
| 5745 5692 | 
             
              const { objectTmp, propertyTmp, objectGet, propertyGet } = memberTmpNames(scope);
         | 
| 5693 | 
            +
              const type = getNodeType(scope, object);
         | 
| 5694 | 
            +
              const known = knownType(scope, type);
         | 
| 5746 5695 |  | 
| 5747 5696 | 
             
              // todo: generate this array procedurally during builtinFuncs creation
         | 
| 5748 5697 | 
             
              if (['size', 'description', 'byteLength', 'byteOffset', 'buffer', 'detached', 'resizable', 'growable', 'maxByteLength'].includes(decl.property.name)) {
         | 
| @@ -5750,7 +5699,6 @@ const generateMember = (scope, decl, _global, _name) => { | |
| 5750 5699 | 
             
                const bc = {};
         | 
| 5751 5700 | 
             
                const cands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + decl.property.name + '$get'));
         | 
| 5752 5701 |  | 
| 5753 | 
            -
                const known = knownType(scope, getNodeType(scope, object));
         | 
| 5754 5702 | 
             
                if (cands.length > 0) {
         | 
| 5755 5703 | 
             
                  for (const x of cands) {
         | 
| 5756 5704 | 
             
                    const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
         | 
| @@ -5786,64 +5734,10 @@ const generateMember = (scope, decl, _global, _name) => { | |
| 5786 5734 | 
             
                if (known == null) extraBC = bc;
         | 
| 5787 5735 | 
             
              }
         | 
| 5788 5736 |  | 
| 5789 | 
            -
               | 
| 5790 | 
            -
                // todo: support optional
         | 
| 5791 | 
            -
                const bc = {};
         | 
| 5792 | 
            -
                const prototypes = Object.keys(builtinVars).filter(x => x.endsWith('_prototype'));
         | 
| 5793 | 
            -
             | 
| 5794 | 
            -
                const known = knownType(scope, getNodeType(scope, decl.object));
         | 
| 5795 | 
            -
                for (const x of prototypes) {
         | 
| 5796 | 
            -
                  let type = TYPES[x.split('_prototype')[0].slice(2).toLowerCase()];
         | 
| 5797 | 
            -
                  if (type == null) continue;
         | 
| 5798 | 
            -
             | 
| 5799 | 
            -
                  // do not __proto__ primitive hack for objects or functions
         | 
| 5800 | 
            -
                  if (type === TYPES.object || type === TYPES.function) continue;
         | 
| 5801 | 
            -
             | 
| 5802 | 
            -
                  // hack: do not support primitives for Object.prototype.isPrototypeOf
         | 
| 5803 | 
            -
                  if (scope.name === '__Object_prototype_isPrototypeOf') {
         | 
| 5804 | 
            -
                    switch (type) {
         | 
| 5805 | 
            -
                      case TYPES.boolean:
         | 
| 5806 | 
            -
                        type = TYPES.booleanobject;
         | 
| 5807 | 
            -
                        break;
         | 
| 5808 | 
            -
             | 
| 5809 | 
            -
                      case TYPES.number:
         | 
| 5810 | 
            -
                        type = TYPES.numberobject;
         | 
| 5811 | 
            -
                        break;
         | 
| 5812 | 
            -
             | 
| 5813 | 
            -
                      case TYPES.string:
         | 
| 5814 | 
            -
                        type = TYPES.stringobject;
         | 
| 5815 | 
            -
                        break;
         | 
| 5816 | 
            -
             | 
| 5817 | 
            -
                      case TYPES.bytestring:
         | 
| 5818 | 
            -
                        continue;
         | 
| 5819 | 
            -
                    }
         | 
| 5820 | 
            -
                  }
         | 
| 5821 | 
            -
             | 
| 5822 | 
            -
                  const ident = {
         | 
| 5823 | 
            -
                    type: 'Identifier',
         | 
| 5824 | 
            -
                    name: x
         | 
| 5825 | 
            -
                  };
         | 
| 5826 | 
            -
             | 
| 5827 | 
            -
                  // hack: bytestrings should return string prototype
         | 
| 5828 | 
            -
                  if (type === TYPES.bytestring) ident.name = '__String_prototype';
         | 
| 5829 | 
            -
             | 
| 5830 | 
            -
                  bc[type] = () => [
         | 
| 5831 | 
            -
                    ...generate(scope, ident),
         | 
| 5832 | 
            -
                    ...setLastType(scope, getNodeType(scope, ident))
         | 
| 5833 | 
            -
                  ];
         | 
| 5834 | 
            -
                  if (type === known) return bc[type]();
         | 
| 5835 | 
            -
                }
         | 
| 5836 | 
            -
             | 
| 5837 | 
            -
                if (known == null) {
         | 
| 5838 | 
            -
                  aliasPrimObjsBC(bc);
         | 
| 5839 | 
            -
                  extraBC = bc;
         | 
| 5840 | 
            -
                }
         | 
| 5841 | 
            -
              }
         | 
| 5842 | 
            -
             | 
| 5843 | 
            -
              const useCoctc = Prefs.coctc && coctcOffset(decl) > 0;
         | 
| 5737 | 
            +
              const useCoctc = coctcOffset(decl) > 0;
         | 
| 5844 5738 | 
             
              const coctcObjTmp = useCoctc && localTmp(scope, '#coctc_obj' + uniqId(), Valtype.i32);
         | 
| 5845 5739 |  | 
| 5846 | 
            -
              const out = typeSwitch(scope,  | 
| 5740 | 
            +
              const out = typeSwitch(scope, type, {
         | 
| 5847 5741 | 
             
                ...(decl.computed ? {
         | 
| 5848 5742 | 
             
                  [TYPES.array]: () => [
         | 
| 5849 5743 | 
             
                    propertyGet,
         | 
| @@ -6009,22 +5903,17 @@ const generateMember = (scope, decl, _global, _name) => { | |
| 6009 5903 | 
             
                  }),
         | 
| 6010 5904 | 
             
                } : {}),
         | 
| 6011 5905 |  | 
| 6012 | 
            -
                [TYPES.undefined]: internalThrow(scope, 'TypeError',  | 
| 5906 | 
            +
                [TYPES.undefined]: internalThrow(scope, 'TypeError', `Cannot read property of undefined`, true),
         | 
| 6013 5907 |  | 
| 6014 | 
            -
                // default: internalThrow(scope, 'TypeError', 'Unsupported member expression object', true)
         | 
| 6015 5908 | 
             
                default: () => [
         | 
| 6016 | 
            -
                   | 
| 6017 | 
            -
             | 
| 6018 | 
            -
             | 
| 6019 | 
            -
                   | 
| 6020 | 
            -
             | 
| 6021 | 
            -
             | 
| 6022 | 
            -
             | 
| 6023 | 
            -
                   | 
| 6024 | 
            -
             | 
| 6025 | 
            -
                  objectGet,
         | 
| 6026 | 
            -
                  Opcodes.i32_to,
         | 
| 6027 | 
            -
                  ...getNodeType(scope, object),
         | 
| 5909 | 
            +
                  ...(useCoctc && known === TYPES.object ? [
         | 
| 5910 | 
            +
                    [ Opcodes.local_get, coctcObjTmp ],
         | 
| 5911 | 
            +
                    number(TYPES.object, Valtype.i32)
         | 
| 5912 | 
            +
                  ] : [
         | 
| 5913 | 
            +
                    objectGet,
         | 
| 5914 | 
            +
                    Opcodes.i32_to,
         | 
| 5915 | 
            +
                    ...type
         | 
| 5916 | 
            +
                  ]),
         | 
| 6028 5917 |  | 
| 6029 5918 | 
             
                  ...toPropertyKey(scope, [ propertyGet ], getNodeType(scope, property), decl.computed, true),
         | 
| 6030 5919 |  | 
| @@ -6044,7 +5933,7 @@ const generateMember = (scope, decl, _global, _name) => { | |
| 6044 5933 | 
             
                  ...generate(scope, object),
         | 
| 6045 5934 | 
             
                  [ Opcodes.local_tee, objectTmp ],
         | 
| 6046 5935 |  | 
| 6047 | 
            -
                  ...nullish(scope, [],  | 
| 5936 | 
            +
                  ...nullish(scope, [], type, false, true),
         | 
| 6048 5937 | 
             
                  [ Opcodes.if, Blocktype.void ],
         | 
| 6049 5938 | 
             
                    ...setLastType(scope, TYPES.undefined),
         | 
| 6050 5939 | 
             
                    number(0),
         | 
| @@ -6164,10 +6053,25 @@ const generateClass = (scope, decl) => { | |
| 6164 6053 | 
             
                  // class Foo {}
         | 
| 6165 6054 | 
             
                  // class Bar extends Foo {}
         | 
| 6166 6055 | 
             
                  // Bar.__proto__ = Foo
         | 
| 6167 | 
            -
                   | 
| 6168 | 
            -
             | 
| 6056 | 
            +
                  ...generate(scope, {
         | 
| 6057 | 
            +
                    type: 'CallExpression',
         | 
| 6058 | 
            +
                    callee: { type: 'Identifier', name: '__Porffor_object_setPrototype' },
         | 
| 6059 | 
            +
                    arguments: [
         | 
| 6060 | 
            +
                      root,
         | 
| 6061 | 
            +
                      decl.superClass
         | 
| 6062 | 
            +
                    ]
         | 
| 6063 | 
            +
                  }),
         | 
| 6169 6064 | 
             
                  [ Opcodes.drop ],
         | 
| 6170 | 
            -
             | 
| 6065 | 
            +
             | 
| 6066 | 
            +
                  // Bar.prototype.__proto__ = Foo.prototype
         | 
| 6067 | 
            +
                  ...generate(scope, {
         | 
| 6068 | 
            +
                    type: 'CallExpression',
         | 
| 6069 | 
            +
                    callee: { type: 'Identifier', name: '__Porffor_object_setPrototype' },
         | 
| 6070 | 
            +
                    arguments: [
         | 
| 6071 | 
            +
                      proto,
         | 
| 6072 | 
            +
                      getObjProp(decl.superClass, 'prototype')
         | 
| 6073 | 
            +
                    ]
         | 
| 6074 | 
            +
                  }),
         | 
| 6171 6075 | 
             
                  [ Opcodes.drop ]
         | 
| 6172 6076 | 
             
                );
         | 
| 6173 6077 | 
             
              }
         | 
| @@ -6354,7 +6258,7 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v | |
| 6354 6258 | 
             
                          return funcIndex[x];
         | 
| 6355 6259 | 
             
                        }
         | 
| 6356 6260 |  | 
| 6357 | 
            -
                        return scope.locals[x]?.idx ?? globals[x]. | 
| 6261 | 
            +
                        return scope.locals[x]?.idx ?? globals[x]?.idx ?? (log.warning('codegen', `unknown immediate in Porffor.wasm: ${x}`) || 0);
         | 
| 6358 6262 | 
             
                      }
         | 
| 6359 6263 |  | 
| 6360 6264 | 
             
                      return n;
         | 
| @@ -6428,7 +6332,6 @@ const objectHack = node => { | |
| 6428 6332 |  | 
| 6429 6333 | 
             
                  // hack: block these properties as they can be accessed on functions
         | 
| 6430 6334 | 
             
                  if (node.object.name !== 'Porffor' && (node.property.name === 'length' || node.property.name === 'name' || node.property.name === 'call')) return abortOut;
         | 
| 6431 | 
            -
             | 
| 6432 6335 | 
             
                  if (node.property.name === '__proto__') return abortOut;
         | 
| 6433 6336 |  | 
| 6434 6337 | 
             
                  let objectName = node.object.name;
         | 
| @@ -7035,39 +6938,6 @@ export default program => { | |
| 7035 6938 | 
             
                f.wasm = f.returns.map(x => number(0, x));
         | 
| 7036 6939 | 
             
              }
         | 
| 7037 6940 |  | 
| 7038 | 
            -
              // // remove never generated functions
         | 
| 7039 | 
            -
              // let indexDelta = 0;
         | 
| 7040 | 
            -
              // const funcRemap = new Map();
         | 
| 7041 | 
            -
              // for (let i = 0; i < funcs.length; i++) {
         | 
| 7042 | 
            -
              //   const f = funcs[i];
         | 
| 7043 | 
            -
              //   if (f.internal || f.wasm) {
         | 
| 7044 | 
            -
              //     if (indexDelta) {
         | 
| 7045 | 
            -
              //       funcRemap.set(f.index, f.index - indexDelta);
         | 
| 7046 | 
            -
              //       f.index -= indexDelta;
         | 
| 7047 | 
            -
              //     }
         | 
| 7048 | 
            -
              //     continue;
         | 
| 7049 | 
            -
              //   }
         | 
| 7050 | 
            -
             | 
| 7051 | 
            -
              //   funcs.splice(i--, 1);
         | 
| 7052 | 
            -
              //   indexDelta++;
         | 
| 7053 | 
            -
              // }
         | 
| 7054 | 
            -
             | 
| 7055 | 
            -
              // // remap call ops
         | 
| 7056 | 
            -
              // if (indexDelta) for (let i = 0; i < funcs.length; i++) {
         | 
| 7057 | 
            -
              //   const wasm = funcs[i].wasm;
         | 
| 7058 | 
            -
              //   for (let j = 0; j < wasm.length; j++) {
         | 
| 7059 | 
            -
              //     const op = wasm[j];
         | 
| 7060 | 
            -
              //     if (op[0] === Opcodes.call) {
         | 
| 7061 | 
            -
              //       let idx = op[1];
         | 
| 7062 | 
            -
              //       wasm[j] = [ Opcodes.call, funcRemap.get(idx) ?? idx ];
         | 
| 7063 | 
            -
              //     }
         | 
| 7064 | 
            -
             | 
| 7065 | 
            -
              //     if (op[0] === Opcodes.const && op[2] === 'funcref') {
         | 
| 7066 | 
            -
              //       wasm[j] = [ Opcodes.const, funcRemap.get(op[1] + importedFuncs.length) - importedFuncs.length ];
         | 
| 7067 | 
            -
              //     }
         | 
| 7068 | 
            -
              //   }
         | 
| 7069 | 
            -
              // }
         | 
| 7070 | 
            -
             | 
| 7071 6941 | 
             
              // add indirect funcs to end of funcs
         | 
| 7072 6942 | 
             
              for (let i = 0; i < indirectFuncs.length; i++) {
         | 
| 7073 6943 | 
             
                const f = indirectFuncs[i];
         | 
    
        package/compiler/precompile.js
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            import { Opcodes, Valtype } from './wasmSpec.js';
         | 
| 2 2 | 
             
            import { read_signedLEB128, read_unsignedLEB128 } from './encoding.js';
         | 
| 3 | 
            -
            import { TYPES } from './types.js';
         | 
| 3 | 
            +
            import { TYPES, TYPE_NAMES } from './types.js';
         | 
| 4 4 | 
             
            import { log } from './log.js';
         | 
| 5 5 |  | 
| 6 6 | 
             
            import process from 'node:process';
         | 
| @@ -41,7 +41,7 @@ const compile = async (file, _funcs) => { | |
| 41 41 | 
             
              let first = source.slice(0, source.indexOf('\n'));
         | 
| 42 42 |  | 
| 43 43 | 
             
              if (first.startsWith('export default')) {
         | 
| 44 | 
            -
                source = await (await import('file://' + file)).default();
         | 
| 44 | 
            +
                source = await (await import('file://' + file)).default({ TYPES, TYPE_NAMES });
         | 
| 45 45 | 
             
                first = source.slice(0, source.indexOf('\n'));
         | 
| 46 46 | 
             
              }
         | 
| 47 47 |  | 
| @@ -155,11 +155,10 @@ const compile = async (file, _funcs) => { | |
| 155 155 | 
             
                    }
         | 
| 156 156 |  | 
| 157 157 | 
             
                    if (n[0] === Opcodes.throw) {
         | 
| 158 | 
            -
                      if (!bodyHasTopLevelThrow && depth === 0) log.warning('codegen', `top-level throw in ${x.name}`);
         | 
| 159 | 
            -
             | 
| 160 158 | 
             
                      x.usesTag = true;
         | 
| 159 | 
            +
                      let id;
         | 
| 161 160 | 
             
                      if (y[0] === Opcodes.i32_const && n[1] === 0) {
         | 
| 162 | 
            -
                         | 
| 161 | 
            +
                        id = read_signedLEB128(y.slice(1));
         | 
| 163 162 | 
             
                        y.splice(0, 10, 'throw', exceptions[id].constructor, exceptions[id].message);
         | 
| 164 163 |  | 
| 165 164 | 
             
                        // remove throw inst
         | 
| @@ -167,6 +166,8 @@ const compile = async (file, _funcs) => { | |
| 167 166 | 
             
                      } else {
         | 
| 168 167 | 
             
                        n[1]--;
         | 
| 169 168 | 
             
                      }
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                      if (!bodyHasTopLevelThrow && depth === 0) log.warning('codegen', `top-level throw in ${x.name} (${exceptions[id].constructor}: ${exceptions[id].message})`);
         | 
| 170 171 | 
             
                    }
         | 
| 171 172 |  | 
| 172 173 | 
             
                    if (n[0] === Opcodes.catch) {
         |