Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory improvements + Type analysis #56

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ce5a503
codegen: optimize string allocation
BobVarioa Jun 1, 2024
7d55544
codegen: fix minor string bugs
BobVarioa Jun 2, 2024
73bf981
codegen: improve string initialization code size
BobVarioa Jun 2, 2024
96b289f
codegen: revert i64 string writing
BobVarioa Jun 2, 2024
5a2ae98
codegen: allow multiple pages for strings
BobVarioa Jun 2, 2024
48fb0f1
codegen: convert constant strings to string buffers
BobVarioa Jun 3, 2024
8601a01
codegen: replace concat strings with function implementation
BobVarioa Jun 3, 2024
479ef95
codegen: un-asm String.concat
BobVarioa Jun 3, 2024
4044d85
allocators: actually allow multiple pages for strings
BobVarioa Jun 3, 2024
571a551
builtins/ecma262: remove unnecessary string buffer
BobVarioa Jun 3, 2024
dcd334b
builtins: seperate internal functions into a seperate file
BobVarioa Jun 4, 2024
042eb94
builtins: replace Porffor.s/bs with actual allocations
BobVarioa Jun 4, 2024
ba07507
builtins: rewrite some builtins to allocate memory on the fly
BobVarioa Jun 4, 2024
501ebaf
builtins/date: cleanup Porffor internal methods
BobVarioa Jun 4, 2024
b8983bb
codegen: reenable js type analysis
BobVarioa Jun 4, 2024
3b3eb2f
builtins: rename porffor.ts to utils.ts
BobVarioa Jun 4, 2024
32a8281
codegen: move string initialization to the beginning of a program
BobVarioa Jun 4, 2024
570c49c
builtins: eliminate some unnecessary locals
BobVarioa Jun 4, 2024
9359bb9
builtins/string: properly cast argument of includes to string
BobVarioa Jun 4, 2024
b18279a
codegen: fix strings added at precompilation
BobVarioa Jun 5, 2024
1f76666
builtins/string: fix string.concat
BobVarioa Jun 5, 2024
bb3c2b7
builtins: fix some types
BobVarioa Jun 5, 2024
aed8528
builtins/string: rewrite string.trim
BobVarioa Jun 5, 2024
d60527e
builtins/symbol: rewrite symbols to not use a page
BobVarioa Jun 5, 2024
b44e299
builtins/utils: rewrite string methods to avoid looping
BobVarioa Jun 5, 2024
67c63a5
codegen: overhaul js type analysis
BobVarioa Jun 5, 2024
0017d35
chore: merge from main
BobVarioa Jun 5, 2024
76e2dca
allocators: use map.has, not a falsy check
BobVarioa Jun 6, 2024
5c504e2
builtins/string: convert compare strings into a builtin
BobVarioa Jun 6, 2024
f7bc3c6
builtins/array: allocate -> allocatePage
BobVarioa Jun 6, 2024
f8586e1
builtins/string: fix charcode for nan values
BobVarioa Jun 6, 2024
3089e7d
codegen/types: fix typo in prototype return type checking
BobVarioa Jun 6, 2024
0004c8c
codegen: add Porffor.allocateNamedPage
BobVarioa Jun 7, 2024
3f04959
builtins/symbol: fix symbol implementation
BobVarioa Jun 7, 2024
6e6ebf2
builtins/string: revert change to string constructor
BobVarioa Jun 7, 2024
3e1a432
builtins/symbol: fix typo
BobVarioa Jun 7, 2024
3da07f4
codegen: fix nonbytestring strings
BobVarioa Jun 7, 2024
7d97eb7
builtins/string: fix trim for strings
BobVarioa Jun 7, 2024
57437a6
codegen: remove makeStringBuffer
BobVarioa Jun 7, 2024
0f94882
chore: regenerate builtins
BobVarioa Jun 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions compiler/allocators.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export class StaticAllocator {

alloc({ scope, pages }, name, { itemType }) {
const reason = `${this.allocType(itemType)}: ${Prefs.scopedPageNames ? (scope.name + '/') : ''}${name}`;
if (Prefs.allocLog) console.log(reason)

if (pages.has(reason)) return number(this.ptr(pages.get(reason).ind), Valtype.i32);

Expand All @@ -52,6 +53,45 @@ export class StaticAllocator {

return number(this.ptr(ind), Valtype.i32);
}

stringPageIndex = 0;

allocString(pages, str, isBytestring) {
let page = { ind: -1, strs: [], strIndex: new Map(), byteSize: 0 }
let size = isBytestring ? 1 : 2;
pages.hasAnyString = true;
if (size == 1) pages.hasByteString = true;
else pages.hasString = true;

for (let i = 0; i < this.stringPageIndex; i++) {
if (pages.has(`strings${i}`)) {
const p = pages.get(`strings${i}`);
if (p.strIndex.has(str)) {
const index = p.strIndex.get(str);
if (Prefs.allocLog) console.log('cstr/ref: '+ str)
return [p.strs[index].ptr, true];
}
if ((p.byteSize + (4 + str.length * size)) < pageSize) {
page = p;
break;
}
}
}
if (page.ind == -1) {
const ind = pages.size;
page.ind = ind;
pages.set(`strings${this.stringPageIndex}`, page);
this.stringPageIndex++;
}

let ptr = this.ptr(page.ind) + page.byteSize;
page.byteSize += 4 + str.length * size; // u32 + u16[len] (or u8)
const index = page.strs.push({ str, ptr, size }) - 1;
page.strIndex.set(str, index);

if (Prefs.allocLog) console.log('cstr/init: '+ str)
return [ptr, false];
}
}

export class GrowAllocator {
Expand Down
50 changes: 50 additions & 0 deletions compiler/builtins.js
Original file line number Diff line number Diff line change
Expand Up @@ -1140,5 +1140,55 @@ export const BuiltinFuncs = function() {
]
};


this.__Porffor_allocateBytes = {
params: [ Valtype.i32 ],
locals: [],
globals: [ Valtype.i32, Valtype.i32 ],
globalNames: [ 'currentPtr', 'bytesWritten' ],
globalInits: [ 0, pageSize ],
returns: [ Valtype.i32 ],
wasm: [
// if bytesWritten + bytesToAllocate would be greater than pageSize,
[ Opcodes.global_get, 1 ],
[ Opcodes.local_get, 0 ],
[ Opcodes.i32_add ],
...number(pageSize, Valtype.i32),
[ Opcodes.i32_ge_s ],
[ Opcodes.if, Blocktype.void ],
// reset our bytes written
[ Opcodes.local_get, 0 ],
[ Opcodes.global_set, 1 ],

// get a new page
...number(1, Valtype.i32),
[ Opcodes.memory_grow, 0x00 ],
...number(pageSize, Valtype.i32),
[ Opcodes.i32_mul ],
// set currentPtr
[ Opcodes.global_set, 0 ],
[ Opcodes.global_get, 0 ],
[ Opcodes.return ],
[ Opcodes.end ],
// else,

// increment our bytes written
[ Opcodes.local_get, 0 ],
[ Opcodes.global_get, 1 ],
[ Opcodes.i32_add ],
[ Opcodes.global_set, 1 ],

// increment currentPtr
[ Opcodes.global_get, 0 ],
[ Opcodes.local_get, 0 ],
[ Opcodes.i32_add ],
[ Opcodes.global_set, 0 ],
[ Opcodes.global_get, 0 ],

// return currentPtr
[ Opcodes.return ]
]
}

GeneratedBuiltins.BuiltinFuncs.call(this);
};
61 changes: 14 additions & 47 deletions compiler/builtins/annexb_string.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,23 @@ export default () => {

const noArgs = (a0, a1) => out += `
export const __String_prototype_${a0} = (_this: string) => {
let out: string = Porffor.s\`<${a1}>\`;
CanadaHonk marked this conversation as resolved.
Show resolved Hide resolved

let outPtr: i32 = Porffor.wasm\`local.get \${out}\` + ${(2 + a1.length) * 2};

let thisPtr: i32 = Porffor.wasm\`local.get \${_this}\`;
let thisLen: i32 = _this.length;
let endPtr: i32 = thisPtr + thisLen * 2;

while (thisPtr < endPtr) {
let chr: i32 = Porffor.wasm.i32.load16_u(thisPtr, 0, 4);
Porffor.wasm.i32.store16(outPtr, chr, 0, 4);

thisPtr += 2;
outPtr += 2;
}

Porffor.wasm.i32.store16(outPtr, 60, 0, 4); // <
Porffor.wasm.i32.store16(outPtr, 47, 0, 6); // /

${[...a1].map((x, i) => ` Porffor.wasm.i32.store16(outPtr, ${x.charCodeAt(0)}, 0, ${8 + i * 2}); // ${x}`).join('\n')}

Porffor.wasm.i32.store16(outPtr, 62, 0, ${8 + a1.length * 2}); // >

out.length = thisLen + ${a1.length * 2 + 2 + 3};

const thisLen: i32 = _this.length;
const outLen: i32 = ${5 + 2*a1.length} + thisLen; // '<${a1}>'.length + '</${a1}>'.length + _this.length
let out = Porffor.allocateBytes<string>(4 + outLen*2);
__Porffor_string_spliceString(out, 0, '<${a1}>');
__Porffor_string_spliceString(out, ${(2 + a1.length) * 2}, _this); // '<${a1}>'.length
__Porffor_string_spliceString(out, ${(2 + a1.length) * 2} + thisLen*2, '</${a1}>'); // '<${a1}>'.length + _this.length
out.length = outLen;
return out;
};
export const __ByteString_prototype_${a0} = (_this: bytestring) => {
let out: bytestring = Porffor.bs\`<${a1}>\`;

let outPtr: i32 = Porffor.wasm\`local.get \${out}\` + ${2 + a1.length};

let thisPtr: i32 = Porffor.wasm\`local.get \${_this}\`;
let thisLen: i32 = _this.length;
let endPtr: i32 = thisPtr + thisLen;

while (thisPtr < endPtr) {
let chr: i32 = Porffor.wasm.i32.load8_u(thisPtr++, 0, 4);
Porffor.wasm.i32.store8(outPtr++, chr, 0, 4);
}

Porffor.wasm.i32.store8(outPtr, 60, 0, 4); // <
Porffor.wasm.i32.store8(outPtr, 47, 0, 5); // /

${[...a1].map((x, i) => ` Porffor.wasm.i32.store8(outPtr, ${x.charCodeAt(0)}, 0, ${6 + i}); // ${x}`).join('\n')}

Porffor.wasm.i32.store8(outPtr, 62, 0, ${6 + a1.length}); // >

out.length = thisLen + ${a1.length * 2 + 2 + 3};

const thisLen: i32 = _this.length;
const outLen: i32 = ${5 + 2*a1.length} + thisLen;
let out = Porffor.allocateBytes<bytestring>(4 + outLen); // '<${a1}>'.length + '</${a1}>'.length + _this.length
__Porffor_bytestring_spliceString(out, 0, '<${a1}>');
__Porffor_bytestring_spliceString(out, ${2 + a1.length}, _this); // '<${a1}>'.length
__Porffor_bytestring_spliceString(out, ${2 + a1.length} + thisLen, '</${a1}>'); // '<${a1}>'.length + _this.length
out.length = outLen;
return out;
};
`;
Expand Down
4 changes: 2 additions & 2 deletions compiler/builtins/annexb_string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const __String_prototype_trimLeft = (_this: string) => {
return __String_prototype_trimStart(_this);
};

export const __ByteString_prototype_trimLeft = (_this: string) => {
BobVarioa marked this conversation as resolved.
Show resolved Hide resolved
export const __ByteString_prototype_trimLeft = (_this: bytestring) => {
return __ByteString_prototype_trimStart(_this);
};

Expand All @@ -14,6 +14,6 @@ export const __String_prototype_trimRight = (_this: string) => {
return __String_prototype_trimEnd(_this);
};

export const __ByteString_prototype_trimRight = (_this: string) => {
export const __ByteString_prototype_trimRight = (_this: bytestring) => {
return __ByteString_prototype_trimEnd(_this);
};
20 changes: 10 additions & 10 deletions compiler/builtins/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const __Array_prototype_slice = (_this: any[], start: number, end: number
}
if (end > len) end = len;

let out: any[] = Porffor.allocate();
let out = Porffor.allocatePage<any[]>();

if (start > end) return out;

Expand Down Expand Up @@ -133,7 +133,7 @@ export const __Array_prototype_with = (_this: any[], index: number, value: any)
throw new RangeError('Invalid index');
}

let out: any[] = Porffor.allocate();
let out = Porffor.allocatePage<any[]>();

Porffor.clone(_this, out);

Expand Down Expand Up @@ -177,7 +177,7 @@ export const __Array_prototype_copyWithin = (_this: any[], target: number, start
// @porf-typed-array
export const __Array_prototype_concat = (_this: any[], ...vals: any[]) => {
// todo/perf: rewrite to use memory.copy (via some Porffor.array.append thing?)
let out: any[] = Porffor.allocate();
let out = Porffor.allocatePage<any[]>();
Porffor.clone(_this, out);

let len: i32 = _this.length;
Expand Down Expand Up @@ -221,7 +221,7 @@ export const __Array_prototype_toReversed = (_this: any[]) => {
let start: i32 = 0;
let end: i32 = len - 1;

let out: any[] = Porffor.allocate();
let out = Porffor.allocatePage<any[]>();
out.length = len;

while (start < end) {
Expand Down Expand Up @@ -249,7 +249,7 @@ export const __Array_prototype_forEach = (_this: any[], callbackFn: any) => {

// @porf-typed-array
export const __Array_prototype_filter = (_this: any[], callbackFn: any) => {
const out: any[] = Porffor.allocate();
const out = Porffor.allocatePage<any[]>();

const len: i32 = _this.length;
let i: i32 = 0;
Expand All @@ -266,7 +266,7 @@ export const __Array_prototype_filter = (_this: any[], callbackFn: any) => {
// @porf-typed-array
export const __Array_prototype_map = (_this: any[], callbackFn: any) => {
const len: i32 = _this.length;
const out: any[] = Porffor.allocate();
const out = Porffor.allocatePage<any[]>();
out.length = len;

let i: i32 = 0;
Expand Down Expand Up @@ -388,10 +388,10 @@ export const __Array_prototype_sort = (_this: any[], callbackFn: any) => {
else {
// 4. If comparefn is not undefined, then
// a. Let v be ? ToNumber(? Call(comparefn, undefined, « x, y »)).
v = callbackFn(x, y);
BobVarioa marked this conversation as resolved.
Show resolved Hide resolved
v = Number(callbackFn(x, y));

// b. If v is NaN, return +0𝔽.
// if (Number.isNaN(v)) v = 0;
if (Number.isNaN(v)) v = 0;

// c. Return v.
}
Expand All @@ -410,7 +410,7 @@ export const __Array_prototype_sort = (_this: any[], callbackFn: any) => {
export const __Array_prototype_toString = (_this: any[]) => {
// todo: this is bytestring only!

let out: bytestring = '';
let out = Porffor.allocatePage<bytestring>();
out.length = 0;

const len: i32 = _this.length;
Expand Down Expand Up @@ -441,7 +441,7 @@ export const __Array_prototype_join = (_this: any[], _separator: any) => {
if (Porffor.rawType(_separator) != Porffor.TYPES.undefined)
separator = ecma262.ToString(_separator);

let out: bytestring = '';
let out = Porffor.allocatePage<bytestring>();
out.length = 0;

const len: i32 = _this.length;
Expand Down
4 changes: 2 additions & 2 deletions compiler/builtins/base64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const btoa = (input: bytestring): bytestring => {
const keyStrPtr: i32 = Porffor.wasm`local.get ${keyStr}`;

let len: i32 = input.length;
let output: bytestring = '';
let output = Porffor.allocatePage<bytestring>();

let i: i32 = Porffor.wasm`local.get ${input}`,
j: i32 = Porffor.wasm`local.get ${output}`;
Expand Down Expand Up @@ -49,7 +49,7 @@ export const atob = (input: bytestring): bytestring => {
const lut: bytestring = '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>@@@?456789:;<=@@@@@@@\x00\x01\x02\x03\x04\x05\x06\x07\b\t\n\x0B\f\r\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19@@@@@@\x1A\x1B\x1C\x1D\x1E\x1F !"#$%&\'()*+,-./0123';
const lutPtr: i32 = Porffor.wasm`local.get ${lut}`;

let output: bytestring = '';
let output = Porffor.allocatePage<bytestring>();

let i: i32 = Porffor.wasm`local.get ${input}`,
j: i32 = Porffor.wasm`local.get ${output}`;
Expand Down
9 changes: 3 additions & 6 deletions compiler/builtins/boolean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ import type {} from './porffor.d.ts';
export const __Boolean_prototype_toString = (_this: boolean) => {
// 1. Let b be ? ThisBooleanValue(this value).
// 2. If b is true, return "true"; else return "false".
let out: bytestring = '';
if (_this) out = 'true';
else out = 'false';

return out;
};
if (_this) return 'true';
else return 'false';
}

// 20.3.3.3 Boolean.prototype.valueOf ()
// https://tc39.es/ecma262/#sec-boolean.prototype.valueof
Expand Down
3 changes: 1 addition & 2 deletions compiler/builtins/console.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type {} from './porffor.d.ts';

export const __console_clear = () => {
const clear: bytestring = '\x1b[1;1H\x1b[J';
Porffor.print(clear);
Porffor.print('\x1b[1;1H\x1b[J');
};
Loading