Implement yield* instruction

This commit is contained in:
Andrew Morris
2023-06-27 14:38:42 +10:00
parent 074774d9d6
commit e49b1ff3da
3 changed files with 164 additions and 111 deletions

View File

@@ -751,7 +751,7 @@ impl<'a> AssemblyParser<'a> {
),
Cat => Instruction::Cat(self.assemble_value(), self.assemble_register()),
Yield => Instruction::Yield(self.assemble_value(), self.assemble_register()),
YieldStar => Instruction::Yield(self.assemble_value(), self.assemble_register()),
YieldStar => Instruction::YieldStar(self.assemble_value(), self.assemble_register()),
};
self.parse_line();

View File

@@ -3,7 +3,7 @@ use std::mem::take;
use queues::*;
use swc_common::Spanned;
use crate::asm::{Array, Builtin, Instruction, Label, Number, Object, Register, Value};
use crate::asm::{Array, Instruction, Label, Number, Object, Register, Value};
use crate::diagnostic::{Diagnostic, DiagnosticLevel};
use crate::function_compiler::{FunctionCompiler, Functionish, QueuedFunction};
use crate::scope::{NameId, OwnerId};
@@ -1191,13 +1191,6 @@ impl<'a> ExpressionCompiler<'a> {
yield_expr: &swc_ecma_ast::YieldExpr,
target_register: Option<Register>,
) -> CompiledExpression {
// TODO: Implement and use the yield* instruction instead
// It will use the stack within the generator which avoids reloading the generator's stack each
// time.
if yield_expr.delegate {
return self.yield_star_expr(yield_expr, target_register);
}
let mut nested_registers = Vec::<Register>::new();
let arg_compiled = match &yield_expr.arg {
@@ -1214,103 +1207,16 @@ impl<'a> ExpressionCompiler<'a> {
}
};
let instr = Instruction::Yield(self.fnc.use_(arg_compiled), dst.clone());
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(instr);
return CompiledExpression::new(Value::Register(dst), nested_registers);
}
pub fn yield_star_expr(
&mut self,
yield_expr: &swc_ecma_ast::YieldExpr,
target_register: Option<Register>,
) -> CompiledExpression {
let mut nested_registers = Vec::<Register>::new();
let arg_compiled = match &yield_expr.arg {
Some(arg) => self.compile(arg, None),
None => CompiledExpression::empty(),
};
let dst = match target_register {
Some(t) => t,
None => {
let tmp = self.fnc.allocate_tmp();
nested_registers.push(tmp.clone());
tmp
}
};
let iter_reg = self.fnc.allocate_numbered_reg(&"_iter".to_string());
let iter_res_reg = self.fnc.allocate_numbered_reg(&"_iter_res".to_string());
let done_reg = self.fnc.allocate_numbered_reg(&"_done".to_string());
let test_label = Label {
name: self
.fnc
.label_allocator
.allocate_numbered(&"yield_star_test".to_string()),
};
let next_label = Label {
name: self
.fnc
.label_allocator
.allocate_numbered(&"yield_star_next".to_string()),
};
let end_label = Label {
name: self
.fnc
.label_allocator
.allocate_numbered(&"yield_star_end".to_string()),
};
let instr = Instruction::ConstSubCall(
self.fnc.use_(arg_compiled),
Value::Builtin(Builtin {
name: "SymbolIterator".to_string(),
}),
Value::Array(Box::new(Array::default())),
iter_reg.clone(),
);
self.fnc.push(instr);
self.fnc.push(Instruction::Jmp(next_label.ref_()));
self.fnc.label(test_label.clone());
self.fnc.push(Instruction::JmpIf(
Value::Register(done_reg.clone()),
end_label.ref_(),
));
self.fnc.push(Instruction::Yield(
Value::Register(dst.clone()),
Register::ignore(),
));
self.fnc.label(next_label);
self
.fnc
.push(Instruction::Next(iter_reg, iter_res_reg.clone()));
self.fnc.push(Instruction::UnpackIterRes(
iter_res_reg,
dst.clone(),
done_reg,
));
self.fnc.push(Instruction::Jmp(test_label.ref_()));
self.fnc.label(end_label);
return CompiledExpression::new(Value::Register(dst), nested_registers);
}
pub fn identifier(
&mut self,
ident: &swc_ecma_ast::Ident,