refactor: 拆分 dispatch 控制流辅助逻辑

This commit is contained in:
爱特每羊队
2026-06-14 00:28:34 +08:00
parent 18f4fe4000
commit 2518b08be1
3 changed files with 219 additions and 177 deletions
+192
View File
@@ -0,0 +1,192 @@
use crate::vm::{FrameContinuation, TryHandler, Vm};
use oxide_compiler::opcode;
use oxide_types::object::PropAttributes;
use oxide_types::value::JsValue;
impl Vm {
pub(crate) fn dispatch_call(&mut self, rd: usize, a: usize, b: usize) -> Result<bool, String> {
let callee_reg = rd;
let this_reg = a as u8;
let first_arg_reg = b as u8;
let callee = self.regs[callee_reg];
if callee.is_object() {
let obj_ptr = callee.as_js_object_ptr();
if !obj_ptr.is_null() {
let obj = unsafe { &*obj_ptr };
if obj.is_function() {
if obj.is_class_constructor() {
return self
.raise_type_error("class constructor cannot be invoked without 'new'")
.map(|_| true);
}
let ext = self.bytecode[self.pc];
self.pc += 1;
let arg_count = (ext & 0xFF) as usize;
oxide_kernel::vm_debug!(
"CALL rd={} this={} args={} depth={}",
rd,
this_reg,
arg_count,
self.frames.len()
);
if obj.native_fn().is_some() {
self.dispatch_native_call(obj, callee, this_reg, first_arg_reg, arg_count)?;
return Ok(true);
} else if obj.sub_module_index() > 0 {
let args: Vec<JsValue> = (0..arg_count)
.map(|i| self.regs[first_arg_reg.wrapping_add(i as u8) as usize])
.collect();
self.push_bytecode_frame(
callee,
self.regs[this_reg as usize],
&args,
None,
None,
JsValue::undefined(),
FrameContinuation::None,
)?;
return Ok(true);
}
}
}
}
self.raise_type_error("CALL target is not callable").map(|_| true)
}
pub(crate) fn dispatch_call_native(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let callee_reg = rd;
let this_reg = a as u8;
let first_arg_reg = b as u8;
let callee = self.regs[callee_reg];
if !callee.is_object() {
return self.raise_type_error("CALL_NATIVE target is not an object");
}
let obj_ptr = callee.as_js_object_ptr();
if obj_ptr.is_null() {
return self.raise_type_error("CALL_NATIVE target is null");
}
let obj = unsafe { &*obj_ptr };
if !obj.is_function() || obj.native_fn().is_none() {
return self.raise_type_error("CALL_NATIVE target is not a native function");
}
let ext = self.bytecode[self.pc];
self.pc += 1;
let arg_count = (ext & 0xFF) as usize;
oxide_kernel::vm_debug!("CALL_NATIVE rd={} args={}", rd, arg_count);
self.dispatch_native_call(obj, callee, this_reg, first_arg_reg, arg_count)
}
pub(crate) fn dispatch_define_accessor(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let prop_idx = self.bytecode[self.pc] as usize;
self.pc += 1;
if prop_idx >= self.constants.len() {
return self.raise_type_error("DEFINE_ACCESSOR constant index out of bounds");
}
let obj_val = self.regs[rd];
if !obj_val.is_object() {
return self.raise_type_error("DEFINE_ACCESSOR target is not object");
}
let prop_name_si = self.property_key_si(self.constants[prop_idx]);
let getter = self.regs[a];
let setter = self.regs[b];
let obj = unsafe { &mut *obj_val.as_js_object_ptr() };
let existing = self
.get_own_property_slot(obj, prop_name_si)
.and_then(|pos| obj.prop_meta_at(pos))
.filter(|meta| meta.is_accessor);
let get = if getter.is_undefined() {
existing.map(|meta| meta.get).unwrap_or(JsValue::undefined())
} else {
getter
};
let set = if setter.is_undefined() {
existing.map(|meta| meta.set).unwrap_or(JsValue::undefined())
} else {
setter
};
self.define_accessor_property(obj, prop_name_si, get, set, PropAttributes::DEFAULT_DATA)
}
pub(crate) fn dispatch_return(&mut self, rd: usize) -> Result<Option<JsValue>, String> {
let result = self.regs[rd];
oxide_kernel::vm_debug!("RETURN depth={}", self.frames.len());
if let Some(frame) = self.frames.pop() {
let construct_result_reg = frame.construct_result_reg;
let constructed_this = frame.constructed_this;
let is_derived_constructor = frame.is_derived_constructor;
let continuation = frame.continuation;
let callee_this = self.regs[254];
self.restore_frame(frame);
if let (Some(target_reg), Some(constructed_this)) = (construct_result_reg, constructed_this) {
if is_derived_constructor && result.is_undefined() && callee_this.is_undefined() {
self.raise_error_kind("ReferenceError", "derived constructor must call super()")?;
return Ok(None);
}
self.regs[target_reg as usize] = if result.is_object() { result } else { constructed_this };
self.regs[0] = self.regs[target_reg as usize];
} else {
match continuation {
FrameContinuation::None => self.regs[0] = result,
FrameContinuation::AccessorGet { target_reg } => self.regs[target_reg as usize] = result,
FrameContinuation::AccessorSet => {}
}
}
Ok(None)
} else {
Ok(Some(result))
}
}
pub(crate) fn dispatch_throw(&mut self, rd: usize) -> Result<bool, String> {
oxide_kernel::vm_debug!("THROW pc={}", self.pc);
let exc_value = self.regs[rd];
self.exception_value = Some(exc_value);
self.pending_error_kind = Some(self.thrown_error_kind(exc_value));
self.unwind().map(|_| true)
}
pub(crate) fn dispatch_try_begin(&mut self, instr: u32) {
oxide_kernel::vm_trace!("TRY_BEGIN frame_depth={}", self.frames.len());
let offset = opcode::offset16(instr) as isize;
let catch_pc = if offset == 0 {
None
} else {
Some(((self.pc as isize) + offset - 1) as usize)
};
self.try_stack.push(TryHandler {
catch_pc,
finally_pc: None,
frame_depth: self.frames.len(),
});
}
pub(crate) fn dispatch_try_end(&mut self) {
self.try_stack.pop();
}
pub(crate) fn dispatch_try_finally_begin(&mut self, instr: u32) {
let offset = opcode::offset16(instr) as isize;
let finally_pc = ((self.pc as isize) + offset - 1) as usize;
self.try_stack.push(TryHandler {
catch_pc: None,
finally_pc: Some(finally_pc),
frame_depth: self.frames.len(),
});
}
pub(crate) fn dispatch_try_finally_end(&mut self) -> Result<bool, String> {
self.try_stack.pop();
if self.pending_exception.is_some() && self.exception_value.is_none() {
self.exception_value = self.pending_exception.take();
self.unwind().map(|_| true)
} else {
self.pending_exception = None;
Ok(false)
}
}
}