refactor: 拆分属性与成员分发并统一 LOAD_CONST 发射

This commit is contained in:
爱特每羊队
2026-06-09 00:27:09 +08:00
parent a0c1181fdc
commit e6ae7fbc46
6 changed files with 574 additions and 645 deletions
+191 -1
View File
@@ -1 +1,191 @@
// dispatch helper functions extracted from vm.rs
use oxide_compiler::opcode::OpCode;
use oxide_types::object::JsObject;
use oxide_types::value::JsValue;
use crate::coercion;
use crate::vm::Vm;
impl Vm {
pub(crate) fn dispatch_member_op(
&mut self,
op: OpCode,
rd: usize,
a: usize,
b: usize,
) -> Result<(), String> {
match op {
OpCode::MEMBER_INC => self.dispatch_member_inc(rd, a, b),
OpCode::MEMBER_DEC => self.dispatch_member_dec(rd, a, b),
OpCode::DYN_MEMBER_INC => self.dispatch_dyn_member_inc(rd, a, b),
OpCode::DYN_MEMBER_DEC => self.dispatch_dyn_member_dec(rd, a, b),
OpCode::COMPOUND_MEMBER_ADD => self.dispatch_compound_member_add(rd, a, b),
OpCode::COMPOUND_MEMBER_SUB => self.dispatch_compound_member_numeric(
rd,
a,
b,
"COMPOUND_MEMBER_SUB on non-object",
|l, r| l - r,
),
OpCode::COMPOUND_MEMBER_MUL => self.dispatch_compound_member_numeric(
rd,
a,
b,
"COMPOUND_MEMBER_MUL on non-object",
|l, r| l * r,
),
OpCode::COMPOUND_MEMBER_DIV => self.dispatch_compound_member_numeric(
rd,
a,
b,
"COMPOUND_MEMBER_DIV on non-object",
|l, r| l / r,
),
OpCode::COMPOUND_MEMBER_MOD => self.dispatch_compound_member_numeric(
rd,
a,
b,
"COMPOUND_MEMBER_MOD on non-object",
|l, r| l % r,
),
OpCode::COMPOUND_MEMBER_EXP => self.dispatch_compound_member_numeric(
rd,
a,
b,
"COMPOUND_MEMBER_EXP on non-object",
|l, r| l.powf(r),
),
_ => unreachable!("non-member opcode passed to dispatch_member_op"),
}
}
fn member_target(
&mut self,
rd: usize,
b: usize,
error_msg: &str,
) -> Result<(*mut JsObject, u32), String> {
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
if obj_ptr.is_null() {
self.raise_type_error(error_msg)?;
return Err(String::new());
}
let prop_name_si = self.property_key_si(self.regs[b]);
Ok((obj_ptr, prop_name_si))
}
fn dispatch_member_inc(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let Ok((obj_ptr, prop_name_si)) = self.member_target(rd, b, "MEMBER_INC on non-object")
else {
return Ok(());
};
let obj = unsafe { &mut *obj_ptr };
let prop_val = self.read_member_prop(obj, prop_name_si);
let n = coercion::to_number(prop_val, self.kernel.string_forge().as_ref());
let new_val = JsValue::float(n + 1.0);
self.set_member_prop(obj, prop_name_si, new_val)?;
self.regs[a] = new_val;
Ok(())
}
fn dispatch_member_dec(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let Ok((obj_ptr, prop_name_si)) = self.member_target(rd, b, "MEMBER_DEC on non-object")
else {
return Ok(());
};
let obj = unsafe { &mut *obj_ptr };
let prop_val = self.read_member_prop(obj, prop_name_si);
let n = coercion::to_number(prop_val, self.kernel.string_forge().as_ref());
let new_val = JsValue::float(n - 1.0);
self.set_member_prop(obj, prop_name_si, new_val)?;
self.regs[a] = new_val;
Ok(())
}
fn dispatch_dyn_member_inc(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
if obj_ptr.is_null() {
self.raise_type_error("DYN_MEMBER_INC on non-object")?;
return Ok(());
}
let obj = unsafe { &mut *obj_ptr };
let prop_name_si = self.property_key_si(self.regs[a]);
let prop_val = self
.resolve_property(obj, prop_name_si)
.unwrap_or(JsValue::undefined());
let n = coercion::to_number(prop_val, self.kernel.string_forge().as_ref());
let new_val = JsValue::float(n + 1.0);
self.set_or_create_prop_value(obj, prop_name_si, new_val);
self.regs[b] = new_val;
Ok(())
}
fn dispatch_dyn_member_dec(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
if obj_ptr.is_null() {
self.raise_type_error("DYN_MEMBER_DEC on non-object")?;
return Ok(());
}
let obj = unsafe { &mut *obj_ptr };
let prop_name_si = self.property_key_si(self.regs[a]);
let prop_val = self
.resolve_property(obj, prop_name_si)
.unwrap_or(JsValue::undefined());
let n = coercion::to_number(prop_val, self.kernel.string_forge().as_ref());
let new_val = JsValue::float(n - 1.0);
self.set_or_create_prop_value(obj, prop_name_si, new_val);
self.regs[b] = new_val;
Ok(())
}
fn dispatch_compound_member_add(
&mut self,
rd: usize,
a: usize,
b: usize,
) -> Result<(), String> {
let Ok((obj_ptr, prop_name_si)) =
self.member_target(rd, b, "COMPOUND_MEMBER_ADD on non-object")
else {
return Ok(());
};
let obj = unsafe { &mut *obj_ptr };
let prop_val = self.read_member_prop(obj, prop_name_si);
let rhs = self.regs[a];
let new_val = if prop_val.is_string() || rhs.is_string() {
let ls = coercion::to_string(self.kernel.string_forge().as_ref(), prop_val);
let rs = coercion::to_string(self.kernel.string_forge().as_ref(), rhs);
self.intern(&format!("{ls}{rs}"))
} else {
let ln = coercion::to_number(prop_val, self.kernel.string_forge().as_ref());
let rn = coercion::to_number(rhs, self.kernel.string_forge().as_ref());
JsValue::float(ln + rn)
};
self.set_member_prop(obj, prop_name_si, new_val)?;
self.regs[a] = new_val;
Ok(())
}
fn dispatch_compound_member_numeric<F>(
&mut self,
rd: usize,
a: usize,
b: usize,
error_msg: &str,
op: F,
) -> Result<(), String>
where
F: FnOnce(f64, f64) -> f64,
{
let Ok((obj_ptr, prop_name_si)) = self.member_target(rd, b, error_msg) else {
return Ok(());
};
let obj = unsafe { &mut *obj_ptr };
let prop_val = self.read_member_prop(obj, prop_name_si);
let ln = coercion::to_number(prop_val, self.kernel.string_forge().as_ref());
let rn = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref());
let new_val = JsValue::float(op(ln, rn));
self.regs[a] = new_val;
self.set_member_prop(obj, prop_name_si, new_val)?;
Ok(())
}
}
+245 -1
View File
@@ -1 +1,245 @@
// dispatch helper functions extracted from vm.rs
use oxide_compiler::opcode::OpCode;
use oxide_kernel::prop_forge::PropTemplate;
use oxide_types::object::JsObject;
use oxide_types::value::JsValue;
use crate::vm::Vm;
impl Vm {
pub(crate) fn dispatch_property_op(
&mut self,
op: OpCode,
rd: usize,
a: usize,
b: usize,
) -> Result<(), String> {
match op {
OpCode::IC_GET_PROP => self.dispatch_ic_get_prop(a, b),
OpCode::IC_SET_PROP => self.dispatch_ic_set_prop(rd, a, b),
OpCode::GET_PROP => self.dispatch_get_prop(rd, a, b),
OpCode::SET_PROP => self.dispatch_set_prop(rd, a, b),
OpCode::GET_PROP_DYNAMIC => self.dispatch_get_prop_dynamic(rd, a, b),
OpCode::SET_PROP_DYNAMIC => self.dispatch_set_prop_dynamic(rd, a, b),
OpCode::SET_ELEM => self.dispatch_set_elem(rd, a, b),
_ => unreachable!("non-property opcode passed to dispatch_property_op"),
}
}
fn dispatch_ic_get_prop(&mut self, a: usize, b: usize) -> Result<(), String> {
let val = self.regs[a];
let obj_ptr = val.as_object_ptr() as *mut JsObject;
if obj_ptr.is_null() {
if val.is_string() {
let proto_ptr = self.kernel.builtin_world().string_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &*proto_ptr };
let prop_name_si = self.property_key_si(self.regs[b]);
if let Some(resolved) = self.resolve_property(proto, prop_name_si) {
self.regs[a] = resolved;
self.pc += 3;
return Ok(());
}
}
if val.is_int() || val.is_double() {
let proto_ptr = self.kernel.builtin_world().number_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &*proto_ptr };
let prop_name_si = self.property_key_si(self.regs[b]);
if let Some(resolved) = self.resolve_property(proto, prop_name_si) {
self.regs[a] = resolved;
self.pc += 3;
return Ok(());
}
}
self.raise_type_error("IC_GET_PROP on non-object")?;
return Ok(());
}
let obj = unsafe { &*obj_ptr };
let prop_name_si = self.property_key_si(self.regs[b]);
let ext0 = self.bytecode[self.pc];
let ext1 = self.bytecode[self.pc + 1];
let ext2 = self.bytecode[self.pc + 2];
self.pc += 3;
let cached_shape_id = ext0 & 0x00FF_FFFF;
let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64);
if cached_shape_id != 0 && cached_shape_id == obj.shape_id() && cached_ptr != 0 {
self.regs[a] = unsafe { *(cached_ptr as *const JsValue) };
} else if let Some(template) = self.kernel.prop_forge().get_template(obj.shape_id()) {
if template.prop_name == prop_name_si {
if let Some(ptr) = self.template_prop_ptr(obj, &template) {
self.write_ic_back(obj.shape_id(), ptr);
self.regs[a] = unsafe { *ptr };
} else {
self.regs[a] = self
.resolve_property(obj, prop_name_si)
.unwrap_or(JsValue::undefined());
}
} else {
self.regs[a] = self
.resolve_property(obj, prop_name_si)
.unwrap_or(JsValue::undefined());
}
} else if let Some(val) = self.resolve_property(obj, prop_name_si) {
if let Some(pos) = self
.kernel
.shape_forge()
.lookup_position(obj.shape_id(), prop_name_si)
{
if let Some(ptr) = obj.prop_ptr_at(pos) {
self.write_ic_back(obj.shape_id(), ptr);
}
}
self.regs[a] = val;
} else {
self.regs[a] = JsValue::undefined();
}
Ok(())
}
fn dispatch_ic_set_prop(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
if obj_ptr.is_null() {
self.raise_type_error("IC_SET_PROP on non-object")?;
return Ok(());
}
let obj = unsafe { &mut *obj_ptr };
let prop_name_si = self.property_key_si(self.regs[b]);
let ext0 = self.bytecode[self.pc];
let ext1 = self.bytecode[self.pc + 1];
let ext2 = self.bytecode[self.pc + 2];
self.pc += 3;
let cached_shape_id = ext0 & 0x00FF_FFFF;
let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64);
if cached_shape_id != 0 && cached_shape_id == obj.shape_id() && cached_ptr != 0 {
unsafe {
*(cached_ptr as *mut JsValue) = self.regs[a];
}
} else if let Some(pos) = self
.kernel
.shape_forge()
.lookup_position(obj.shape_id(), prop_name_si)
{
obj.set_prop_at(pos, self.regs[a]);
if let Some(ptr) = obj.prop_ptr_at(pos) {
self.write_ic_back(obj.shape_id(), ptr);
}
} else {
let new_shape_id = self
.kernel
.shape_forge()
.make_shape(obj.shape_id(), prop_name_si);
obj.set_shape_id(new_shape_id);
let new_pos = obj.push_prop(self.regs[a]);
obj.bump_generation();
if let Some(ptr) = obj.prop_ptr_at(new_pos) {
self.write_ic_back(new_shape_id, ptr);
self.kernel.prop_forge().upsert(
new_shape_id,
PropTemplate {
shape_id: new_shape_id,
prop_name: prop_name_si,
position: new_pos,
generation: obj.generation(),
},
);
}
}
Ok(())
}
fn dispatch_get_prop(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
if obj_ptr.is_null() {
self.raise_type_error("GET_PROP on non-object")?;
return Ok(());
}
let obj = unsafe { &*obj_ptr };
let prop_name_si = self.property_key_si(self.regs[b]);
self.regs[a] = self
.resolve_property(obj, prop_name_si)
.unwrap_or(JsValue::undefined());
Ok(())
}
fn dispatch_set_prop(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
if obj_ptr.is_null() {
self.raise_type_error("SET_PROP on non-object")?;
return Ok(());
}
let obj = unsafe { &mut *obj_ptr };
let prop_name_si = self.property_key_si(self.regs[b]);
if let Some(pos) = self
.kernel
.shape_forge()
.lookup_position(obj.shape_id(), prop_name_si)
{
obj.set_prop_at(pos, self.regs[a]);
} else {
let new_shape_id = self
.kernel
.shape_forge()
.make_shape(obj.shape_id(), prop_name_si);
obj.set_shape_id(new_shape_id);
obj.push_prop(self.regs[a]);
obj.bump_generation();
}
Ok(())
}
fn dispatch_get_prop_dynamic(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
if obj_ptr.is_null() {
self.raise_type_error("GET_PROP_DYNAMIC on non-object")?;
return Ok(());
}
let obj = unsafe { &*obj_ptr };
let prop_name_si = self.property_key_si(self.regs[a]);
self.regs[b] = self
.resolve_property(obj, prop_name_si)
.unwrap_or(JsValue::undefined());
Ok(())
}
fn dispatch_set_prop_dynamic(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
if obj_ptr.is_null() {
self.raise_type_error("SET_PROP_DYNAMIC on non-object")?;
return Ok(());
}
let obj = unsafe { &mut *obj_ptr };
let prop_name_si = self.property_key_si(self.regs[a]);
if let Some(pos) = self
.kernel
.shape_forge()
.lookup_position(obj.shape_id(), prop_name_si)
{
obj.set_prop_at(pos, self.regs[b]);
} else {
let new_shape_id = self
.kernel
.shape_forge()
.make_shape(obj.shape_id(), prop_name_si);
obj.set_shape_id(new_shape_id);
obj.push_prop(self.regs[b]);
obj.bump_generation();
}
Ok(())
}
fn dispatch_set_elem(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
if obj_ptr.is_null() {
self.raise_type_error("SET_ELEM on non-object")?;
return Ok(());
}
let idx = self.regs[a].as_int().max(0) as u32;
let obj = unsafe { &mut *obj_ptr };
obj.set_prop_at(idx, self.regs[b]);
Ok(())
}
}