porffor 0.16.0-b099006b8 → 0.16.0-c4cdb5460
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/CONTRIBUTING.md +1 -1
- package/compiler/2c.js +67 -7
- package/compiler/allocators.js +128 -0
- package/compiler/assemble.js +7 -1
- package/compiler/builtins/array.ts +3 -4
- package/compiler/builtins/date.ts +2 -5
- package/compiler/builtins/set.ts +2 -5
- package/compiler/codegen.js +253 -300
- package/compiler/cyclone.js +11 -11
- package/compiler/generated_builtins.js +46 -46
- package/compiler/index.js +15 -1
- package/compiler/opt.js +7 -5
- package/compiler/parse.js +1 -7
- package/compiler/pgo.js +13 -8
- package/compiler/precompile.js +12 -7
- package/compiler/prefs.js +2 -3
- package/compiler/prototype.js +34 -43
- package/compiler/wasmSpec.js +2 -2
- package/compiler/wrap.js +3 -2
- package/package.json +3 -5
- package/runner/index.js +13 -3
- package/no_pgo.txt +0 -923
- package/pgo.txt +0 -916
package/CONTRIBUTING.md
CHANGED
@@ -26,7 +26,7 @@ You can also swap out `node` in the alias to use another runtime like Deno (`den
|
|
26
26
|
|
27
27
|
### Precompile
|
28
28
|
|
29
|
-
**If you update any file inside `compiler/builtins` you will need to do this for it to update inside Porffor otherwise your changes will have no effect.** Run
|
29
|
+
**If you update any file inside `compiler/builtins` you will need to do this for it to update inside Porffor otherwise your changes will have no effect.** Run `./porf precompile` to precompile. It may error during this, if so, you might have an error in your code or there could be a compiler error with Porffor (feel free to ask for help as soon as you encounter any errors with it).
|
30
30
|
|
31
31
|
<br>
|
32
32
|
|
package/compiler/2c.js
CHANGED
@@ -2,6 +2,7 @@ import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from '.
|
|
2
2
|
import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
|
3
3
|
import { operatorOpcode } from './expression.js';
|
4
4
|
import { log } from './log.js';
|
5
|
+
import Prefs from './prefs.js';
|
5
6
|
|
6
7
|
const CValtype = {
|
7
8
|
i8: 'i8',
|
@@ -33,11 +34,11 @@ struct ReturnValue {
|
|
33
34
|
i32 type;
|
34
35
|
};\n\n`;
|
35
36
|
|
36
|
-
// todo:
|
37
|
+
// todo: review whether 2cMemcpy should be default or not
|
37
38
|
|
38
39
|
// all:
|
39
40
|
// immediates: ['align', 'offset']
|
40
|
-
const CMemFuncs = {
|
41
|
+
const CMemFuncs = Prefs['2cMemcpy'] ? {
|
41
42
|
[Opcodes.i32_store]: {
|
42
43
|
c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
|
43
44
|
args: ['pointer', 'value'],
|
@@ -96,6 +97,57 @@ return out;`,
|
|
96
97
|
argTypes: ['i32'],
|
97
98
|
returns: 'f64'
|
98
99
|
},
|
100
|
+
} : {
|
101
|
+
[Opcodes.i32_store]: {
|
102
|
+
c: `*((i32*)(_memory + offset + pointer)) = value;`,
|
103
|
+
args: ['pointer', 'value'],
|
104
|
+
argTypes: ['i32', 'i32'],
|
105
|
+
returns: false
|
106
|
+
},
|
107
|
+
[Opcodes.i32_store16]: {
|
108
|
+
c: `*((i16*)(_memory + offset + pointer)) = value;`,
|
109
|
+
args: ['pointer', 'value'],
|
110
|
+
argTypes: ['i32', 'i16'],
|
111
|
+
returns: false
|
112
|
+
},
|
113
|
+
[Opcodes.i32_store8]: {
|
114
|
+
c: `*((i8*)(_memory + offset + pointer)) = value;`,
|
115
|
+
args: ['pointer', 'value'],
|
116
|
+
argTypes: ['i32', 'i8'],
|
117
|
+
returns: false
|
118
|
+
},
|
119
|
+
|
120
|
+
[Opcodes.i32_load]: {
|
121
|
+
c: `return *((i32*)(_memory + offset + pointer));`,
|
122
|
+
args: ['pointer'],
|
123
|
+
argTypes: ['i32'],
|
124
|
+
returns: 'i32'
|
125
|
+
},
|
126
|
+
[Opcodes.i32_load16_u]: {
|
127
|
+
c: `return *((u16*)(_memory + offset + pointer));`,
|
128
|
+
args: ['pointer'],
|
129
|
+
argTypes: ['i32'],
|
130
|
+
returns: 'i32'
|
131
|
+
},
|
132
|
+
[Opcodes.i32_load8_u]: {
|
133
|
+
c: `return *((i8*)(_memory + offset + pointer));`,
|
134
|
+
args: ['pointer'],
|
135
|
+
argTypes: ['i32'],
|
136
|
+
returns: 'i32'
|
137
|
+
},
|
138
|
+
|
139
|
+
[Opcodes.f64_store]: {
|
140
|
+
c: `*((f64*)(_memory + offset + pointer)) = value;`,
|
141
|
+
args: ['pointer', 'value'],
|
142
|
+
argTypes: ['i32', 'f64'],
|
143
|
+
returns: false
|
144
|
+
},
|
145
|
+
[Opcodes.f64_load]: {
|
146
|
+
c: `return *((f64*)(_memory + offset + pointer));`,
|
147
|
+
args: ['pointer'],
|
148
|
+
argTypes: ['i32'],
|
149
|
+
returns: 'f64'
|
150
|
+
},
|
99
151
|
};
|
100
152
|
|
101
153
|
const inv = (obj, keyMap = x => x) => Object.keys(obj).reduce((acc, x) => { acc[keyMap(obj[x])] = x; return acc; }, {});
|
@@ -152,11 +204,16 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
152
204
|
|
153
205
|
if (pages.size > 0) {
|
154
206
|
prepend.set('_memory', `char _memory[${pages.size * pageSize}];\n`);
|
155
|
-
includes.set('string.h', true);
|
207
|
+
if (Prefs['2cMemcpy']) includes.set('string.h', true);
|
156
208
|
}
|
157
209
|
|
158
210
|
if (data.length > 0) {
|
159
|
-
|
211
|
+
if (Prefs['2cMemcpy']) {
|
212
|
+
prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n '));
|
213
|
+
includes.set('string.h', true);
|
214
|
+
} else {
|
215
|
+
prependMain.set('_data', data.map(x => x.bytes.reduce((acc, y, i) => acc + `_memory[${x.offset + i}]=(i8)${y};`, '')).join('\n '));
|
216
|
+
}
|
160
217
|
}
|
161
218
|
|
162
219
|
if (importFuncs.find(x => x.name === '__Porffor_readArgv')) {
|
@@ -362,7 +419,10 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
362
419
|
|
363
420
|
case Opcodes.return:
|
364
421
|
// line(`return${returns ? ` ${removeBrackets(vals.pop())}` : ''}`);
|
365
|
-
|
422
|
+
const b = vals.pop();
|
423
|
+
const a = vals.pop();
|
424
|
+
line(`return${returns ? ` (struct ReturnValue){ ${removeBrackets(a)}, ${removeBrackets(b)} }` : ''}`);
|
425
|
+
// line(`return${returns ? ` (struct ReturnValue){ ${removeBrackets(vals.pop())}, ${removeBrackets(vals.pop())} }` : ''}`);
|
366
426
|
break;
|
367
427
|
|
368
428
|
case Opcodes.if: {
|
@@ -474,7 +534,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
|
|
474
534
|
out[read++] = ch;
|
475
535
|
}
|
476
536
|
|
477
|
-
|
537
|
+
*((i32*)(_memory + outPtr)) = (i32)read;
|
478
538
|
return read;
|
479
539
|
}`);
|
480
540
|
|
@@ -504,7 +564,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
|
|
504
564
|
|
505
565
|
fclose(fp);
|
506
566
|
|
507
|
-
|
567
|
+
*((i32*)(_memory + outPtr)) = (i32)read;
|
508
568
|
return read;
|
509
569
|
}`);
|
510
570
|
const outPtr = vals.pop();
|
@@ -0,0 +1,128 @@
|
|
1
|
+
import { Opcodes, PageSize, Valtype } from './wasmSpec.js';
|
2
|
+
import { number } from './embedding.js';
|
3
|
+
import Prefs from './prefs.js';
|
4
|
+
|
5
|
+
// we currently have 3 allocators:
|
6
|
+
// - static (default): a static/compile-time allocator. fast (no grow/run-time alloc needed) but can break some code
|
7
|
+
// - grow: perform a memory.grow every allocation. simple but maybe slow?
|
8
|
+
// - chunk: perform large memory.grow's in chunks when needed. needs investigation
|
9
|
+
|
10
|
+
export default name => {
|
11
|
+
switch (name) {
|
12
|
+
case 'static': return new StaticAllocator();
|
13
|
+
case 'grow': return new GrowAllocator();
|
14
|
+
case 'chunk': return new ChunkAllocator();
|
15
|
+
default: throw new Error(`unknown allocator: ${name}`);
|
16
|
+
}
|
17
|
+
};
|
18
|
+
|
19
|
+
export class StaticAllocator {
|
20
|
+
constructor() {
|
21
|
+
}
|
22
|
+
|
23
|
+
allocType(itemType) {
|
24
|
+
switch (itemType) {
|
25
|
+
case 'i8': return 'bytestring';
|
26
|
+
case 'i16': return 'string';
|
27
|
+
|
28
|
+
default: return 'array';
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
ptr(ind) {
|
33
|
+
if (ind === 0) return 4;
|
34
|
+
return ind * PageSize;
|
35
|
+
}
|
36
|
+
|
37
|
+
alloc({ scope, pages }, name, { itemType }) {
|
38
|
+
const reason = `${this.allocType(itemType)}: ${Prefs.scopedPageNames ? (scope.name + '/') : ''}${name}`;
|
39
|
+
|
40
|
+
if (pages.has(reason)) return number(this.ptr(pages.get(reason).ind), Valtype.i32);
|
41
|
+
|
42
|
+
if (reason.startsWith('array:')) pages.hasArray = true;
|
43
|
+
if (reason.startsWith('string:')) pages.hasString = true;
|
44
|
+
if (reason.startsWith('bytestring:')) pages.hasByteString = true;
|
45
|
+
if (reason.includes('string:')) pages.hasAnyString = true;
|
46
|
+
|
47
|
+
let ind = pages.size;
|
48
|
+
pages.set(reason, { ind, type: itemType });
|
49
|
+
|
50
|
+
scope.pages ??= new Map();
|
51
|
+
scope.pages.set(reason, { ind, type: itemType });
|
52
|
+
|
53
|
+
return number(this.ptr(ind), Valtype.i32);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
export class GrowAllocator {
|
58
|
+
constructor() {
|
59
|
+
Prefs.rmUnusedTypes = false;
|
60
|
+
}
|
61
|
+
|
62
|
+
alloc() {
|
63
|
+
return [
|
64
|
+
// grow by 1 page
|
65
|
+
[ Opcodes.i32_const, 1 ],
|
66
|
+
[ Opcodes.memory_grow, 0 ], // returns old page count
|
67
|
+
|
68
|
+
// get ptr (page count * page size)
|
69
|
+
number(65536, Valtype.i32)[0],
|
70
|
+
[ Opcodes.i32_mul ]
|
71
|
+
];
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
export class ChunkAllocator {
|
76
|
+
constructor(chunkSize) {
|
77
|
+
Prefs.rmUnusedTypes = false;
|
78
|
+
|
79
|
+
// 64KiB * chunk size each growth
|
80
|
+
// 16: 1MiB chunks
|
81
|
+
this.chunkSize = chunkSize ?? Prefs.chunkAllocatorSize ?? 16;
|
82
|
+
}
|
83
|
+
|
84
|
+
alloc({ asmFunc, funcIndex }) {
|
85
|
+
const func = funcIndex['#chunkallocator_alloc'] ?? asmFunc('#chunkallocator_alloc', {
|
86
|
+
wasm: [
|
87
|
+
[ Opcodes.global_get, 0 ],
|
88
|
+
[ Opcodes.global_get, 1 ],
|
89
|
+
[ Opcodes.i32_ge_s ],
|
90
|
+
[ Opcodes.if, Valtype.i32 ], // ptr >= next
|
91
|
+
// grow by chunk size pages
|
92
|
+
[ Opcodes.i32_const, this.chunkSize ],
|
93
|
+
[ Opcodes.memory_grow, 0 ],
|
94
|
+
|
95
|
+
// ptr = prev memory size * PageSize
|
96
|
+
number(65536, Valtype.i32)[0],
|
97
|
+
[ Opcodes.i32_mul ],
|
98
|
+
[ Opcodes.global_set, 0 ],
|
99
|
+
|
100
|
+
// next = ptr + ((chunkSize - 1) * PageSize)
|
101
|
+
[ Opcodes.global_get, 0 ],
|
102
|
+
number(65536 * (this.chunkSize - 1), Valtype.i32)[0],
|
103
|
+
[ Opcodes.i32_add ],
|
104
|
+
[ Opcodes.global_set, 1 ],
|
105
|
+
|
106
|
+
// return ptr
|
107
|
+
[ Opcodes.global_get, 0 ],
|
108
|
+
[ Opcodes.else ],
|
109
|
+
// return ptr = ptr + PageSize
|
110
|
+
[ Opcodes.global_get, 0 ],
|
111
|
+
number(65536, Valtype.i32)[0],
|
112
|
+
[ Opcodes.i32_add ],
|
113
|
+
[ Opcodes.global_set, 0 ],
|
114
|
+
[ Opcodes.global_get, 0 ],
|
115
|
+
[ Opcodes.end ],
|
116
|
+
],
|
117
|
+
params: [],
|
118
|
+
locals: [],
|
119
|
+
globals: [ Valtype.i32, Valtype.i32 ],
|
120
|
+
globalNames: ['#chunkallocator_ptr', '#chunkallocator_next'],
|
121
|
+
returns: [ Valtype.i32 ],
|
122
|
+
}).index;
|
123
|
+
|
124
|
+
return [
|
125
|
+
[ Opcodes.call, func ]
|
126
|
+
];
|
127
|
+
}
|
128
|
+
}
|
package/compiler/assemble.js
CHANGED
@@ -240,7 +240,13 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
240
240
|
|
241
241
|
const dataSection = data.length === 0 ? [] : createSection(
|
242
242
|
Section.data,
|
243
|
-
encodeVector(data.map(x =>
|
243
|
+
encodeVector(data.map(x => {
|
244
|
+
// type: active
|
245
|
+
if (x.offset != null) return [ 0x00, Opcodes.i32_const, ...signedLEB128(x.offset), Opcodes.end, ...encodeVector(x.bytes) ];
|
246
|
+
|
247
|
+
// type: passive
|
248
|
+
return [ 0x01, ...encodeVector(x.bytes) ];
|
249
|
+
}))
|
244
250
|
);
|
245
251
|
|
246
252
|
const dataCountSection = data.length === 0 ? [] : createSection(
|
@@ -171,12 +171,11 @@ export const __Array_prototype_filter = (_this: any[], callbackFn: any) => {
|
|
171
171
|
};
|
172
172
|
|
173
173
|
export const __Array_prototype_map = (_this: any[], callbackFn: any) => {
|
174
|
-
const out: any[] = [];
|
175
|
-
|
176
|
-
const len: i32 = _this.length;
|
177
174
|
let i: i32 = 0;
|
175
|
+
const len: i32 = _this.length;
|
176
|
+
const out: any[] = new Array(len);
|
178
177
|
while (i < len) {
|
179
|
-
out
|
178
|
+
out[i] = callbackFn(_this[i], i++, _this);
|
180
179
|
}
|
181
180
|
|
182
181
|
return out;
|
@@ -722,12 +722,9 @@ export const __Porffor_date_allocate = (): Date => {
|
|
722
722
|
const hack: bytestring = '';
|
723
723
|
|
724
724
|
if (hack.length == 0) {
|
725
|
-
hack.length = Porffor.wasm`
|
726
|
-
memory.grow 0
|
727
|
-
drop
|
728
|
-
memory.size 0
|
725
|
+
hack.length = Porffor.wasm`
|
729
726
|
i32.const 1
|
730
|
-
|
727
|
+
memory.grow 0
|
731
728
|
i32.const 65536
|
732
729
|
i32.mul
|
733
730
|
i32.from_u`;
|
package/compiler/builtins/set.ts
CHANGED
@@ -2,12 +2,9 @@ import type {} from './porffor.d.ts';
|
|
2
2
|
|
3
3
|
// dark wasm magic for dealing with memory, sorry.
|
4
4
|
export const __Porffor_allocate = (): number => {
|
5
|
-
Porffor.wasm`
|
6
|
-
memory.grow 0
|
7
|
-
drop
|
8
|
-
memory.size 0
|
5
|
+
Porffor.wasm`
|
9
6
|
i32.const 1
|
10
|
-
|
7
|
+
memory.grow 0
|
11
8
|
i32.const 65536
|
12
9
|
i32.mul
|
13
10
|
i32.from_u
|