Skip to content

Commit

Permalink
codegen: handle nested scopes in a much more performant way
Browse files Browse the repository at this point in the history
  • Loading branch information
BobVarioa committed Jul 29, 2024
1 parent a173b2f commit 959f1fa
Showing 1 changed file with 57 additions and 52 deletions.
109 changes: 57 additions & 52 deletions compiler/codegen.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,11 +347,16 @@ const createVar = (scope, kind, name, global, type = true) => {
}

const pushScope = (scope) => {
return { ...scope, upper: scope, variables: {} };
scope.scopeQueue ??= [];
const vars = scope.variables;
scope.scopeQueue.push(vars);
scope.variables = {};
return scope;
}

const popScope = (scope, inner) => {
scope.localInd = inner.localInd;
const popScope = (scope) => {
const vars = scope.scopeQueue.pop() ?? {};
scope.variables = vars;
}

const setVar = (scope, name, wasm, typeWasm, tee = false, initalizing = false) => {
Expand Down Expand Up @@ -4107,18 +4112,18 @@ const generateIf = (scope, decl) => {
out.push([ Opcodes.if, Blocktype.void ]);
depth.push('if');

const newScope = pushScope(scope);
const consOut = generate(newScope, decl.consequent);
popScope(scope, newScope);
pushScope(scope);
const consOut = generate(scope, decl.consequent);
popScope(scope);
disposeLeftover(consOut);
out.push(...consOut);

if (decl.alternate) {
out.push([ Opcodes.else ]);

const newScope = pushScope(scope);
const altOut = generate(newScope, decl.alternate);
popScope(scope, newScope);
pushScope(scope);
const altOut = generate(scope, decl.alternate);
popScope(scope);

disposeLeftover(altOut);
out.push(...altOut);
Expand Down Expand Up @@ -4294,22 +4299,22 @@ const generateForOf = (scope, decl) => {
const tmpName = '#forof_tmp' + count;
const tmp = allocVar(scope, tmpName, false);

const newScope = pushScope(scope);
pushScope(scope);

// setup local for left
let initVar;
if (decl.left.type !== 'VariableDeclaration') {
if (scope.strict) return internalThrow(newScope, 'ReferenceError', `${decl.left.name} is not defined`);
initVar = generateVarDstr(newScope, 'bare', decl.left, { type: 'Identifier', name: tmpName }, undefined, true);
if (scope.strict) return internalThrow(scope, 'ReferenceError', `${decl.left.name} is not defined`);
initVar = generateVarDstr(scope, 'bare', decl.left, { type: 'Identifier', name: tmpName }, undefined, true);
} else {
// todo: verify this is correct
const global = scope.name === 'main' && decl.left.kind === 'var';
initVar = generateVarDstr(newScope, decl.left.kind, decl.left.declarations[0].id, { type: 'Identifier', name: tmpName }, undefined, global);
initVar = generateVarDstr(scope, decl.left.kind, decl.left.declarations[0].id, { type: 'Identifier', name: tmpName }, undefined, global);
}

// set type for local
// todo: optimize away counter and use end pointer
out.push(...typeSwitch(newScope, iterType, {
out.push(...typeSwitch(scope, iterType, {
[TYPES.array]: [
[ Opcodes.loop, Blocktype.void ],

Expand All @@ -4318,7 +4323,7 @@ const generateForOf = (scope, decl) => {

[ Opcodes.local_set, tmp ],

...setType(newScope, tmpName, [
...setType(scope, tmpName, [
[ Opcodes.local_get, pointer ],
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
]),
Expand All @@ -4327,7 +4332,7 @@ const generateForOf = (scope, decl) => {

[ Opcodes.block, Blocktype.void ],
[ Opcodes.block, Blocktype.void ],
...generate(newScope, decl.body),
...generate(scope, decl.body),
[ Opcodes.end ],

// increment iter pointer by valtype size + 1
Expand All @@ -4352,11 +4357,11 @@ const generateForOf = (scope, decl) => {
],

[TYPES.string]: [
...setType(newScope, tmpName, TYPES.string),
...setType(scope, tmpName, TYPES.string),

// allocate out string
[ Opcodes.call, includeBuiltin(newScope, '__Porffor_allocate').index ],
[ Opcodes.local_tee, localTmp(newScope, '#forof_allocd', Valtype.i32) ],
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
[ Opcodes.local_tee, localTmp(scope, '#forof_allocd', Valtype.i32) ],

// set length to 1
...number(1, Valtype.i32),
Expand All @@ -4365,7 +4370,7 @@ const generateForOf = (scope, decl) => {
[ Opcodes.loop, Blocktype.void ],

// use as pointer for store later
[ Opcodes.local_get, localTmp(newScope, '#forof_allocd', Valtype.i32) ],
[ Opcodes.local_get, localTmp(scope, '#forof_allocd', Valtype.i32) ],

// load current string ind {arg}
[ Opcodes.local_get, pointer ],
Expand All @@ -4375,15 +4380,15 @@ const generateForOf = (scope, decl) => {
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],

// return new string (page)
[ Opcodes.local_get, localTmp(newScope, '#forof_allocd', Valtype.i32) ],
[ Opcodes.local_get, localTmp(scope, '#forof_allocd', Valtype.i32) ],
Opcodes.i32_from_u,
[ Opcodes.local_set, tmp ],

...initVar,

[ Opcodes.block, Blocktype.void ],
[ Opcodes.block, Blocktype.void ],
...generate(newScope, decl.body),
...generate(scope, decl.body),
[ Opcodes.end ],

// increment iter pointer by valtype size
Expand All @@ -4407,11 +4412,11 @@ const generateForOf = (scope, decl) => {
[ Opcodes.end ]
],
[TYPES.bytestring]: [
...setType(newScope, tmpName, TYPES.bytestring),
...setType(scope, tmpName, TYPES.bytestring),

// allocate out string
[ Opcodes.call, includeBuiltin(newScope, '__Porffor_allocate').index ],
[ Opcodes.local_tee, localTmp(newScope, '#forof_allocd', Valtype.i32) ],
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
[ Opcodes.local_tee, localTmp(scope, '#forof_allocd', Valtype.i32) ],

// set length to 1
...number(1, Valtype.i32),
Expand All @@ -4420,7 +4425,7 @@ const generateForOf = (scope, decl) => {
[ Opcodes.loop, Blocktype.void ],

// use as pointer for store later
[ Opcodes.local_get, localTmp(newScope, '#forof_allocd', Valtype.i32) ],
[ Opcodes.local_get, localTmp(scope, '#forof_allocd', Valtype.i32) ],

// load current string ind {arg}
[ Opcodes.local_get, pointer ],
Expand All @@ -4432,15 +4437,15 @@ const generateForOf = (scope, decl) => {
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],

// return new string (page)
[ Opcodes.local_get, localTmp(newScope, '#forof_allocd', Valtype.i32) ],
[ Opcodes.local_get, localTmp(scope, '#forof_allocd', Valtype.i32) ],
Opcodes.i32_from_u,
[ Opcodes.local_set, tmp ],

...initVar,

[ Opcodes.block, Blocktype.void ],
[ Opcodes.block, Blocktype.void ],
...generate(newScope, decl.body),
...generate(scope, decl.body),
[ Opcodes.end ],

// increment counter by 1
Expand All @@ -4466,7 +4471,7 @@ const generateForOf = (scope, decl) => {

[ Opcodes.local_set, tmp ],

...setType(newScope, tmpName, [
...setType(scope, tmpName, [
[ Opcodes.local_get, pointer ],
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
]),
Expand All @@ -4475,7 +4480,7 @@ const generateForOf = (scope, decl) => {

[ Opcodes.block, Blocktype.void ],
[ Opcodes.block, Blocktype.void ],
...generate(newScope, decl.body),
...generate(scope, decl.body),
[ Opcodes.end ],

// increment iter pointer by valtype size + 1
Expand Down Expand Up @@ -4567,7 +4572,7 @@ const generateForOf = (scope, decl) => {
],
}, {
prelude: [
...setType(newScope, tmpName, TYPES.number),
...setType(scope, tmpName, TYPES.number),

[ Opcodes.loop, Blocktype.void ],

Expand All @@ -4582,7 +4587,7 @@ const generateForOf = (scope, decl) => {

[ Opcodes.block, Blocktype.void ],
[ Opcodes.block, Blocktype.void ],
...generate(newScope, decl.body),
...generate(scope, decl.body),
[ Opcodes.end ],

// increment counter by 1
Expand All @@ -4602,12 +4607,12 @@ const generateForOf = (scope, decl) => {
}),

// note: should be impossible to reach?
default: internalThrow(newScope, 'TypeError', `Tried for..of on non-iterable type`)
default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
}, Blocktype.void));

out.push([ Opcodes.end ]); // end if

popScope(scope, newScope);
popScope(scope);

depth.pop();
depth.pop();
Expand Down Expand Up @@ -4665,21 +4670,21 @@ const generateForIn = (scope, decl) => {
const tmp = localTmp(scope, tmpName, Valtype.i32);
localTmp(scope, tmpName + '#type', Valtype.i32);

const newScope = pushScope(scope);
pushScope(scope);

let initVar;
if (decl.left.type === 'Identifier') {
if (scope.strict) return internalThrow(newScope, 'ReferenceError', `${decl.left.name} is not defined`);
initVar = generateVarDstr(newScope, 'var', decl.left, { type: 'Identifier', name: tmpName }, undefined, true);
if (scope.strict) return internalThrow(scope, 'ReferenceError', `${decl.left.name} is not defined`);
initVar = generateVarDstr(scope, 'var', decl.left, { type: 'Identifier', name: tmpName }, undefined, true);
} else {
// todo: verify this is correct
const global = scope.name === 'main' && decl.left.kind === 'var';
initVar = generateVarDstr(newScope, decl.left.kind, decl.left?.declarations?.[0]?.id ?? decl.left, { type: 'Identifier', name: tmpName }, undefined, global);
initVar = generateVarDstr(scope, decl.left.kind, decl.left?.declarations?.[0]?.id ?? decl.left, { type: 'Identifier', name: tmpName }, undefined, global);
}

// set type for local
// todo: optimize away counter and use end pointer
out.push(...typeSwitch(newScope, iterType, {
out.push(...typeSwitch(scope, iterType, {
[TYPES.object]: [
[ Opcodes.loop, Blocktype.void ],

Expand All @@ -4688,7 +4693,7 @@ const generateForIn = (scope, decl) => {
[ Opcodes.i32_load, 0, 5 ],
[ Opcodes.local_tee, tmp ],

...setType(newScope, tmpName, [
...setType(scope, tmpName, [
[ Opcodes.i32_const, 31 ],
[ Opcodes.i32_shr_u ],
[ Opcodes.if, Valtype.i32 ],
Expand All @@ -4715,7 +4720,7 @@ const generateForIn = (scope, decl) => {
[ Opcodes.i32_const, 0b0100 ],
[ Opcodes.i32_and ],
[ Opcodes.if, Blocktype.void ],
...generate(newScope, decl.body),
...generate(scope, decl.body),
[ Opcodes.end ],

// increment pointer by 14
Expand All @@ -4741,12 +4746,12 @@ const generateForIn = (scope, decl) => {

// todo: use Object.keys as fallback
// should be unreachable?
default: internalThrow(newScope, 'TypeError', `Tried for..in on unsupported type`)
default: internalThrow(scope, 'TypeError', `Tried for..in on unsupported type`)
}, Blocktype.void));

out.push([ Opcodes.end ]); // end if

popScope(scope, newScope);
popScope(scope);

depth.pop();
depth.pop();
Expand Down Expand Up @@ -4809,7 +4814,7 @@ const generateSwitch = (scope, decl) => {
cases.push(cases.splice(defaultCase, 1)[0]);
}

const newScope = pushScope(scope);
pushScope(scope);

for (let i = 0; i < cases.length; i++) {
out.push([ Opcodes.block, Blocktype.void ]);
Expand All @@ -4822,7 +4827,7 @@ const generateSwitch = (scope, decl) => {
// todo: this should use same value zero
out.push(
[ Opcodes.local_get, tmp ],
...generate(newScope, x.test),
...generate(scope, x.test),
[ Opcodes.eq ],
[ Opcodes.br_if, i ]
);
Expand All @@ -4837,14 +4842,14 @@ const generateSwitch = (scope, decl) => {
depth.pop();
out.push(
[ Opcodes.end ],
...generateCode(newScope, { body: cases[i].consequent })
...generateCode(scope, { body: cases[i].consequent })
);
}

out.push([ Opcodes.end ]);
depth.pop();

popScope(scope, newScope);
popScope(scope);

return out;
};
Expand Down Expand Up @@ -6371,7 +6376,7 @@ const generateFunc = (scope, decl) => {
const generateCode = (scope, decl) => {
let out = [];

const newScope = decl._funcBody ? scope : pushScope(scope);
const blockScope = decl._funcBody ? scope : pushScope(scope);

const body = decl.body;
// let eager = [];
Expand Down Expand Up @@ -6424,19 +6429,19 @@ const generateCode = (scope, decl) => {
}

for (const name of names) {
newScope.variables[name] = { nonLocal: false, kind: decl.kind, scope, name };
blockScope.variables[name] = { nonLocal: false, kind: decl.kind, scope, name };
}
}

// for (const x of eager) {
// out = out.concat(generate(newScope, x));
// out = out.concat(generate(blockScope, x));
// }

for (const x of body) {
out = out.concat(generate(newScope, x));
out = out.concat(generate(blockScope, x));
}

popScope(scope, newScope);
if (!decl._funcBody) popScope(blockScope);

return out;
};
Expand Down

0 comments on commit 959f1fa

Please sign in to comment.