onion_vm/types/lambda/
runnable.rs

1use std::sync::Arc;
2
3use arc_gc::gc::GC;
4
5use crate::{
6    lambda::runnable::{Runnable, RuntimeError, StepResult},
7    types::{
8        lambda::vm_instructions::opcode::get_processed_opcode,
9        object::{OnionObject, OnionObjectCell, OnionStaticObject},
10    },
11};
12
13use super::{
14    context::{Context, Frame},
15    vm_instructions::{
16        self,
17        instruction_set::{VMInstruction, VMInstructionPackage},
18        opcode::ProcessedOpcode,
19    },
20};
21
22type InstructionHandler =
23    fn(&mut OnionLambdaRunnable, &ProcessedOpcode, &mut GC<OnionObjectCell>) -> StepResult;
24
25// 静态指令表,在程序启动时初始化一次
26static INSTRUCTION_TABLE: std::sync::LazyLock<Vec<InstructionHandler>> =
27    std::sync::LazyLock::new(|| {
28        let mut instruction_table: Vec<InstructionHandler> = vec![
29        |_, opcode, _| StepResult::Error(RuntimeError::DetailedError(format!("Invalid instruction: {:?}", opcode).into())); // 默认处理函数 - 返回无效指令错误
30        256 // 数组大小,确保能容纳所有可能的操作码
31    ];
32
33        // 使用枚举值作为索引,填充对应的处理函数
34        // 栈操作
35        instruction_table[VMInstruction::LoadNull as usize] = vm_instructions::load_null;
36        instruction_table[VMInstruction::LoadInt32 as usize] = vm_instructions::load_int;
37        instruction_table[VMInstruction::LoadInt64 as usize] = vm_instructions::load_int;
38        instruction_table[VMInstruction::LoadFloat32 as usize] = vm_instructions::load_float;
39        instruction_table[VMInstruction::LoadFloat64 as usize] = vm_instructions::load_float;
40        instruction_table[VMInstruction::LoadString as usize] = vm_instructions::load_string;
41        instruction_table[VMInstruction::LoadBytes as usize] = vm_instructions::load_bytes;
42        instruction_table[VMInstruction::LoadBool as usize] = vm_instructions::load_bool;
43        instruction_table[VMInstruction::LoadLambda as usize] = vm_instructions::load_lambda;
44        instruction_table[VMInstruction::LoadUndefined as usize] = vm_instructions::load_undefined;
45
46        // 数据结构构建
47        instruction_table[VMInstruction::BuildTuple as usize] = vm_instructions::build_tuple;
48        instruction_table[VMInstruction::BuildKeyValue as usize] = vm_instructions::build_keyval;
49        instruction_table[VMInstruction::BuildNamed as usize] = vm_instructions::build_named;
50        instruction_table[VMInstruction::BuildRange as usize] = vm_instructions::build_range;
51        instruction_table[VMInstruction::BuildSet as usize] = vm_instructions::build_set;
52        // 二元操作符
53        instruction_table[VMInstruction::BinaryIn as usize] = vm_instructions::is_in;
54        instruction_table[VMInstruction::BinaryIs as usize] = vm_instructions::check_is_same_object;
55
56        instruction_table[VMInstruction::BinaryAdd as usize] = vm_instructions::binary_add;
57        instruction_table[VMInstruction::BinarySub as usize] = vm_instructions::binary_subtract;
58        instruction_table[VMInstruction::BinaryMul as usize] = vm_instructions::binary_multiply;
59        instruction_table[VMInstruction::BinaryDiv as usize] = vm_instructions::binary_divide;
60        instruction_table[VMInstruction::BinaryMod as usize] = vm_instructions::binary_modulus;
61        instruction_table[VMInstruction::BinaryPow as usize] = vm_instructions::binary_power;
62        instruction_table[VMInstruction::BinaryBitAnd as usize] =
63            vm_instructions::binary_bitwise_and;
64        instruction_table[VMInstruction::BinaryBitOr as usize] = vm_instructions::binary_bitwise_or;
65        instruction_table[VMInstruction::BinaryBitXor as usize] =
66            vm_instructions::binary_bitwise_xor;
67        instruction_table[VMInstruction::BinaryShl as usize] = vm_instructions::binary_shift_left;
68        instruction_table[VMInstruction::BinaryShr as usize] = vm_instructions::binary_shift_right;
69        instruction_table[VMInstruction::BinaryEq as usize] = vm_instructions::binary_equal;
70        instruction_table[VMInstruction::BinaryNe as usize] = vm_instructions::binary_not_equal;
71        instruction_table[VMInstruction::BinaryGt as usize] = vm_instructions::binary_greater;
72        instruction_table[VMInstruction::BinaryLt as usize] = vm_instructions::binary_less;
73        instruction_table[VMInstruction::BinaryGe as usize] = vm_instructions::binary_greater_equal;
74        instruction_table[VMInstruction::BinaryLe as usize] = vm_instructions::binary_less_equal;
75        instruction_table[VMInstruction::MapTo as usize] = vm_instructions::map_to;
76
77        // 一元操作
78        instruction_table[VMInstruction::UnaryBitNot as usize] = vm_instructions::unary_bitwise_not;
79        instruction_table[VMInstruction::UnaryAbs as usize] = vm_instructions::unary_plus;
80        instruction_table[VMInstruction::UnaryNeg as usize] = vm_instructions::unary_minus;
81
82        // 变量与引用
83        instruction_table[VMInstruction::StoreVar as usize] = vm_instructions::let_var;
84        instruction_table[VMInstruction::LoadVar as usize] = vm_instructions::get_var;
85        instruction_table[VMInstruction::SetValue as usize] = vm_instructions::set_var;
86        instruction_table[VMInstruction::GetAttr as usize] = vm_instructions::get_attr;
87        instruction_table[VMInstruction::IndexOf as usize] = vm_instructions::index_of;
88        instruction_table[VMInstruction::KeyOf as usize] = vm_instructions::key_of;
89        instruction_table[VMInstruction::ValueOf as usize] = vm_instructions::value_of;
90        instruction_table[VMInstruction::TypeOf as usize] = vm_instructions::type_of;
91        instruction_table[VMInstruction::ShallowCopy as usize] = vm_instructions::copy;
92        instruction_table[VMInstruction::Swap as usize] = vm_instructions::swap;
93        instruction_table[VMInstruction::LengthOf as usize] = vm_instructions::get_length;
94        instruction_table[VMInstruction::Mut as usize] = vm_instructions::mutablize;
95        instruction_table[VMInstruction::Const as usize] = vm_instructions::immutablize;
96        instruction_table[VMInstruction::ForkInstruction as usize] =
97            vm_instructions::fork_instruction;
98        instruction_table[VMInstruction::Launch as usize] = vm_instructions::launch_thread;
99        instruction_table[VMInstruction::Spawn as usize] = vm_instructions::spawn_task;
100
101        // 控制流
102        instruction_table[VMInstruction::Call as usize] = vm_instructions::call_lambda;
103        instruction_table[VMInstruction::AsyncCall as usize] = vm_instructions::async_call;
104        instruction_table[VMInstruction::SyncCall as usize] = vm_instructions::sync_call;
105        instruction_table[VMInstruction::Return as usize] = vm_instructions::return_value;
106        instruction_table[VMInstruction::Raise as usize] = vm_instructions::raise;
107        instruction_table[VMInstruction::Jump as usize] = vm_instructions::jump;
108        instruction_table[VMInstruction::JumpIfFalse as usize] = vm_instructions::jump_if_false;
109
110        // 帧操作
111        instruction_table[VMInstruction::NewFrame as usize] = vm_instructions::new_frame;
112        instruction_table[VMInstruction::PopFrame as usize] = vm_instructions::pop_frame;
113        instruction_table[VMInstruction::ResetStack as usize] = vm_instructions::clear_stack;
114        instruction_table[VMInstruction::Pop as usize] = vm_instructions::discard_top;
115
116        // 模块操作
117        instruction_table[VMInstruction::Import as usize] = vm_instructions::import;
118
119        instruction_table[VMInstruction::Assert as usize] = vm_instructions::assert;
120
121        instruction_table
122    });
123
124pub struct OnionLambdaRunnable {
125    pub(crate) argument: OnionStaticObject,
126    pub(crate) result: OnionStaticObject,
127    pub(crate) this_lambda: OnionStaticObject,
128    pub(crate) context: Context,
129    pub(crate) ip: isize, // Instruction pointer
130    pub(crate) instruction: Arc<VMInstructionPackage>,
131}
132
133impl OnionLambdaRunnable {
134    pub fn new(
135        argument: OnionStaticObject,
136        self_object: &OnionObject,
137        this_lambda: &OnionStaticObject,
138        instruction: Arc<VMInstructionPackage>,
139        ip: isize,
140    ) -> Result<Self, RuntimeError> {
141        let mut new_context = Context::new();
142        Context::push_frame(
143            &mut new_context,
144            Frame {
145                variables: rustc_hash::FxHashMap::default(),
146                stack: Vec::new(),
147            },
148        );
149
150        let (index_this, index_self, index_arguments) = {
151            let string_pool = instruction.get_string_pool();
152
153            let index_this = string_pool
154                .iter()
155                .position(|s| s == "this")
156                .ok_or_else(|| {
157                    RuntimeError::InvalidOperation(
158                        "Missing required variable 'this' in string pool"
159                            .to_string()
160                            .into(),
161                    )
162                })?;
163
164            let index_self = string_pool
165                .iter()
166                .position(|s| s == "self")
167                .ok_or_else(|| {
168                    RuntimeError::InvalidOperation(
169                        "Missing required variable 'self' in string pool"
170                            .to_string()
171                            .into(),
172                    )
173                })?;
174
175            let index_arguments = string_pool
176                .iter()
177                .position(|s| s == "arguments")
178                .ok_or_else(|| {
179                    RuntimeError::InvalidOperation(
180                        "Missing required variable 'arguments' in string pool"
181                            .to_string()
182                            .into(),
183                    )
184                })?;
185
186            (index_this, index_self, index_arguments)
187        };
188
189        // 设置内置变量
190        new_context
191            .let_variable(index_this, this_lambda.clone())
192            .map_err(|e| {
193                RuntimeError::InvalidOperation(
194                    format!("Failed to initialize 'this' variable: {}", e).into(),
195                )
196            })?;
197
198        new_context
199            .let_variable(index_self, self_object.stabilize())
200            .map_err(|e| {
201                RuntimeError::InvalidOperation(
202                    format!("Failed to initialize 'self' variable: {}", e).into(),
203                )
204            })?;
205
206        new_context
207            .let_variable(index_arguments, argument.clone())
208            .map_err(|e| {
209                RuntimeError::InvalidOperation(
210                    format!("Failed to initialize 'arguments' variable: {}", e).into(),
211                )
212            })?;
213
214        let pool = instruction.get_string_pool();
215
216        argument.weak().with_data(|data| {
217            if let OnionObject::Tuple(tuple) = data {
218                for item in tuple.get_elements().iter() {
219                    match item {
220                        OnionObject::Named(named) => {
221                            named.get_key().with_data(|key| match key {
222                                OnionObject::String(key_str) => {
223                                    match pool.iter().position(|s| s.eq(key_str.as_ref())) {
224                                        Some(index) => new_context
225                                            .let_variable(index, named.get_value().stabilize()),
226                                        None => {
227                                            // do nothing because the runnable does not need this variable
228                                            Ok(())
229                                        }
230                                    }
231                                }
232                                _ => Ok(()),
233                            })?;
234                        }
235                        _ => {}
236                    }
237                }
238                Ok(())
239            } else {
240                Err(RuntimeError::InvalidOperation(
241                    "Argument must be a tuple".to_string().into(),
242                ))
243            }
244        })?;
245
246        Ok(OnionLambdaRunnable {
247            argument,
248            this_lambda: this_lambda.clone(),
249            result: OnionStaticObject::default(),
250            context: new_context,
251            ip,
252            instruction,
253        })
254    }
255}
256
257impl Runnable for OnionLambdaRunnable {
258    fn receive(
259        &mut self,
260        step_result: &StepResult,
261        _gc: &mut GC<OnionObjectCell>,
262    ) -> Result<(), RuntimeError> {
263        if let StepResult::Return(result) = step_result {
264            self.context.push_object(result.as_ref().clone())?;
265            Ok(())
266        } else {
267            Err(RuntimeError::DetailedError(
268                "receive not implemented for cases except `Return`"
269                    .to_string()
270                    .into(),
271            ))
272        }
273    }
274    fn step(&mut self, gc: &mut GC<OnionObjectCell>) -> StepResult {
275        const MAX_INLINE_STEPS: usize = 1024;
276
277        let mut steps = 0;
278
279        // 获取代码的原始指针和长度,避免借用冲突
280        let (code_ptr, code_len) = {
281            let code = self.instruction.get_code();
282            (code.as_ptr(), code.len())
283        };
284
285        loop {
286            if steps >= MAX_INLINE_STEPS {
287                break;
288            }
289            steps += 1;
290
291            let mut ip = self.ip as usize;
292            if ip >= code_len {
293                return StepResult::Error(RuntimeError::DetailedError(
294                    "Instruction pointer out of bounds".to_string().into(),
295                ));
296            }
297
298            // 使用 unsafe 从原始指针创建切片
299            let code = unsafe { std::slice::from_raw_parts(code_ptr, code_len) };
300            let pending_ip = ip;
301            let opcode = get_processed_opcode(code, &mut ip);
302
303            let handler = unsafe { *INSTRUCTION_TABLE.get_unchecked(opcode.instruction as usize) };
304            self.ip = ip as isize;
305
306            match handler(self, &opcode, gc) {
307                StepResult::Continue => continue,
308                StepResult::Error(RuntimeError::Pending) => {
309                    // 如果是 Pending 状态,继续等待
310                    self.ip = pending_ip as isize; // 恢复 IP
311                    return StepResult::Error(RuntimeError::Pending);
312                }
313                v => return v,
314            }
315        }
316
317        StepResult::Continue
318    }
319    fn copy(&self) -> Box<dyn Runnable> {
320        Box::new(OnionLambdaRunnable {
321            argument: self.argument.clone(),
322            this_lambda: self.this_lambda.clone(),
323            result: self.result.clone(),
324            context: self.context.clone(),
325            ip: self.ip,
326            instruction: self.instruction.clone(),
327        })
328    }
329
330    fn format_context(&self) -> Result<serde_json::Value, RuntimeError> {
331        let mut stack_json_array = serde_json::Value::Array(vec![]);
332        for frame in &self.context.frames {
333            let frame_json = frame.format_context();
334            stack_json_array.as_array_mut().unwrap().push(frame_json);
335        }
336        // {type: "OnionLambdaRunnable", frames: frame_json_array}
337        Ok(serde_json::json!({
338            "type": "lambda_runnable",
339            "frames": stack_json_array,
340            "ip": self.ip,
341            "argument": self.argument.to_string(),
342            "this_lambda": self.this_lambda.to_string(),
343            "result": self.result.to_string(),
344        }))
345    }
346}
347#[cfg(test)]
348mod size_tests {
349    use super::*;
350
351    #[test]
352    fn print_sizes() {
353        println!("StepResult size: {}", std::mem::size_of::<StepResult>());
354        println!("RuntimeError size: {}", std::mem::size_of::<RuntimeError>());
355        println!("StepResult size: {}", std::mem::size_of::<StepResult>());
356    }
357}