Fiberクラスの実装
monorubyにFiberクラスを実装した。
code: Ruby
fib = Fiber.new do
a = b = 1
loop do
Fiber.yield a
a, b = a + b, a
end
end
fib.resume #=> 1
fib.resume #=> 2
fib.resume #=> 3
fib.resume #=> 5
fib.resume #=> 8
fib.resume #=> 13
Fiber.new 新しいFiberを生成する
Fiber.yield Fiberの実行を中断し、値を親Fiberへ返す
Fiber#resume Fiberの実行を再開する
monorubyでの実装
Fiberオブジェクトを生成する際にExecutorを新しく生成し、1対1で紐づける。
Executorに対応するマシンスタック領域を準備する。
resume/yieldでスタックポインタを切り替える
Enumeratorクラスの実装
code:Ruby
fib = Enumerator.new do |y|
a = b = 1
loop do
y << a
a, b = a + b, a
end
end
fib.next
fib.each do |x|
if x > 30 then raise StopIteration end
puts x.to_s
end
code:Ruby
e = 1,2,3,4.to_enum
e.each do |x|
puts x
end
今後の課題
Fiber用のスタックプールを作って使いまわす。
Fiber.yield、Fiber#resumeのインライン化
code: Rust
#naked
extern "C" fn resume_fiber(vm: *mut Executor, child: &mut Executor, val: Value) -> Option<Value> {
unsafe {
std::arch::asm!(
"push r15",
"push r14",
"push r13",
"push r12",
"push rbx",
"push rbp",
"mov rdi + 16, rsp", // 現在のrspを保存
"mov rsp, rsi + 16", // childのrspを復帰
"mov rsi + 24, rdi", // 呼び出し元のExecutorを毎回保存
"pop rbp",
"pop rbx",
"pop r12",
"pop r13",
"pop r14",
"pop r15",
"mov rax, rdx",
"ret",
options(noreturn)
);
}
}