porffor 0.19.4 → 0.19.6
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/builtins/z_map.ts +31 -16
- package/compiler/codegen.js +278 -172
- package/compiler/generated_builtins.js +7 -7
- package/compiler/wrap.js +66 -37
- package/package.json +1 -1
- package/runner/index.js +1 -1
- package/runner/repl.js +4 -1
@@ -6,17 +6,20 @@ export const __Map_prototype_size$get = (_this: Map) => {
|
|
6
6
|
|
7
7
|
export const __Map_prototype_has = (_this: Map, key: any) => {
|
8
8
|
const keys: Set = Porffor.wasm.i32.load(_this, 0, 0);
|
9
|
-
return __Set_prototype_has(key);
|
9
|
+
return __Set_prototype_has(keys, key);
|
10
10
|
};
|
11
11
|
|
12
12
|
export const __Map_prototype_get = (_this: Map, key: any) => {
|
13
13
|
const keys: Set = Porffor.wasm.i32.load(_this, 0, 0);
|
14
14
|
const vals: any[] = Porffor.wasm.i32.load(_this, 0, 4);
|
15
15
|
|
16
|
-
const
|
17
|
-
|
16
|
+
const size: i32 = Porffor.wasm.i32.load(keys, 0, 0);
|
17
|
+
|
18
|
+
for (let i: i32 = 0; i < size; i++) {
|
19
|
+
if (Porffor.set.read(keys, i) === key) return vals[i];
|
20
|
+
}
|
18
21
|
|
19
|
-
return
|
22
|
+
return undefined;
|
20
23
|
};
|
21
24
|
|
22
25
|
export const __Map_prototype_set = (_this: Map, key: any, value: any) => {
|
@@ -25,30 +28,42 @@ export const __Map_prototype_set = (_this: Map, key: any, value: any) => {
|
|
25
28
|
|
26
29
|
const size: i32 = Porffor.wasm.i32.load(keys, 0, 0);
|
27
30
|
|
28
|
-
let
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
for (let i: i32 = 0; i < size; i++) {
|
32
|
+
if (Porffor.set.read(keys, i) === key) {
|
33
|
+
vals[i] = value;
|
34
|
+
return _this;
|
35
|
+
}
|
33
36
|
}
|
34
37
|
|
35
|
-
|
38
|
+
// add key if non-existent
|
39
|
+
// increment size by 1
|
40
|
+
Porffor.wasm.i32.store(keys, size + 1, 0, 0);
|
41
|
+
|
42
|
+
// write new key at end
|
43
|
+
__Porffor_set_write(keys, size, key);
|
44
|
+
|
45
|
+
// write new value at end
|
46
|
+
vals[size] = value;
|
36
47
|
|
37
48
|
return _this;
|
38
49
|
};
|
39
50
|
|
40
51
|
export const __Map_prototype_delete = (_this: Map, key: any) => {
|
41
52
|
const keys: Set = Porffor.wasm.i32.load(_this, 0, 0);
|
53
|
+
const vals: any[] = Porffor.wasm.i32.load(_this, 0, 4);
|
42
54
|
|
43
|
-
const
|
44
|
-
if (keyIdx == -1) return false;
|
55
|
+
const size: i32 = Porffor.wasm.i32.load(keys, 0, 0);
|
45
56
|
|
46
|
-
|
57
|
+
for (let i: i32 = 0; i < size; i++) {
|
58
|
+
if (Porffor.set.read(keys, i) === key) {
|
59
|
+
__Set_prototype_delete(keys, key);
|
60
|
+
__Array_prototype_splice(vals, i, 1);
|
47
61
|
|
48
|
-
|
49
|
-
|
62
|
+
return true;
|
63
|
+
}
|
64
|
+
}
|
50
65
|
|
51
|
-
return
|
66
|
+
return false;
|
52
67
|
};
|
53
68
|
|
54
69
|
export const __Map_prototype_clear = (_this: Map) => {
|
package/compiler/codegen.js
CHANGED
@@ -1341,6 +1341,10 @@ const getNodeType = (scope, node) => {
|
|
1341
1341
|
return getType(scope, node.name);
|
1342
1342
|
}
|
1343
1343
|
|
1344
|
+
if (node.type === 'ObjectExpression') {
|
1345
|
+
return TYPES.object;
|
1346
|
+
}
|
1347
|
+
|
1344
1348
|
if (node.type === 'CallExpression' || node.type === 'NewExpression') {
|
1345
1349
|
const name = node.callee.name;
|
1346
1350
|
if (!name) {
|
@@ -1926,7 +1930,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1926
1930
|
}
|
1927
1931
|
|
1928
1932
|
// TODO: only allows callee as identifier
|
1929
|
-
if (!name) return todo(scope, `only identifier callees (got ${decl.callee.type})`);
|
1933
|
+
// if (!name) return todo(scope, `only identifier callees (got ${decl.callee.type})`);
|
1930
1934
|
|
1931
1935
|
let idx = funcIndex[name] ?? importedFuncs[name];
|
1932
1936
|
if (idx === undefined && builtinFuncs[name]) {
|
@@ -1942,7 +1946,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1942
1946
|
return internalConstrs[name].generate(scope, decl, _global, _name);
|
1943
1947
|
}
|
1944
1948
|
|
1945
|
-
if (idx === undefined && !decl._new && name.startsWith('__Porffor_wasm_')) {
|
1949
|
+
if (idx === undefined && !decl._new && name && name.startsWith('__Porffor_wasm_')) {
|
1946
1950
|
const wasmOps = {
|
1947
1951
|
// pointer, align, offset
|
1948
1952
|
i32_load: { imms: 2, args: [ true ], returns: 1 },
|
@@ -1989,162 +1993,171 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1989
1993
|
}
|
1990
1994
|
|
1991
1995
|
if (idx === undefined) {
|
1992
|
-
if (
|
1993
|
-
const [ local, global ] = lookupName(scope, name);
|
1994
|
-
if (!Prefs.indirectCalls || local == null) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true);
|
1996
|
+
if (!Prefs.indirectCalls) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true);
|
1995
1997
|
|
1996
|
-
|
1998
|
+
// todo: only works when function uses typedParams and typedReturns
|
1997
1999
|
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
2000
|
+
const indirectMode = Prefs.indirectCallMode ?? 'vararg';
|
2001
|
+
// options: vararg, strict
|
2002
|
+
// - strict: simpler, smaller size usage, no func lut needed.
|
2003
|
+
// ONLY works when arg count of call == arg count of function being called
|
2004
|
+
// - vararg: large size usage, cursed.
|
2005
|
+
// works when arg count of call != arg count of function being called*
|
2006
|
+
// * most of the time, some edgecases
|
2005
2007
|
|
2006
|
-
|
2007
|
-
|
2008
|
+
funcs.table = true;
|
2009
|
+
scope.table = true;
|
2008
2010
|
|
2009
|
-
|
2010
|
-
|
2011
|
+
let args = decl.arguments;
|
2012
|
+
let locals = [];
|
2011
2013
|
|
2012
|
-
|
2013
|
-
|
2014
|
+
if (indirectMode === 'vararg') {
|
2015
|
+
const minArgc = Prefs.indirectCallMinArgc ?? 3;
|
2014
2016
|
|
2015
|
-
|
2016
|
-
|
2017
|
-
}
|
2017
|
+
if (args.length < minArgc) {
|
2018
|
+
args = args.concat(new Array(minArgc - args.length).fill(DEFAULT_VALUE));
|
2018
2019
|
}
|
2020
|
+
}
|
2019
2021
|
|
2020
|
-
|
2021
|
-
|
2022
|
-
|
2022
|
+
for (let i = 0; i < args.length; i++) {
|
2023
|
+
const arg = args[i];
|
2024
|
+
out = out.concat(generate(scope, arg));
|
2023
2025
|
|
2024
|
-
|
2025
|
-
|
2026
|
-
|
2027
|
-
|
2028
|
-
|
2029
|
-
|
2026
|
+
if (valtypeBinary !== Valtype.i32 && (
|
2027
|
+
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
|
2028
|
+
(importedFuncs[name] && name.startsWith('profile'))
|
2029
|
+
)) {
|
2030
|
+
out.push(Opcodes.i32_to);
|
2031
|
+
}
|
2030
2032
|
|
2031
|
-
|
2033
|
+
out = out.concat(getNodeType(scope, arg));
|
2032
2034
|
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
2035
|
+
if (indirectMode === 'vararg') {
|
2036
|
+
const typeLocal = localTmp(scope, `#indirect_arg${i}_type`, Valtype.i32);
|
2037
|
+
const valLocal = localTmp(scope, `#indirect_arg${i}_val`);
|
2036
2038
|
|
2037
|
-
|
2039
|
+
locals.push([valLocal, typeLocal]);
|
2038
2040
|
|
2039
|
-
|
2040
|
-
|
2041
|
-
|
2042
|
-
|
2043
|
-
}
|
2041
|
+
out.push(
|
2042
|
+
[ Opcodes.local_set, typeLocal ],
|
2043
|
+
[ Opcodes.local_set, valLocal ]
|
2044
|
+
);
|
2044
2045
|
}
|
2046
|
+
}
|
2045
2047
|
|
2046
|
-
|
2047
|
-
|
2048
|
+
if (indirectMode === 'strict') {
|
2049
|
+
return [
|
2050
|
+
...generate(scope, decl.callee),
|
2051
|
+
[ Opcodes.local_set, localTmp(scope, '#indirect_callee') ],
|
2052
|
+
|
2053
|
+
...typeSwitch(scope, getNodeType(scope, decl.callee), {
|
2048
2054
|
[TYPES.function]: [
|
2049
2055
|
...out,
|
2050
|
-
|
2056
|
+
|
2057
|
+
[ Opcodes.local_get, localTmp(scope, '#indirect_callee') ],
|
2058
|
+
...generate(scope, decl.callee),
|
2051
2059
|
Opcodes.i32_to_u,
|
2052
2060
|
[ Opcodes.call_indirect, args.length, 0 ],
|
2053
2061
|
...setLastType(scope)
|
2054
2062
|
],
|
2055
2063
|
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
2056
|
-
})
|
2064
|
+
})
|
2065
|
+
];
|
2066
|
+
}
|
2067
|
+
|
2068
|
+
// hi, I will now explain how vararg mode works:
|
2069
|
+
// wasm's indirect_call instruction requires you know the func type at compile-time
|
2070
|
+
// since we have varargs (variable argument count), we do not know it.
|
2071
|
+
// we could just store args in memory and not use wasm func args,
|
2072
|
+
// but that is slow (probably) and breaks js exports.
|
2073
|
+
// instead, we generate every* possibility of argc and use different indirect_call
|
2074
|
+
// ops for each one, with type depending on argc for that branch.
|
2075
|
+
// then we load the argc for the wanted function from a memory lut,
|
2076
|
+
// and call the branch with the matching argc we require.
|
2077
|
+
// sorry, yes it is very cursed (and size inefficient), but indirect calls
|
2078
|
+
// are kind of rare anyway (mostly callbacks) so I am not concerned atm.
|
2079
|
+
// *for argc 0-3, in future (todo:) the max number should be
|
2080
|
+
// dynamically changed to the max argc of any func in the js file.
|
2081
|
+
|
2082
|
+
const funcLocal = localTmp(scope, '#indirect_func', Valtype.i32);
|
2083
|
+
const flags = localTmp(scope, '#indirect_flags', Valtype.i32);
|
2084
|
+
|
2085
|
+
const gen = argc => {
|
2086
|
+
const argsOut = [];
|
2087
|
+
for (let i = 0; i < argc; i++) {
|
2088
|
+
argsOut.push(
|
2089
|
+
[ Opcodes.local_get, locals[i][0] ],
|
2090
|
+
[ Opcodes.local_get, locals[i][1] ]
|
2091
|
+
);
|
2057
2092
|
}
|
2058
2093
|
|
2059
|
-
|
2060
|
-
|
2061
|
-
|
2062
|
-
|
2063
|
-
|
2064
|
-
|
2065
|
-
|
2066
|
-
|
2067
|
-
|
2068
|
-
|
2069
|
-
// are kind of rare anyway (mostly callbacks) so I am not concerned atm.
|
2070
|
-
// *for argc 0-3, in future (todo:) the max number should be
|
2071
|
-
// dynamically changed to the max argc of any func in the js file.
|
2072
|
-
|
2073
|
-
const funcLocal = localTmp(scope, '#indirect_func', Valtype.i32);
|
2074
|
-
const flags = localTmp(scope, '#indirect_flags', Valtype.i32);
|
2075
|
-
|
2076
|
-
const gen = argc => {
|
2077
|
-
const argsOut = [];
|
2078
|
-
for (let i = 0; i < argc; i++) {
|
2079
|
-
argsOut.push(
|
2080
|
-
[ Opcodes.local_get, locals[i][0] ],
|
2081
|
-
[ Opcodes.local_get, locals[i][1] ]
|
2082
|
-
);
|
2083
|
-
}
|
2094
|
+
const checkFlag = (flag, pass, fail) => [
|
2095
|
+
[ Opcodes.local_get, flags ],
|
2096
|
+
...number(flag, Valtype.i32),
|
2097
|
+
[ Opcodes.i32_and ],
|
2098
|
+
[ Opcodes.if, valtypeBinary ],
|
2099
|
+
...pass,
|
2100
|
+
[ Opcodes.else ],
|
2101
|
+
...fail,
|
2102
|
+
[ Opcodes.end ]
|
2103
|
+
];
|
2084
2104
|
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2089
|
-
|
2090
|
-
|
2091
|
-
|
2092
|
-
|
2093
|
-
|
2094
|
-
|
2105
|
+
// pain.
|
2106
|
+
// return checkFlag(0b10, [ // constr
|
2107
|
+
// [ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2108
|
+
// ...argsOut,
|
2109
|
+
// [ Opcodes.local_get, funcLocal ],
|
2110
|
+
// [ Opcodes.call_indirect, argc, 0, 'constr' ],
|
2111
|
+
// ...setLastType(scope),
|
2112
|
+
// ], [
|
2113
|
+
// ...argsOut,
|
2114
|
+
// [ Opcodes.local_get, funcLocal ],
|
2115
|
+
// [ Opcodes.call_indirect, argc, 0 ],
|
2116
|
+
// ...setLastType(scope),
|
2117
|
+
// ]);
|
2118
|
+
|
2119
|
+
return checkFlag(0b1, // no type return
|
2120
|
+
checkFlag(0b10, [ // no type return & constr
|
2121
|
+
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2122
|
+
...argsOut,
|
2123
|
+
[ Opcodes.local_get, funcLocal ],
|
2124
|
+
[ Opcodes.call_indirect, argc, 0, 'no_type_return', 'constr' ],
|
2125
|
+
], [
|
2126
|
+
...argsOut,
|
2127
|
+
[ Opcodes.local_get, funcLocal ],
|
2128
|
+
[ Opcodes.call_indirect, argc, 0, 'no_type_return' ]
|
2129
|
+
]),
|
2130
|
+
checkFlag(0b10, [ // type return & constr
|
2131
|
+
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2132
|
+
...argsOut,
|
2133
|
+
[ Opcodes.local_get, funcLocal ],
|
2134
|
+
[ Opcodes.call_indirect, argc, 0, 'constr' ],
|
2135
|
+
...setLastType(scope),
|
2136
|
+
], [
|
2137
|
+
...argsOut,
|
2138
|
+
[ Opcodes.local_get, funcLocal ],
|
2139
|
+
[ Opcodes.call_indirect, argc, 0 ],
|
2140
|
+
...setLastType(scope),
|
2141
|
+
]),
|
2142
|
+
);
|
2143
|
+
};
|
2095
2144
|
|
2096
|
-
|
2097
|
-
|
2098
|
-
|
2099
|
-
|
2100
|
-
// [ Opcodes.local_get, funcLocal ],
|
2101
|
-
// [ Opcodes.call_indirect, argc, 0, 'constr' ],
|
2102
|
-
// ...setLastType(scope),
|
2103
|
-
// ], [
|
2104
|
-
// ...argsOut,
|
2105
|
-
// [ Opcodes.local_get, funcLocal ],
|
2106
|
-
// [ Opcodes.call_indirect, argc, 0 ],
|
2107
|
-
// ...setLastType(scope),
|
2108
|
-
// ]);
|
2109
|
-
|
2110
|
-
return checkFlag(0b1, // no type return
|
2111
|
-
checkFlag(0b10, [ // no type return & constr
|
2112
|
-
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2113
|
-
...argsOut,
|
2114
|
-
[ Opcodes.local_get, funcLocal ],
|
2115
|
-
[ Opcodes.call_indirect, argc, 0, 'no_type_return', 'constr' ],
|
2116
|
-
], [
|
2117
|
-
...argsOut,
|
2118
|
-
[ Opcodes.local_get, funcLocal ],
|
2119
|
-
[ Opcodes.call_indirect, argc, 0, 'no_type_return' ]
|
2120
|
-
]),
|
2121
|
-
checkFlag(0b10, [ // type return & constr
|
2122
|
-
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2123
|
-
...argsOut,
|
2124
|
-
[ Opcodes.local_get, funcLocal ],
|
2125
|
-
[ Opcodes.call_indirect, argc, 0, 'constr' ],
|
2126
|
-
...setLastType(scope),
|
2127
|
-
], [
|
2128
|
-
...argsOut,
|
2129
|
-
[ Opcodes.local_get, funcLocal ],
|
2130
|
-
[ Opcodes.call_indirect, argc, 0 ],
|
2131
|
-
...setLastType(scope),
|
2132
|
-
]),
|
2133
|
-
);
|
2134
|
-
};
|
2145
|
+
const tableBc = {};
|
2146
|
+
for (let i = 0; i <= args.length; i++) {
|
2147
|
+
tableBc[i] = gen(i);
|
2148
|
+
}
|
2135
2149
|
|
2136
|
-
|
2137
|
-
for (let i = 0; i <= args.length; i++) {
|
2138
|
-
tableBc[i] = gen(i);
|
2139
|
-
}
|
2150
|
+
// todo/perf: check if we should use br_table here or just generate our own big if..elses
|
2140
2151
|
|
2141
|
-
|
2152
|
+
return [
|
2153
|
+
...generate(scope, decl.callee),
|
2154
|
+
[ Opcodes.local_set, localTmp(scope, '#indirect_callee') ],
|
2142
2155
|
|
2143
|
-
|
2156
|
+
...typeSwitch(scope, getNodeType(scope, decl.callee), {
|
2144
2157
|
[TYPES.function]: [
|
2145
2158
|
...out,
|
2146
2159
|
|
2147
|
-
[
|
2160
|
+
[ Opcodes.local_get, localTmp(scope, '#indirect_callee') ],
|
2148
2161
|
Opcodes.i32_to_u,
|
2149
2162
|
[ Opcodes.local_set, funcLocal ],
|
2150
2163
|
|
@@ -2177,10 +2190,8 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2177
2190
|
], tableBc, valtypeBinary)
|
2178
2191
|
],
|
2179
2192
|
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
2180
|
-
})
|
2181
|
-
|
2182
|
-
|
2183
|
-
return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
2193
|
+
})
|
2194
|
+
];
|
2184
2195
|
}
|
2185
2196
|
|
2186
2197
|
const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
|
@@ -2296,6 +2307,8 @@ const codeToSanitizedStr = code => {
|
|
2296
2307
|
const sanitize = str => str.replace(/[^0-9a-zA-Z_]/g, _ => codeToSanitizedStr(_.charCodeAt(0)));
|
2297
2308
|
|
2298
2309
|
const unhackName = name => {
|
2310
|
+
if (!name) return name;
|
2311
|
+
|
2299
2312
|
if (name.startsWith('__')) return name.slice(2).replaceAll('_', '.');
|
2300
2313
|
return name;
|
2301
2314
|
};
|
@@ -2702,22 +2715,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2702
2715
|
const { type, name } = decl.left;
|
2703
2716
|
const [ local, isGlobal ] = lookupName(scope, name);
|
2704
2717
|
|
2705
|
-
if (isFuncType(decl.right.type)) {
|
2706
|
-
|
2707
|
-
|
2718
|
+
// if (isFuncType(decl.right.type)) {
|
2719
|
+
// // hack for a = function () { ... }
|
2720
|
+
// decl.right.id = { name };
|
2708
2721
|
|
2709
|
-
|
2722
|
+
// const func = generateFunc(scope, decl.right);
|
2710
2723
|
|
2711
|
-
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2724
|
+
// return [
|
2725
|
+
// ...number(func.index - importedFuncs.length),
|
2726
|
+
// ...(local != null ? [
|
2727
|
+
// [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2728
|
+
// [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
2716
2729
|
|
2717
|
-
|
2718
|
-
|
2719
|
-
|
2720
|
-
}
|
2730
|
+
// ...setType(scope, name, TYPES.function)
|
2731
|
+
// ] : [])
|
2732
|
+
// ];
|
2733
|
+
// }
|
2721
2734
|
|
2722
2735
|
const op = decl.operator.slice(0, -1) || '=';
|
2723
2736
|
|
@@ -2746,18 +2759,27 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2746
2759
|
}
|
2747
2760
|
|
2748
2761
|
// arr[i]
|
2749
|
-
if (decl.left.type === 'MemberExpression'
|
2762
|
+
if (decl.left.type === 'MemberExpression') {
|
2750
2763
|
const newValueTmp = localTmp(scope, '#member_setter_val_tmp');
|
2751
2764
|
const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
|
2752
2765
|
|
2766
|
+
const object = decl.left.object;
|
2767
|
+
const property = decl.left.computed ? decl.left.property : {
|
2768
|
+
type: 'Literal',
|
2769
|
+
value: decl.left.property.name
|
2770
|
+
};
|
2771
|
+
|
2772
|
+
includeBuiltin(scope, '__Map_prototype_get');
|
2773
|
+
includeBuiltin(scope, '__Map_prototype_set');
|
2774
|
+
|
2753
2775
|
return [
|
2754
2776
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2755
2777
|
[TYPES.array]: [
|
2756
|
-
...generate(scope,
|
2778
|
+
...generate(scope, object),
|
2757
2779
|
Opcodes.i32_to_u,
|
2758
2780
|
|
2759
2781
|
// get index as valtype
|
2760
|
-
...generate(scope,
|
2782
|
+
...generate(scope, property),
|
2761
2783
|
Opcodes.i32_to_u,
|
2762
2784
|
|
2763
2785
|
// turn into byte offset by * valtypeSize + 1
|
@@ -2781,6 +2803,34 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2781
2803
|
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
2782
2804
|
],
|
2783
2805
|
|
2806
|
+
[TYPES.object]: [
|
2807
|
+
...generate(scope, object),
|
2808
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, localTmp(scope, '#objset_object') ] ]),
|
2809
|
+
...getNodeType(scope, object),
|
2810
|
+
|
2811
|
+
...generate(scope, property),
|
2812
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, localTmp(scope, '#objset_property') ] ]),
|
2813
|
+
...getNodeType(scope, property),
|
2814
|
+
|
2815
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2816
|
+
[ Opcodes.local_get, localTmp(scope, '#objset_object') ],
|
2817
|
+
...getNodeType(scope, object),
|
2818
|
+
|
2819
|
+
[ Opcodes.local_get, localTmp(scope, '#objset_property') ],
|
2820
|
+
...getNodeType(scope, property),
|
2821
|
+
|
2822
|
+
[ Opcodes.call, funcIndex.__Map_prototype_get ],
|
2823
|
+
...setLastType(scope)
|
2824
|
+
], generate(scope, decl.right), getLastType(scope), getNodeType(scope, decl.right), false, name, true)),
|
2825
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2826
|
+
...getNodeType(scope, decl),
|
2827
|
+
|
2828
|
+
[ Opcodes.call, funcIndex.__Map_prototype_set ],
|
2829
|
+
[ Opcodes.drop ],
|
2830
|
+
|
2831
|
+
...setLastType(scope, getNodeType(scope, decl)),
|
2832
|
+
],
|
2833
|
+
|
2784
2834
|
...wrapBC({
|
2785
2835
|
[TYPES.uint8array]: [
|
2786
2836
|
[ Opcodes.i32_add ],
|
@@ -2924,11 +2974,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2924
2974
|
],
|
2925
2975
|
}, {
|
2926
2976
|
prelude: [
|
2927
|
-
...generate(scope,
|
2977
|
+
...generate(scope, object),
|
2928
2978
|
Opcodes.i32_to_u,
|
2929
2979
|
[ Opcodes.i32_load, 0, 4 ],
|
2930
2980
|
|
2931
|
-
...generate(scope,
|
2981
|
+
...generate(scope, property),
|
2932
2982
|
Opcodes.i32_to_u,
|
2933
2983
|
],
|
2934
2984
|
postlude: setLastType(scope, TYPES.number)
|
@@ -2957,7 +3007,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2957
3007
|
// set global and return (eg a = 2)
|
2958
3008
|
return [
|
2959
3009
|
...generateVar(scope, { kind: 'var', _bare: true, declarations: [ { id: { name }, init: decl.right } ] }),
|
2960
|
-
|
3010
|
+
...generate(scope, decl.left)
|
2961
3011
|
];
|
2962
3012
|
}
|
2963
3013
|
|
@@ -4193,12 +4243,50 @@ const generateArray = (scope, decl, global = false, name = '$undeclared', initEm
|
|
4193
4243
|
};
|
4194
4244
|
|
4195
4245
|
const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
4196
|
-
if (
|
4246
|
+
if (!funcIndex.Map) includeBuiltin(scope, 'Map');
|
4247
|
+
if (!funcIndex.__Map_prototype_set) includeBuiltin(scope, '__Map_prototype_set');
|
4197
4248
|
|
4198
|
-
|
4199
|
-
|
4200
|
-
|
4249
|
+
// todo: optimize const objects
|
4250
|
+
const tmp = localTmp(scope, `#objectexpr${randId()}`);
|
4251
|
+
const out = [
|
4252
|
+
...generateCall(scope, {
|
4253
|
+
callee: {
|
4254
|
+
type: 'Identifier',
|
4255
|
+
name: 'Map'
|
4256
|
+
},
|
4257
|
+
arguments: [],
|
4258
|
+
_new: true
|
4259
|
+
}),
|
4260
|
+
[ Opcodes.local_tee, tmp ]
|
4201
4261
|
];
|
4262
|
+
|
4263
|
+
for (const x of decl.properties) {
|
4264
|
+
const { method, shorthand, computed, kind, key, value } = x;
|
4265
|
+
if (method || shorthand || kind !== 'init' || key.type !== 'Identifier') return todo(scope, 'complex objects are not supported yet', true);
|
4266
|
+
|
4267
|
+
const k = computed ? key : {
|
4268
|
+
type: 'Literal',
|
4269
|
+
value: key.name
|
4270
|
+
};
|
4271
|
+
|
4272
|
+
out.push(
|
4273
|
+
[ Opcodes.local_get, tmp ],
|
4274
|
+
...number(TYPES.map, Valtype.i32),
|
4275
|
+
|
4276
|
+
...generate(scope, k),
|
4277
|
+
...getNodeType(scope, k),
|
4278
|
+
|
4279
|
+
...generate(scope, value),
|
4280
|
+
...getNodeType(scope, value),
|
4281
|
+
|
4282
|
+
[ Opcodes.call, funcIndex.__Map_prototype_set ],
|
4283
|
+
|
4284
|
+
[ Opcodes.drop ],
|
4285
|
+
[ Opcodes.drop ]
|
4286
|
+
);
|
4287
|
+
}
|
4288
|
+
|
4289
|
+
return out;
|
4202
4290
|
};
|
4203
4291
|
|
4204
4292
|
const withType = (scope, wasm, type) => [
|
@@ -4323,14 +4411,19 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4323
4411
|
}, valtypeBinary);
|
4324
4412
|
}
|
4325
4413
|
|
4326
|
-
const object =
|
4327
|
-
const
|
4414
|
+
const object = decl.object;
|
4415
|
+
const objectWasm = generate(scope, object);
|
4416
|
+
const property = decl.computed ? decl.property : {
|
4417
|
+
type: 'Literal',
|
4418
|
+
value: decl.property.name
|
4419
|
+
};
|
4420
|
+
const propertyWasm = generate(scope, property);
|
4328
4421
|
|
4329
4422
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
4330
4423
|
// hack: this is naughty and will break things!
|
4331
4424
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
4332
4425
|
|
4333
|
-
const known = knownType(scope, getNodeType(scope,
|
4426
|
+
const known = knownType(scope, getNodeType(scope, object));
|
4334
4427
|
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
4335
4428
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
4336
4429
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
@@ -4338,11 +4431,14 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4338
4431
|
}, _global, _name, true, 'i16', true);
|
4339
4432
|
}
|
4340
4433
|
|
4341
|
-
|
4434
|
+
includeBuiltin(scope, '__Map_prototype_get');
|
4435
|
+
|
4436
|
+
return typeSwitch(scope, getNodeType(scope, object), {
|
4342
4437
|
[TYPES.array]: [
|
4343
|
-
...loadArray(scope,
|
4438
|
+
...loadArray(scope, objectWasm, propertyWasm),
|
4344
4439
|
...setLastType(scope)
|
4345
4440
|
],
|
4441
|
+
|
4346
4442
|
[TYPES.string]: [
|
4347
4443
|
// setup new/out array
|
4348
4444
|
...newOut,
|
@@ -4354,13 +4450,13 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4354
4450
|
// use as pointer for store later
|
4355
4451
|
...newPointer,
|
4356
4452
|
|
4357
|
-
...
|
4453
|
+
...propertyWasm,
|
4358
4454
|
Opcodes.i32_to_u,
|
4359
4455
|
|
4360
4456
|
...number(ValtypeSize.i16, Valtype.i32),
|
4361
4457
|
[ Opcodes.i32_mul ],
|
4362
4458
|
|
4363
|
-
...
|
4459
|
+
...objectWasm,
|
4364
4460
|
Opcodes.i32_to_u,
|
4365
4461
|
[ Opcodes.i32_add ],
|
4366
4462
|
|
@@ -4375,6 +4471,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4375
4471
|
Opcodes.i32_from_u,
|
4376
4472
|
...setLastType(scope, TYPES.string)
|
4377
4473
|
],
|
4474
|
+
|
4378
4475
|
[TYPES.bytestring]: [
|
4379
4476
|
// setup new/out array
|
4380
4477
|
...newOut,
|
@@ -4386,10 +4483,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4386
4483
|
// use as pointer for store later
|
4387
4484
|
...newPointer,
|
4388
4485
|
|
4389
|
-
...
|
4486
|
+
...propertyWasm,
|
4390
4487
|
Opcodes.i32_to_u,
|
4391
4488
|
|
4392
|
-
...
|
4489
|
+
...objectWasm,
|
4393
4490
|
Opcodes.i32_to_u,
|
4394
4491
|
[ Opcodes.i32_add ],
|
4395
4492
|
|
@@ -4405,6 +4502,17 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4405
4502
|
...setLastType(scope, TYPES.bytestring)
|
4406
4503
|
],
|
4407
4504
|
|
4505
|
+
[TYPES.object]: [
|
4506
|
+
...objectWasm,
|
4507
|
+
...getNodeType(scope, object),
|
4508
|
+
|
4509
|
+
...propertyWasm,
|
4510
|
+
...getNodeType(scope, property),
|
4511
|
+
|
4512
|
+
[ Opcodes.call, funcIndex.__Map_prototype_get ],
|
4513
|
+
...setLastType(scope)
|
4514
|
+
],
|
4515
|
+
|
4408
4516
|
...wrapBC({
|
4409
4517
|
[TYPES.uint8array]: [
|
4410
4518
|
[ Opcodes.i32_add ],
|
@@ -4473,22 +4581,23 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4473
4581
|
],
|
4474
4582
|
}, {
|
4475
4583
|
prelude: [
|
4476
|
-
...
|
4584
|
+
...objectWasm,
|
4477
4585
|
Opcodes.i32_to_u,
|
4478
4586
|
[ Opcodes.i32_load, 0, 4 ],
|
4479
4587
|
|
4480
|
-
...
|
4588
|
+
...propertyWasm,
|
4481
4589
|
Opcodes.i32_to_u
|
4482
4590
|
],
|
4483
4591
|
postlude: setLastType(scope, TYPES.number)
|
4484
4592
|
}),
|
4485
4593
|
|
4486
|
-
default: internalThrow(scope, 'TypeError', '
|
4594
|
+
default: internalThrow(scope, 'TypeError', 'Unsupported member expression object', true)
|
4487
4595
|
});
|
4488
4596
|
};
|
4489
4597
|
|
4490
4598
|
const randId = () => Math.random().toString(16).slice(1, -2).padEnd(12, '0');
|
4491
4599
|
|
4600
|
+
let objectHackers = [];
|
4492
4601
|
const objectHack = node => {
|
4493
4602
|
if (!node) return node;
|
4494
4603
|
|
@@ -4503,16 +4612,10 @@ const objectHack = node => {
|
|
4503
4612
|
if (objectName && ['undefined', 'null', 'NaN', 'Infinity'].includes(objectName)) return;
|
4504
4613
|
|
4505
4614
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
4506
|
-
|
4507
|
-
// if .name or .length, give up (hack within a hack!)
|
4508
|
-
if (['name', 'length', 'size', 'description', 'byteLength', 'byteOffset', 'buffer', 'detached', 'resizable', 'growable', 'maxByteLength'].includes(node.property.name)) {
|
4509
|
-
node.object = objectHack(node.object);
|
4615
|
+
if (!objectName || (!objectHackers.includes(objectName) && !objectHackers.some(x => objectName.startsWith(`${x}_`)))) {
|
4510
4616
|
return;
|
4511
4617
|
}
|
4512
4618
|
|
4513
|
-
// no object name, give up
|
4514
|
-
if (!objectName) return;
|
4515
|
-
|
4516
4619
|
const name = '__' + objectName + '_' + node.property.name;
|
4517
4620
|
if (Prefs.codeLog) log('codegen', `object hack! ${node.object.name}.${node.property.name} -> ${name}`);
|
4518
4621
|
|
@@ -4861,6 +4964,9 @@ export default program => {
|
|
4861
4964
|
prototypeFuncs = new PrototypeFuncs();
|
4862
4965
|
allocator = makeAllocator(Prefs.allocator ?? 'static');
|
4863
4966
|
|
4967
|
+
const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
|
4968
|
+
objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
|
4969
|
+
|
4864
4970
|
program.id = { name: 'main' };
|
4865
4971
|
|
4866
4972
|
const scope = {
|
@@ -3998,28 +3998,28 @@ export const BuiltinFuncs = function() {
|
|
3998
3998
|
locals: [], localNames: ["_this","_this#type"],
|
3999
3999
|
};
|
4000
4000
|
this.__Map_prototype_has = {
|
4001
|
-
wasm: (scope, {builtin}) => [[32,0],[252,2],[40,0,0],[183],[
|
4001
|
+
wasm: (scope, {builtin}) => [[32,0],[252,2],[40,0,0],[183],[34,4],[65,19],[32,2],[32,3],[16, builtin('__Set_prototype_has')],[34,5],[15]],
|
4002
4002
|
params: [124,127,124,127], typedParams: 1,
|
4003
4003
|
returns: [124,127], typedReturns: 1,
|
4004
4004
|
locals: [124,127], localNames: ["_this","_this#type","key","key#type","keys","#last_type"],
|
4005
4005
|
};
|
4006
4006
|
this.__Map_prototype_get = {
|
4007
|
-
wasm: (scope, {builtin}) => [[32,0],[252,2],[40,0,0],[183],[33,4],[32,0],[252,2],[40,0,4],[183],[33,5],[32,4],[
|
4007
|
+
wasm: (scope, {builtin}) => [[32,0],[252,2],[40,0,0],[183],[33,4],[32,0],[252,2],[40,0,4],[183],[33,5],[32,4],[252,2],[40,0,0],[183],[33,6],[68,0,0,0,0,0,0,0,0],[33,7],[3,64],[32,7],[32,6],[99],[4,64],[2,64],[2,127,"string_only"],[32,4],[65,19],[32,7],[65,1],[16, builtin('__Porffor_set_read')],[33,8],[34,9,"string_only"],[32,2],[34,10,"string_only"],[32,8,"string_only|start"],[65,195,1],[70],[32,3],[65,195,1],[70],[113],[4,64],[32,9],[252,3],[34,11],[32,10],[252,3],[34,13],[71],[4,127],[32,11],[40,0,0],[34,12],[32,13],[40,0,0],[71],[4,64],[65,0],[12,1],[11],[65,0],[33,14],[32,12],[33,15],[3,64],[32,14],[32,11],[106],[45,0,4],[32,14],[32,13],[106],[45,0,4],[71],[4,64],[65,0],[12,2],[11],[32,14],[65,1],[106],[34,14],[32,15],[72],[13,0],[11],[65,1],[5],[65,1],[11],[12,1],[11],[32,8],[65,195,0],[70],[32,8],[65,195,1],[70],[114],[32,3],[65,195,0],[70],[32,3],[65,195,1],[70],[114],[114],[4,64],[32,9],[252,3],[34,11],[32,10],[252,3],[34,13],[71],[4,127],[32,11],[40,0,0],[34,12],[32,13],[40,0,0],[32,8],[65,195,1],[70],[4,64],[32,11],[32,12],[16, builtin('__Porffor_bytestringToString')],[33,11],[11],[32,3],[65,195,1],[70],[4,64],[32,13],[32,13],[40,0,0],[16, builtin('__Porffor_bytestringToString')],[33,13],[11],[71],[4,64],[65,0],[12,1],[11],[65,0],[33,14],[32,12],[65,2],[108],[33,15],[3,64],[32,14],[32,11],[106],[47,0,4],[32,14],[32,13],[106],[47,0,4],[71],[4,64],[65,0],[12,2],[11],[32,14],[65,2],[106],[34,14],[32,15],[72],[13,0],[11],[65,1],[5],[65,1],[11],[12,1],[11,"string_only|end"],[97],[11,"string_only"],[32,8],[65,128,1],[114],[32,3],[65,128,1],[114],[70],[113],[4,64],[32,7],[252,3],[65,9],[108],[32,5],[252,3],[106],[34,16],[43,0,4],[32,16],[45,0,12],[34,8],[15],[11],[11],[32,7],[68,0,0,0,0,0,0,240,63],[160],[33,7],[12,1],[11],[11],[68,0,0,0,0,0,0,0,0],[65,128,1],[15]],
|
4008
4008
|
params: [124,127,124,127], typedParams: 1,
|
4009
4009
|
returns: [124,127], typedReturns: 1,
|
4010
|
-
locals: [124,124,124,127,127], localNames: ["_this","_this#type","key","key#type","keys","vals","
|
4010
|
+
locals: [124,124,124,124,127,124,124,127,127,127,127,127,127], localNames: ["_this","_this#type","key","key#type","keys","vals","size","i","#last_type","__tmpop_left","__tmpop_right","compare_left_pointer","compare_left_length","compare_right_pointer","compare_index","compare_index_end","#loadArray_offset"],
|
4011
4011
|
};
|
4012
4012
|
this.__Map_prototype_set = {
|
4013
|
-
wasm: (scope, {builtin}) => [[32,0],[252,2],[40,0,0],[183],[33,6],[32,0],[252,2],[40,0,4],[183],[33,7],[32,6],[252,2],[40,0,0],[183],[33,8],[32,6],[65,19],[32,2],[32,3],[16, builtin('
|
4013
|
+
wasm: (scope, {builtin}) => [[32,0],[252,2],[40,0,0],[183],[33,6],[32,0],[252,2],[40,0,4],[183],[33,7],[32,6],[252,2],[40,0,0],[183],[33,8],[68,0,0,0,0,0,0,0,0],[33,9],[3,64],[32,9],[32,8],[99],[4,64],[2,64],[2,127,"string_only"],[32,6],[65,19],[32,9],[65,1],[16, builtin('__Porffor_set_read')],[33,10],[34,11,"string_only"],[32,2],[34,12,"string_only"],[32,10,"string_only|start"],[65,195,1],[70],[32,3],[65,195,1],[70],[113],[4,64],[32,11],[252,3],[34,13],[32,12],[252,3],[34,15],[71],[4,127],[32,13],[40,0,0],[34,14],[32,15],[40,0,0],[71],[4,64],[65,0],[12,1],[11],[65,0],[33,16],[32,14],[33,17],[3,64],[32,16],[32,13],[106],[45,0,4],[32,16],[32,15],[106],[45,0,4],[71],[4,64],[65,0],[12,2],[11],[32,16],[65,1],[106],[34,16],[32,17],[72],[13,0],[11],[65,1],[5],[65,1],[11],[12,1],[11],[32,10],[65,195,0],[70],[32,10],[65,195,1],[70],[114],[32,3],[65,195,0],[70],[32,3],[65,195,1],[70],[114],[114],[4,64],[32,11],[252,3],[34,13],[32,12],[252,3],[34,15],[71],[4,127],[32,13],[40,0,0],[34,14],[32,15],[40,0,0],[32,10],[65,195,1],[70],[4,64],[32,13],[32,14],[16, builtin('__Porffor_bytestringToString')],[33,13],[11],[32,3],[65,195,1],[70],[4,64],[32,15],[32,15],[40,0,0],[16, builtin('__Porffor_bytestringToString')],[33,15],[11],[71],[4,64],[65,0],[12,1],[11],[65,0],[33,16],[32,14],[65,2],[108],[33,17],[3,64],[32,16],[32,13],[106],[47,0,4],[32,16],[32,15],[106],[47,0,4],[71],[4,64],[65,0],[12,2],[11],[32,16],[65,2],[106],[34,16],[32,17],[72],[13,0],[11],[65,1],[5],[65,1],[11],[12,1],[11,"string_only|end"],[97],[11,"string_only"],[32,10],[65,128,1],[114],[32,3],[65,128,1],[114],[70],[113],[4,64],[32,7],[252,3],[32,9],[252,3],[65,9],[108],[106],[34,19],[32,4],[34,18],[57,0,4],[32,19],[32,5],[58,0,12],[32,0],[65,20],[15],[11],[11],[32,9],[68,0,0,0,0,0,0,240,63],[160],[33,9],[12,1],[11],[11],[32,6],[252,2],[32,8],[68,0,0,0,0,0,0,240,63],[160],[252,2],[54,0,0],[32,6],[65,19],[32,8],[65,1],[32,2],[32,3],[16, builtin('__Porffor_set_write')],[33,10],[26],[32,7],[252,3],[32,8],[252,3],[65,9],[108],[106],[34,19],[32,4],[34,18],[57,0,4],[32,19],[32,5],[58,0,12],[32,0],[65,20],[15]],
|
4014
4014
|
params: [124,127,124,127,124,127], typedParams: 1,
|
4015
4015
|
returns: [124,127], typedReturns: 1,
|
4016
|
-
locals: [124,124,124,124,127,124,127], localNames: ["_this","_this#type","key","key#type","value","value#type","keys","vals","size","
|
4016
|
+
locals: [124,124,124,124,127,124,124,127,127,127,127,127,124,127], localNames: ["_this","_this#type","key","key#type","value","value#type","keys","vals","size","i","#last_type","__tmpop_left","__tmpop_right","compare_left_pointer","compare_left_length","compare_right_pointer","compare_index","compare_index_end","#member_setter_val_tmp","#member_setter_ptr_tmp"],
|
4017
4017
|
};
|
4018
4018
|
this.__Map_prototype_delete = {
|
4019
|
-
wasm: (scope, {builtin}) => [[32,0],[252,2],[40,0,0],[183],[
|
4019
|
+
wasm: (scope, {builtin}) => [[32,0],[252,2],[40,0,0],[183],[33,4],[32,0],[252,2],[40,0,4],[183],[33,5],[32,4],[252,2],[40,0,0],[183],[33,6],[68,0,0,0,0,0,0,0,0],[33,7],[3,64],[32,7],[32,6],[99],[4,64],[2,64],[2,127,"string_only"],[32,4],[65,19],[32,7],[65,1],[16, builtin('__Porffor_set_read')],[33,8],[34,9,"string_only"],[32,2],[34,10,"string_only"],[32,8,"string_only|start"],[65,195,1],[70],[32,3],[65,195,1],[70],[113],[4,64],[32,9],[252,3],[34,11],[32,10],[252,3],[34,13],[71],[4,127],[32,11],[40,0,0],[34,12],[32,13],[40,0,0],[71],[4,64],[65,0],[12,1],[11],[65,0],[33,14],[32,12],[33,15],[3,64],[32,14],[32,11],[106],[45,0,4],[32,14],[32,13],[106],[45,0,4],[71],[4,64],[65,0],[12,2],[11],[32,14],[65,1],[106],[34,14],[32,15],[72],[13,0],[11],[65,1],[5],[65,1],[11],[12,1],[11],[32,8],[65,195,0],[70],[32,8],[65,195,1],[70],[114],[32,3],[65,195,0],[70],[32,3],[65,195,1],[70],[114],[114],[4,64],[32,9],[252,3],[34,11],[32,10],[252,3],[34,13],[71],[4,127],[32,11],[40,0,0],[34,12],[32,13],[40,0,0],[32,8],[65,195,1],[70],[4,64],[32,11],[32,12],[16, builtin('__Porffor_bytestringToString')],[33,11],[11],[32,3],[65,195,1],[70],[4,64],[32,13],[32,13],[40,0,0],[16, builtin('__Porffor_bytestringToString')],[33,13],[11],[71],[4,64],[65,0],[12,1],[11],[65,0],[33,14],[32,12],[65,2],[108],[33,15],[3,64],[32,14],[32,11],[106],[47,0,4],[32,14],[32,13],[106],[47,0,4],[71],[4,64],[65,0],[12,2],[11],[32,14],[65,2],[106],[34,14],[32,15],[72],[13,0],[11],[65,1],[5],[65,1],[11],[12,1],[11,"string_only|end"],[97],[11,"string_only"],[32,8],[65,128,1],[114],[32,3],[65,128,1],[114],[70],[113],[4,64],[32,4],[65,19],[32,2],[32,3],[16, builtin('__Set_prototype_delete')],[33,8],[26],[32,5],[65,208,0],[32,7],[65,1],[68,0,0,0,0,0,0,240,63],[65,1],[65,4],[65,0],[54,1,0],[68,0,0,0,0,0,0,16,64],[65,208,0],[16, builtin('__Array_prototype_splice')],[33,8],[26],[68,0,0,0,0,0,0,240,63],[65,2],[15],[11],[11],[32,7],[68,0,0,0,0,0,0,240,63],[160],[33,7],[12,1],[11],[11],[68,0,0,0,0,0,0,0,0],[65,2],[15]],
|
4020
4020
|
params: [124,127,124,127], typedParams: 1,
|
4021
4021
|
returns: [124,127], typedReturns: 1,
|
4022
|
-
locals: [124,124,127,127,
|
4022
|
+
locals: [124,124,124,124,127,124,124,127,127,127,127,127], localNames: ["_this","_this#type","key","key#type","keys","vals","size","i","#last_type","__tmpop_left","__tmpop_right","compare_left_pointer","compare_left_length","compare_right_pointer","compare_index","compare_index_end"],
|
4023
4023
|
};
|
4024
4024
|
this.__Map_prototype_clear = {
|
4025
4025
|
wasm: (scope, {builtin}) => [[32,0],[252,2],[40,0,0],[183],[34,2],[65,19],[16, builtin('__Set_prototype_clear')],[26],[26],[32,0],[252,2],[40,0,4],[183],[34,4],[252,3],[68,0,0,0,0,0,0,0,0],[34,5],[252,3],[54,1,0],[68,0,0,0,0,0,0,0,0],[65,128,1],[15]],
|
package/compiler/wrap.js
CHANGED
@@ -10,16 +10,26 @@ const fs = (typeof process?.version !== 'undefined' ? (await import('node:fs'))
|
|
10
10
|
|
11
11
|
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
12
12
|
|
13
|
+
const checkOOB = (memory, ptr) => ptr >= memory.buffer.byteLength;
|
14
|
+
|
15
|
+
let dv;
|
16
|
+
const read = (ta, memory, ptr, length) => {
|
17
|
+
if (ta === Uint8Array) return new Uint8Array(memory.buffer, ptr, length);
|
18
|
+
return new ta(memory.buffer.slice(ptr, ptr + length * ta.BYTES_PER_ELEMENT), 0, length);
|
19
|
+
};
|
20
|
+
|
13
21
|
export const readByteStr = (memory, ptr) => {
|
14
|
-
const length = (
|
15
|
-
return Array.from(
|
22
|
+
const length = read(Uint32Array, memory, ptr, 1)[0];
|
23
|
+
return Array.from(read(Uint8Array, memory, ptr + 4, length)).map(x => String.fromCharCode(x)).join('');
|
16
24
|
};
|
17
25
|
|
18
26
|
export const writeByteStr = (memory, ptr, str) => {
|
19
27
|
const length = str.length;
|
20
|
-
(new Uint32Array(memory.buffer, ptr, 1))[0] = length;
|
21
28
|
|
22
|
-
|
29
|
+
if (dv.memory !== memory) dv = new DataView(memory.buffer);
|
30
|
+
dv.setUint32(ptr, length, true);
|
31
|
+
|
32
|
+
const arr = read(Uint8Array, memory, ptr + 4, length);
|
23
33
|
for (let i = 0; i < length; i++) {
|
24
34
|
arr[i] = str.charCodeAt(i);
|
25
35
|
}
|
@@ -32,7 +42,31 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
|
32
42
|
return undefined;
|
33
43
|
|
34
44
|
case TYPES.boolean: return Boolean(value);
|
35
|
-
case TYPES.object:
|
45
|
+
case TYPES.object: {
|
46
|
+
if (value === 0 || checkOOB(memory, value)) return null;
|
47
|
+
|
48
|
+
const [ keysPtr, valsPtr ] = read(Uint32Array, memory, value, 2);
|
49
|
+
if (checkOOB(memory, keysPtr) || checkOOB(memory, valsPtr)) return null;
|
50
|
+
|
51
|
+
const size = read(Uint32Array, memory, keysPtr, 1);
|
52
|
+
|
53
|
+
const out = {};
|
54
|
+
for (let i = 0; i < size; i++) {
|
55
|
+
const offset = 4 + (i * 9);
|
56
|
+
|
57
|
+
const kValue = read(Float64Array, memory, keysPtr + offset, 1)[0];
|
58
|
+
const kType = read(Uint8Array, memory, keysPtr + offset + 8, 1)[0];
|
59
|
+
const k = porfToJSValue({ memory, funcs, pages }, kValue, kType);
|
60
|
+
|
61
|
+
const vValue = read(Float64Array, memory, valsPtr + offset, 1)[0];
|
62
|
+
const vType = read(Uint8Array, memory, valsPtr + offset + 8, 1)[0];
|
63
|
+
const v = porfToJSValue({ memory, funcs, pages }, vValue, vType);
|
64
|
+
|
65
|
+
out[k] = v;
|
66
|
+
}
|
67
|
+
|
68
|
+
return out;
|
69
|
+
}
|
36
70
|
|
37
71
|
case TYPES.function: {
|
38
72
|
let func;
|
@@ -49,29 +83,24 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
|
49
83
|
}
|
50
84
|
|
51
85
|
case TYPES.string: {
|
52
|
-
const length = (
|
53
|
-
return Array.from(
|
86
|
+
const length = read(Uint32Array, memory, value, 1)[0];
|
87
|
+
return Array.from(read(Uint16Array, memory, value + 4, length)).map(x => String.fromCharCode(x)).join('');
|
54
88
|
}
|
55
89
|
|
56
90
|
case TYPES.bytestring: {
|
57
|
-
const length = (
|
58
|
-
return Array.from(
|
91
|
+
const length = read(Uint32Array, memory, value, 1)[0];
|
92
|
+
return Array.from(read(Uint8Array, memory, value + 4, length)).map(x => String.fromCharCode(x)).join('');
|
59
93
|
}
|
60
94
|
|
61
95
|
case TYPES.array: {
|
62
|
-
const length = (
|
96
|
+
const length = read(Uint32Array, memory, value, 1)[0];
|
63
97
|
|
64
98
|
const out = [];
|
65
99
|
for (let i = 0; i < length; i++) {
|
66
100
|
const offset = value + 4 + (i * 9);
|
67
101
|
|
68
|
-
|
69
|
-
const
|
70
|
-
const t = (new Uint8Array(memory.buffer, offset + 8, 1))[0];
|
71
|
-
|
72
|
-
// console.log(`reading value at index ${i}...`)
|
73
|
-
// console.log(' memory:', Array.from(new Uint8Array(memory.buffer, offset, 9)).map(x => x.toString(16).padStart(2, '0')).join(' '));
|
74
|
-
// console.log(' read:', { value: v, type: t }, '\n');
|
102
|
+
const v = read(Float64Array, memory, offset, 1)[0];
|
103
|
+
const t = read(Uint8Array, memory, offset + 8, 1)[0];
|
75
104
|
|
76
105
|
out.push(porfToJSValue({ memory, funcs, pages }, v, t));
|
77
106
|
}
|
@@ -80,7 +109,7 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
|
80
109
|
}
|
81
110
|
|
82
111
|
case TYPES.date: {
|
83
|
-
const t = (
|
112
|
+
const t = read(Float64Array, memory, value, 1)[0];
|
84
113
|
return new Date(t);
|
85
114
|
}
|
86
115
|
|
@@ -90,15 +119,15 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
|
90
119
|
|
91
120
|
const offset = descStore + 4 + ((value - 1) * 9);
|
92
121
|
|
93
|
-
const v = (
|
94
|
-
const t = (
|
122
|
+
const v = read(Float64Array, memory, offset, 1)[0];
|
123
|
+
const t = read(Uint8Array, memory, offset + 8, 1)[0];
|
95
124
|
|
96
125
|
const desc = porfToJSValue({ memory, funcs, pages }, v, t);
|
97
126
|
return Symbol(desc);
|
98
127
|
}
|
99
128
|
|
100
129
|
case TYPES.arraybuffer: {
|
101
|
-
const length = (
|
130
|
+
const length = read(Uint32Array, memory, value, 1)[0];
|
102
131
|
if (length === 4294967295) {
|
103
132
|
// mock detached
|
104
133
|
const buf = new ArrayBuffer(0);
|
@@ -110,16 +139,16 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
|
110
139
|
}
|
111
140
|
|
112
141
|
case TYPES.sharedarraybuffer: {
|
113
|
-
const length = (
|
142
|
+
const length = read(Uint32Array, memory, value, 1)[0];
|
114
143
|
const buf = memory.buffer.slice(value + 4, value + 4 + length);
|
115
144
|
buf.shared = true;
|
116
145
|
return buf;
|
117
146
|
}
|
118
147
|
|
119
148
|
case TYPES.dataview: {
|
120
|
-
const [ length, ptr, byteOffset ] = (
|
149
|
+
const [ length, ptr, byteOffset ] = read(Uint32Array, memory, value, 3);
|
121
150
|
const bufferPtr = ptr - byteOffset;
|
122
|
-
const bufferLen = (
|
151
|
+
const bufferLen = read(Uint32Array, memory, bufferPtr, 1)[0];
|
123
152
|
const buffer = memory.buffer.slice(bufferPtr + 4, bufferPtr + 4 + bufferLen);
|
124
153
|
return new DataView(buffer, byteOffset, length);
|
125
154
|
}
|
@@ -133,26 +162,26 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
|
133
162
|
case TYPES.int32array:
|
134
163
|
case TYPES.float32array:
|
135
164
|
case TYPES.float64array: {
|
136
|
-
const [ length, ptr ] = (
|
137
|
-
return
|
165
|
+
const [ length, ptr ] = read(Uint32Array, memory, value, 2);
|
166
|
+
return read(globalThis[TYPE_NAMES[type]], memory, ptr + 4, length);
|
138
167
|
}
|
139
168
|
|
140
169
|
case TYPES.weakref: {
|
141
|
-
const v = (
|
142
|
-
const t = (
|
170
|
+
const v = read(Float64Array, memory, value, 1)[0];
|
171
|
+
const t = read(Uint8Array, memory, value + 8, 1)[0];
|
143
172
|
|
144
173
|
return new WeakRef(porfToJSValue({ memory, funcs, pages }, v, t));
|
145
174
|
}
|
146
175
|
|
147
176
|
case TYPES.weakset:
|
148
177
|
case TYPES.set: {
|
149
|
-
const size = (
|
178
|
+
const size = read(Uint32Array, memory, value, 1)[0];
|
150
179
|
|
151
180
|
const out = type === TYPES.weakset ? new WeakSet() : new Set();
|
152
181
|
for (let i = 0; i < size; i++) {
|
153
182
|
const offset = value + 4 + (i * 9);
|
154
|
-
const v = (
|
155
|
-
const t = (
|
183
|
+
const v = read(Float64Array, memory, offset, 1)[0];
|
184
|
+
const t = read(Uint8Array, memory, offset + 8, 1)[0];
|
156
185
|
|
157
186
|
out.add(porfToJSValue({ memory, funcs, pages }, v, t));
|
158
187
|
}
|
@@ -162,19 +191,19 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
|
162
191
|
|
163
192
|
case TYPES.weakmap:
|
164
193
|
case TYPES.map: {
|
165
|
-
const [ keysPtr, valsPtr ] = (
|
166
|
-
const size = (
|
194
|
+
const [ keysPtr, valsPtr ] = read(Uint32Array, memory, value, 2);
|
195
|
+
const size = read(Uint32Array, memory, keysPtr, 1)[0];
|
167
196
|
|
168
197
|
const out = type === TYPES.weakmap ? new WeakMap() : new Map();
|
169
198
|
for (let i = 0; i < size; i++) {
|
170
199
|
const offset = 4 + (i * 9);
|
171
200
|
|
172
|
-
const kValue = (
|
173
|
-
const kType = (
|
201
|
+
const kValue = read(Float64Array, memory, keysPtr + offset, 1)[0];
|
202
|
+
const kType = read(Uint8Array, memory, keysPtr + offset + 8, 1)[0];
|
174
203
|
const k = porfToJSValue({ memory, funcs, pages }, kValue, kType);
|
175
204
|
|
176
|
-
const vValue = (
|
177
|
-
const vType = (
|
205
|
+
const vValue = read(Float64Array, memory, valsPtr + offset, 1)[0];
|
206
|
+
const vType = read(Uint8Array, memory, valsPtr + offset + 8, 1)[0];
|
178
207
|
const v = porfToJSValue({ memory, funcs, pages }, vValue, vType);
|
179
208
|
|
180
209
|
out.set(k, v);
|
package/package.json
CHANGED
package/runner/index.js
CHANGED
package/runner/repl.js
CHANGED
@@ -82,7 +82,10 @@ let prev = '';
|
|
82
82
|
const run = (source, _context, _filename, callback, run = true) => {
|
83
83
|
// hack: print "secret" before latest code ran to only enable printing for new code
|
84
84
|
|
85
|
-
|
85
|
+
source = source.trim();
|
86
|
+
if (source.startsWith('{') && source.endsWith('}')) source = '(' + source + ')';
|
87
|
+
|
88
|
+
let toRun = (prev ? (prev + `;\nprint(-0x1337);\n`) : '') + source;
|
86
89
|
|
87
90
|
let shouldPrint = !prev;
|
88
91
|
const { exports, pages } = compile(toRun, [], {}, str => {
|