mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-04-18 03:00:27 -04:00
move (release ..) to after usage
This commit is contained in:
@@ -10,16 +10,15 @@ use crate::scope::{NameId, OwnerId};
|
||||
use crate::scope_analysis::{fn_to_owner_id, NameType};
|
||||
use crate::target_accessor::TargetAccessor;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct CompiledExpression {
|
||||
/** It is usually better to access this via functionCompiler.use_ */
|
||||
pub value: Value,
|
||||
|
||||
pub nested_registers: Vec<Register>,
|
||||
pub release_checker: ReleaseChecker,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ReleaseChecker {
|
||||
pub has_unreleased_registers: bool,
|
||||
}
|
||||
@@ -248,22 +247,24 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
}
|
||||
|
||||
pub fn compile_into(&mut self, expr: &swc_ecma_ast::Expr, target_register: Register) {
|
||||
let mut ce = self.compile(expr, Some(target_register.clone()));
|
||||
let ce = self.compile(expr, Some(target_register.clone()));
|
||||
let mut in_target = false;
|
||||
|
||||
if let Value::Register(ce_reg) = &ce.value {
|
||||
if ce_reg == &target_register {
|
||||
in_target = true;
|
||||
self.fnc.use_ref(&mut ce);
|
||||
// Result is already in the target register, no mov needed
|
||||
}
|
||||
}
|
||||
|
||||
if !in_target {
|
||||
// Put the value into the target
|
||||
let value = self.fnc.use_(ce);
|
||||
self.fnc.push(Instruction::Mov(value, target_register));
|
||||
self
|
||||
.fnc
|
||||
.push(Instruction::Mov(ce.value.clone(), target_register));
|
||||
}
|
||||
|
||||
self.fnc.release_ce(ce);
|
||||
}
|
||||
|
||||
pub fn unary_expression(
|
||||
@@ -284,18 +285,20 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
Some(t) => t.clone(),
|
||||
};
|
||||
|
||||
let instr = match make_unary_op(un_exp.op, self.fnc.use_(arg), target.clone()) {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
self
|
||||
.fnc
|
||||
.todo(un_exp.span, &format!("Unary operator {:?}", un_exp.op));
|
||||
self.fnc.push(
|
||||
match make_unary_op(un_exp.op, arg.value.clone(), target.clone()) {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
self
|
||||
.fnc
|
||||
.todo(un_exp.span, &format!("Unary operator {:?}", un_exp.op));
|
||||
|
||||
return CompiledExpression::empty();
|
||||
}
|
||||
};
|
||||
return CompiledExpression::empty();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
self.fnc.push(instr);
|
||||
self.fnc.release_ce(arg);
|
||||
|
||||
return CompiledExpression::new(Value::Register(target), nested_registers);
|
||||
}
|
||||
@@ -322,14 +325,15 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
Some(t) => t.clone(),
|
||||
};
|
||||
|
||||
let instr = make_binary_op(
|
||||
self.fnc.push(make_binary_op(
|
||||
bin.op,
|
||||
self.fnc.use_(left),
|
||||
self.fnc.use_(right),
|
||||
left.value.clone(),
|
||||
right.value.clone(),
|
||||
target.clone(),
|
||||
);
|
||||
));
|
||||
|
||||
self.fnc.push(instr);
|
||||
self.fnc.release_ce(left);
|
||||
self.fnc.release_ce(right);
|
||||
|
||||
return CompiledExpression::new(Value::Register(target), nested_registers);
|
||||
}
|
||||
@@ -653,13 +657,14 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let sub_instr = Instruction::Sub(
|
||||
self.fnc.use_(compiled_obj),
|
||||
self.fnc.use_(compiled_prop),
|
||||
self.fnc.push(Instruction::Sub(
|
||||
compiled_obj.value.clone(),
|
||||
compiled_prop.value.clone(),
|
||||
dest.clone(),
|
||||
);
|
||||
));
|
||||
|
||||
self.fnc.push(sub_instr);
|
||||
self.fnc.release_ce(compiled_obj);
|
||||
self.fnc.release_ce(compiled_prop);
|
||||
|
||||
CompiledExpression::new(Value::Register(dest.clone()), nested_registers)
|
||||
}
|
||||
@@ -840,12 +845,14 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let args_value = self.fnc.use_(compiled_args);
|
||||
let callee_value = self.fnc.use_(callee);
|
||||
self.fnc.push(Instruction::Call(
|
||||
callee.value.clone(),
|
||||
compiled_args.value.clone(),
|
||||
dest.clone(),
|
||||
));
|
||||
|
||||
self
|
||||
.fnc
|
||||
.push(Instruction::Call(callee_value, args_value, dest.clone()));
|
||||
self.fnc.release_ce(compiled_args);
|
||||
self.fnc.release_ce(callee);
|
||||
|
||||
CompiledExpression::new(Value::Register(dest), nested_registers)
|
||||
}
|
||||
@@ -879,12 +886,14 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let callee_value = self.fnc.use_(callee);
|
||||
let args_value = self.fnc.use_(compiled_args);
|
||||
self.fnc.push(Instruction::New(
|
||||
callee.value.clone(),
|
||||
compiled_args.value.clone(),
|
||||
dest.clone(),
|
||||
));
|
||||
|
||||
self
|
||||
.fnc
|
||||
.push(Instruction::New(callee_value, args_value, dest.clone()));
|
||||
self.fnc.release_ce(callee);
|
||||
self.fnc.release_ce(compiled_args);
|
||||
|
||||
CompiledExpression::new(Value::Register(dest), nested_registers)
|
||||
}
|
||||
@@ -943,24 +952,35 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
TargetAccessorOrCompiledExpression::TargetAccessor(mut ta) => {
|
||||
let targets_this = ta.targets_this();
|
||||
|
||||
let args_value = self.fnc.use_(compiled_args);
|
||||
self.fnc.push(match targets_this {
|
||||
false => Instruction::SubCall(
|
||||
obj_value.clone(),
|
||||
prop.value,
|
||||
compiled_args.value.clone(),
|
||||
dest.clone(),
|
||||
),
|
||||
true => Instruction::ThisSubCall(
|
||||
obj_value.clone(),
|
||||
prop.value,
|
||||
compiled_args.value.clone(),
|
||||
dest.clone(),
|
||||
),
|
||||
});
|
||||
|
||||
let instr = match targets_this {
|
||||
false => Instruction::SubCall(obj_value.clone(), prop.value, args_value, dest.clone()),
|
||||
true => Instruction::ThisSubCall(obj_value.clone(), prop.value, args_value, dest.clone()),
|
||||
};
|
||||
self.fnc.release_ce(compiled_args);
|
||||
|
||||
self.fnc.push(instr);
|
||||
ta.assign_and_packup(self, &obj_value, targets_this);
|
||||
}
|
||||
TargetAccessorOrCompiledExpression::CompiledExpression(ce) => {
|
||||
let args_value = self.fnc.use_(compiled_args);
|
||||
self.fnc.push(Instruction::ConstSubCall(
|
||||
obj_value.clone(),
|
||||
prop.value,
|
||||
compiled_args.value.clone(),
|
||||
dest.clone(),
|
||||
));
|
||||
|
||||
let instr =
|
||||
Instruction::ConstSubCall(obj_value.clone(), prop.value, args_value, dest.clone());
|
||||
|
||||
self.fnc.push(instr);
|
||||
self.fnc.use_(ce);
|
||||
self.fnc.release_ce(compiled_args);
|
||||
self.fnc.release_ce(ce);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1196,13 +1216,13 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
|
||||
let first_expr = self.compile(&tpl.exprs[0], None);
|
||||
|
||||
let plus_instr = Instruction::OpPlus(
|
||||
self.fnc.push(Instruction::OpPlus(
|
||||
Value::String(tpl.quasis[0].raw.to_string()),
|
||||
self.fnc.use_(first_expr),
|
||||
first_expr.value.clone(),
|
||||
acc_reg.clone(),
|
||||
);
|
||||
));
|
||||
|
||||
self.fnc.push(plus_instr);
|
||||
self.fnc.release_ce(first_expr);
|
||||
|
||||
for i in 1..len {
|
||||
self.fnc.push(Instruction::OpPlus(
|
||||
@@ -1213,13 +1233,13 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
|
||||
let expr_i = self.compile(&tpl.exprs[i], None);
|
||||
|
||||
let plus_instr = Instruction::OpPlus(
|
||||
self.fnc.push(Instruction::OpPlus(
|
||||
Value::Register(acc_reg.clone()),
|
||||
self.fnc.use_(expr_i),
|
||||
expr_i.value.clone(),
|
||||
acc_reg.clone(),
|
||||
);
|
||||
));
|
||||
|
||||
self.fnc.push(plus_instr);
|
||||
self.fnc.release_ce(expr_i);
|
||||
}
|
||||
|
||||
let last_str = tpl.quasis[len].raw.to_string();
|
||||
@@ -1256,12 +1276,12 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let instr = match yield_expr.delegate {
|
||||
false => Instruction::Yield(self.fnc.use_(arg_compiled), dst.clone()),
|
||||
true => Instruction::YieldStar(self.fnc.use_(arg_compiled), dst.clone()),
|
||||
};
|
||||
self.fnc.push(match yield_expr.delegate {
|
||||
false => Instruction::Yield(arg_compiled.value.clone(), dst.clone()),
|
||||
true => Instruction::YieldStar(arg_compiled.value.clone(), dst.clone()),
|
||||
});
|
||||
|
||||
self.fnc.push(instr);
|
||||
self.fnc.release_ce(arg_compiled);
|
||||
|
||||
return CompiledExpression::new(Value::Register(dst), nested_registers);
|
||||
}
|
||||
@@ -1424,13 +1444,13 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
let param_reg = self.fnc.get_pattern_register(&kv.value);
|
||||
let compiled_key = self.prop_name(&kv.key);
|
||||
|
||||
let sub_instr = Instruction::Sub(
|
||||
self.fnc.push(Instruction::Sub(
|
||||
Value::Register(register.clone()),
|
||||
self.fnc.use_(compiled_key),
|
||||
compiled_key.value.clone(),
|
||||
param_reg.clone(),
|
||||
);
|
||||
));
|
||||
|
||||
self.fnc.push(sub_instr);
|
||||
self.fnc.release_ce(compiled_key);
|
||||
|
||||
self.pat(&kv.value, ¶m_reg, false);
|
||||
}
|
||||
|
||||
@@ -551,9 +551,10 @@ impl FunctionCompiler {
|
||||
let mut expression_compiler = ExpressionCompiler { fnc: self };
|
||||
|
||||
let arg = expression_compiler.compile(&throw.arg, None);
|
||||
let instr = Instruction::Throw(self.use_(arg));
|
||||
let instr = Instruction::Throw(arg.value.clone());
|
||||
|
||||
self.push(instr);
|
||||
self.release_ce(arg);
|
||||
}
|
||||
Try(try_) => {
|
||||
self.try_(try_);
|
||||
@@ -587,19 +588,16 @@ impl FunctionCompiler {
|
||||
}
|
||||
|
||||
fn if_(&mut self, if_: &swc_ecma_ast::IfStmt) {
|
||||
let mut expression_compiler = ExpressionCompiler { fnc: self };
|
||||
let mut ec = ExpressionCompiler { fnc: self };
|
||||
|
||||
let condition = expression_compiler.compile(&*if_.test, None);
|
||||
|
||||
// Usually we wouldn't capture the value_assembly before release, but
|
||||
// it's safe to do so here, and allows cond_reg to re-use a register
|
||||
// from the condition
|
||||
let condition_asm = self.use_(condition);
|
||||
|
||||
let cond_reg = self.allocate_numbered_reg("_cond");
|
||||
let cond_reg = ec.fnc.allocate_numbered_reg("_cond");
|
||||
ec.compile_into(&*if_.test, cond_reg.clone());
|
||||
|
||||
// TODO: Add negated jmpif instruction to avoid this
|
||||
self.push(Instruction::OpNot(condition_asm, cond_reg.clone()));
|
||||
self.push(Instruction::OpNot(
|
||||
Value::Register(cond_reg.clone()),
|
||||
cond_reg.clone(),
|
||||
));
|
||||
|
||||
let else_label = Label {
|
||||
name: self.label_allocator.allocate_numbered(&"else".to_string()),
|
||||
@@ -867,19 +865,16 @@ impl FunctionCompiler {
|
||||
|
||||
self.label(start_label.clone());
|
||||
|
||||
let mut expression_compiler = ExpressionCompiler { fnc: self };
|
||||
let mut ec = ExpressionCompiler { fnc: self };
|
||||
|
||||
let condition = expression_compiler.compile(&*while_.test, None);
|
||||
|
||||
// Usually we wouldn't capture the value_assembly before release, but
|
||||
// it's safe to do so here, and allows cond_reg to re-use a register
|
||||
// from the condition
|
||||
let condition_asm = self.use_(condition);
|
||||
|
||||
let cond_reg = self.allocate_numbered_reg(&"_cond".to_string());
|
||||
let cond_reg = ec.fnc.allocate_numbered_reg(&"_cond".to_string());
|
||||
ec.compile_into(&*while_.test, cond_reg.clone());
|
||||
|
||||
// TODO: Add negated jmpif instruction to avoid this
|
||||
self.push(Instruction::OpNot(condition_asm, cond_reg.clone()));
|
||||
self.push(Instruction::OpNot(
|
||||
Value::Register(cond_reg.clone()),
|
||||
cond_reg.clone(),
|
||||
));
|
||||
|
||||
self.push(Instruction::JmpIf(
|
||||
Value::Register(cond_reg.clone()),
|
||||
@@ -928,8 +923,12 @@ impl FunctionCompiler {
|
||||
|
||||
self.label(continue_label);
|
||||
|
||||
let jmpif = Instruction::JmpIf(self.use_(condition), start_label.ref_());
|
||||
self.push(jmpif);
|
||||
self.push(Instruction::JmpIf(
|
||||
condition.value.clone(),
|
||||
start_label.ref_(),
|
||||
));
|
||||
|
||||
self.release_ce(condition);
|
||||
|
||||
self.label(end_label);
|
||||
|
||||
@@ -978,17 +977,14 @@ impl FunctionCompiler {
|
||||
Some(cond) => {
|
||||
let mut ec = ExpressionCompiler { fnc: self };
|
||||
|
||||
let condition = ec.compile(cond, None);
|
||||
|
||||
// Usually we wouldn't capture the value_assembly before release, but
|
||||
// it's safe to do so here, and allows cond_reg to re-use a register
|
||||
// from the condition
|
||||
let condition_asm = self.use_(condition);
|
||||
|
||||
let cond_reg = self.allocate_numbered_reg("_cond");
|
||||
let cond_reg = ec.fnc.allocate_numbered_reg("_cond");
|
||||
ec.compile_into(cond, cond_reg.clone());
|
||||
|
||||
// TODO: Add negated jmpif instruction to avoid this
|
||||
self.push(Instruction::OpNot(condition_asm, cond_reg.clone()));
|
||||
self.push(Instruction::OpNot(
|
||||
Value::Register(cond_reg.clone()),
|
||||
cond_reg.clone(),
|
||||
));
|
||||
|
||||
self.push(Instruction::JmpIf(
|
||||
Value::Register(cond_reg.clone()),
|
||||
@@ -1175,27 +1171,15 @@ impl FunctionCompiler {
|
||||
let mut expression_compiler = ExpressionCompiler { fnc: self };
|
||||
let compiled = expression_compiler.compile_top_level(expr, None);
|
||||
|
||||
self.use_(compiled);
|
||||
self.release_ce(compiled);
|
||||
}
|
||||
|
||||
pub fn use_(&mut self, mut compiled_expr: CompiledExpression) -> Value {
|
||||
pub fn release_ce(&mut self, mut compiled_expr: CompiledExpression) {
|
||||
for reg in &compiled_expr.nested_registers {
|
||||
self.release_reg(reg);
|
||||
}
|
||||
|
||||
compiled_expr.release_checker.has_unreleased_registers = false;
|
||||
|
||||
return compiled_expr.value;
|
||||
}
|
||||
|
||||
pub fn use_ref(&mut self, compiled_expr: &mut CompiledExpression) -> Value {
|
||||
for reg in &compiled_expr.nested_registers {
|
||||
self.release_reg(reg);
|
||||
}
|
||||
|
||||
compiled_expr.release_checker.has_unreleased_registers = false;
|
||||
|
||||
return compiled_expr.value.clone();
|
||||
}
|
||||
|
||||
fn get_mutated_registers(&self, span: swc_common::Span) -> HashSet<Register> {
|
||||
|
||||
@@ -802,11 +802,14 @@ impl ModuleCompiler {
|
||||
Some(expr) => ec.compile(expr, None),
|
||||
};
|
||||
|
||||
let key_asm = ec.fnc.use_(compiled_key);
|
||||
let value_asm = ec.fnc.use_(compiled_value);
|
||||
ec.fnc.push(Instruction::SubMov(
|
||||
compiled_key.value.clone(),
|
||||
compiled_value.value.clone(),
|
||||
Register::this(),
|
||||
));
|
||||
|
||||
ec.fnc
|
||||
.push(Instruction::SubMov(key_asm, value_asm, Register::this()));
|
||||
ec.fnc.release_ce(compiled_key);
|
||||
ec.fnc.release_ce(compiled_value);
|
||||
}
|
||||
swc_ecma_ast::ClassMember::PrivateProp(private_prop) => {
|
||||
self.todo(private_prop.span, "private props")
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::mem::take;
|
||||
|
||||
use crate::{
|
||||
asm::{Instruction, Register, Value},
|
||||
expression_compiler::{CompiledExpression, ExpressionCompiler},
|
||||
@@ -127,7 +129,7 @@ impl TargetAccessor {
|
||||
}
|
||||
Nested(nta) => {
|
||||
let submov_instr = Instruction::SubMov(
|
||||
ec.fnc.use_ref(&mut nta.subscript),
|
||||
nta.subscript.value.clone(),
|
||||
value.clone(),
|
||||
nta.obj.register(),
|
||||
);
|
||||
@@ -141,6 +143,7 @@ impl TargetAccessor {
|
||||
ec.fnc.push(submov_instr);
|
||||
}
|
||||
|
||||
ec.fnc.release_ce(take(&mut nta.subscript));
|
||||
ec.fnc.release_reg(&nta.register);
|
||||
|
||||
nta.obj.packup(ec, uses_this_subcall);
|
||||
@@ -190,7 +193,7 @@ impl TargetAccessor {
|
||||
Register(_) => {}
|
||||
Nested(nta) => {
|
||||
let submov_instr = Instruction::SubMov(
|
||||
ec.fnc.use_ref(&mut nta.subscript),
|
||||
nta.subscript.value.clone(),
|
||||
Value::Register(nta.register.clone()),
|
||||
nta.obj.register(),
|
||||
);
|
||||
@@ -201,6 +204,7 @@ impl TargetAccessor {
|
||||
ec.fnc.push(submov_instr);
|
||||
}
|
||||
|
||||
ec.fnc.release_ce(take(&mut nta.subscript));
|
||||
ec.fnc.release_reg(&nta.register);
|
||||
|
||||
nta.obj.packup(ec, uses_this_subcall);
|
||||
|
||||
Reference in New Issue
Block a user