porffor 0.19.5 → 0.19.7
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 +30 -15
- package/compiler/codegen.js +279 -178
- package/compiler/generated_builtins.js +6 -6
- package/compiler/wrap.js +66 -37
- package/package.json +1 -1
- package/runner/index.js +1 -1
- package/runner/repl.js +4 -1
@@ -13,10 +13,13 @@ 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
@@ -1231,12 +1231,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1231
1231
|
return func;
|
1232
1232
|
};
|
1233
1233
|
|
1234
|
-
const includeBuiltin = (scope, builtin) =>
|
1235
|
-
const code = builtinFuncs[builtin];
|
1236
|
-
if (code.wasm) return asmFunc(builtin, code);
|
1237
|
-
|
1238
|
-
return code.body.map(x => generate(scope, x));
|
1239
|
-
};
|
1234
|
+
const includeBuiltin = (scope, builtin) => asmFunc(builtin, builtinFuncs[builtin]);
|
1240
1235
|
|
1241
1236
|
const generateLogicExp = (scope, decl) => {
|
1242
1237
|
return performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right));
|
@@ -1341,6 +1336,10 @@ const getNodeType = (scope, node) => {
|
|
1341
1336
|
return getType(scope, node.name);
|
1342
1337
|
}
|
1343
1338
|
|
1339
|
+
if (node.type === 'ObjectExpression') {
|
1340
|
+
return TYPES.object;
|
1341
|
+
}
|
1342
|
+
|
1344
1343
|
if (node.type === 'CallExpression' || node.type === 'NewExpression') {
|
1345
1344
|
const name = node.callee.name;
|
1346
1345
|
if (!name) {
|
@@ -1926,7 +1925,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1926
1925
|
}
|
1927
1926
|
|
1928
1927
|
// TODO: only allows callee as identifier
|
1929
|
-
if (!name) return todo(scope, `only identifier callees (got ${decl.callee.type})`);
|
1928
|
+
// if (!name) return todo(scope, `only identifier callees (got ${decl.callee.type})`);
|
1930
1929
|
|
1931
1930
|
let idx = funcIndex[name] ?? importedFuncs[name];
|
1932
1931
|
if (idx === undefined && builtinFuncs[name]) {
|
@@ -1942,7 +1941,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1942
1941
|
return internalConstrs[name].generate(scope, decl, _global, _name);
|
1943
1942
|
}
|
1944
1943
|
|
1945
|
-
if (idx === undefined && !decl._new && name.startsWith('__Porffor_wasm_')) {
|
1944
|
+
if (idx === undefined && !decl._new && name && name.startsWith('__Porffor_wasm_')) {
|
1946
1945
|
const wasmOps = {
|
1947
1946
|
// pointer, align, offset
|
1948
1947
|
i32_load: { imms: 2, args: [ true ], returns: 1 },
|
@@ -1989,162 +1988,171 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1989
1988
|
}
|
1990
1989
|
|
1991
1990
|
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);
|
1991
|
+
if (!Prefs.indirectCalls) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true);
|
1995
1992
|
|
1996
|
-
|
1993
|
+
// todo: only works when function uses typedParams and typedReturns
|
1997
1994
|
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
1995
|
+
const indirectMode = Prefs.indirectCallMode ?? 'vararg';
|
1996
|
+
// options: vararg, strict
|
1997
|
+
// - strict: simpler, smaller size usage, no func lut needed.
|
1998
|
+
// ONLY works when arg count of call == arg count of function being called
|
1999
|
+
// - vararg: large size usage, cursed.
|
2000
|
+
// works when arg count of call != arg count of function being called*
|
2001
|
+
// * most of the time, some edgecases
|
2005
2002
|
|
2006
|
-
|
2007
|
-
|
2003
|
+
funcs.table = true;
|
2004
|
+
scope.table = true;
|
2008
2005
|
|
2009
|
-
|
2010
|
-
|
2006
|
+
let args = decl.arguments;
|
2007
|
+
let locals = [];
|
2011
2008
|
|
2012
|
-
|
2013
|
-
|
2009
|
+
if (indirectMode === 'vararg') {
|
2010
|
+
const minArgc = Prefs.indirectCallMinArgc ?? 3;
|
2014
2011
|
|
2015
|
-
|
2016
|
-
|
2017
|
-
}
|
2012
|
+
if (args.length < minArgc) {
|
2013
|
+
args = args.concat(new Array(minArgc - args.length).fill(DEFAULT_VALUE));
|
2018
2014
|
}
|
2015
|
+
}
|
2019
2016
|
|
2020
|
-
|
2021
|
-
|
2022
|
-
|
2017
|
+
for (let i = 0; i < args.length; i++) {
|
2018
|
+
const arg = args[i];
|
2019
|
+
out = out.concat(generate(scope, arg));
|
2023
2020
|
|
2024
|
-
|
2025
|
-
|
2026
|
-
|
2027
|
-
|
2028
|
-
|
2029
|
-
|
2021
|
+
if (valtypeBinary !== Valtype.i32 && (
|
2022
|
+
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
|
2023
|
+
(importedFuncs[name] && name.startsWith('profile'))
|
2024
|
+
)) {
|
2025
|
+
out.push(Opcodes.i32_to);
|
2026
|
+
}
|
2030
2027
|
|
2031
|
-
|
2028
|
+
out = out.concat(getNodeType(scope, arg));
|
2032
2029
|
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
2030
|
+
if (indirectMode === 'vararg') {
|
2031
|
+
const typeLocal = localTmp(scope, `#indirect_arg${i}_type`, Valtype.i32);
|
2032
|
+
const valLocal = localTmp(scope, `#indirect_arg${i}_val`);
|
2036
2033
|
|
2037
|
-
|
2034
|
+
locals.push([valLocal, typeLocal]);
|
2038
2035
|
|
2039
|
-
|
2040
|
-
|
2041
|
-
|
2042
|
-
|
2043
|
-
}
|
2036
|
+
out.push(
|
2037
|
+
[ Opcodes.local_set, typeLocal ],
|
2038
|
+
[ Opcodes.local_set, valLocal ]
|
2039
|
+
);
|
2044
2040
|
}
|
2041
|
+
}
|
2042
|
+
|
2043
|
+
if (indirectMode === 'strict') {
|
2044
|
+
return [
|
2045
|
+
...generate(scope, decl.callee),
|
2046
|
+
[ Opcodes.local_set, localTmp(scope, '#indirect_callee') ],
|
2045
2047
|
|
2046
|
-
|
2047
|
-
return typeSwitch(scope, getNodeType(scope, decl.callee), {
|
2048
|
+
...typeSwitch(scope, getNodeType(scope, decl.callee), {
|
2048
2049
|
[TYPES.function]: [
|
2049
2050
|
...out,
|
2050
|
-
|
2051
|
+
|
2052
|
+
[ Opcodes.local_get, localTmp(scope, '#indirect_callee') ],
|
2053
|
+
...generate(scope, decl.callee),
|
2051
2054
|
Opcodes.i32_to_u,
|
2052
2055
|
[ Opcodes.call_indirect, args.length, 0 ],
|
2053
2056
|
...setLastType(scope)
|
2054
2057
|
],
|
2055
2058
|
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
2056
|
-
})
|
2059
|
+
})
|
2060
|
+
];
|
2061
|
+
}
|
2062
|
+
|
2063
|
+
// hi, I will now explain how vararg mode works:
|
2064
|
+
// wasm's indirect_call instruction requires you know the func type at compile-time
|
2065
|
+
// since we have varargs (variable argument count), we do not know it.
|
2066
|
+
// we could just store args in memory and not use wasm func args,
|
2067
|
+
// but that is slow (probably) and breaks js exports.
|
2068
|
+
// instead, we generate every* possibility of argc and use different indirect_call
|
2069
|
+
// ops for each one, with type depending on argc for that branch.
|
2070
|
+
// then we load the argc for the wanted function from a memory lut,
|
2071
|
+
// and call the branch with the matching argc we require.
|
2072
|
+
// sorry, yes it is very cursed (and size inefficient), but indirect calls
|
2073
|
+
// are kind of rare anyway (mostly callbacks) so I am not concerned atm.
|
2074
|
+
// *for argc 0-3, in future (todo:) the max number should be
|
2075
|
+
// dynamically changed to the max argc of any func in the js file.
|
2076
|
+
|
2077
|
+
const funcLocal = localTmp(scope, '#indirect_func', Valtype.i32);
|
2078
|
+
const flags = localTmp(scope, '#indirect_flags', Valtype.i32);
|
2079
|
+
|
2080
|
+
const gen = argc => {
|
2081
|
+
const argsOut = [];
|
2082
|
+
for (let i = 0; i < argc; i++) {
|
2083
|
+
argsOut.push(
|
2084
|
+
[ Opcodes.local_get, locals[i][0] ],
|
2085
|
+
[ Opcodes.local_get, locals[i][1] ]
|
2086
|
+
);
|
2057
2087
|
}
|
2058
2088
|
|
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
|
-
}
|
2089
|
+
const checkFlag = (flag, pass, fail) => [
|
2090
|
+
[ Opcodes.local_get, flags ],
|
2091
|
+
...number(flag, Valtype.i32),
|
2092
|
+
[ Opcodes.i32_and ],
|
2093
|
+
[ Opcodes.if, valtypeBinary ],
|
2094
|
+
...pass,
|
2095
|
+
[ Opcodes.else ],
|
2096
|
+
...fail,
|
2097
|
+
[ Opcodes.end ]
|
2098
|
+
];
|
2084
2099
|
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2089
|
-
|
2090
|
-
|
2091
|
-
|
2092
|
-
|
2093
|
-
|
2094
|
-
|
2100
|
+
// pain.
|
2101
|
+
// return checkFlag(0b10, [ // constr
|
2102
|
+
// [ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2103
|
+
// ...argsOut,
|
2104
|
+
// [ Opcodes.local_get, funcLocal ],
|
2105
|
+
// [ Opcodes.call_indirect, argc, 0, 'constr' ],
|
2106
|
+
// ...setLastType(scope),
|
2107
|
+
// ], [
|
2108
|
+
// ...argsOut,
|
2109
|
+
// [ Opcodes.local_get, funcLocal ],
|
2110
|
+
// [ Opcodes.call_indirect, argc, 0 ],
|
2111
|
+
// ...setLastType(scope),
|
2112
|
+
// ]);
|
2113
|
+
|
2114
|
+
return checkFlag(0b1, // no type return
|
2115
|
+
checkFlag(0b10, [ // no type return & constr
|
2116
|
+
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2117
|
+
...argsOut,
|
2118
|
+
[ Opcodes.local_get, funcLocal ],
|
2119
|
+
[ Opcodes.call_indirect, argc, 0, 'no_type_return', 'constr' ],
|
2120
|
+
], [
|
2121
|
+
...argsOut,
|
2122
|
+
[ Opcodes.local_get, funcLocal ],
|
2123
|
+
[ Opcodes.call_indirect, argc, 0, 'no_type_return' ]
|
2124
|
+
]),
|
2125
|
+
checkFlag(0b10, [ // type return & constr
|
2126
|
+
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2127
|
+
...argsOut,
|
2128
|
+
[ Opcodes.local_get, funcLocal ],
|
2129
|
+
[ Opcodes.call_indirect, argc, 0, 'constr' ],
|
2130
|
+
...setLastType(scope),
|
2131
|
+
], [
|
2132
|
+
...argsOut,
|
2133
|
+
[ Opcodes.local_get, funcLocal ],
|
2134
|
+
[ Opcodes.call_indirect, argc, 0 ],
|
2135
|
+
...setLastType(scope),
|
2136
|
+
]),
|
2137
|
+
);
|
2138
|
+
};
|
2095
2139
|
|
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
|
-
};
|
2140
|
+
const tableBc = {};
|
2141
|
+
for (let i = 0; i <= args.length; i++) {
|
2142
|
+
tableBc[i] = gen(i);
|
2143
|
+
}
|
2135
2144
|
|
2136
|
-
|
2137
|
-
for (let i = 0; i <= args.length; i++) {
|
2138
|
-
tableBc[i] = gen(i);
|
2139
|
-
}
|
2145
|
+
// todo/perf: check if we should use br_table here or just generate our own big if..elses
|
2140
2146
|
|
2141
|
-
|
2147
|
+
return [
|
2148
|
+
...generate(scope, decl.callee),
|
2149
|
+
[ Opcodes.local_set, localTmp(scope, '#indirect_callee') ],
|
2142
2150
|
|
2143
|
-
|
2151
|
+
...typeSwitch(scope, getNodeType(scope, decl.callee), {
|
2144
2152
|
[TYPES.function]: [
|
2145
2153
|
...out,
|
2146
2154
|
|
2147
|
-
[
|
2155
|
+
[ Opcodes.local_get, localTmp(scope, '#indirect_callee') ],
|
2148
2156
|
Opcodes.i32_to_u,
|
2149
2157
|
[ Opcodes.local_set, funcLocal ],
|
2150
2158
|
|
@@ -2177,10 +2185,8 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2177
2185
|
], tableBc, valtypeBinary)
|
2178
2186
|
],
|
2179
2187
|
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);
|
2188
|
+
})
|
2189
|
+
];
|
2184
2190
|
}
|
2185
2191
|
|
2186
2192
|
const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
|
@@ -2296,6 +2302,8 @@ const codeToSanitizedStr = code => {
|
|
2296
2302
|
const sanitize = str => str.replace(/[^0-9a-zA-Z_]/g, _ => codeToSanitizedStr(_.charCodeAt(0)));
|
2297
2303
|
|
2298
2304
|
const unhackName = name => {
|
2305
|
+
if (!name) return name;
|
2306
|
+
|
2299
2307
|
if (name.startsWith('__')) return name.slice(2).replaceAll('_', '.');
|
2300
2308
|
return name;
|
2301
2309
|
};
|
@@ -2702,22 +2710,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2702
2710
|
const { type, name } = decl.left;
|
2703
2711
|
const [ local, isGlobal ] = lookupName(scope, name);
|
2704
2712
|
|
2705
|
-
if (isFuncType(decl.right.type)) {
|
2706
|
-
|
2707
|
-
|
2713
|
+
// if (isFuncType(decl.right.type)) {
|
2714
|
+
// // hack for a = function () { ... }
|
2715
|
+
// decl.right.id = { name };
|
2708
2716
|
|
2709
|
-
|
2717
|
+
// const func = generateFunc(scope, decl.right);
|
2710
2718
|
|
2711
|
-
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2719
|
+
// return [
|
2720
|
+
// ...number(func.index - importedFuncs.length),
|
2721
|
+
// ...(local != null ? [
|
2722
|
+
// [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2723
|
+
// [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
2716
2724
|
|
2717
|
-
|
2718
|
-
|
2719
|
-
|
2720
|
-
}
|
2725
|
+
// ...setType(scope, name, TYPES.function)
|
2726
|
+
// ] : [])
|
2727
|
+
// ];
|
2728
|
+
// }
|
2721
2729
|
|
2722
2730
|
const op = decl.operator.slice(0, -1) || '=';
|
2723
2731
|
|
@@ -2746,18 +2754,27 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2746
2754
|
}
|
2747
2755
|
|
2748
2756
|
// arr[i]
|
2749
|
-
if (decl.left.type === 'MemberExpression'
|
2757
|
+
if (decl.left.type === 'MemberExpression') {
|
2750
2758
|
const newValueTmp = localTmp(scope, '#member_setter_val_tmp');
|
2751
2759
|
const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
|
2752
2760
|
|
2761
|
+
const object = decl.left.object;
|
2762
|
+
const property = decl.left.computed ? decl.left.property : {
|
2763
|
+
type: 'Literal',
|
2764
|
+
value: decl.left.property.name
|
2765
|
+
};
|
2766
|
+
|
2767
|
+
includeBuiltin(scope, '__Map_prototype_get');
|
2768
|
+
includeBuiltin(scope, '__Map_prototype_set');
|
2769
|
+
|
2753
2770
|
return [
|
2754
2771
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2755
2772
|
[TYPES.array]: [
|
2756
|
-
...generate(scope,
|
2773
|
+
...generate(scope, object),
|
2757
2774
|
Opcodes.i32_to_u,
|
2758
2775
|
|
2759
2776
|
// get index as valtype
|
2760
|
-
...generate(scope,
|
2777
|
+
...generate(scope, property),
|
2761
2778
|
Opcodes.i32_to_u,
|
2762
2779
|
|
2763
2780
|
// turn into byte offset by * valtypeSize + 1
|
@@ -2781,6 +2798,34 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2781
2798
|
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
2782
2799
|
],
|
2783
2800
|
|
2801
|
+
[TYPES.object]: [
|
2802
|
+
...generate(scope, object),
|
2803
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, localTmp(scope, '#objset_object') ] ]),
|
2804
|
+
...getNodeType(scope, object),
|
2805
|
+
|
2806
|
+
...generate(scope, property),
|
2807
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, localTmp(scope, '#objset_property') ] ]),
|
2808
|
+
...getNodeType(scope, property),
|
2809
|
+
|
2810
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2811
|
+
[ Opcodes.local_get, localTmp(scope, '#objset_object') ],
|
2812
|
+
...getNodeType(scope, object),
|
2813
|
+
|
2814
|
+
[ Opcodes.local_get, localTmp(scope, '#objset_property') ],
|
2815
|
+
...getNodeType(scope, property),
|
2816
|
+
|
2817
|
+
[ Opcodes.call, funcIndex.__Map_prototype_get ],
|
2818
|
+
...setLastType(scope)
|
2819
|
+
], generate(scope, decl.right), getLastType(scope), getNodeType(scope, decl.right), false, name, true)),
|
2820
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2821
|
+
...getNodeType(scope, decl),
|
2822
|
+
|
2823
|
+
[ Opcodes.call, funcIndex.__Map_prototype_set ],
|
2824
|
+
[ Opcodes.drop ],
|
2825
|
+
|
2826
|
+
...setLastType(scope, getNodeType(scope, decl)),
|
2827
|
+
],
|
2828
|
+
|
2784
2829
|
...wrapBC({
|
2785
2830
|
[TYPES.uint8array]: [
|
2786
2831
|
[ Opcodes.i32_add ],
|
@@ -2924,11 +2969,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2924
2969
|
],
|
2925
2970
|
}, {
|
2926
2971
|
prelude: [
|
2927
|
-
...generate(scope,
|
2972
|
+
...generate(scope, object),
|
2928
2973
|
Opcodes.i32_to_u,
|
2929
2974
|
[ Opcodes.i32_load, 0, 4 ],
|
2930
2975
|
|
2931
|
-
...generate(scope,
|
2976
|
+
...generate(scope, property),
|
2932
2977
|
Opcodes.i32_to_u,
|
2933
2978
|
],
|
2934
2979
|
postlude: setLastType(scope, TYPES.number)
|
@@ -2957,7 +3002,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2957
3002
|
// set global and return (eg a = 2)
|
2958
3003
|
return [
|
2959
3004
|
...generateVar(scope, { kind: 'var', _bare: true, declarations: [ { id: { name }, init: decl.right } ] }),
|
2960
|
-
|
3005
|
+
...generate(scope, decl.left)
|
2961
3006
|
];
|
2962
3007
|
}
|
2963
3008
|
|
@@ -4193,12 +4238,50 @@ const generateArray = (scope, decl, global = false, name = '$undeclared', initEm
|
|
4193
4238
|
};
|
4194
4239
|
|
4195
4240
|
const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
4196
|
-
|
4241
|
+
includeBuiltin(scope, 'Map');
|
4242
|
+
includeBuiltin(scope, '__Map_prototype_set');
|
4197
4243
|
|
4198
|
-
|
4199
|
-
|
4200
|
-
|
4244
|
+
// todo: optimize const objects
|
4245
|
+
const tmp = localTmp(scope, `#objectexpr${randId()}`);
|
4246
|
+
const out = [
|
4247
|
+
...generateCall(scope, {
|
4248
|
+
callee: {
|
4249
|
+
type: 'Identifier',
|
4250
|
+
name: 'Map'
|
4251
|
+
},
|
4252
|
+
arguments: [],
|
4253
|
+
_new: true
|
4254
|
+
}),
|
4255
|
+
[ Opcodes.local_tee, tmp ]
|
4201
4256
|
];
|
4257
|
+
|
4258
|
+
for (const x of decl.properties) {
|
4259
|
+
const { method, shorthand, computed, kind, key, value } = x;
|
4260
|
+
if (kind !== 'init') return todo(scope, 'complex objects are not supported yet', true);
|
4261
|
+
|
4262
|
+
const k = computed ? key : {
|
4263
|
+
type: 'Literal',
|
4264
|
+
value: key.name
|
4265
|
+
};
|
4266
|
+
|
4267
|
+
out.push(
|
4268
|
+
[ Opcodes.local_get, tmp ],
|
4269
|
+
...number(TYPES.map, Valtype.i32),
|
4270
|
+
|
4271
|
+
...generate(scope, k),
|
4272
|
+
...getNodeType(scope, k),
|
4273
|
+
|
4274
|
+
...generate(scope, value),
|
4275
|
+
...getNodeType(scope, value),
|
4276
|
+
|
4277
|
+
[ Opcodes.call, funcIndex.__Map_prototype_set ],
|
4278
|
+
|
4279
|
+
[ Opcodes.drop ],
|
4280
|
+
[ Opcodes.drop ]
|
4281
|
+
);
|
4282
|
+
}
|
4283
|
+
|
4284
|
+
return out;
|
4202
4285
|
};
|
4203
4286
|
|
4204
4287
|
const withType = (scope, wasm, type) => [
|
@@ -4323,14 +4406,19 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4323
4406
|
}, valtypeBinary);
|
4324
4407
|
}
|
4325
4408
|
|
4326
|
-
const object =
|
4327
|
-
const
|
4409
|
+
const object = decl.object;
|
4410
|
+
const objectWasm = generate(scope, object);
|
4411
|
+
const property = decl.computed ? decl.property : {
|
4412
|
+
type: 'Literal',
|
4413
|
+
value: decl.property.name
|
4414
|
+
};
|
4415
|
+
const propertyWasm = generate(scope, property);
|
4328
4416
|
|
4329
4417
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
4330
4418
|
// hack: this is naughty and will break things!
|
4331
4419
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
4332
4420
|
|
4333
|
-
const known = knownType(scope, getNodeType(scope,
|
4421
|
+
const known = knownType(scope, getNodeType(scope, object));
|
4334
4422
|
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
4335
4423
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
4336
4424
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
@@ -4338,11 +4426,14 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4338
4426
|
}, _global, _name, true, 'i16', true);
|
4339
4427
|
}
|
4340
4428
|
|
4341
|
-
|
4429
|
+
includeBuiltin(scope, '__Map_prototype_get');
|
4430
|
+
|
4431
|
+
return typeSwitch(scope, getNodeType(scope, object), {
|
4342
4432
|
[TYPES.array]: [
|
4343
|
-
...loadArray(scope,
|
4433
|
+
...loadArray(scope, objectWasm, propertyWasm),
|
4344
4434
|
...setLastType(scope)
|
4345
4435
|
],
|
4436
|
+
|
4346
4437
|
[TYPES.string]: [
|
4347
4438
|
// setup new/out array
|
4348
4439
|
...newOut,
|
@@ -4354,13 +4445,13 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4354
4445
|
// use as pointer for store later
|
4355
4446
|
...newPointer,
|
4356
4447
|
|
4357
|
-
...
|
4448
|
+
...propertyWasm,
|
4358
4449
|
Opcodes.i32_to_u,
|
4359
4450
|
|
4360
4451
|
...number(ValtypeSize.i16, Valtype.i32),
|
4361
4452
|
[ Opcodes.i32_mul ],
|
4362
4453
|
|
4363
|
-
...
|
4454
|
+
...objectWasm,
|
4364
4455
|
Opcodes.i32_to_u,
|
4365
4456
|
[ Opcodes.i32_add ],
|
4366
4457
|
|
@@ -4375,6 +4466,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4375
4466
|
Opcodes.i32_from_u,
|
4376
4467
|
...setLastType(scope, TYPES.string)
|
4377
4468
|
],
|
4469
|
+
|
4378
4470
|
[TYPES.bytestring]: [
|
4379
4471
|
// setup new/out array
|
4380
4472
|
...newOut,
|
@@ -4386,10 +4478,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4386
4478
|
// use as pointer for store later
|
4387
4479
|
...newPointer,
|
4388
4480
|
|
4389
|
-
...
|
4481
|
+
...propertyWasm,
|
4390
4482
|
Opcodes.i32_to_u,
|
4391
4483
|
|
4392
|
-
...
|
4484
|
+
...objectWasm,
|
4393
4485
|
Opcodes.i32_to_u,
|
4394
4486
|
[ Opcodes.i32_add ],
|
4395
4487
|
|
@@ -4405,6 +4497,17 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4405
4497
|
...setLastType(scope, TYPES.bytestring)
|
4406
4498
|
],
|
4407
4499
|
|
4500
|
+
[TYPES.object]: [
|
4501
|
+
...objectWasm,
|
4502
|
+
...getNodeType(scope, object),
|
4503
|
+
|
4504
|
+
...propertyWasm,
|
4505
|
+
...getNodeType(scope, property),
|
4506
|
+
|
4507
|
+
[ Opcodes.call, funcIndex.__Map_prototype_get ],
|
4508
|
+
...setLastType(scope)
|
4509
|
+
],
|
4510
|
+
|
4408
4511
|
...wrapBC({
|
4409
4512
|
[TYPES.uint8array]: [
|
4410
4513
|
[ Opcodes.i32_add ],
|
@@ -4473,22 +4576,23 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4473
4576
|
],
|
4474
4577
|
}, {
|
4475
4578
|
prelude: [
|
4476
|
-
...
|
4579
|
+
...objectWasm,
|
4477
4580
|
Opcodes.i32_to_u,
|
4478
4581
|
[ Opcodes.i32_load, 0, 4 ],
|
4479
4582
|
|
4480
|
-
...
|
4583
|
+
...propertyWasm,
|
4481
4584
|
Opcodes.i32_to_u
|
4482
4585
|
],
|
4483
4586
|
postlude: setLastType(scope, TYPES.number)
|
4484
4587
|
}),
|
4485
4588
|
|
4486
|
-
default: internalThrow(scope, 'TypeError', '
|
4589
|
+
default: internalThrow(scope, 'TypeError', 'Unsupported member expression object', true)
|
4487
4590
|
});
|
4488
4591
|
};
|
4489
4592
|
|
4490
4593
|
const randId = () => Math.random().toString(16).slice(1, -2).padEnd(12, '0');
|
4491
4594
|
|
4595
|
+
let objectHackers = [];
|
4492
4596
|
const objectHack = node => {
|
4493
4597
|
if (!node) return node;
|
4494
4598
|
|
@@ -4503,16 +4607,10 @@ const objectHack = node => {
|
|
4503
4607
|
if (objectName && ['undefined', 'null', 'NaN', 'Infinity'].includes(objectName)) return;
|
4504
4608
|
|
4505
4609
|
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);
|
4610
|
+
if (!objectName || (!objectHackers.includes(objectName) && !objectHackers.some(x => objectName.startsWith(`${x}_`)))) {
|
4510
4611
|
return;
|
4511
4612
|
}
|
4512
4613
|
|
4513
|
-
// no object name, give up
|
4514
|
-
if (!objectName) return;
|
4515
|
-
|
4516
4614
|
const name = '__' + objectName + '_' + node.property.name;
|
4517
4615
|
if (Prefs.codeLog) log('codegen', `object hack! ${node.object.name}.${node.property.name} -> ${name}`);
|
4518
4616
|
|
@@ -4861,6 +4959,9 @@ export default program => {
|
|
4861
4959
|
prototypeFuncs = new PrototypeFuncs();
|
4862
4960
|
allocator = makeAllocator(Prefs.allocator ?? 'static');
|
4863
4961
|
|
4962
|
+
const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
|
4963
|
+
objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
|
4964
|
+
|
4864
4965
|
program.id = { name: 'main' };
|
4865
4966
|
|
4866
4967
|
const scope = {
|
@@ -4004,22 +4004,22 @@ export const BuiltinFuncs = function() {
|
|
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 => {
|