onion_vm/types/lambda/
runnable.rs

1use std::{ptr::addr_eq, sync::Arc};
2
3use arc_gc::gc::GC;
4use unicode_width::UnicodeWidthStr;
5
6use crate::{
7    lambda::runnable::{Runnable, RuntimeError, StepResult},
8    types::{
9        lambda::vm_instructions::opcode::{
10            self, OpcodeArgument, build_operand_argument, decode_opcode, get_operand_arg,
11            get_processed_opcode,
12        },
13        object::{OnionObject, OnionObjectCell, OnionStaticObject},
14    },
15    utils::{fastmap::OnionFastMap, find_line_and_col_from_source},
16};
17
18use super::{
19    context::{Context, Frame},
20    vm_instructions::{
21        self,
22        instruction_set::{VMInstruction, VMInstructionPackage},
23        opcode::ProcessedOpcode,
24    },
25};
26
27type InstructionHandler =
28    fn(&mut OnionLambdaRunnable, &ProcessedOpcode, &mut GC<OnionObjectCell>) -> StepResult;
29
30// 静态指令表,在程序启动时初始化一次
31static INSTRUCTION_TABLE: std::sync::LazyLock<Vec<InstructionHandler>> =
32    std::sync::LazyLock::new(|| {
33        let mut instruction_table: Vec<InstructionHandler> = vec![
34        |_, opcode, _| StepResult::Error(RuntimeError::DetailedError(format!("Invalid instruction: {:?}", opcode).into())); // 默认处理函数 - 返回无效指令错误
35        256 // 数组大小,确保能容纳所有可能的操作码
36    ];
37
38        // 使用枚举值作为索引,填充对应的处理函数
39        // 栈操作
40        instruction_table[VMInstruction::LoadNull as usize] = vm_instructions::load_null;
41        instruction_table[VMInstruction::LoadInt32 as usize] = vm_instructions::load_int;
42        instruction_table[VMInstruction::LoadInt64 as usize] = vm_instructions::load_int;
43        instruction_table[VMInstruction::LoadFloat32 as usize] = vm_instructions::load_float;
44        instruction_table[VMInstruction::LoadFloat64 as usize] = vm_instructions::load_float;
45        instruction_table[VMInstruction::LoadString as usize] = vm_instructions::load_string;
46        instruction_table[VMInstruction::LoadBytes as usize] = vm_instructions::load_bytes;
47        instruction_table[VMInstruction::LoadBool as usize] = vm_instructions::load_bool;
48        instruction_table[VMInstruction::LoadLambda as usize] = vm_instructions::load_lambda;
49        instruction_table[VMInstruction::LoadUndefined as usize] = vm_instructions::load_undefined;
50
51        // 数据结构构建
52        instruction_table[VMInstruction::BuildTuple as usize] = vm_instructions::build_tuple;
53        instruction_table[VMInstruction::BuildKeyValue as usize] = vm_instructions::build_keyval;
54        instruction_table[VMInstruction::BuildRange as usize] = vm_instructions::build_range;
55        instruction_table[VMInstruction::BuildSet as usize] = vm_instructions::build_set;
56        // 二元操作符
57        instruction_table[VMInstruction::BinaryIn as usize] = vm_instructions::is_in;
58        instruction_table[VMInstruction::BinaryIs as usize] = vm_instructions::check_is_same_object;
59
60        instruction_table[VMInstruction::BinaryAdd as usize] = vm_instructions::binary_add;
61        instruction_table[VMInstruction::BinarySub as usize] = vm_instructions::binary_subtract;
62        instruction_table[VMInstruction::BinaryMul as usize] = vm_instructions::binary_multiply;
63        instruction_table[VMInstruction::BinaryDiv as usize] = vm_instructions::binary_divide;
64        instruction_table[VMInstruction::BinaryMod as usize] = vm_instructions::binary_modulus;
65        instruction_table[VMInstruction::BinaryPow as usize] = vm_instructions::binary_power;
66        instruction_table[VMInstruction::BinaryBitAnd as usize] =
67            vm_instructions::binary_bitwise_and;
68        instruction_table[VMInstruction::BinaryBitOr as usize] = vm_instructions::binary_bitwise_or;
69        instruction_table[VMInstruction::BinaryBitXor as usize] =
70            vm_instructions::binary_bitwise_xor;
71        instruction_table[VMInstruction::BinaryShl as usize] = vm_instructions::binary_shift_left;
72        instruction_table[VMInstruction::BinaryShr as usize] = vm_instructions::binary_shift_right;
73        instruction_table[VMInstruction::BinaryEq as usize] = vm_instructions::binary_equal;
74        instruction_table[VMInstruction::BinaryNe as usize] = vm_instructions::binary_not_equal;
75        instruction_table[VMInstruction::BinaryGt as usize] = vm_instructions::binary_greater;
76        instruction_table[VMInstruction::BinaryLt as usize] = vm_instructions::binary_less;
77        instruction_table[VMInstruction::BinaryGe as usize] = vm_instructions::binary_greater_equal;
78        instruction_table[VMInstruction::BinaryLe as usize] = vm_instructions::binary_less_equal;
79        instruction_table[VMInstruction::MapTo as usize] = vm_instructions::map_to;
80
81        // 一元操作
82        instruction_table[VMInstruction::UnaryBitNot as usize] = vm_instructions::unary_bitwise_not;
83        instruction_table[VMInstruction::UnaryAbs as usize] = vm_instructions::unary_plus;
84        instruction_table[VMInstruction::UnaryNeg as usize] = vm_instructions::unary_minus;
85
86        // 变量与引用
87        instruction_table[VMInstruction::StoreVar as usize] = vm_instructions::let_var;
88        instruction_table[VMInstruction::LoadVar as usize] = vm_instructions::get_var;
89        instruction_table[VMInstruction::SetValue as usize] = vm_instructions::set_var;
90        instruction_table[VMInstruction::GetAttr as usize] = vm_instructions::get_attr;
91        instruction_table[VMInstruction::KeyOf as usize] = vm_instructions::key_of;
92        instruction_table[VMInstruction::ValueOf as usize] = vm_instructions::value_of;
93        instruction_table[VMInstruction::TypeOf as usize] = vm_instructions::type_of;
94        instruction_table[VMInstruction::Swap as usize] = vm_instructions::swap;
95        instruction_table[VMInstruction::LengthOf as usize] = vm_instructions::get_length;
96        instruction_table[VMInstruction::Mut as usize] = vm_instructions::mutablize;
97        instruction_table[VMInstruction::Const as usize] = vm_instructions::immutablize;
98        instruction_table[VMInstruction::ForkInstruction as usize] =
99            vm_instructions::fork_instruction;
100        instruction_table[VMInstruction::Launch as usize] = vm_instructions::launch_thread;
101        instruction_table[VMInstruction::Spawn as usize] = vm_instructions::spawn_task;
102        instruction_table[VMInstruction::MakeAtomic as usize] = vm_instructions::make_atomic;
103        instruction_table[VMInstruction::MakeAsync as usize] = vm_instructions::make_async;
104        instruction_table[VMInstruction::MakeSync as usize] = vm_instructions::make_sync;
105
106        // 控制流
107        instruction_table[VMInstruction::Apply as usize] = vm_instructions::apply;
108        instruction_table[VMInstruction::Return as usize] = vm_instructions::return_value;
109        instruction_table[VMInstruction::Raise as usize] = vm_instructions::raise;
110        instruction_table[VMInstruction::Jump as usize] = vm_instructions::jump;
111        instruction_table[VMInstruction::JumpIfFalse as usize] = vm_instructions::jump_if_false;
112
113        // 帧操作
114        instruction_table[VMInstruction::NewFrame as usize] = vm_instructions::new_frame;
115        instruction_table[VMInstruction::PopFrame as usize] = vm_instructions::pop_frame;
116        instruction_table[VMInstruction::ResetStack as usize] = vm_instructions::clear_stack;
117        instruction_table[VMInstruction::Pop as usize] = vm_instructions::discard_top;
118
119        // 模块操作
120        instruction_table[VMInstruction::Import as usize] = vm_instructions::import;
121
122        instruction_table[VMInstruction::Assert as usize] = vm_instructions::assert;
123
124        instruction_table
125    });
126
127pub struct OnionLambdaRunnable {
128    pub(crate) context: Context,
129    pub(crate) ip: isize,             // Instruction pointer
130    pub(crate) ip_before_step: isize, // previous instruction pointer
131    pub(crate) instruction: Arc<VMInstructionPackage>,
132}
133
134impl OnionLambdaRunnable {
135    pub fn new(
136        argument: &OnionFastMap<Box<str>, OnionStaticObject>,
137        capture: &OnionFastMap<Box<str>, OnionObject>,
138        self_object: &OnionObject,
139        this_lambda: &OnionStaticObject,
140        instruction: Arc<VMInstructionPackage>,
141        ip: isize,
142    ) -> Result<Self, RuntimeError> {
143        if !addr_eq(argument.pool().keys(), instruction.get_string_pool()) {
144            panic!(
145                "Argument pool does not match instruction string pool: {:?} != {:?}",
146                argument.pool().keys(),
147                instruction.get_string_pool()
148            );
149        }
150        if !addr_eq(capture.pool().keys(), instruction.get_string_pool()) {
151            panic!(
152                "Capture pool does not match instruction string pool: {:?} != {:?}",
153                capture.pool().keys(),
154                instruction.get_string_pool()
155            );
156        }
157
158        let mut new_context = Context::new();
159        Context::push_frame(
160            &mut new_context,
161            Frame {
162                variables: rustc_hash::FxHashMap::default(),
163                stack: Vec::new(),
164            },
165        );
166
167        let index_this = instruction.get_string_index("this").ok_or_else(|| {
168            RuntimeError::InvalidOperation(
169                "Missing required variable 'this' in string pool"
170                    .to_string()
171                    .into(),
172            )
173        })?;
174        let index_self = instruction.get_string_index("self").ok_or_else(|| {
175            RuntimeError::InvalidOperation(
176                "Missing required variable 'self' in string pool"
177                    .to_string()
178                    .into(),
179            )
180        })?;
181        /*
182        let index_arguments = string_pool
183            .iter()
184            .position(|s| s == "arguments")
185            .ok_or_else(|| {
186                RuntimeError::InvalidOperation(
187                    "Missing required variable 'arguments' in string pool"
188                        .to_string()
189                        .into(),
190                )
191            })?;
192        */
193
194        // 设置内置变量
195        new_context
196            .let_variable(index_this, this_lambda.clone())
197            .map_err(|e| {
198                RuntimeError::InvalidOperation(
199                    format!("Failed to initialize 'this' variable: {}", e).into(),
200                )
201            })?;
202
203        new_context
204            .let_variable(index_self, self_object.stabilize())
205            .map_err(|e| {
206                RuntimeError::InvalidOperation(
207                    format!("Failed to initialize 'self' variable: {}", e).into(),
208                )
209            })?;
210
211        // new_context
212        //     .let_variable(index_arguments, build_dict_from_hashmap(argument))
213        //     .map_err(|e| {
214        //         RuntimeError::InvalidOperation(
215        //             format!("Failed to initialize 'arguments' variable: {}", e).into(),
216        //         )
217        //     })?;
218
219        for (argument_index, value) in argument.pairs() {
220            new_context
221                .let_variable(*argument_index, value.clone())
222                .map_err(|e| {
223                    RuntimeError::InvalidOperation(
224                        format!("Failed to initialize argument '{}': {}", argument_index, e).into(),
225                    )
226                })?;
227        }
228
229        // 设置捕获的变量
230        for (capture_index, value) in capture.pairs() {
231            new_context
232                .let_variable(*capture_index, value.stabilize())
233                .map_err(|e| {
234                    RuntimeError::InvalidOperation(
235                        format!(
236                            "Failed to initialize captured variable '{}': {}",
237                            capture_index, e
238                        )
239                        .into(),
240                    )
241                })?;
242        }
243
244        Ok(OnionLambdaRunnable {
245            context: new_context,
246            ip,
247            ip_before_step: ip,
248            instruction,
249        })
250    }
251}
252
253impl Runnable for OnionLambdaRunnable {
254    fn receive(
255        &mut self,
256        step_result: &StepResult,
257        _gc: &mut GC<OnionObjectCell>,
258    ) -> Result<(), RuntimeError> {
259        if let StepResult::Return(result) = step_result {
260            self.context.push_object(result.as_ref().clone())?;
261            Ok(())
262        } else {
263            Err(RuntimeError::DetailedError(
264                "receive not implemented for cases except 'Return'"
265                    .to_string()
266                    .into(),
267            ))
268        }
269    }
270    fn step(&mut self, gc: &mut GC<OnionObjectCell>) -> StepResult {
271        const MAX_INLINE_STEPS: usize = 1024;
272
273        let mut steps = 0;
274
275        // 获取代码的原始指针和长度,避免借用冲突
276        let (code_ptr, code_len) = {
277            let code = self.instruction.get_code();
278            (code.as_ptr(), code.len())
279        };
280
281        loop {
282            if steps >= MAX_INLINE_STEPS {
283                break;
284            }
285            steps += 1;
286
287            let mut ip = self.ip as usize;
288            if ip >= code_len {
289                return StepResult::Error(RuntimeError::DetailedError(
290                    "Instruction pointer out of bounds".into(),
291                ));
292            }
293
294            // 使用 unsafe 从原始指针创建切片
295            let code = unsafe { std::slice::from_raw_parts(code_ptr, code_len) };
296            let pending_ip = ip;
297            let opcode = get_processed_opcode(code, &mut ip);
298
299            let handler = unsafe { *INSTRUCTION_TABLE.get_unchecked(opcode.instruction as usize) };
300            self.ip = ip as isize;
301            self.ip_before_step = pending_ip as isize; // 保存上一步的 IP
302
303            match handler(self, &opcode, gc) {
304                StepResult::Continue => continue,
305                StepResult::Error(e) => {
306                    self.ip = pending_ip as isize; // 恢复 IP
307                    return StepResult::Error(e);
308                }
309                v => return v,
310            }
311        }
312
313        StepResult::Continue
314    }
315
316    fn format_context(&self) -> String {
317        let ip = self.ip_before_step as usize;
318        let mut parts = Vec::new();
319
320        // 尝试获取详细的源码位置信息
321        if let Some(location) = get_source_location_for_ip(&self.instruction, ip) {
322            // --- Part 1: 高级、人类可读的上下文 ---
323            parts.push(format!("-> at {}:{}", location.line, location.column));
324            parts.push(location.code_snippet);
325        } else {
326            // --- Part 1 (回退): 原始的、无源码的上下文 ---
327            let disassembly = disassemble_instruction(&self.instruction, ip); // 假设这个函数存在
328            parts.push(format!("-> Executing VM Code at ip: {}", ip));
329            parts.push(format!("  - Current Instruction: {}", disassembly));
330        }
331
332        // --- Part 2: VM 调用栈和操作数栈状态 ---
333        let context_state = self.context.format_context(self.instruction.as_ref());
334        parts.push("\n--- Lambda Execution State ---".to_string());
335        parts.push(context_state);
336
337        parts.join("\n")
338    }
339}
340
341/// 反汇编函数:将给定 IP 位置的指令转换为人类可读的字符串。
342///
343/// 此版本适配了变长指令集,其中第一个 u32 word 是元数据,
344/// 后续的 words 是操作数的实际值。
345pub fn disassemble_instruction(package: &VMInstructionPackage, ip: usize) -> String {
346    let code = package.get_code();
347    if ip >= code.len() {
348        return format!("<IP:{} out of bounds>", ip);
349    }
350
351    // --- 1. 解码元数据 ---
352    // 我们需要一个可变的指针来模拟执行过程,但不能影响原始 ip
353    let mut temp_ip = ip;
354    let opcode_word = opcode::take_u32(code, &mut temp_ip);
355    let decoded_opcode = decode_opcode(opcode_word);
356
357    // --- 2. 获取操作数的原始值 ---
358    // 注意:这里我们只读取值,但不解释它们,因为格式化依赖于标志
359    let mut next_ip = temp_ip; // 保存操作数开始的位置
360    let raw_operand1 = get_operand_arg(code, &mut next_ip, decoded_opcode.operand1());
361    let raw_operand2 = get_operand_arg(code, &mut next_ip, decoded_opcode.operand2());
362    let raw_operand3 = get_operand_arg(code, &mut next_ip, decoded_opcode.operand3());
363
364    // --- 3. 格式化每个操作数 ---
365    // 这是一个辅助闭包,用于将单个操作数格式化为字符串
366    let format_operand = |flag: u8, raw_value: u64| -> Option<String> {
367        // 使用你的 'build_operand_argument' 来获取结构化的操作数类型
368        let arg = build_operand_argument(flag, raw_value);
369
370        match arg {
371            OpcodeArgument::None => None,
372            OpcodeArgument::Int32(v) => Some(format!("{}", v)),
373            OpcodeArgument::Int64(v) => Some(format!("{}L", v)), // 'L' for long
374            OpcodeArgument::Float32(v) => Some(format!("{}f", v)), // 'f' for float
375            OpcodeArgument::Float64(v) => Some(format!("{}", v)),
376            OpcodeArgument::String(idx) => {
377                let s = package
378                    .get_string_pool()
379                    .get(idx as usize)
380                    .map(|s| format!("Str({}) -> \"{}\"", idx, s))
381                    .unwrap_or_else(|| format!("Str({}) -> <Invalid>", idx));
382                Some(s)
383            }
384            OpcodeArgument::ByteArray(idx) => {
385                let b = package
386                    .get_bytes_pool()
387                    .get(idx as usize)
388                    .map(|b| format!("Bytes({}) -> {:X?}", idx, b))
389                    .unwrap_or_else(|| format!("Bytes({}) -> <Invalid>", idx));
390                Some(b)
391            }
392        }
393    };
394
395    let op1_str = format_operand(decoded_opcode.operand1(), raw_operand1);
396    let op2_str = format_operand(decoded_opcode.operand2(), raw_operand2);
397    let op3_str = format_operand(decoded_opcode.operand3(), raw_operand3);
398
399    // --- 4. 组合最终的字符串 ---
400    let instruction_name = VMInstruction::from_opcode(decoded_opcode.instruction())
401        .map(|instr| format!("{:?}", instr))
402        .unwrap_or_else(|| format!("Invalid({})", decoded_opcode.instruction()));
403
404    let parts = vec![op1_str, op2_str, op3_str];
405    // 过滤掉 None 的操作数
406    let operands_str = parts
407        .into_iter()
408        .filter_map(|p| p)
409        .collect::<Vec<String>>()
410        .join(", ");
411
412    if operands_str.is_empty() {
413        instruction_name
414    } else {
415        format!("{} {}", instruction_name, operands_str)
416    }
417}
418#[derive(Debug)]
419pub struct SourceLocation {
420    pub line: usize,
421    pub column: usize,
422    // 包含高亮的代码片段,例如:
423    //   "  12 | let x = 10 / 0;\n"
424    //   "     |         ^^^^^^"
425    pub code_snippet: String,
426}
427
428pub fn get_source_location_for_ip(
429    package: &VMInstructionPackage,
430    ip: usize,
431) -> Option<SourceLocation> {
432    let source = package.get_source().as_ref()?;
433    let debug_info = package.get_debug_info().get(&ip)?;
434
435    let (span_start, span_end) = debug_info.token_span();
436
437    if span_start >= span_end {
438        return None;
439    }
440
441    let (line_idx, col_char_idx) = find_line_and_col_from_source(span_start, source);
442    let line_content = source.lines().nth(line_idx).unwrap_or("");
443
444    let error_token_text: String = source
445        .chars()
446        .skip(span_start)
447        .take(span_end - span_start)
448        .collect();
449
450    let display_offset = line_content
451        .chars()
452        .take(col_char_idx)
453        .collect::<String>()
454        .width();
455
456    let underline_width = error_token_text.width();
457
458    let line_num_width = 5;
459    let line_num = line_idx + 1;
460
461    let code_snippet = format!(
462        " {:>width$} | {}\n {empty:>width$} | {padding}{underline}",
463        line_num,
464        line_content,
465        empty = "",
466        padding = " ".repeat(display_offset),
467        underline = "^".repeat(underline_width),
468        width = line_num_width
469    );
470
471    Some(SourceLocation {
472        line: line_num,
473        column: col_char_idx + 1,
474        code_snippet,
475    })
476}
477#[cfg(test)]
478mod size_tests {
479    use super::*;
480
481    #[test]
482    fn print_sizes() {
483        println!("StepResult size: {}", std::mem::size_of::<StepResult>());
484        println!("RuntimeError size: {}", std::mem::size_of::<RuntimeError>());
485        println!("StepResult size: {}", std::mem::size_of::<StepResult>());
486    }
487}