[be] Limit scope of temporaries in codegen

This morning @mofeiZ reminded me that our codegen doesn't really have any guards 
against reordering, since temporaries are lazily emitted. We're relying on the 
fact that our lowering and memoization carefully preserves order of evaluation, 
such that delaying the instructions in codegen doesn't change semantics. 

To help catch any mistakes with this, I had previously added code that reset the 
codegen context's temporaries before/after exiting a reactive scope. That 
ensured that temporaries from within the scope weren't accessible outside it. 
This PR extends that approach to _all_ blocks, so that temporaries created 
within a block aren't accessible outside it. 

I'm also going to explore more actively resetting temporaries after they 
"should" be used. There are a couple cases where temporaries are reused, though, 
which we have to change first.
This commit is contained in:
Joe Savona
2023-10-10 13:15:51 -07:00
parent 495fec19e7
commit 52c6a34da3
@@ -139,6 +139,36 @@ class Context {
}
function codegenBlock(cx: Context, block: ReactiveBlock): t.BlockStatement {
const temp = new Map(cx.temp);
const result = codegenBlockNoReset(cx, block);
// Check that the block only added new temporaries and did not update the
// value of any existing temporary
for (const [key, value] of cx.temp) {
if (!temp.has(key)) {
continue;
}
CompilerError.invariant(temp.get(key)! === value, {
loc: null,
reason: "Expected temporary value to be unchanged",
description: null,
suggestions: null,
});
}
cx.temp = temp;
return result;
}
/**
* Generates code for the block, without resetting the Context's temporary state.
* This should not be used unless it is expected that temporaries from this block
* can be referenced later, which is currently only true for sequence expressions
* where the final `value` is expected to reference the temporary created in the
* preceding instructions of the sequence.
*/
function codegenBlockNoReset(
cx: Context,
block: ReactiveBlock
): t.BlockStatement {
const statements: Array<t.Statement> = [];
for (const item of block) {
switch (item.kind) {
@@ -1282,7 +1312,7 @@ function codegenInstructionValue(
break;
}
case "SequenceExpression": {
const body = codegenBlock(
const body = codegenBlockNoReset(
cx,
instrValue.instructions.map((instruction) => ({
kind: "instruction",