porffor 0.58.18 → 0.58.19
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/AGENT.md +13 -0
- package/compiler/builtins/array.ts +48 -0
- package/compiler/builtins/regexp.ts +14 -7
- package/compiler/builtins/string.ts +75 -12
- package/compiler/builtins/string_f64.ts +19 -0
- package/compiler/builtins_precompiled.js +589 -541
- package/compiler/codegen.js +5 -96
- package/compiler/precompile.js +1 -1
- package/package.json +1 -1
- package/runtime/index.js +1 -1
- package/wow.js +1 -0
- package/compiler/prototype.js +0 -407
package/compiler/codegen.js
CHANGED
@@ -2,7 +2,6 @@ import { Blocktype, Opcodes, Valtype, ValtypeSize } from './wasmSpec.js';
|
|
2
2
|
import { number, ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector, read_signedLEB128 } from './encoding.js';
|
3
3
|
import { operatorOpcode } from './expression.js';
|
4
4
|
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
|
5
|
-
import { PrototypeFuncs } from './prototype.js';
|
6
5
|
import { TYPES, TYPE_FLAGS, TYPE_NAMES } from './types.js';
|
7
6
|
import parse from './parse.js';
|
8
7
|
import { log } from './log.js';
|
@@ -556,7 +555,7 @@ const lookup = (scope, name, failEarly = false) => {
|
|
556
555
|
includeBuiltin(scope, name);
|
557
556
|
}
|
558
557
|
|
559
|
-
if (
|
558
|
+
if (Object.hasOwn(internalConstrs, name)) {
|
560
559
|
// todo: return an actual something
|
561
560
|
return [ number(1) ];
|
562
561
|
}
|
@@ -1520,13 +1519,6 @@ const includeBuiltin = (scope, builtin) => {
|
|
1520
1519
|
const generateLogicExp = (scope, decl) =>
|
1521
1520
|
performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right));
|
1522
1521
|
|
1523
|
-
const isExistingProtoFunc = name => {
|
1524
|
-
if (name.startsWith('__Array_prototype')) return Object.hasOwn(prototypeFuncs[TYPES.array], name.slice(18));
|
1525
|
-
if (name.startsWith('__String_prototype_')) return Object.hasOwn(prototypeFuncs[TYPES.string], name.slice(19));
|
1526
|
-
|
1527
|
-
return false;
|
1528
|
-
};
|
1529
|
-
|
1530
1522
|
const getInferred = (scope, name, global = false) => {
|
1531
1523
|
if (global) {
|
1532
1524
|
if (globalInfer.has(name) && inferLoopPrev.length === 0) return globalInfer.get(name);
|
@@ -1595,7 +1587,7 @@ const getType = (scope, name, failEarly = false) => {
|
|
1595
1587
|
[ global ? Opcodes.global_get : Opcodes.local_get, typeLocal.idx ]
|
1596
1588
|
];
|
1597
1589
|
|
1598
|
-
if (hasFuncWithName(name)
|
1590
|
+
if (hasFuncWithName(name)) {
|
1599
1591
|
return [ number(TYPES.function, Valtype.i32) ];
|
1600
1592
|
}
|
1601
1593
|
|
@@ -2294,9 +2286,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2294
2286
|
});
|
2295
2287
|
}
|
2296
2288
|
|
2297
|
-
const protoBC = {};
|
2298
2289
|
const builtinProtoCands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + protoName));
|
2299
|
-
|
2300
2290
|
if (!decl._protoInternalCall && builtinProtoCands.length > 0) {
|
2301
2291
|
out.push(
|
2302
2292
|
...generate(scope, target),
|
@@ -2315,6 +2305,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2315
2305
|
);
|
2316
2306
|
}
|
2317
2307
|
|
2308
|
+
const protoBC = {};
|
2318
2309
|
for (const x of builtinProtoCands) {
|
2319
2310
|
const name = x.split('_prototype_')[0].toLowerCase();
|
2320
2311
|
const type = TYPES[name.slice(2)] ?? TYPES[name];
|
@@ -2338,88 +2329,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2338
2329
|
_protoInternalCall: true
|
2339
2330
|
});
|
2340
2331
|
}
|
2341
|
-
}
|
2342
|
-
|
2343
|
-
const protoCands = Object.keys(prototypeFuncs).reduce((acc, x) => {
|
2344
|
-
if (Object.hasOwn(prototypeFuncs[x], protoName)) acc[x] = prototypeFuncs[x][protoName];
|
2345
|
-
return acc;
|
2346
|
-
}, {});
|
2347
|
-
|
2348
|
-
if (Object.keys(protoCands).length > 0) {
|
2349
|
-
// use local for cached i32 length as commonly used
|
2350
|
-
const lengthLocal = localTmp(scope, '__proto_length_cache', Valtype.i32);
|
2351
|
-
const pointerLocal = localTmp(scope, '__proto_pointer_cache', Valtype.i32);
|
2352
|
-
|
2353
|
-
if (out.length === 0) {
|
2354
|
-
out.push(
|
2355
|
-
...generate(scope, target),
|
2356
|
-
Opcodes.i32_to_u,
|
2357
|
-
[ Opcodes.local_set, pointerLocal ]
|
2358
|
-
);
|
2359
|
-
} else {
|
2360
|
-
out.push(
|
2361
|
-
[ Opcodes.local_get, localTmp(scope, '#proto_target') ],
|
2362
|
-
Opcodes.i32_to_u,
|
2363
|
-
[ Opcodes.local_set, pointerLocal ]
|
2364
|
-
);
|
2365
|
-
}
|
2366
|
-
|
2367
|
-
for (const x in protoCands) {
|
2368
|
-
const protoFunc = protoCands[x];
|
2369
|
-
const getPointer = [ [ Opcodes.local_get, pointerLocal ] ];
|
2370
|
-
|
2371
|
-
if (protoFunc.noArgRetLength && decl.arguments.length === 0) {
|
2372
|
-
protoBC[x] = [
|
2373
|
-
...ArrayUtil.getLength(getPointer),
|
2374
|
-
...setLastType(scope, TYPES.number)
|
2375
|
-
];
|
2376
|
-
continue;
|
2377
|
-
}
|
2378
|
-
|
2379
|
-
protoBC[x] = () => {
|
2380
|
-
const protoLocal = protoFunc.local ? localTmp(scope, `__${protoName}_tmp`, protoFunc.local) : -1;
|
2381
|
-
const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${protoName}_tmp2`, protoFunc.local2) : -1;
|
2382
|
-
|
2383
|
-
let optUnused = false;
|
2384
|
-
const protoOut = protoFunc({
|
2385
|
-
pointer: getPointer,
|
2386
|
-
length: {
|
2387
|
-
getCachedI32: () => [ [ Opcodes.local_get, lengthLocal ] ],
|
2388
|
-
setCachedI32: () => [ [ Opcodes.local_set, lengthLocal ] ],
|
2389
|
-
get: () => ArrayUtil.getLength(getPointer),
|
2390
|
-
getI32: () => ArrayUtil.getLengthI32(getPointer),
|
2391
|
-
set: value => ArrayUtil.setLength(getPointer, value),
|
2392
|
-
setI32: value => ArrayUtil.setLengthI32(getPointer, value)
|
2393
|
-
},
|
2394
|
-
arg: generate(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
|
2395
|
-
argType: getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
|
2396
|
-
iTmp: protoLocal,
|
2397
|
-
iTmp2: protoLocal2,
|
2398
|
-
alloc: bytes => [
|
2399
|
-
number(bytes, Valtype.i32),
|
2400
|
-
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ]
|
2401
|
-
],
|
2402
|
-
unusedValue: () => {
|
2403
|
-
optUnused = true;
|
2404
|
-
return unusedValue;
|
2405
|
-
},
|
2406
|
-
setType: type => setLastType(scope, type)
|
2407
|
-
});
|
2408
|
-
|
2409
|
-
return [
|
2410
|
-
...ArrayUtil.getLengthI32(getPointer),
|
2411
|
-
[ Opcodes.local_set, lengthLocal ],
|
2412
|
-
|
2413
|
-
[ Opcodes.block, unusedValue && optUnused ? Blocktype.void : valtypeBinary ],
|
2414
|
-
...protoOut,
|
2415
|
-
[ Opcodes.end ],
|
2416
|
-
...(unusedValue && optUnused ? [ number(UNDEFINED) ] : [])
|
2417
|
-
];
|
2418
|
-
};
|
2419
|
-
}
|
2420
|
-
}
|
2421
2332
|
|
2422
|
-
if (Object.keys(protoBC).length > 0) {
|
2423
2333
|
protoBC.default = decl.optional ?
|
2424
2334
|
withType(scope, [ number(UNDEFINED) ], TYPES.undefined) :
|
2425
2335
|
internalThrow(scope, 'TypeError', `'${protoName}' proto func tried to be called on a type without an impl`, true);
|
@@ -6717,7 +6627,7 @@ const objectHack = node => {
|
|
6717
6627
|
if (objectName !== 'Object_prototype' && (node.property.name === 'propertyIsEnumerable' || node.property.name === 'hasOwnProperty' || node.property.name === 'isPrototypeOf')) return abortOut;
|
6718
6628
|
|
6719
6629
|
const name = '__' + objectName + '_' + node.property.name;
|
6720
|
-
if ((!hasFuncWithName(name) && !Object.hasOwn(builtinVars, name) && !
|
6630
|
+
if ((!hasFuncWithName(name) && !Object.hasOwn(builtinVars, name) && !hasFuncWithName(name + '$get')) && (hasFuncWithName(objectName) || Object.hasOwn(builtinVars, objectName) || hasFuncWithName('__' + objectName) || Object.hasOwn(builtinVars, '__' + objectName))) return abortOut;
|
6721
6631
|
|
6722
6632
|
if (Prefs.codeLog) log('codegen', `object hack! ${node.object.name}.${node.property.name} -> ${name}`);
|
6723
6633
|
|
@@ -7294,7 +7204,7 @@ const internalConstrs = {
|
|
7294
7204
|
}
|
7295
7205
|
};
|
7296
7206
|
|
7297
|
-
let globals, tags, exceptions, funcs, indirectFuncs, funcIndex, currentFuncIndex, depth, pages, data, typeswitchDepth, usedTypes, coctc, globalInfer, builtinFuncs, builtinVars,
|
7207
|
+
let globals, tags, exceptions, funcs, indirectFuncs, funcIndex, currentFuncIndex, depth, pages, data, typeswitchDepth, usedTypes, coctc, globalInfer, builtinFuncs, builtinVars, lastValtype;
|
7298
7208
|
export default program => {
|
7299
7209
|
globals = { ['#ind']: 0 };
|
7300
7210
|
tags = [];
|
@@ -7333,7 +7243,6 @@ export default program => {
|
|
7333
7243
|
lastValtype = valtypeBinary;
|
7334
7244
|
builtinFuncs = new BuiltinFuncs();
|
7335
7245
|
builtinVars = new BuiltinVars({ builtinFuncs });
|
7336
|
-
prototypeFuncs = new PrototypeFuncs();
|
7337
7246
|
|
7338
7247
|
const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
|
7339
7248
|
objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
|
package/compiler/precompile.js
CHANGED
@@ -57,7 +57,7 @@ const compile = async (file, _funcs) => {
|
|
57
57
|
first = source.slice(0, source.indexOf('\n'));
|
58
58
|
}
|
59
59
|
|
60
|
-
let args = ['--module', '--todo-time=compile', '--truthy=no_nan_negative', '--no-rm-unused-types', '--scoped-page-names', '--
|
60
|
+
let args = ['--module', '--todo-time=compile', '--truthy=no_nan_negative', '--no-rm-unused-types', '--scoped-page-names', '--fast-length', '--parse-types', '--opt-types', '--no-passive-data', '--active-data', '--no-treeshake-wasm-imports', '--no-coctc'];
|
61
61
|
if (first.startsWith('// @porf')) {
|
62
62
|
args = first.slice('// @porf '.length).split(' ').concat(args);
|
63
63
|
}
|
package/package.json
CHANGED
package/runtime/index.js
CHANGED
package/wow.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
(false ? 42 : 42) + (false ? null : 'G9vBsCA4GzkqlZN')
|
package/compiler/prototype.js
DELETED
@@ -1,407 +0,0 @@
|
|
1
|
-
import { Opcodes, Blocktype, Valtype, ValtypeSize } from './wasmSpec.js';
|
2
|
-
import { number } from './encoding.js';
|
3
|
-
import { UNDEFINED } from './builtins.js';
|
4
|
-
import { TYPES } from './types.js';
|
5
|
-
import './prefs.js';
|
6
|
-
|
7
|
-
// todo: turn these into built-ins once arrays and these become less hacky
|
8
|
-
|
9
|
-
export const PrototypeFuncs = function() {
|
10
|
-
const noUnlikelyChecks = Prefs.funsafeNoUnlikelyProtoChecks;
|
11
|
-
|
12
|
-
let zeroChecks;
|
13
|
-
if (Prefs.zeroChecks) zeroChecks = Prefs.zeroChecks.split(',').reduce((acc, x) => { acc[x.toLowerCase()] = true; return acc; }, {});
|
14
|
-
else zeroChecks = {};
|
15
|
-
|
16
|
-
this[TYPES.array] = {
|
17
|
-
pop: ({ pointer, length, iTmp, unusedValue, setType }) => [
|
18
|
-
// if length == 0, noop
|
19
|
-
...length.getCachedI32(),
|
20
|
-
[ Opcodes.i32_eqz ],
|
21
|
-
[ Opcodes.if, Blocktype.void ],
|
22
|
-
...(unusedValue() ? [] : [
|
23
|
-
number(UNDEFINED),
|
24
|
-
...setType(TYPES.undefined)
|
25
|
-
]),
|
26
|
-
[ Opcodes.br, 1 ],
|
27
|
-
[ Opcodes.end ],
|
28
|
-
|
29
|
-
// todo: should we store 0/undefined in "removed" element?
|
30
|
-
|
31
|
-
// decrement length by 1
|
32
|
-
...length.setI32([
|
33
|
-
...length.getCachedI32(),
|
34
|
-
number(1, Valtype.i32),
|
35
|
-
[ Opcodes.i32_sub ],
|
36
|
-
|
37
|
-
...(unusedValue() ? [] : [
|
38
|
-
...length.setCachedI32(),
|
39
|
-
...length.getCachedI32(),
|
40
|
-
])
|
41
|
-
]),
|
42
|
-
|
43
|
-
// load last element
|
44
|
-
...(unusedValue() ? [] : [
|
45
|
-
...length.getCachedI32(),
|
46
|
-
number(ValtypeSize[valtype] + 1, Valtype.i32),
|
47
|
-
[ Opcodes.i32_mul ],
|
48
|
-
|
49
|
-
...pointer,
|
50
|
-
[ Opcodes.i32_add ],
|
51
|
-
[ Opcodes.local_set, iTmp ],
|
52
|
-
|
53
|
-
[ Opcodes.local_get, iTmp ],
|
54
|
-
[ Opcodes.load, 0, ValtypeSize.i32 ],
|
55
|
-
|
56
|
-
[ Opcodes.local_get, iTmp ],
|
57
|
-
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
58
|
-
...setType()
|
59
|
-
])
|
60
|
-
],
|
61
|
-
|
62
|
-
shift: ({ pointer, length, setType }) => [
|
63
|
-
// if length == 0, noop
|
64
|
-
...length.getCachedI32(),
|
65
|
-
[ Opcodes.i32_eqz ],
|
66
|
-
[ Opcodes.if, Blocktype.void ],
|
67
|
-
number(UNDEFINED),
|
68
|
-
...setType(TYPES.undefined),
|
69
|
-
[ Opcodes.br, 1 ],
|
70
|
-
[ Opcodes.end ],
|
71
|
-
|
72
|
-
// todo: should we store 0/undefined in "removed" element?
|
73
|
-
|
74
|
-
// decrement length by 1
|
75
|
-
...length.setI32([
|
76
|
-
...length.getCachedI32(),
|
77
|
-
number(1, Valtype.i32),
|
78
|
-
[ Opcodes.i32_sub ],
|
79
|
-
|
80
|
-
...length.setCachedI32(),
|
81
|
-
...length.getCachedI32(),
|
82
|
-
]),
|
83
|
-
|
84
|
-
// load first element
|
85
|
-
// todo/perf: unusedValue opt
|
86
|
-
...pointer,
|
87
|
-
[ Opcodes.load, 0, ValtypeSize.i32 ],
|
88
|
-
|
89
|
-
...pointer,
|
90
|
-
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
91
|
-
...setType(),
|
92
|
-
|
93
|
-
// offset page by -1 ind
|
94
|
-
// number(pointer + ValtypeSize.i32, Valtype.i32), // dst = base array index + length size
|
95
|
-
// number(pointer + ValtypeSize.i32 + ValtypeSize[valtype], Valtype.i32), // src = base array index + length size + an index
|
96
|
-
// number(pageSize - ValtypeSize.i32 - ValtypeSize[valtype], Valtype.i32), // size = PageSize - length size - an index
|
97
|
-
// [ ...Opcodes.memory_copy, 0x00, 0x00 ]
|
98
|
-
|
99
|
-
// offset all elements by -1 ind
|
100
|
-
|
101
|
-
// dst = base array index + length size
|
102
|
-
number(ValtypeSize.i32, Valtype.i32),
|
103
|
-
...pointer,
|
104
|
-
[ Opcodes.i32_add ],
|
105
|
-
|
106
|
-
// src = base array index + length size + an index
|
107
|
-
number(ValtypeSize.i32 + ValtypeSize[valtype] + 1, Valtype.i32),
|
108
|
-
...pointer,
|
109
|
-
[ Opcodes.i32_add ],
|
110
|
-
|
111
|
-
// size = new length * sizeof element
|
112
|
-
...length.getCachedI32(),
|
113
|
-
number(ValtypeSize[valtype] + 1, Valtype.i32),
|
114
|
-
[ Opcodes.i32_mul ],
|
115
|
-
[ ...Opcodes.memory_copy, 0x00, 0x00 ]
|
116
|
-
|
117
|
-
// move pointer + sizeof element
|
118
|
-
// ...pointer.get(),
|
119
|
-
// number(ValtypeSize[valtype], Valtype.i32),
|
120
|
-
// [ Opcodes.i32_add ],
|
121
|
-
// ...pointer.set(),
|
122
|
-
|
123
|
-
// // write length - 1 in new address
|
124
|
-
// ...length.setI32([
|
125
|
-
// ...length.getCachedI32(),
|
126
|
-
// number(1, Valtype.i32),
|
127
|
-
// [ Opcodes.i32_sub ]
|
128
|
-
// ]),
|
129
|
-
]
|
130
|
-
};
|
131
|
-
|
132
|
-
this[TYPES.array].pop.local = Valtype.i32;
|
133
|
-
|
134
|
-
this[TYPES.string] = {
|
135
|
-
at: ({ pointer, length, arg, iTmp, iTmp2, alloc, setType }) => [
|
136
|
-
// setup out string and use pointer for store
|
137
|
-
...alloc(8),
|
138
|
-
[ Opcodes.local_tee, iTmp2 ],
|
139
|
-
|
140
|
-
// out.length = 1
|
141
|
-
[ Opcodes.local_get, iTmp2 ],
|
142
|
-
number(1, Valtype.i32),
|
143
|
-
[ Opcodes.i32_store, 0, 0 ],
|
144
|
-
|
145
|
-
...arg,
|
146
|
-
Opcodes.i32_to_u,
|
147
|
-
[ Opcodes.local_tee, iTmp ],
|
148
|
-
|
149
|
-
// if index < 0: access index + array length
|
150
|
-
number(0, Valtype.i32),
|
151
|
-
[ Opcodes.i32_lt_s ],
|
152
|
-
[ Opcodes.if, Blocktype.void ],
|
153
|
-
[ Opcodes.local_get, iTmp ],
|
154
|
-
...length.getCachedI32(),
|
155
|
-
[ Opcodes.i32_add ],
|
156
|
-
[ Opcodes.local_set, iTmp ],
|
157
|
-
[ Opcodes.end ],
|
158
|
-
|
159
|
-
// if still < 0 or >= length: return undefined
|
160
|
-
[ Opcodes.local_get, iTmp ],
|
161
|
-
number(0, Valtype.i32),
|
162
|
-
[ Opcodes.i32_lt_s ],
|
163
|
-
|
164
|
-
[ Opcodes.local_get, iTmp ],
|
165
|
-
...length.getCachedI32(),
|
166
|
-
[ Opcodes.i32_ge_s ],
|
167
|
-
[ Opcodes.i32_or ],
|
168
|
-
|
169
|
-
[ Opcodes.if, Blocktype.void ],
|
170
|
-
number(UNDEFINED),
|
171
|
-
...setType(TYPES.undefined),
|
172
|
-
[ Opcodes.br, 1 ],
|
173
|
-
[ Opcodes.end ],
|
174
|
-
|
175
|
-
[ Opcodes.local_get, iTmp ],
|
176
|
-
number(ValtypeSize.i16, Valtype.i32),
|
177
|
-
[ Opcodes.i32_mul ],
|
178
|
-
|
179
|
-
...pointer,
|
180
|
-
[ Opcodes.i32_add ],
|
181
|
-
|
182
|
-
// load current string ind {arg}
|
183
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
184
|
-
|
185
|
-
// store to new string ind 0
|
186
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
187
|
-
|
188
|
-
// return new string (pointer)
|
189
|
-
[ Opcodes.local_get, iTmp2 ],
|
190
|
-
Opcodes.i32_from_u,
|
191
|
-
|
192
|
-
...setType(TYPES.string)
|
193
|
-
],
|
194
|
-
|
195
|
-
// todo: out of bounds properly
|
196
|
-
charAt: ({ pointer, arg, iTmp, alloc, setType }) => [
|
197
|
-
// setup out string and use as pointer for store
|
198
|
-
...alloc(8),
|
199
|
-
[ Opcodes.local_tee, iTmp ],
|
200
|
-
|
201
|
-
// out.length = 1
|
202
|
-
[ Opcodes.local_get, iTmp ],
|
203
|
-
number(1, Valtype.i32),
|
204
|
-
[ Opcodes.i32_store, 0, 0 ],
|
205
|
-
|
206
|
-
...arg,
|
207
|
-
Opcodes.i32_to,
|
208
|
-
|
209
|
-
number(ValtypeSize.i16, Valtype.i32),
|
210
|
-
[ Opcodes.i32_mul ],
|
211
|
-
|
212
|
-
...pointer,
|
213
|
-
[ Opcodes.i32_add ],
|
214
|
-
|
215
|
-
// load current string ind {arg}
|
216
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
217
|
-
|
218
|
-
// store to new string ind 0
|
219
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
220
|
-
|
221
|
-
// return new string (page)
|
222
|
-
[ Opcodes.local_get, iTmp ],
|
223
|
-
Opcodes.i32_from_u,
|
224
|
-
|
225
|
-
...setType(TYPES.string)
|
226
|
-
],
|
227
|
-
|
228
|
-
charCodeAt: ({ pointer, length, arg, iTmp, setType }) => [
|
229
|
-
...setType(TYPES.number),
|
230
|
-
|
231
|
-
...arg,
|
232
|
-
Opcodes.i32_to,
|
233
|
-
|
234
|
-
...(zeroChecks.charcodeat ? [] : [
|
235
|
-
[ Opcodes.local_set, iTmp ],
|
236
|
-
|
237
|
-
// index < 0
|
238
|
-
...(noUnlikelyChecks ? [] : [
|
239
|
-
[ Opcodes.local_get, iTmp ],
|
240
|
-
number(0, Valtype.i32),
|
241
|
-
[ Opcodes.i32_lt_s ],
|
242
|
-
]),
|
243
|
-
|
244
|
-
// index >= length
|
245
|
-
[ Opcodes.local_get, iTmp ],
|
246
|
-
...length.getCachedI32(),
|
247
|
-
[ Opcodes.i32_ge_s ],
|
248
|
-
|
249
|
-
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
250
|
-
[ Opcodes.if, Blocktype.void ],
|
251
|
-
number(valtype === 'i32' ? -1 : NaN),
|
252
|
-
[ Opcodes.br, 1 ],
|
253
|
-
[ Opcodes.end ],
|
254
|
-
|
255
|
-
[ Opcodes.local_get, iTmp ],
|
256
|
-
]),
|
257
|
-
|
258
|
-
number(ValtypeSize.i16, Valtype.i32),
|
259
|
-
[ Opcodes.i32_mul ],
|
260
|
-
|
261
|
-
...pointer,
|
262
|
-
[ Opcodes.i32_add ],
|
263
|
-
|
264
|
-
// load current string ind {arg}
|
265
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
266
|
-
Opcodes.i32_from_u
|
267
|
-
]
|
268
|
-
};
|
269
|
-
|
270
|
-
this[TYPES.string].at.local = Valtype.i32;
|
271
|
-
this[TYPES.string].at.local2 = Valtype.i32;
|
272
|
-
this[TYPES.string].charAt.local = Valtype.i32;
|
273
|
-
this[TYPES.string].charCodeAt.local = Valtype.i32;
|
274
|
-
|
275
|
-
this[TYPES.bytestring] = {
|
276
|
-
at: ({ pointer, length, arg, iTmp, iTmp2, alloc, setType }) => [
|
277
|
-
// setup out string and use pointer for store
|
278
|
-
...alloc(8),
|
279
|
-
[ Opcodes.local_tee, iTmp2 ],
|
280
|
-
|
281
|
-
// out.length = 1
|
282
|
-
[ Opcodes.local_get, iTmp2 ],
|
283
|
-
number(1, Valtype.i32),
|
284
|
-
[ Opcodes.i32_store, 0, 0 ],
|
285
|
-
|
286
|
-
...arg,
|
287
|
-
Opcodes.i32_to_u,
|
288
|
-
[ Opcodes.local_tee, iTmp ],
|
289
|
-
|
290
|
-
// if index < 0: access index + array length
|
291
|
-
number(0, Valtype.i32),
|
292
|
-
[ Opcodes.i32_lt_s ],
|
293
|
-
[ Opcodes.if, Blocktype.void ],
|
294
|
-
[ Opcodes.local_get, iTmp ],
|
295
|
-
...length.getCachedI32(),
|
296
|
-
[ Opcodes.i32_add ],
|
297
|
-
[ Opcodes.local_set, iTmp ],
|
298
|
-
[ Opcodes.end ],
|
299
|
-
|
300
|
-
// if still < 0 or >= length: return undefined
|
301
|
-
[ Opcodes.local_get, iTmp ],
|
302
|
-
number(0, Valtype.i32),
|
303
|
-
[ Opcodes.i32_lt_s ],
|
304
|
-
|
305
|
-
[ Opcodes.local_get, iTmp ],
|
306
|
-
...length.getCachedI32(),
|
307
|
-
[ Opcodes.i32_ge_s ],
|
308
|
-
[ Opcodes.i32_or ],
|
309
|
-
|
310
|
-
[ Opcodes.if, Blocktype.void ],
|
311
|
-
number(UNDEFINED),
|
312
|
-
...setType(TYPES.undefined),
|
313
|
-
[ Opcodes.br, 1 ],
|
314
|
-
[ Opcodes.end ],
|
315
|
-
|
316
|
-
[ Opcodes.local_get, iTmp ],
|
317
|
-
|
318
|
-
...pointer,
|
319
|
-
[ Opcodes.i32_add ],
|
320
|
-
|
321
|
-
// load current string ind {arg}
|
322
|
-
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
323
|
-
|
324
|
-
// store to new string ind 0
|
325
|
-
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
326
|
-
|
327
|
-
// return new string (pointer)
|
328
|
-
[ Opcodes.local_get, iTmp2 ],
|
329
|
-
Opcodes.i32_from_u,
|
330
|
-
|
331
|
-
...setType(TYPES.bytestring)
|
332
|
-
],
|
333
|
-
|
334
|
-
// todo: out of bounds properly
|
335
|
-
charAt: ({ pointer, arg, iTmp, alloc, setType }) => [
|
336
|
-
// setup out string and use as pointer for store
|
337
|
-
...alloc(8),
|
338
|
-
[ Opcodes.local_tee, iTmp ],
|
339
|
-
|
340
|
-
// out.length = 1
|
341
|
-
[ Opcodes.local_get, iTmp ],
|
342
|
-
number(1, Valtype.i32),
|
343
|
-
[ Opcodes.i32_store, 0, 0 ],
|
344
|
-
|
345
|
-
...arg,
|
346
|
-
Opcodes.i32_to,
|
347
|
-
|
348
|
-
...pointer,
|
349
|
-
[ Opcodes.i32_add ],
|
350
|
-
|
351
|
-
// load current string ind {arg}
|
352
|
-
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
353
|
-
|
354
|
-
// store to new string ind 0
|
355
|
-
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
356
|
-
|
357
|
-
// return new string (page)
|
358
|
-
[ Opcodes.local_get, iTmp ],
|
359
|
-
Opcodes.i32_from_u,
|
360
|
-
|
361
|
-
...setType(TYPES.bytestring)
|
362
|
-
],
|
363
|
-
|
364
|
-
charCodeAt: ({ pointer, length, arg, iTmp, setType }) => [
|
365
|
-
...setType(TYPES.number),
|
366
|
-
|
367
|
-
...arg,
|
368
|
-
Opcodes.i32_to,
|
369
|
-
|
370
|
-
...(zeroChecks.charcodeat ? [] : [
|
371
|
-
[ Opcodes.local_set, iTmp ],
|
372
|
-
|
373
|
-
// index < 0
|
374
|
-
...(noUnlikelyChecks ? [] : [
|
375
|
-
[ Opcodes.local_get, iTmp ],
|
376
|
-
number(0, Valtype.i32),
|
377
|
-
[ Opcodes.i32_lt_s ],
|
378
|
-
]),
|
379
|
-
|
380
|
-
// index >= length
|
381
|
-
[ Opcodes.local_get, iTmp ],
|
382
|
-
...length.getCachedI32(),
|
383
|
-
[ Opcodes.i32_ge_s ],
|
384
|
-
|
385
|
-
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
386
|
-
[ Opcodes.if, Blocktype.void ],
|
387
|
-
number(valtype === 'i32' ? -1 : NaN),
|
388
|
-
[ Opcodes.br, 1 ],
|
389
|
-
[ Opcodes.end ],
|
390
|
-
|
391
|
-
[ Opcodes.local_get, iTmp ],
|
392
|
-
]),
|
393
|
-
|
394
|
-
...pointer,
|
395
|
-
[ Opcodes.i32_add ],
|
396
|
-
|
397
|
-
// load current string ind {arg}
|
398
|
-
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
399
|
-
Opcodes.i32_from_u
|
400
|
-
]
|
401
|
-
};
|
402
|
-
|
403
|
-
this[TYPES.bytestring].at.local = Valtype.i32;
|
404
|
-
this[TYPES.bytestring].at.local2 = Valtype.i32;
|
405
|
-
this[TYPES.bytestring].charAt.local = Valtype.i32;
|
406
|
-
this[TYPES.bytestring].charCodeAt.local = Valtype.i32;
|
407
|
-
};
|