Limit register copying to only variables that are mutated

This commit is contained in:
Andrew Morris
2023-03-31 17:05:09 +11:00
parent a5a861d570
commit eaa5616193
4 changed files with 38 additions and 30 deletions

View File

@@ -1333,23 +1333,15 @@ impl<'a> ExpressionCompiler<'a> {
}
};
let value = match self.fnc.lookup_value(ident) {
Some(v) => v, // TODO: Capturing functions
let name = match self.fnc.lookup(ident) {
Some(v) => v,
None => {
self.fnc.diagnostics.push(Diagnostic {
level: DiagnosticLevel::InternalError,
message: format!(
"Failed to lookup identifier `{}`, ref: {:?}",
ident.sym,
self.fnc.scope_analysis.refs.get(&ident.span)
),
span: ident.span,
});
Value::Register(self.fnc.allocate_numbered_reg("_todo_identifier"))
return self.inline(Value::Undefined, target_register);
}
};
let value = name.value.clone();
match fn_as_owner_id {
Some(owner_id) => {
let capture_params = self.fnc.scope_analysis.captures.get(&owner_id).cloned();
@@ -1367,7 +1359,15 @@ impl<'a> ExpressionCompiler<'a> {
}
None => match value {
Value::Register(reg) => {
if name.mutations.is_empty() {
// Just use the register for the variable if it's not mutated
return self.inline(Value::Register(reg), target_register);
}
// Otherwise, we need to capture the current value for the result of the expression
// TODO: This case can be limited further by checking *where* the mutations are
let new_reg = self.fnc.allocate_tmp();
self.fnc.push(Instruction::Mov(
Value::Register(reg.clone()),
new_reg.clone(),

View File

@@ -14,7 +14,7 @@ use crate::expression_compiler::CompiledExpression;
use crate::expression_compiler::ExpressionCompiler;
use crate::name_allocator::{NameAllocator, RegAllocator};
use crate::scope::{NameId, OwnerId};
use crate::scope_analysis::{fn_to_owner_id, ScopeAnalysis};
use crate::scope_analysis::{fn_to_owner_id, Name, ScopeAnalysis};
#[derive(Clone, Debug)]
pub enum Functionish {
@@ -121,6 +121,20 @@ impl FunctionCompiler {
self.current.body.push(InstructionOrLabel::Label(label));
}
pub fn lookup(&mut self, ident: &swc_ecma_ast::Ident) -> Option<&Name> {
let name = self.scope_analysis.lookup(ident);
if name.is_none() {
self.diagnostics.push(Diagnostic {
level: DiagnosticLevel::InternalError,
message: format!("Could not find name for ident {:?}", ident),
span: ident.span,
});
}
name
}
pub fn lookup_value(&self, ident: &swc_ecma_ast::Ident) -> Option<Value> {
self.scope_analysis.lookup_value(&self.owner_id, ident)
}