use thin_vec::thin_vec;
use crate::{
bytecompiler::{ByteCompiler, Label, Register},
js_string,
vm::GeneratorResumeKind,
};
impl ByteCompiler<'_> {
pub(crate) fn generator_next(&mut self, value: &Register, resume_kind: &Register) {
let jump_table_index = self.next_opcode_location() + size_of::<u32>() as u32;
self.bytecode.emit_jump_table(
resume_kind.index(),
thin_vec![
Self::DUMMY_ADDRESS, Self::DUMMY_ADDRESS, ],
);
self.bytecode.emit_set_accumulator(value.variable());
self.bytecode.emit_re_throw();
let normal = self.next_opcode_location();
let end = self.jump();
let throw = self.next_opcode_location();
self.bytecode.emit_throw(value.variable());
self.patch_jump(end);
self.bytecode
.patch_jump_table(jump_table_index, &[normal, throw]);
}
pub(crate) fn generator_delegate_next(
&mut self,
value: &Register,
resume_kind: &Register,
is_return: &Register,
) -> (Label, Label) {
let iterator = self.register_allocator.alloc();
let next = self.register_allocator.alloc();
self.bytecode
.emit_iterator_pop(iterator.variable(), next.variable());
let jump_table_index = self.next_opcode_location() + size_of::<u32>() as u32;
self.bytecode.emit_jump_table(
resume_kind.index(),
thin_vec![
Self::DUMMY_ADDRESS, Self::DUMMY_ADDRESS, ],
);
let name_index = self.get_or_insert_string(js_string!("return"));
self.bytecode
.emit_move(is_return.variable(), iterator.variable());
self.bytecode
.emit_get_method(is_return.variable(), name_index.into());
let return_method_undefined = self.jump_if_null_or_undefined(is_return);
self.push_from_register(&iterator);
self.push_from_register(is_return);
self.push_from_register(value);
self.bytecode.emit_call(1u8.into());
self.bytecode.emit_store_true(is_return.variable());
self.pop_into_register(value);
let return_jump = self.jump();
let normal = self.next_opcode_location();
self.push_from_register(&iterator);
self.push_from_register(&next);
self.push_from_register(value);
self.bytecode.emit_call(1u8.into());
self.bytecode.emit_store_false(is_return.variable());
self.pop_into_register(value);
let normal_jump = self.jump();
let throw = self.next_opcode_location();
let name_index = self.get_or_insert_string(js_string!("throw"));
self.bytecode
.emit_move(is_return.variable(), iterator.variable());
self.bytecode
.emit_get_method(is_return.variable(), name_index.into());
let skip_push = self.jump_if_not_undefined(is_return);
self.bytecode
.emit_iterator_push(iterator.variable(), next.variable());
let throw_method_undefined = self.jump();
self.patch_jump(skip_push);
self.push_from_register(&iterator);
self.push_from_register(is_return);
self.push_from_register(value);
self.bytecode.emit_call(1u8.into());
self.bytecode.emit_store_false(is_return.variable());
self.pop_into_register(value);
self.bytecode
.patch_jump_table(jump_table_index, &[normal, throw]);
self.patch_jump(return_jump);
self.patch_jump(normal_jump);
self.bytecode
.emit_iterator_push(iterator.variable(), next.variable());
self.register_allocator.dealloc(iterator);
self.register_allocator.dealloc(next);
(return_method_undefined, throw_method_undefined)
}
pub(crate) fn generator_delegate_resume(
&mut self,
value: &Register,
resume_kind: &Register,
is_return: &Register,
) -> (Label, Label) {
let not_throw = self.jump_if_not_resume_kind(GeneratorResumeKind::Throw, resume_kind);
self.bytecode
.emit_iterator_pop(resume_kind.variable(), resume_kind.variable());
self.bytecode.emit_throw(value.variable());
self.patch_jump(not_throw);
self.bytecode.emit_iterator_update_result(value.variable());
let skip_pop = self.jump_if_false(value);
self.bytecode.emit_iterator_value(value.variable());
self.bytecode
.emit_iterator_pop(resume_kind.variable(), resume_kind.variable());
let return_gen = self.jump_if_true(is_return);
let exit = self.jump();
self.patch_jump(skip_pop);
(return_gen, exit)
}
}